spring boot 新增自定義監聽器、過濾器、攔截器

lightwing發表於2021-09-09

場景1:需要專案啟動的時候把資料載入到快取中去 使用:監聽器

1.自定義listenner類 新增@WebListener 實現ServletContextListener


圖片描述

一個註解 一個實現


2.重寫contextInitialized方法

    @Override
    public void contextInitialized(ServletContextEvent sce) {  //當服務啟動時候的業務邏輯

    }

3.在啟動類新增註解掃描
@EnableScheduling
@ServletComponentScan


圖片描述

指定掃描類

場景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

@Componentpublic 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})



作者:VincentPeng
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3407/viewspace-2820340/,如需轉載,請註明出處,否則將追究法律責任。

相關文章