springboot 2.x过滤器
1.什么是 springboot 2.x过滤器
- 类似于检票员,检验游客的门票
2.springboot里的过滤器
ApplicationContextHeaderFilter
OrderedCharacterEncodingFilter
OrderedFormContentFilter
OrderedRequestContextFilter
3.过滤器的优先级
- 低位值意味着更⾼的优先级 Higher values are interpreted as lower priority
4.自定义Filter,避免和默认的Filter优先级一样,不然会冲突
- 注册Filter配置俩种方式
- bean FilterRegistrationBean
- Servlet 3.0 webFilter
5.使用新版servlet 3.0的注解开发自定义Filter
- 在启动类里添加注解@ServletComponentScan ,进行扫描
- 新建一个Filter类,implements Filter,并实现对应的接口
- @WebFilter 标记一个类为filter,被spring扫描
- urlPatterns:拦截规则,支持正则, urlPatterns为过滤的路径,filterName为过滤器的名称
- 控制chain.doFilter的方法调用,来实现是否放行
- 不放行,web应用resp.sendRedirect("/index.html")或者返回json字符串
使用范围:权限控制、⽤户登录状态控制
5.1 启动类里添加注解@ServletComponentScan
@SpringBootApplication //标记此类为springboot 应用
@ServletComponentScan
public class MavenDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MavenDemoApplication.class, args);
}
}
5.2新建一个filter 包,包里创建一个Filter类
5.3类里实现Filter接口,并且类被标注为 @WebFilter, urlPatterns为过滤的路径(过滤/api/v1/pri/ 下所有的路径),filterName为过滤器的名称(登录过滤器)
5.4 在实现接口的类里重写3个方法
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {}
public void destroy() {}
上述三个方法均在类加载时使用,初始化–过滤–销毁,过滤的过程发生在第二个过滤的时候
过滤过程中的代码:
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("过滤开始");
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse rep = (HttpServletResponse) servletResponse;
String token =req.getHeader("token"); //从headers中得到token
if (StringUtils.isEmpty(token)){
// 如果header里面没有token时,从请求的参数里面拿token
token = req.getParameter("token");
}
if (!StringUtils.isEmpty(token)){
//如果还为空,直接返回json字符串或跳转index页面
// 判断token是否合法
User user = UserServiceImpl.sessionMap.get(token); //在登录时在sessionMap里存了token,通过token取出user,若为空则未登录,若不为空则显示正确
if(user !=null){
filterChain.doFilter(servletRequest,servletResponse);
}else{
JsonData jsonData = JsonData.buildError("登录失败,token无效",-2);
String jsonStr = objectMapper.writeValueAsString(jsonData); //json转字符
renderJson(rep,jsonStr);
}
}else {
JsonData jsonData = JsonData.buildError("登录失败,token无效",-3);
String jsonStr = objectMapper.writeValueAsString(jsonData);
renderJson(rep,jsonStr);
}
}
private void renderJson(HttpServletResponse response,String json){
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
try(PrintWriter writer=response.getWriter()){
writer.print(json);
}catch (Exception e){
e.printStackTrace();
}
}
springboot监听器
监听器:
应⽤启动监听器,会话监听器,请求监听器
作用:
- ServletContextListener 应⽤启动监听
- HttpSessionLisener 会话监听
- ServletRequestListener 请求监听
常⽤的监听器
ServletContextListener、HttpSessionListener、ServletRequestListener)
代码:
@WebListener
public class CustomSessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("会话监听已开启");
//HttpSessionListener.super.sessionCreated(se);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("会话监听已销毁");
//HttpSessionListener.super.sessionDestroyed(se);
}
}
SpringBoot2.X拦截器
1. 拦截器:
和过滤器⽤途基本类似
2.SpringBoot2.X拦截器使用步骤:
- 2.1 创建一个类(列如:CustomWebConfigurer类)实现WebMvcConfigurer接口 拦截器配置类
- 2.2 在类上加注解@COnfiguration
- 2.3 在类里override 重写addInterceptors这个方法,在方法里可添加自定义的多个拦截器
- 2.4 自定义拦截器
- preHandle:调⽤Controller某个⽅法之前
- postHandle:Controller之后调⽤,视图渲染之前,如果控制器Controller出现了
异常,则不会执⾏此⽅法 - afterCompletion:不管有没有异常,这个afterCompletion都会被调⽤,⽤于资
源清理
拦截器的配置类 代码:
/**
* 拦截器配置类
*/
@Configuration
public class CustomWebConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getLoginInterceptor()).addPathPatterns("/api/v1/pri/**");
//可添加多个拦截器
registry.addInterceptor(new TwoLoginIntercepter()).addPathPatterns("/api/v1/pri/**");
WebMvcConfigurer.super.addInterceptors(registry);
}
@Bean
public LoginIntercepter getLoginInterceptor(){
return new LoginIntercepter();
}
}
拦截器实现类代码:
public class LoginIntercepter implements HandlerInterceptor {
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("LoginIntercepter preHandle...");
String token =request.getHeader("token"); //从headers中得到token
if (StringUtils.isEmpty(token)){
token = request.getParameter("token");
}
if (!StringUtils.isEmpty(token)){
// 判断token是否合法
User user = UserServiceImpl.sessionMap.get(token);
if(user !=null){
return true;
}else{
JsonData jsonData = JsonData.buildError("登录失败,token无效",-2);
String jsonStr = objectMapper.writeValueAsString(jsonData);
renderJson(response,jsonStr);
return false;
}
}else {
JsonData jsonData =JsonData.buildError("未登录",-3);
String jsonStr = objectMapper.writeValueAsString(jsonData);
renderJson(response,jsonStr);
return false;
}
//return HandlerInterceptor.super.preHandle(request, response, handler);
}
private void renderJson(HttpServletResponse response,String json){
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
try(PrintWriter writer=response.getWriter()){
writer.print(json);
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("LoginIntercepter postHandle...");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("LoginIntercepter afterCompletion...");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
拦截器不生效的常见问题:
- 是否有加@Configuration
- 拦截路径是否有问题 ** 和 *
- 拦截器最后路径⼀定要 /** 如果是⽬录的话则是 /*/
和Filter过滤器的区别
- Filter和Interceptor⼆者都是AOP编程思想的体现,功能基本都可以实现
- 拦截器功能更强⼤些,Filter能做的事情它都能做
- Filter在只在Servlet前后起作⽤,⽽Interceptor够深⼊到⽅法前后、异常抛出前后等
- filter依赖于Servlet容器即web应⽤中,⽽Interceptor不依赖于Servlet容器所以可以运⾏在
多种环境。 - 在接⼝调⽤的⽣命周期⾥,Interceptor可以被多次调⽤,⽽Filter只能在容器初始化时调⽤⼀
次。 - Filter和Interceptor的执⾏顺序 过滤前->拦截前->action执⾏->拦截后->过滤后
如何配置不拦截某些路径?
registry.addInterceptor(new
LoginIntercepter()).addPathPatterns("/api/v1/pri/**")
//配置不拦截某些路径,⽐如静态资源
.excludePathPatterns("//*.html","//*.js");