SpringBoot中filter的使用

在使用@RequestBody注解时,我们通常使用如下代码实现功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
@RequestMapping("/category")
public class CategoryController {

@Autowired
private ICategoryService categoryService;

@RequestMapping(value = "/xxx", method = RequestMethod.POST)
@ResponseBody
public Category getAllCategory(@RequestBody Category category) {
category = categoryService.selectById(1);
return category;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@ControllerAdvice
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
ObjectMapper objectMapper = builder.build();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(objectMapper);
List<MediaType> types = Lists.newArrayList();
types.add(MediaType.APPLICATION_JSON);
// types.add(MediaType.TEXT_PLAIN);
converter.setSupportedMediaTypes(types);
converters.add(converter);
super.configureMessageConverters(converters);
}

但是如果请求头信息里,Content-Type不是MediaType.APPLICATION_JSON类型,请求会报450错误。

在尝试解决这个问题时,有两个思路,一是请求必须使用正确的头信息(推荐),二是服务端做拦截兼容。
过程中使用了两种方法达到效果,记录一下。

方法一

将上文中converter配置中添加一个支持类型。

方法二

过滤器(Filter)和拦截器(Interceptor)之间的区别

过滤器可以包装Request和Response,而拦截器并不能,所以为了跳过验证,我们可以使用Filter而不是Interceptor。

如何修改HttpServletRequest的请求头信息?

实际HttpServletRequest并未开放接口提供修改头信息,但是利用过滤器+装饰模式可以达到跳过验证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package com.anruence.filter;

import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.util.Enumeration;

@Component
@ServletComponentScan
@WebFilter(urlPatterns = "/category/*", filterName = "requestFilter")
public class RequestFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) {

}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
String ret = servletRequest.getContentType();
chain.doFilter(new CustomizedRequest((HttpServletRequest) servletRequest), servletResponse);
// chain.doFilter(servletRequest, servletResponse);
String ret1 = servletRequest.getContentType();
}

@Override
public void destroy() {

}

private class CustomizedRequest extends HttpServletRequestWrapper {

public CustomizedRequest(HttpServletRequest request) {
super(request);
}

@Override
public Enumeration<String> getHeaders(String name) {
if (null != name && name.equalsIgnoreCase("Content-Type")) {
return new Enumeration<String>() {
private boolean hasGetted = false;

@Override
public String nextElement() {
if (hasGetted) {
return "";
} else {
hasGetted = true;
return MediaType.APPLICATION_JSON_UTF8_VALUE;
}
}

@Override
public boolean hasMoreElements() {
return !hasGetted;
}
};
}
return super.getHeaders(name);
}
}
}
您的支持将鼓励我继续创作 笔芯