SpringBoot實(shí)現(xiàn)過(guò)濾器Filter的三種方式
過(guò)濾器 Filter 由 Servlet 提供,基于函數(shù)回調(diào)實(shí)現(xiàn)鏈?zhǔn)綄?duì)網(wǎng)絡(luò)請(qǐng)求與響應(yīng)的攔截與修改。由于基于 Servlet ,其可以對(duì)web服務(wù)器管理的幾乎所有資源進(jìn)行攔截(JSP、圖片文件、HTML 文件、CSS文件等)。
Filter 的生命周期
- init(): 初始化Filter 實(shí)例,F(xiàn)ilter 的生命周期與 Servlet 是相同的,也就是當(dāng) Web 容器(tomcat)啟動(dòng)時(shí),調(diào)用 init() 方法初始化實(shí)例,F(xiàn)ilter只會(huì)初始化一次。需要設(shè)置初始化參數(shù)的時(shí)候,可以寫(xiě)到init()方法中。
- doFilter(): 業(yè)務(wù)處理,攔截要執(zhí)行的請(qǐng)求,對(duì)請(qǐng)求和響應(yīng)進(jìn)行處理,一般需要處理的業(yè)務(wù)操作都在這個(gè)方法中實(shí)現(xiàn)
- destroy() : 銷(xiāo)毀實(shí)例,關(guān)閉容器時(shí)調(diào)用 destroy() 銷(xiāo)毀 Filter 的實(shí)例。
方式① 使用Filter接口
1、在啟動(dòng)類(lèi)添加注解@ServletComponentScan ,讓 Spring 可以掃描到。
2、通過(guò) @WebFilter 注解,將類(lèi)聲明為 Bean 過(guò)濾器類(lèi)。此時(shí)可以指定要攔截的url , 但是不能指定過(guò)濾器執(zhí)行順序。
@Slf4j
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {
@Resource
private RedisTemplate redisTemplate;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
//獲取訪問(wèn) ip 地址
String ipAddr = getIpAddr(request);
// 存入緩存10s不允許訪問(wèn)
String key = new StringBuilder().append("bizKey").append(ipAddr).toString();
if (redisTemplate.hasKey(key)) {
// 訪問(wèn)次數(shù)自增1
redisTemplate.opsForValue().increment(key, 1);
log.warn("訪問(wèn)過(guò)快,存在強(qiáng)刷行為!key={}", key);
} else {
// 第一次訪問(wèn)
redisTemplate.opsForValue().set(key, 1, 10,
TimeUnit.SECONDS);
}
try {
filterChain.doFilter(servletRequest, servletResponse);
} catch (Exception e) {
log.warn("認(rèn)證失敗,e:{},url:{},parameters:{}", e,request.getRequestURL(),request.getParameterMap());
servletResponse.setContentType("application/json");
servletResponse.setCharacterEncoding("UTF-8");
servletResponse.getWriter().write(JSONUtil.toJsonStr(Result.fail("業(yè)務(wù)執(zhí)行報(bào)錯(cuò)~")));
}
}
@Override
public void destroy() {
Filter.super.destroy();
}
public static String getIpAddr(HttpServletRequest request){
String ipAddress = null;
try {
ipAddress = request.getHeader("X-Forwarded-For");
if (ipAddress != null && ipAddress.length() != 0 && !"unknown".equalsIgnoreCase(ipAddress)) {
// 多次反向代理后會(huì)有多個(gè)ip值,第一個(gè)ip才是真實(shí)ip
if (ipAddress.indexOf(",") != -1) {
ipAddress = ipAddress.split(",")[0];
}
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("HTTP_CLIENT_IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
}
}catch (Exception e) {
}
return ipAddress;
}
}方式② 使用@Component注解
使用@Component注解后,可以使用@Order注解保證過(guò)濾器執(zhí)行順序,@Order 注解用于指定組件的執(zhí)行順序,其中值越小的組件優(yōu)先執(zhí)行。
@Component
@Order(1)
public class MyFilter1 implements Filter {
// ...
}
@Component
@Order(2)
public class MyFilter2 implements Filter {
// ...
}注意:
1、不使用@Order注解,則按照f(shuō)ilter類(lèi)名的字母順序來(lái)執(zhí)行
2、方式②可以保證執(zhí)行順序, 但是過(guò)濾器不能指定攔截的url , 只能默認(rèn)攔截全部

