1、定义拦截器

将来所有的日志记录代码就是写在这个里面,包含请求和响应数据的获取

package com.hzzfxx.intercept;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author betieforever
 * @description 描述
 * @date 2022/8/9
 */
public class OperationLogHandlerIntercept implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

2.重新定义DispatcherServlet

之所以重新定义改造,是因为HttpServletRequest 和 HttpServletResponse 这两个类的输出流只能被读取一次,再次读写将会读取不到任何内容,所以采用包装类进行改造,方便取请求的数据和响应的数据。

package com.hzzfxx.util.wrapper;

import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author betieforever
 * @description 自定义改造的servlet
 * @date 2022/8/7
 */
public class TieDispatcherServlet extends DispatcherServlet {
    @Override
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        super.doDispatch(new ContentCachingRequestWrapper(request), new ContentCachingResponseWrapper(response));
    }
}

3.加载拦截器和新的DispatcherServlet核心控制器 

@Configuration
public class HandlerInterceptConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogHandlerIntercept());
        WebMvcConfigurer.super.addInterceptors(registry);
    }

    @Bean
    @Qualifier(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
    public DispatcherServlet dispatcherServlet(){
        return new TieDispatcherServlet();
    }
}

4.定义注解类Annotation

用来标识哪些方法、操作需要被拦截(一般情况下,主要记录一些挂件业务的操作日志)以及简单介绍将要拦截的方法的内容是什么等等

import java.lang.annotation.*;

/**
 * @author betieforever
 * @description 描述
 * @date 2022/8/7
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogOperationAnotation {
    String value() default "暂无配置";
}

5.配置controller中的方法,标识将要拦截的方法,下面是demo的信息

@RestController
public class YjxxController {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @RequestMapping("/getDataYjxx")
    @LogOperationAnotation("预警信息")
    public String getDataYjxx(PageDp pageDp){
        .......
    }
}

6.获取请求request中参数

这个里面数据非常丰富,可以从header中取相关信息,可以根据不同的contentType调用不同的方法来获取数据(此处待补充.....)application/x- www-form-urlencoded 对应formData,可以使用request.getParameter进行获取;当请求体内容是其它类型时,比如 multipart/form-data或application/json时对应payLoad,无法通过request.getParameter()获取到请求内容,此时只能通过request.getInputStream()和request.getReader()方法获取请求内容

 @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       HandlerMethod handlerMethod = (HandlerMethod)handler;
        LogOperationAnotation logOperationAnotation = handlerMethod.getMethodAnnotation(LogOperationAnotation.class);
        ContentCachingResponseWrapper contentResponse = (ContentCachingResponseWrapper)(response);
        if(logOperationAnotation != null){
            String queryString = request.getQueryString();
            String formData = request.getParameterMap().entrySet().toString();
            String xmlJson = JSON.toJSONString(request.getParameterMap());
            String contentType = request.getContentType();
            String body = new String(StreamUtils.copyToByteArray(request.getInputStream()));
            System.out.println("contentType===" + contentType);
            System.out.println("queryString===" + queryString);
            System.out.println("formData===" + formData);
            System.out.println("xmlJson ===" + xmlJson );
            System.out.println("body====" + body);
            String operationName = logOperationAnotation.value();
            System.out.println("operationName===" + operationName);
        }
        return true;
    }

7.取响应中参数

注意ContentCachingResponseWrapper 在取完数据之后需要调用copyBodyToResponse()方法,只有这样响应里面才会有数据返回,否则响应里面 是没有数据的

@Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod)handler;
        LogOperationAnotation logOperationAnotation = handlerMethod.getMethodAnnotation(LogOperationAnotation.class);
        ContentCachingResponseWrapper contentResponse = (ContentCachingResponseWrapper)(response);
        if(logOperationAnotation != null){
            String responseBody= new String(contentResponse.getContentAsByteArray(),contentResponse.getCharacterEncoding());
            System.out.println("responseBody===" + responseBody.substring(0,100));
            System.out.println("responseContentType===" + response.getContentType());
        }
        contentResponse.copyBodyToResponse();

    }

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