springboot 如何在请求进入controller之前改变body中的值
springboot 如何在请求进入controller之前改变body中的值
- 拦截器HandlerInterceptorAdapter
通过继承HandlerInterceptorAdapter
拦截器,可以重写preHandle
方法,但是在这个方法里直接对HttpServletRequest
中的body进行更改是无效的。HttpServletRequest
请求实际上并没有改变。
- HttpServletRequestWrapper 请求包装类
通过继承HttpServletRequestWrapper
可以重写自己的包装类。如:
public class MultiReadHttpServletRequestWrapper extends HttpServletRequestWrapper {
private String tempBody;
public MultiReadHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
tempBody = AbstractRequestUtils.getRequestBody(request);
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(tempBody.getBytes());
return new ServletInputStream() {
@Override
public boolean isReady() {
return false;
}
@Override
public int readLine(byte[] b, int off, int len) throws IOException {
return super.readLine(b, off, len);
}
@Override
public boolean isFinished() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() {
return byteArrayInputStream.read();
}
};
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.tempBody;
}
public void setBody(String body) {
this.tempBody = body;
}
}
在这里面定义了一个tempbody,可以防止出现流只能被读取一次而出现的流重读错误。
- 定义一个过滤器,以过滤相应请求,让它们使用包装过的HttpServletRequest。
@Slf4j
public class RequestWrapperFilter implements Filter {
@Override
public void init(FilterConfig config) {
log.info("==>RequestWrapperFilter启动");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws java.io.IOException, ServletException {
MultiReadHttpServletRequestWrapper requestWrapper = new MultiReadHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(requestWrapper, response);
}
@Override
public void destroy() {
}
}
- 在WebMvcConfigurer中注册过滤器(这里也注册了最开始的拦截器)
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public WebInterceptor webInterceptor() {
return new WebInterceptor();
}
@Bean
public FilterRegistrationBean addRequestWrapperFilter() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(new RequestWrapperFilter());
registration.setName("RequestWrapperFilter");
registration.addUrlPatterns("/interest/*");
registration.setOrder(1);
return registration;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(webInterceptor()).addPathPatterns("/interest/**");
}
}
- 在拦截器中对body中的值进行修改
@Slf4j
public class WebInterceptor extends HandlerInterceptorAdapter {
@Resource
private IpVisitService ipVisitService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String ip = HttpUtils.getRemoteIP(request);
log.info("!!!!!!!!!!!!!!!!currentIp:{}", ip);
MultiReadHttpServletRequestWrapper requestWrapper = (MultiReadHttpServletRequestWrapper) request;
String body = requestWrapper.getBody();
Preconditions.checkArgument(!StringUtils.isEmpty(body), "请求参数有误!");
BaseReq baseReq = JSON.parseObject(body, BaseReq.class);
baseReq.setIp(ip);
requestWrapper.setBody(JSON.toJSONString(baseReq));
return true;
}
}