Spring打印请求响应日志的两种方式

Spring打印请求响应日志的两种方式


第一种:Filter拦截Request、Response

@WebFilter(urlPatterns="/*")
public class WebFilter implements Filter {
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        //请求URI
        String requestUril = httpServletRequest.getRequestURI();
        //请求方法
        String method = httpServlet.getMethod();
        //请求ip
        String ip = HttpUtils.getIp(httpServletRequest);
        //请求内容类型
        String contentType = servletRequest.getContentType();
        
        //使用包装器类型封装request response
        RequestWrapper requestWrapper = new RequestWrapper(httpServletRequest);
        ResponseWrapper responseWrapper = new ResponseWrapper(httpServletResponse);
        String param = parseParams(requestWrapper);
        //继续请求调用连
        filterChain.doFilter(requestWrapper, responseWrapper);
        String respBody = responseWrapper.getResponseBody();
        //ip 请求方法 url 请求类型 参数 返回值
        log.info("{} {} {} {} {} {}", ip, method, url, contentType, param, respBody);
        
        //因为响应流只能写一次,已经写到responseWrapper离了,所以要把返回值写回到响应提
        byte[] byteArr = respBody.getBytes(StandardCharsets.UTF8);
        httpServletResponse.setStatus(200);
        httpServletResponse.setHeader(MediaType.APPLICATION_JSON_UTF8_VALUE);
        httpServletResponse.setContentLength(byteArr.length);
        httpServletResponse.getOutputStream().write(byteArr);
    }
    
    @Override
    public void destroy() {
    }
    
    private String parseParams(RequestWrapper wrapper) {
        //JSON格式直接返回
        if(MediaType.APPLICATION_JSON_VALUE.equls(wrapper.getContentType())) {
            return wrapper.getBody();
        } 
        //组装参数数组
        else {
            String[] parameters = wrapper.getParameterNames();
            String[] data = new String[parameters.length];
            int i=0;
            for(String name :wrapper.getParameterNames()) {
                data[i++] = name+"="+wrapper.getParameter(name);
            }
            return StringUtils.join(data,"&");
        }
    }
}

第二种:通过RequestBodyAdvice/ResponseBodyAdvice

@ControllerAdvice(annotations = {Controller.class, RestController.class})
public class WebRequestHandler implements RequestBodyAdvice {

    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        //为true时可以执行建议的方法,即所有请求都执行
        return true;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return inputMessage;
    }

    @Override
    public HttpInputMessage beforeBodyRead(final HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        return inputMessage;
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        String method = parameter.getMethod().getName();
        StringBuilder sb = new StringBuilder();
        sb.append("请求:"+method);
        sb.append("类:" + parameter.getDeclaringClass().getName());
        sb.append("方法:"+parameter.getMethod().getName());
        sb.append("入参:"+String.valueOf(body));
        System.out.println(sb.toString());
        return body;
    }

}
@ControllerAdvice(annotations = {Controller.class, RestController.class})
public class WebResponseHandler implements ResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        String requestPath = serverHttpRequest.getURI().getPath();
        StringBuilder sb = new StringBuilder();
        sb.append("路径:" + requestPath);
        sb.append("返回结果:" + JSON.toJSONString(o));
        System.out.println(sb.toString());
        return o;
    }

}

在这里踩了一个坑,即不能同时继承,否则会出现问题:requestAdvice执行两次而resposneAdvice不执行。探索了下原因是RequestResponseBodyAdviceChain.initAdvice方法中,if-else结构导致不能同时继承。

if (RequestBodyAdvice.class.isAssignableFrom(beanType)) {
				this.requestBodyAdvice.add(advice);
			}
			else if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
				this.responseBodyAdvice.add(advice);
			}
  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:精致技术 设计师:CSDN官方博客 返回首页
评论

打赏作者

程序员小辰

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值