一,过滤器
1.1,自定义Filter
使用Servlet3.0的注解进行配置
启动类里面增加 @ServletComponentScan ,进行扫描
新建一个Filter类,implements Filter ,并实现对应接口
@WebFilter 标记一个类为Filter,被spring进行扫描
urlPatterns:拦截规则,支持正则
控制chain.doFilter的方法的调用,来实现是否通过放行,
不放行的话,web应用resp.sendRedirect(“/index.html”)
场景:权限控制,用户登录(非前端后端分离场景)等
1.2,启动类代码
package com.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; @SpringBootApplication @ServletComponentScan // 扫描select的注解 public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class,args); } }
1.2,创建filter类和LoginFilter包
1.2.1,编写loginFilter类 过滤器代码
package com.demo.filter; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.PrintWriter; @WebFilter(urlPatterns = {"/*"}) @Order(Ordered.HIGHEST_PRECEDENCE) // 设置过滤器的排序,int类型 public class LoginFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("初始化过滤器"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("doFilter"); // servletResponse.setCharacterEncoding("UTF-8"); // 设置响应的字符编码为UTF-8 servletResponse.setCharacterEncoding("UTF-8"); // 设置响应的内容类型为text/plain;charset=UTF-8 servletResponse.setContentType("text/plain;charset=UTF-8"); // 登录过滤器 有两种情况,需要放行 // 1,登录请求要放行 // 2. 不是登录请求,但是有登录token String uri = ((HttpServletRequest)servletRequest).getRequestURI(); System.out.println(uri); if (uri.startsWith("/login/")){ // 判断是否以 /login/ 开头 // 放行 filterChain.doFilter(servletRequest,servletResponse); }else { // 从请求中获取token String token = ((HttpServletRequest)servletRequest).getParameter("token"); if (token != null && !"".equals(token)){ // 其实还需要进行解码,现在是只要有token就放行 filterChain.doFilter(servletRequest,servletResponse); }else { PrintWriter pw = servletResponse.getWriter(); pw.flush(); pw.write("请先登录"); pw.close(); } } } @Override public void destroy() { System.out.println("销毁过滤器"); } }
1.2.2,创建二个Controller类
看看是不是以login开头的放行
第一个controller类为LoginController
package com.demo.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/login") public class LoginController { @RequestMapping("/doLogin") public Object doLogin(){ return "登录接口"; } }
第二个controller类为HelloController
看看不是以login会不会过滤
package com.demo.controller; import com.demo.bean.Person; import com.demo.config.BootProperties; import com.demo.config.SysProperties; import com.demo.util.ResultUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; import org.springframework.util.ClassUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.xml.crypto.Data; import java.io.File; import java.io.IOException; import java.util.Date; import java.util.UUID; @RestController public class HelloController { @Autowired private BootProperties bootProperties; @RequestMapping("/test6") public Object test6(){ return sysProperties.getParam1()+sysProperties.getParam2(); } } // 整个之前的代码试试
证明过滤了,试试登录后
二,监听器
2.1,自定义监听器
- 自定义Listenter(常用监听器
servletContextListenter,
httpSessionListenter,
HTTPSessionAttributeListenter,
servletRequestListenter)
2.2,创建listenter包和MyListenter类
2.2.1,编写MyListenter类 监听器代码
package com.demo.listener; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; import javax.servlet.annotation.WebListener; @WebListener public class MyListener implements ServletRequestListener { @Override public void requestDestroyed(ServletRequestEvent servletRequestEvent) { System.out.println("请求被销毁"); } @Override public void requestInitialized(ServletRequestEvent servletRequestEvent) { System.out.println("请求被初始化创建"); } }
三,拦截器
3.1,创建自定义拦截器配置类
@Configuration
继承WebMvcConfigurationAdapter(SpringBoot2.X之前旧版本)
SpringBoot2.X新版本配置拦截器 implements WebMvcConfigurer
3.2,创建配置包config和配置类MyWebMvcConfigurer
package com.demo.config; import com.demo.interceptor.Logininterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration // 添加了Configuration的类,我们称之为配置类 public class MyWebMvcConfigurer implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new Logininterceptor()).addPathPatterns("/login/**"); WebMvcConfigurer.super.addInterceptors(registry); } }
3.3,创建拦截器包interceptor和Logininterceptor类
Logininterceptor类代码
package com.demo.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Logininterceptor implements HandlerInterceptor { // 调用Controller某个方法之前,判断是否要不要处理 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return false; // false是拦截, true是不拦截 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); } }
四,按顺序进行拦截,先注册,先被拦截
拦截器不生效的常见问题:
- 是否有加@Configuration
- 拦截器是否有路径问题 ** 和 *
- 拦截器最后路径一定要 " /** " ,如果是目录的话则是 /*/
Filter
是基于函数回调 doFilter(),而lnterceptor则是基于AOP思想
Filter在只在Servlet前后起作用,而lnterceptor够深入到方法前后,异常抛出前后等
依赖于Servlet容器即web应用中,而lnterceptor不依赖于Servlet容器所以可以运行在多种环境。
在接口调用的声明周期里,lnterceptor可以被多次调用,而Filter只能在容器中初始化调用一次。
Filter和lnterceptor的执行顺序
过滤前 --> 拦截前 --> action(handler) --> 执行 --> 拦截后 --> 过滤后