在项目开发过程中,过滤器或者拦截器几乎是必用的,他可以很方便的完成类似日志处理、token验证等一系列操作,区别于业务接口,独立进行处理,感觉就是一种Aop思想。下面模拟请求接口前的token验证,进行过滤器的实战。
qq交流群导航——>231378628
springboot篇章整体栏目:
【二】springboot整合swagger(自定义)(超详细)
【四】springboot整合mybatis-plus(超详细)(上)
【五】springboot整合mybatis-plus(超详细)(下)
【十】springboot整合redis实现启动服务即将热点数据保存在全局以及redis(超详细)
【十一】springboot整合quartz实现定时任务优化(超详细)
【十二】springboot整合线程池解决高并发(超详细,保你理解)
【十三】springboot整合异步调用并获取返回值(超详细)
【十四】springboot整合WebService(超详细)
【十五】springboot整合WebService(关于传参数)(超详细)
【十六】springboot整合WebSocket(超详细)
【十七】springboot整合WebSocket实现聊天室(超详细)
【十九】springboot整合ElasticSearch实战(万字篇)
【二十二】springboot整合activiti7(1) 实战演示篇
【二十三】springboot整合spring事务详解以及实战
【二十四】springboot使用EasyExcel和线程池实现多线程导入Excel数据
【二十五】springboot整合jedis和redisson布隆过滤器处理缓存穿透
【二十六】springboot实现多线程事务处理_springboot多线程事务
【二十七】springboot之通过threadLocal+参数解析器实现同session一样保存当前登录信息的功能
目录
下面先建立一个MVC的基本请求接口,如下:
一、普通的接口访问
如上,先新增一个testController。
先用postman测试一下通不通。
结果是通的,准备工作完成。
二、增加一个过滤器
下面增加一个过滤器来实现一个接口拦截并处理token校验的模拟。
简单处理,有如下两个步骤。
1、自定义过滤器
package com.example.demo_filter_interceptor.config;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @Classname TestFilter
* @Description TODO
* @Date 2022/4/11 19:30
* @Created by zrc
*/
//实现Filter接口,基于回调的方式,类似ajax请求的success。
public class TestFilter implements Filter {
//init方法,初始化过滤器,可以在init()方法中完成与构造方法类似的初始化功能,
//如果初始化代码中要使用到FillerConfig对象,那么这些初始化代码就只能在Filler的init()方法中编写而不能在构造方法中编写
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
System.out.println("第一个过滤器成功初始化。。。。。。。。。。。。。");
}
//doFilter()方法有多个参数,其中
//参数request和response为Web服务器或Filter链中的上一个Filter传递过来的请求和响应对象;
//参数chain代表当前Filter链的对象,
//只有在当前Filter对象中的doFilter()方法内部需要调用FilterChain对象的doFilter()法才能把请求交付给Filter链中的下一个Filter或者目标程序处理
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
//这里为了使用getHeader方法获取token,转型成HttpServletRequest
System.out.println("token:"+req.getHeader("token"));
String token = req.getHeader("token");
//再判断token是否正确
if(null==token){
throw new RuntimeException("token为空");
}
//调用doFilter方法,正常返回servletResponse
filterChain.doFilter(servletRequest, servletResponse);
}
//destroy()方法在Web服务器卸载Filter对象之前被调用,该方法用于释放被Filter对象打开的资源,例如关闭数据库和I/O流
@Override
public void destroy() {
Filter.super.destroy();
System.out.println("过滤器被销毁");
}
}
实现servlet的Filter接口,并重写他的三个方法,分别是init,doFilter,destroy。
- init:过滤器初始化时回调,可以在这里做过滤器的初始化操作,例如设置白名单路径列表。
- doFilter:过滤器初始化后并在请求到达后端且进入到注册过滤器设置的匹配路径时回调。
- destroy:过滤器销毁时回调。
上图是一个简单实现token校验是否为空,没有进行正确与否的校验,可以引入redis(前面章节有讲到)或者其他的存储,然后进行一个正确性的校验。从request中获取token头,若存在则调用doFilter方法(通过过滤器),否则不作操作(就是不通过过滤器,不会抵达controller)。
2、注册到容器
@Configuration
public class TestFilterConfig {
@Bean
public FilterRegistrationBean filterRegistrationBean(){
//创建一个注册过滤器对象
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
//设置自定义过滤器
registrationBean.setFilter(new TestFilter());
//设置过滤拦截匹配规则,/*是匹配所有
// registrationBean.addUrlPatterns("/*");
//只拦截testController下面的接口
registrationBean.addUrlPatterns("/testController/*");
//存在多个过滤器时,设置执行顺序,值越大,执行顺序越靠后
registrationBean.setOrder(2);
//返回这个注册过滤器对象
return registrationBean;
}
}
将自定义过滤器注册到容器中,通过FilterRegistrationBean的一系列方法设置过滤器的参数,例如需要过滤的路径,过滤器的优先级等等。
3、演示一下效果:
不带token:
带token:
三、增加两个过滤器
下面再整一下当存在多个过滤器时,怎么设置哪一个过滤器先拦截,哪一个后执行(优先级)。
跟第二节一样,再整一个自定义过滤器。
package com.example.demo_filter_interceptor.config;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @Classname TestFilter
* @Description TODO
* @Date 2022/4/11 19:30
* @Created by zrc
*/
//实现Filter接口,基于回调的方式,类似ajax请求的success。
public class TestFilter2 implements Filter {
//init方法,初始化过滤器,可以在init()方法中完成与构造方法类似的初始化功能,
//如果初始化代码中要使用到FillerConfig对象,那么这些初始化代码就只能在Filler的init()方法中编写而不能在构造方法中编写
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
System.out.println("第二个过滤器成功初始化。。。。。。。。。。。。。");
}
//doFilter()方法有多个参数,其中
//参数request和response为Web服务器或Filter链中的上一个Filter传递过来的请求和响应对象;
//参数chain代表当前Filter链的对象,
//只有在当前Filter对象中的doFilter()方法内部需要调用FilterChain对象的doFilter()法才能把请求交付给Filter链中的下一个Filter或者目标程序处理
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("这里是第一顺序的拦截器");
filterChain.doFilter(servletRequest, servletResponse);
}
//destroy()方法在Web服务器卸载Filter对象之前被调用,该方法用于释放被Filter对象打开的资源,例如关闭数据库和I/O流
@Override
public void destroy() {
Filter.super.destroy();
System.out.println("过滤器被销毁");
}
}
修改注册过滤器的类。
类似第一个过滤器的注册,再注册一个第二个过滤器即可,可以设置不同的拦截路径,各负责各的逻辑处理,此处只演示一下执行顺序问题,第一个设置Order参数为2,第二个设置为1,越大的越后执行。设置后,用postman测试一下。
调用接口后发现,先进入了第一个过滤器的doFilter方法,再进入的第二个过滤器的doFilter方法,验证order参数是有效的。