SpringBoot 中Filter的作用以及使用
1、Filter的作用
Filter使用户可以改变一个 request和修改一个response.
Filter 不是一个servlet,它不能产生一个response,它能够在一个request到达servlet之前预处理request,也可以在离开 servlet时处理response.
换种说法,filter其实是一个”servlet chaining”(servlet 链).
通俗点说法filter相当于加油站,request是条路,response是条路,
目的地是servlet,这个加油站设在什么地方对什么数据操作可以由你来控制。
Filter过滤器实现的是javax.servlet.Filter接口的类,而在javax.servlet.Filter中定义了以下三个方法:
- init(FilterConfig fConfig)
init()方法用来初始化过滤器,可以在init()方法中获取Filter中的初始化参数。
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//用来获取Filter中初始化的参数
}
- doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
doFilter()方法完成过滤操作。当请求发过来的时候,过滤器将执行doFilter方法。
在HttpServletRequest 执行doFilter()之前,根据需要检查 HttpServletRequest ,同时也可以修改HttpServletRequest 请求头和数据。
在HttpServletResponse 执行doFilter()之后,根据需要检查 HttpServletResponse ,同时也可以修改HttpServletResponse响应头和数据。
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("进行过滤以及逻辑判断操作");
filterChain.doFilter(servletRequest,servletResponse);
}
- destroy()
Filter对象创建后会驻留在内存,当web应用移除或服务器停止时调用destroy()方法进行销毁。在Web容器卸载 Filter 对象之前被调用。destroy()方法在Filter的生命周期中仅执行一次。通过destroy()方法,可以释放过滤器占用的资源。
@Override
public void destroy() {
//销毁Filter对象,Filter生命周期结束
}
上来我们先创建一个小demo 然后我们再讲解其中的原理
我们在IDEA中创建一个SpringBoot的基础项目(这里不介绍这么创建了)
一、这里采用的@WebFilter注解过滤
目录结构
@Order(x)x越小优先级 越高
@WebFilter 用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。**该注解具有下表给出的一些常用属性 ( 以下所有属性均为可选属性,但是 value、urlPatterns、servletNames 三者必需至少包含一个,且 value 和 urlPatterns 不能共存,如果同时指定,通常忽略 value 的取值 )
package cn.tll.config;
import org.springframework.core.annotation.Order;
import javax.servlet.*;
import javax.servlet.FilterConfig;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author tll
* @create 2020/8/1 12:41
* @Order(x) 里面的数越小 越优先执行
* @WebFilter() 代表着这是个Filter类 并把它注入到容器中
*/
@Order(1)
@WebFilter(initParams = {@WebInitParam(name = "nofilter",value = "/one,/two")})
public class FirstFilter implements Filter {
/**
* 不过滤的资源
*/
private String[] nofilter;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//将不过滤的资源存入数组中
String nofilterString = filterConfig.getInitParameter("nofilter");
if (nofilterString!=null&&nofilterString.length()>0){
nofilter = nofilterString.split(",");
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
boolean flag = isNofilter(request);
if (flag){
filterChain.doFilter(servletRequest,servletResponse);
}else {
request.getRequestDispatcher("/forword").forward(servletRequest,servletResponse);
}
}
@Override
public void destroy() {
}
/**
*isNofilter 判断路径是否不需要过滤
*/
public boolean isNofilter(HttpServletRequest request){
String requestURI = request.getRequestURI();
System.out.println(requestURI);
for (String s : nofilter) {
if (requestURI.contains(s)){
return true;
}
}
return false;
}
}
Controller中的代码
这里的@RestController注解作用就不用多说了
package cn.tll.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author tll
* @create 2020/8/1 12:48
*/
@RestController
public class IndexController {
@RequestMapping({"/","/index"})
public String index(){
return "访问成功";
}
@RequestMapping("/forword")
public String forword(){
return "请先登录";
}
@RequestMapping("/one")
public String one(){
return "one";
}
@RequestMapping("/two")
public String two(){
return "two";
}
}
最后千万不要忘了在启动类上加上@ServletComponentScan
注:@ServletComponentScan注解的含义在SpringBootApplication(启动类)上使用@ServletComponentScan注解后,Servlet、Filter(过滤器)、Listener(监听器)可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码!
package cn.tll;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
/**
* 因为使用的是注解Filter 所以需要在程序入口加入@ServletComponentScan
*
*/
@SpringBootApplication
@ServletComponentScan
public class SpringbootFilterApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootFilterApplication.class, args);
}
}
二,@Bean注解方式
我们还是先创建一个干净的SpringBoot项目吧
首先把Controller写好 先测试一下有无问题
package cn.tll.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author tll
* @create 2020/8/2 8:51
*/
@RestController
public class IndexController {
@RequestMapping({"/","/index"})
public String index(){
return "欢迎进入首页";
}
@RequestMapping("noRoot")
public String noRoot(){
return "对不起,请先登录";
}
@RequestMapping("/one")
public String one(){
return "one";
}
@RequestMapping("/two")
public String two(){
return "two";
}
}
好的没问题
再创建一个WebConfig
package cn.tll.config;
import cn.tll.filter.FirstFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author tll
* @create 2020/8/2 8:57
*/
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean(new FirstFilter());
//过滤所有路径
registrationBean.addUrlPatterns("/*");
//添加不过滤路径
registrationBean.addInitParameter("noFilter","/one,/two");
registrationBean.setName("firstFilter");
registrationBean.setOrder(1);
return registrationBean;
}
@Bean
public FilterRegistrationBean twoFilterRegistrationBean(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean(new TwoFilter());
registrationBean.setOrder(2);
registrationBean.addUrlPatterns("/*");
registrationBean.setName("TwoFilter");
return registrationBean;
}
}
接着就是创建Filter了
这里创建两个Filter主要是用于查看setOrder优先级是否有用
Order(x) 里面的x数值越小优先级越高
package cn.tll.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author tll
* @create 2020/8/2 9:00
*/
public class FirstFilter implements Filter {
private String[] noFilters;
/**
* 过滤器初始化
* @param filterConfig
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String noFilter = filterConfig.getInitParameter("noFilter");
if (noFilter!=null&&noFilter.length()>0){
noFilters = noFilter.split(",");
}
}
/**
* 过滤器方法
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("这里是FirstFilter");
HttpServletRequest request = (HttpServletRequest) servletRequest;
boolean flag = isFilter(request);
if (flag){
System.out.println("可以访问");
filterChain.doFilter(servletRequest,servletResponse);
}else {
System.out.println("不可以访问");
//没有权限不可以访问,需要转发到友好界面
request.getRequestDispatcher("/noRoot").forward(servletRequest,servletResponse);
}
}
/**
* 过滤器销毁
*/
@Override
public void destroy() {
}
/**
* 判断URL是否包含不过滤的路径
* @param request
* @return
*/
public boolean isFilter(HttpServletRequest request){
String requestURI = request.getRequestURI();
for (String noFilter : noFilters) {
System.out.println(noFilter);
if (requestURI.contains(noFilter)){
return true;
}
}
return false;
}
}
package cn.tll.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* @author tll
* @create 2020/8/2 9:23
*/
public class TwoFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("这里是TwoFiter");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
大功告成,你觉得那种方法简单呢?