方式③ Java Config 配置類(lèi)
使用 @Configuration + @Bean 配置類(lèi),注解聲明Bean,交由 Spring 容器管理。此方式既能攔截Url,也能指定執(zhí)行順序
Java Config 的方式可以通過(guò) @Bean 配置順序或 FilterRegistrationBean.setOrder() 決定 Filter 執(zhí)行順序。(在啟動(dòng)類(lèi)配置攔截器,此時(shí)自定義過(guò)濾器不加注解,為普通類(lèi)即可) 可以指定過(guò)濾器要攔截的url 和 過(guò)濾器執(zhí)行順序, 但需要代碼方式實(shí)現(xiàn).
public class MyFilter1 implements Filter {
// ...
}
public class MyFilter2 implements Filter {
// ...
}通過(guò)在springboot的configuration中配置不同的FilterRegistrationBean實(shí)例,來(lái)注冊(cè)自定義過(guò)濾器
這里創(chuàng)建一個(gè)configuration類(lèi)
@Configuration
public class DemoConfiguration {
@Bean
public FilterRegistrationBean RegistTest1(){
//通過(guò)FilterRegistrationBean實(shí)例設(shè)置優(yōu)先級(jí)可以生效
//通過(guò)@WebFilter無(wú)效
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new Test1Filter());//注冊(cè)自定義過(guò)濾器
bean.setName("flilter1");//過(guò)濾器名稱(chēng)
bean.addUrlPatterns("/*");//過(guò)濾所有路徑
bean.setOrder(1);//優(yōu)先級(jí),最頂級(jí)
return bean;
}
@Bean
public FilterRegistrationBean RegistTest2(){
//通過(guò)FilterRegistrationBean實(shí)例設(shè)置優(yōu)先級(jí)可以生效
//通過(guò)@WebFilter無(wú)效
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new Test2Filter());//注冊(cè)自定義過(guò)濾器
bean.setName("flilter2");//過(guò)濾器名稱(chēng)
bean.addUrlPatterns("/test/*");//過(guò)濾所有路徑
bean.setOrder(6);//優(yōu)先級(jí),越低越優(yōu)先
return bean;
}
}以上就是SpringBoot實(shí)現(xiàn)過(guò)濾器Filter的三種方式的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot實(shí)現(xiàn)過(guò)濾器Filter的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- 淺析SpringBoot中的過(guò)濾器和攔截器
- Springboot?過(guò)濾器、攔截器、全局異常處理的方案處理小結(jié)
- Springboot中使用攔截器、過(guò)濾器、監(jiān)聽(tīng)器的流程分析
- Springboot實(shí)現(xiàn)過(guò)濾器的兩種方式
- SpringBoot對(duì)Filter過(guò)濾器中的異常進(jìn)行全局處理方案詳解
- SpringBoot項(xiàng)目如何設(shè)置權(quán)限攔截器和過(guò)濾器
- springboot應(yīng)用中使用過(guò)濾器的過(guò)程詳解
- springboot實(shí)現(xiàn)過(guò)濾器的示例代碼
相關(guān)文章
SpringCloud?Gateway中GatewayFilterChain執(zhí)行流程詳解
Spring?Cloud?Gateway旨在為微服務(wù)架構(gòu)提供一種簡(jiǎn)單有效的、統(tǒng)一的?API?路由管理方式。Spring?Cloud?Gateway?作為?Spring?Cloud?生態(tài)系中的網(wǎng)關(guān),它不僅提供統(tǒng)一的路由方式,并且基于?Filter?鏈的方式提供了網(wǎng)關(guān)基本的功能,例如:安全、監(jiān)控/埋點(diǎn)和限流等2022-10-10

