Springboot
1:拦截器(Interceptor)
java中的拦截器是动态拦截action调用的对象。依赖于web框架,在springmvc中依赖于SpringMVC框架,在实现上基于Java的反射机制,属于AOP的一种应用,作用类似于过滤器,但是拦截器只能对Controller请求进行拦截,对其他的直接访问静态资源的请求无法拦截处理。
拦截器可以拦截前端请求,定义拦截器需要实现 HandlerInterceptor 接口,然后根据需求重写preHandle,postHandle,afterCompletion三个方法。
/** * 拦截器 * * @program: myspringboot * @author: syt * @create: 2020-03-05 21:11 */ @Component @Slf4j public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("前置拦截器****"); //返回true表示通过请求,返回false表示请求被拦截 return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { log.info("后置拦截器****"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { log.info("拦截器执行完成****"); } } 复制代码
想要让自己的拦截器生效需要进行webmvc配置,自定义一个配置类实现WebMvcConfigurer接口,然后重写addInterceptors方法添加需要拦截的路径,JDK1.8以前都是继承于WebMvcConfigurerAdapter然后重新其中的方法,但是JDK1.8支持接口默认方法,官方就定义了可以不用继承WebMvcConfigurerAdapter直接实现WebMvcConfigurer即可。
**
* 配置拦截器和过滤器
*
* @program: myspringboot * @author: syt * @create: 2020-03-05 21:16 */ @Configuration public class MyConfig implements WebMvcConfigurer { @Autowired private MyInterceptor myInterceptor; /** * 添加拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { //addPa-thPatterns 用于添加拦截规则 //excludePathPatterns 用于排除拦截 /*要执行的拦截器*/ registry.addInterceptor(myInterceptor). addPathPatterns("/**"). excludePathPatterns("/**/login", "/**/esProductinfo/**"); } /** * 解决跨域问题 * 源(origin)就是协议、域名和端口号。 * URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口全部相同, * 则表示他们同源。否则,只要协议、域名、端口有任何一个不同,就是跨域 * * @param registry */ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/*") .allowedOrigins("*") .allowCredentials(true) .allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH") .maxAge(3600); } } 复制代码
自定义自己的配置类也可以继承WebMvcConfigurationSupport类。这个类有许多默认的配置,但是如果继承了WebMvcConfigurationSupport这个类,SpringBoot的mvc自动装配就好失效,默认配置都需要自己定义,如静态文件地址 /**,需要重新addResourceHandlers方法添加静态文件地址
/** * 配置拦截器和过滤器 * * @program: myspringboot * @author: syt * @create: 2020-03-05 21:16 */ @Configuration public class MyConfig extends WebMvcConfigurationSupport { @Autowired private MyInterceptor myInterceptor; /** * 静态资源 * * @param registry */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); registry.addResourceHandler("/static/**").addResourceLocations("classpath:/META-INF/resources/static/"); } /** * 添加拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { //addPa-thPatterns 用于添加拦截规则 //excludePathPatterns 用于排除拦截 /*要执行的拦截器*/ registry.addInterceptor(myInterceptor). addPathPatterns("/**"). excludePathPatterns("/**/login", "/**/esProductinfo/**"); } /** * 解决跨域问题 * 源(origin)就是协议、域名和端口号。 * URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口全部相同, * 则表示他们同源。否则,只要协议、域名、端口有任何一个不同,就是跨域 * * @param registry */ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/*") .allowedOrigins("*") .allowCredentials(true) .allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH") .maxAge(3600); } } 复制代码
2:过滤器(filter)
方式一
对目标资源的请求和响应进行过滤截取。在请求到达servlet之前,进行逻辑判断,判断是否放行到servlet;也可以在一个响应response到达客户端之前进行过滤,判断是否允许返回客户端。
定义过滤器需要实现Filter接口
@Slf4j public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { log.info("MyFilter的init方法"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { log.info("MyFilter的doFilter方法"); //这里可以加一个判断,在过滤器请求不通过时可以返回自己的信息 if (false) { filterChain.doFilter(servletRequest, servletResponse); return; } else { servletResponse.setContentType("text/html;charset=UTF-8;"); PrintWriter out = servletResponse.getWriter(); out.write("过滤器不通过"); log.info("过滤器不通过"); out.flush(); out.close(); return; } } @Override public void destroy() { log.info("MyFilter的destroy方法"); } } 复制代码
想要让过滤器生效需要进行配置
@Configuration public class MyConfig{ /** * 添加filter * * @return */ @Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new MyFilter()); //该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 registration.addInitParameter("targetFilterLifecycle", "true"); registration.setEnabled(true); //filter的执行顺序,数字小先执行 registration.setOrder(1); //需要拦截的url路径 registration.addUrlPatterns("/demand/*", "/notice/*", "/query/*"); return registration; } } 复制代码
方式二
可以直接用@WebFilter注解加@Component注解直接就可以创建过滤器了
@Slf4j @Component @WebFilter(filterName = "myFilter",urlPatterns = "/*") public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { log.info("MyFilter的init方法"); } /** * 这里是过滤请求的方法 */ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { log.info("MyFilter的doFilter方法"); if (false) { filterChain.doFilter(servletRequest, servletResponse); return; } else { servletResponse.setContentType("text/html;charset=UTF-8;"); PrintWriter out = servletResponse.getWriter(); out.write("过滤器不通过"); log.info("过滤器不通过"); out.flush(); out.close(); return; } } @Override public void destroy() { log.info("MyFilter的destroy方法"); } } 复制代码
感觉拦截器和过滤器很像,都是可以拦截请求做相应的处理。接下来说下他俩的具体区别。
①:拦截器是基于java的反射机制,而过滤器基于函数回调。 ②:过滤器依赖于servlet容器,拦截器不依赖于servlet容器。 ③:拦截器只能对action请求起作用,而过滤器几乎对所有的请求都起作用。 ④:拦截器可以访问action上下文,值栈里的对象,而过滤器不能。 ⑤:在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。 ⑥:拦截器可以获取IOC容器中的各个bean,而过滤器就不行,(在拦截器里注入一个service,可以调用业务逻辑)。 ⑦:过滤器是在请求进入容器后,但进入servlert前进行预处理的。响应请求也是,在servlet处理结束后,返回给客户端前触发。而拦截器提供了三个方法支持(1)preHandle:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器(如我们上一章的Controller实现); 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;postHandle:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。 afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。
作者:着迷。
链接:https://juejin.im/post/5e639f33f265da570829f63c
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。