过滤器
实现方法:
- 定义一个类,实现Filter接口
- 重写doFilter()方法
@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// filter对传给servlet的request进行过滤:预处理
filterChain.doFilter(servletRequest,servletResponse);
// filter对servlet返还给客户端的response进行后处理
}
- 配置拦截路径: 注解方式@WebFilter或web.xml
过滤器链(配置多个过滤器)
web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。
所以当我们只实现了一个filter时,调用filter.dofilter(),它去寻找filter链的下一个filter,但它下面已经没有了,因此就直接转发给对应的servlet中了。
* 执行顺序:如果有两个过滤器:过滤器1和过滤器2
1. 过滤器1
2. 过滤器2
3. 资源执行
4. 过滤器2
5. 过滤器1
* 过滤器先后顺序问题:
1. 注解配置:按照类名的字符串比较规则比较,值小的先执行
* 如: AFilter 和 BFilter,AFilter就先执行了。
2. web.xml配置: <filter-mapping>谁定义在上边,谁先执行
Springboot中编写filter的配置类代替@WebFilter注解配置
- 编写实现了Filter接口的类,无需添加注解
- 配置类中使用
FilterRegistrationBean
来添加filter并设置过滤路径和优先级等:
@Configuration
public class FilterConfig {
@Bean // 将自定义filter对象注入到spring容器中
public MyFilter myFilter(){
return new MyFilter();
}
@Bean
public FilterRegistrationBean getFilterRegistrationBean(MyFilter myFilter){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(myFilter);
filterRegistrationBean.addUrlPatterns("/filter/*");
filterRegistrationBean.setName("myFilter");
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
}
过滤器 用户登录
我们在FilterConfig
中通过addUrlPatterns()
设置了过滤路径, 之后客户端请求中包含该过滤路径的请求都转到doFilter()
中来,这些请求中带有/**/open/**
模式的会放行,其他的如果没有设置token header
都不放行,认为用户未登录,转到未登录中。
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// HttpServletRequest extends ServletRequest, 因为传过来的引用为Http的请求因此可以通过强转转为子接口,这是为了使用子接口特有的功能
HttpServletRequest request = (HttpServletRequest)servletRequest;
String uri = request.getRequestURI();
System.out.println(uri);
/*String method = request.getMethod();
System.out.println(uri+" "+method+"哈哈我进入了 MyFilter 过滤器了");
filterChain.doFilter(servletRequest, servletResponse);*/
// 路径匹配器 https://blog.csdn.net/andy_zhang2007/article/details/88884286
AntPathMatcher matcher = new AntPathMatcher();
if (matcher.match(openUrl, uri)){ // 如果是开放路径open 直接放行
System.out.println("匹配成功!直接放行!");
filterChain.doFilter(servletRequest, servletResponse);
}else{
String token = request.getHeader("token");
if (token == null || "".equals(token)){ // 加上open才能通过拦截器
servletRequest.getRequestDispatcher("/filter/open/unLogin").forward(servletRequest, servletResponse);
}else{// 有token代表用户登录,放行
filterChain.doFilter(servletRequest, servletResponse);
}
}
}
拦截器
类似于filter,但拦截器interceptor
是springmvc的一部分:
实现
- 实现
HandlerInterceptor
接口
- preHandler():目标方法执行前执行,返回值为布尔类型,返回为true时会执行目标资源
- postHandler():目标方法执行后,视图对象返回前执行
- afterCompletion():所有流程执行完之后执行
- 配置springmvc的配置文件
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--对哪些资源执行拦截操作-->
<mvc:mapping path="/**"/>
<bean class="com.itheima.interceptor.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
springboot整合SpringMVC拦截器
在编写拦截器后,配置方法从编写spring-mvc.xml到编写配置类实现WebMvcConfigurer
:
@Configuration
public class MvcConfig implements WebMvcConfigurer {
//注册拦截器
@Bean
public MyInterceptor myInterceptor(){
return new MyInterceptor();
}
//添加拦截器到spring mvc拦截器链,快捷键ctrl + 0/o, 配置拦截器和拦截器路径
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor()).addPathPatterns("/*").excludePathPatterns("/*/open/*"); // 这里的路径不能写成/**/open/** 不然会报错!
}
}
用户登录
这里和filter的区别就是匹配放行路径通过excludePathPatterns()
给设置好了,代码中只需要判断是否登录即可:
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor....在请求处理之前进行调用(Controller方法调用之前)");
String requestUrl=request.getRequestURI();
System.out.println("过滤器MyFilter拦截了请求为" + requestUrl);
// 拦截验证用户是否登录,判断是否携带token即可
String token = request.getHeader("token");
if (StringUtils.isEmpty(token)){
request.getRequestDispatcher("/filter/open/unLogin").forward(request, response);
return false; // 未登录,进行拦截
}
return true;
}
过滤器和拦截器是可以同时配置的,都可以实现我们想要的功能。
postman安装使用
https://zhuanlan.zhihu.com/p/41212281
复制url到postman中,可以设置请求头token等信息,比swagger要灵活