springBoot的過濾器,監聽器,攔截器
- 2019 年 10 月 3 日
- 筆記
概述
在開發中,我們經常要考慮一些問題,對敏感詞進行過濾,用戶是否已經登錄,是否需要對他的請求進行攔截,或者領導問現在在線人數有多少人?我們如何實現這些功能哪
@WebFilter
package com.xmlxy.firstspringbootproject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @WebFilter(filterName = "customFilter",urlPatterns = "/*") public class CustomFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(CustomFilter.class); @Override public void init(FilterConfig filterConfig) throws ServletException { log.info("===========攔截器初始化=========="); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("utf-8"); servletResponse.setCharacterEncoding("utf-8"); log.info("doFilter請求處理"); } @Override public void destroy() { log.info("fifter銷毀"); } }
在application類中添加@ServletComponentScan註解
package com; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.context.annotation.PropertySource; @SpringBootApplication @ServletComponentScan @PropertySource(value = "classpath:jdbc.properties",encoding = "utf-8") public class FirstSpringbootProjectApplication { public static void main(String[] args) { SpringApplication.run(FirstSpringbootProjectApplication.class, args); } }
運行結果
(筆誤,應該是過濾器初始化)過濾器已經生效,但若有多個過濾器,無法指定執行順序,我們可以通過Java類的名稱,從A-L,按順序執行。但這種方式畢竟不大靠譜,所以,有第二種寫法,它提供setOrder函數,為filter設置排序值。
package com.xmlxy.service; import com.xmlxy.firstspringbootproject.CustomFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class WebFilterConfig { @Bean public FilterRegistrationBean someFilterRegistration1() { FilterRegistrationBean registration = new FilterRegistrationBean<>(); System.out.println("我執行了。。。。。。。"); registration.setFilter(new CustomFilter()); registration.addUrlPatterns("/*");
registration.setOrder(1);
return registration; } }
我們嘗試寫個demo,驗證一下過濾器是否執行。
用戶登錄對象
User.java
package com.xmlxy.bean; import lombok.Data; import org.springframework.stereotype.Component; @Data @Component public class User { private String user; private String pwd; }
登錄控制
LoginController.java
package com.xmlxy.firstspringbootproject; import com.xmlxy.bean.User; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @RestController public class LoginController { @RequestMapping(value = "login",method = RequestMethod.GET) public String login(HttpServletRequest request) { String user = request.getParameter("user"); String pwd = request.getParameter("pwd"); HttpSession session = request.getSession(); if ("admin".equals(user) && "admin".equals(pwd)) { User user1 = new User(); user1.setUser(user); user1.setPwd(pwd); session.setAttribute("user",user1); return "登錄成功"; } return "密碼錯誤,登錄失敗"; }
@RequestMapping(value = "test",method = RequestMethod.GET)
public String test()
{
return "test介面";
}
}
過濾器
CustomFilter.java
package com.xmlxy.firstspringbootproject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; //@WebFilter(filterName = "customFilter",urlPatterns = "/*") public class CustomFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(CustomFilter.class); String includes[] = {"/login","register"}; @Override public void init(FilterConfig filterConfig) throws ServletException { log.info("===========過濾器初始化=========="); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; servletRequest.setCharacterEncoding("utf-8"); servletResponse.setCharacterEncoding("utf-8"); HttpSession session = request.getSession(false); String uri = request.getRequestURI(); boolean flag = isNeedFilter(uri); if (!flag) { filterChain.doFilter(servletRequest,servletResponse); System.err.printf("登錄成功"); }else { if (session != null && session.getAttribute("user") != null) { filterChain.doFilter(servletRequest,servletResponse); }else { System.err.printf("暫時未登錄"); } } log.info("doFilter請求處理"); } public boolean isNeedFilter(String uri) { for (String include:includes) { if (include.equals(uri)) { return false; } } return true; } @Override public void destroy() { log.info("fifter銷毀"); } }
過濾器配置
WebFilterConfig
package com.xmlxy.service; import com.xmlxy.firstspringbootproject.CustomFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class WebFilterConfig { @Bean public FilterRegistrationBean someFilterRegistration1() { FilterRegistrationBean registration = new FilterRegistrationBean<>(); System.out.println("我執行了。。。。。。。"); registration.setFilter(new CustomFilter()); registration.addUrlPatterns("/*"); return registration; } }
運行測試。。訪問 127.0.0.1/test 控制台
訪問 http://127.0.0.1:8080/login?user=admin&pwd=admin,可以看到登錄成功
在次訪問 127.0.0.1/test 頁面顯示
所以,我們的過濾器成功過濾未登錄的用戶
監聽器
正在你為自己會了過濾用戶自鳴得意時,你的組長過來了,小明,你看下我們平台的在線用戶有多少人。如果不知道監聽器童鞋,是否會在登錄介面處每次登錄成功都+1,然而這種統計結果是不準確的,因為用戶如果反覆登錄退出,那這個在值就遠遠大於實際值,最後就面臨著,加班在加班的悲慘下場。
CustomLister.java
package com.xmlxy.firstspringbootproject; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; @WebFilter public class CustomLister implements HttpSessionListener { public static int online = 0; @Override public void sessionCreated(HttpSessionEvent sessionEvent) { System.out.println("創建session,統計在線人數"); online ++; } @Override public void sessionDestroyed(HttpSessionEvent sessionEvent) { System.out.println("session已經銷毀"); } }
配置監聽器配置,在剛才的WebFilterConfig.java添加
@Bean public ServletListenerRegistrationBean listenerRegistrationBean() { ServletListenerRegistrationBean srb = new ServletListenerRegistrationBean(); srb.setListener(new CustomLister()); System.out.println(""); return srb; }
添加一個訪問在線人數的介面
@RequestMapping(value = "onLinePerson",method = RequestMethod.GET) public String onLinePerson() { StringBuffer stringBuffer = new StringBuffer(""); stringBuffer.append(" 在線人數 "); stringBuffer.append(CustomLister.online); stringBuffer.append(" 個人 "); return stringBuffer.toString(); }
訪問127.0.0.1/onLinePerson,發現被攔截器攔截了,我們先登錄。在查看介面
換個瀏覽器,調用下login介面,在查看
攔截器
攔截器,個人理解,在web上有些像是過濾器的補充,它能更精確的控制攔截哪些函數或者欄位,在攔截之前或之後做一些操作。我們現在做一個敏感詞的攔截,其實這個操作放在過濾器操作也是可以的,但lz因為剛才把攔截用戶的操作放在過濾器了,在大規模更改,lz覺得沒必要,因為都是大同小異。
CustomInterceptor.java
package com.xmlxy.firstspringbootproject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; public class CustomInterceptor implements HandlerInterceptor { private static final Logger log = LoggerFactory.getLogger(CustomInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception { log.info("=======攔截器被調用====="); String url = request.getRequestURI(); if (url != null && url.indexOf("seqing") != -1) { PrintWriter printWriter = response.getWriter(); printWriter.write("ming gan ci"); return false; } log.info("返回false 則中斷請求"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { log.info("請求後調用"); } @Override public void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception e) { log.info("視圖渲染完回調"); } }
配置攔截
package com.xmlxy.service; import com.xmlxy.firstspringbootproject.CustomFilter; import com.xmlxy.firstspringbootproject.CustomInterceptor; import com.xmlxy.firstspringbootproject.CustomLister; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebFilterConfig implements WebMvcConfigurer { @Bean public FilterRegistrationBean someFilterRegistration1() { FilterRegistrationBean registration = new FilterRegistrationBean<>(); System.out.println("我執行了。。。。。。。"); registration.setFilter(new CustomFilter()); registration.addUrlPatterns("/*"); return registration; } @Bean public ServletListenerRegistrationBean listenerRegistrationBean() { ServletListenerRegistrationBean srb = new ServletListenerRegistrationBean(); srb.setListener(new CustomLister()); return srb; } @Override public void addInterceptors(InterceptorRegistry registry) { /*攔截規則*/ registry.addInterceptor(new CustomInterceptor()).addPathPatterns("/*"); } }
現在測試訪問127.0.0.1/seqing,被過濾,要求先登錄。我們調用登錄介面後,再次調用,發現被攔截了
看下日誌調用,可以發現,攔截器是在訪問介面前被調用的
過濾器,攔截器區別
這裡主要說下攔截器和過濾器的區別和使用場景,通過demo可以發現,它們都能實現許可權的檢查,日誌記錄這些功能,主要說下它們的區別
- 過濾器和攔截器觸發的時機是不同的,在進入servlet之前,過濾器就進行預處理了。而攔截器是在調用Controller之前才觸發執行,過濾器的範圍較廣,對所有的請求都起作用,而攔截起只 對action起作用
2.攔截器可以獲取IOC容器的各個bean,而過濾器就不行。因為攔截器是spring提供管理的,也因此攔截器可以使用spring的任何資源。
3.攔截器是利用Java反射機制實現,過濾器是函數的回調。因此實現方式是不同的。
三者使用場景
監聽器:常用統計在線用戶,統計網站的訪問量,記錄用戶的訪問路徑
過濾器:過濾敏感詞,許可權訪問控制
攔截器:許可權驗證,判斷用戶是否登錄等