一、先了解一下过滤器和拦截器的区别:
1、过滤器是依赖于Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在任何情 况下使用。
2、过滤器的执行由Servlet容器回调完成,而拦截器通常通过动态代理的方式来执行。
3、过滤器的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。
二、过滤器:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(urlPatterns = "/api/*",filterName = "TestFilter")//说明这是一个web过滤器,它拦截的url为/api下所有的请求,过滤器名字为TestFilter
public class TestFilter implements Filter{
@Override//初始化
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request= (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
System.out.println("过滤器通过");
filterChain.doFilter(request,response);
}
@Override//摧毁
public void destroy() {
}
}
注意几点:
1、Filter是import javax.servlet.*下面的
2、@WebFilter注解下的urlPatterns属性用来确定过滤的路径,这个是通过注解配置,也可以用FilterRegistrationBean去配置
3、filterName是过滤器的名字,一般与类名相同。这里要注意的是,在多个过滤器的情况下,是根据Filter类名(注意不是配置的filterName)的字母顺序倒序排列,并且@WebFilter指定的过滤器优先级都高于FilterRegistrationBean配置的过滤器。
4、这边不要通过@Component去注册这个过滤器,而是在启动类中用@ServletComponentScan注解去扫描,如下:
@SpringBootApplication
@ServletComponentScan
public class ShoppingDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ShoppingDemoApplication.class, args);
}
}
三、拦截器:
使用场景:
一般在web项目中,定义拦截器就是为了对用户进行鉴权,常用的方式就是拦截所有请求,从session或token获取用户的登录状态信息。
1、实现HandlerInterceptor中的三个方法,也可以去继承HandlerInterceptorAdapter,方法名一样
@Component
public class TestInterceptor implements HandlerInterceptor {
//在请求处理之前进行调用(Controller方法调用之前)
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.printf("preHandle被调用");
return true; //如果false,停止流程,api被拦截
}
//请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle被调用");
}
//在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("afterCompletion被调用");
}
}
2、配置过滤器
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
@Autowired
private TestInterceptor testInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
// 多个拦截器组成一个拦截器链
registry.addInterceptor(testInterceptor) //注册拦截器
.addPathPatterns("/**") // addPathPatterns 用于添加拦截规则,/**表示拦截所有请求
.excludePathPatterns("/stuInfo/getAllStuInfoA","/account/register"); // excludePathPatterns 用户排除拦截
super.addInterceptors(registry);
}
}
四、基于注解的拦截器:
使用场景:
上面这种配置式的拦截器配置不够灵活,所以我们可以自定义注解进行拦截,在需要被拦截的接口上直接添加注解,方便快捷
1、自定义注解
@Inherited
@Retention(RetentionPolicy.RUNTIME) //运行时有效
@Target({ElementType.METHOD, ElementType.TYPE})// 让该注解可以注解在方法和类上
public @interface Security {
}
2、过滤器
@Component
public class SecurityInterceptor implements HandlerInterceptor {
//在请求处理之前进行调用(Controller方法调用之前)
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
System.out.printf("注解:preHandle被调用");
if (handler instanceof HandlerMethod) //判断此次请求是否属于静态请求,如果是则放行
{
HandlerMethod handlerMethod = (HandlerMethod) handler;// 把handler强转为HandlerMethod
// 从handlerMethod中获取本次请求的接口方法对象然后判断该方法上是否标有我们自定义的注解@Security
Security security = handlerMethod.getMethod().getAnnotation(Security.class);
if (null != security) {
// 对用户进行鉴权
System.out.println("请求已经拦截");
return false;
}
}
return true;
}
//请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, ModelAndView modelAndView) throws Exception {
}
//在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
3、配置过滤器
这边要特别注意一下:我尝试在在一个项目中有多个拦截器配置类时,只有一个生效,所以我就把两个拦截器(包括上面那个拦截器)放一个配置类里面了,如下:(这边实现的是WebMvcConfigurer,和之前不同)
@Configuration
public class SecurityInterceptorConfig implements WebMvcConfigurer {
@Autowired
private SecurityInterceptor securityInterceptor;
@Autowired
private TestInterceptor testInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(securityInterceptor)// 注册拦截器
.addPathPatterns("/**");// 拦截所有请求
registry.addInterceptor(testInterceptor)// 注册拦截器
.addPathPatterns("/**");// 拦截所有请求
}
}
4、最后,直接在请求的方法上加上@ Security就可以了。