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;
}
}