spring boot 添加自定义监听器、过滤器、拦截器

场景1:需要项目启动的时候把数据加载到缓存中去 使用:监听器

1.自定义listenner类 添加@WebListener 实现ServletContextListener


spring boot 添加自定义监听器、过滤器、拦截器_第1张图片
一个注解 一个实现

2.重写contextInitialized方法

    @Override
    public void contextInitialized(ServletContextEvent sce) {

  //当服务启动时候的业务逻辑

    }

3.在启动类添加注解扫描
@EnableScheduling
@ServletComponentScan


spring boot 添加自定义监听器、过滤器、拦截器_第2张图片
指定扫描类

场景2:在Rest接口中,在拦截器位置判断请求体的参数是否签名符合规范,符合放行在handler中进行业务逻辑的处理,不符合直接不进行响应 使用:过滤器+拦截器

这类功能有一些点还是需要注意的

  • 过滤器请求被处理前调用一次,拦截器可以调用多次
  • 过滤器无法直接响应请求
  • 过滤器和拦截器中httpServletRequest中getInputStream()只可读取一次,无法重复读取

想要在拦截器中读取输入流之后,handler依旧可以再次读取输入流需要在过滤器中读取inputStream,之后缓存起来,然后包装httpServletRequest;重写其中getInputStream()方法去拿缓存数据,就可以满足在拦截器处理getInputStream之后,handler依旧可以从httpServletRequest中拿到数据

1.过滤器处理

//过滤顺序
@Order(1)
//过滤器配置
@WebFilter(filterName = "xxxRequestFilter", urlPatterns = "/path/*")
public class xxxRequestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        if (!(request instanceof ApiRequestWrapper)) {
//XXXRequestWrapper是HttpServletRequest包装类
            XXXRequestWrapper xxxRequestWrapper = new XXXRequestWrapper((HttpServletRequest) request);
            chain.doFilter(xxxRequestWrapper, response);
            return;
        }
        chain.doFilter(request,response);
    }
    @Override
    public void destroy() {

    }
}

2.XXXRequestWrapper包装HttpServletRequest 缓存数据

public class XXXRequestWrapper extends HttpServletRequestWrapper {
    
    private byte[] rawData;
    private HttpServletRequest request;
    private ResettableServletInputStream servletStream;

    public XXXRequestWrapper(HttpServletRequest request) {
        super(request);
        this.request = request;
        this.servletStream = new ResettableServletInputStream();

    }


    public void resetInputStream() {
        servletStream.stream = new ByteArrayInputStream(rawData);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (rawData == null) {
            rawData = readBytes(request).getBytes(Charset.forName("UTF-8"));
            servletStream.stream = new ByteArrayInputStream(rawData);
        }
        return servletStream;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        if (rawData == null) {
            rawData = readBytes(request).getBytes(Charset.forName("UTF-8"));
            servletStream.stream = new ByteArrayInputStream(rawData);
        }
        return new BufferedReader(new InputStreamReader(servletStream));
    }


    private class ResettableServletInputStream extends ServletInputStream {

        private InputStream stream;

        @Override
        public int read() throws IOException {
            return stream.read();
        }

        @Override
        public boolean isFinished() {
            return false;
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setReadListener(ReadListener listener) {

        }
    }
    private String readBytes(HttpServletRequest request){
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = request.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }

    public String getBodyString() {
        try {
            return new String(rawData, "UTF-8");
        } catch (UnsupportedEncodingException ex) {
            return new String(rawData);
        }
    }
 
}

3.拦截器Interceptor

@Component
public class XXXRequestInterceptor implements HandlerInterceptor {
    protected Logger log = LoggerFactory.getLogger(getClass());

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {

         if (httpServletRequest instanceof XXXRequestWrapper) {
             XXXRequestWrapper xxxRequestWrapper = (XXXRequestWrapper) httpServletRequest;
          //使用getInputStream 不影响后续的处理器获取请求体中的数据
             xxxRequestWrapper.getInputStream();
              log.info("校验成功 ");
             }catch (Exception e) {
                 log.error("请求校验失败 ");
                 return false;
             }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}

4.其他配置

拦截器不需要单独添加注解,在类上添加@Component即可
过滤器需要在启动类上配置

@ServletComponentScan(basePackageClasses={xxx.xxxRequestFilter.class})

你可能感兴趣的:(spring boot 添加自定义监听器、过滤器、拦截器)