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

}

经过实验,证明修改成功!

posted @ 2020-03-30 14:36  一把水果刀  阅读(3178)  评论(0编辑  收藏  举报