springboot中实现拦截器的俩种方式,分别为实现HandlerInterceptor接口和使用servlet的filter拦截器
自定义拦截器HandlerInterceptor会实现三个方法
package com.mye.hl18springbootinterceptor.intercept;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** * 拦截器一 */
@Component
public class OneInterceptor implements HandlerInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(OneInterceptor.class.getName());
/** * 预处理回调方法,实现处理器预处理 * 返回值:true表示继续流程;false表示流程中断,不会继续调用其他的拦截器或者处理器 */
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object o) throws Exception {
String url = String.valueOf(request.getRequestURL());
LOGGER.info("1、url==" + url);
// 放开拦截
return true;
}
/** * 后处理回调方法,实现处理器(controller)的后处理,但在渲染视图之前 * 此时我们可以通过modelAndView对模型数据进行处理或对视图进行处理 */
@Override
public void postHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, ModelAndView modelAndView) throws Exception {
LOGGER.info("1、postHandle");
}
/** * 整个请求处理完毕回调方法,即在视图渲染完毕时回调, * 如性能监控中我们可以在此记录结束时间并输出消耗时间, * 还可以进行一些资源清理,类似于try-catch-finally中的finally, * 但仅调用处理器执行链中 */
@Override
public void afterCompletion(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
LOGGER.info("1、afterCompletion");
}
}
TwoInterceptor.java
package com.mye.hl18springbootinterceptor.intercept;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** * 拦截器二 */
@Component
public class TwoInterceptor implements HandlerInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(TwoInterceptor.class.getName());
/** * 预处理回调方法,实现处理器预处理 * 返回值:true表示继续流程;false表示流程中断,不会继续调用其他的拦截器或者处理器 */
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object o) throws Exception {
String url = String.valueOf(request.getRequestURL());
LOGGER.info("2、url==" + url);
// 放开拦截
return true;
}
/** * 后处理回调方法,实现处理器(controller)的后处理,但在渲染视图之前 * 此时我们可以通过modelAndView对模型数据进行处理或对视图进行处理 */
@Override
public void postHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, ModelAndView modelAndView) throws Exception {
LOGGER.info("2、postHandle");
}
/** * 整个请求处理完毕回调方法,即在视图渲染完毕时回调, * 如性能监控中我们可以在此记录结束时间并输出消耗时间, * 还可以进行一些资源清理,类似于try-catch-finally中的finally, * 但仅调用处理器执行链中 */
@Override
public void afterCompletion(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
LOGGER.info("2、afterCompletion");
}
}
Spring Boot1.0的时候可以通过继承WebMvcConfigurerAdapter完成,但在Spring Boot2.0中这个适配类是被弃用了的,所以我们可以直接实现WebMvcConfigurer来完成拦截器的添加
在实现WebMvcConfigurer之后可以选择你要重写的方法,这里重写addInterceptors这个方法来添加自定义的拦截器。
addInterceptor用于添加你自定义的拦截器实例
*
addPathPatterns用于添加要拦截的url,可以写多个。
*
excludePathPatterns用于添加不需要拦截的url,可以写多个。
package com.mye.hl18springbootinterceptor.config;
import com.mye.hl18springbootinterceptor.intercept.OneInterceptor;
import com.mye.hl18springbootinterceptor.intercept.TwoInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/** * Web配置文件 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private OneInterceptor oneInterceptor;
@Autowired
private TwoInterceptor twoInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 拦截所有路径 多个拦截器组成一个拦截器链
// 注册自定义两个拦截器
// addPathPatterns 用来添加拦截规则,/** 表示拦截所有请求 /*/表示拦截目录
// excludePatterns 用户排除拦截
//拦截器的拦截顺序,是按照Web配置文件中注入拦截器的顺序执行的
registry.addInterceptor(oneInterceptor).addPathPatterns("/**");
registry.addInterceptor(twoInterceptor).addPathPatterns("/**");
// registry.addInterceptor(oneInterceptor).addPathPatterns("/**")
// .excludePathPatterns("/stuInfo/getAllStuInfoA","/account/register");
}
}
@RestController
public class InterceptController {
@RequestMapping("/reqUrl")
public String reqUrl() {
return "success";
}
}
正常的拦截器执行顺序
总结:
拦截器1放行,拦截器2 preHandle才会执行。
拦截器2 preHandle不放行,拦截器2 postHandle和afterCompletion不会执行。
只要有一个拦截器不放行,postHandle不会执行。
excludePathPatterns失效的问题
这个现象就是你在excludePathPatterns方法中添加了要忽略的路径,但当你访问此路径的时候拦截器依然进行了拦截。
这是因为你要忽略的路径在项目中并不存在,springboot会将路径编程/error,从而无法进行排除
静态资源被拦截的问题
在Spring Boot1.0中,我们自定义的拦截器并不会对静态资源做出拦截,但是在Spring Boot2.0中,我们自定义的拦截器对静态资源同样做出了拦截
解决方法:
因为自定义的拦截器拦截了所有的路径,所以首先我们需要重写addResourceHandlers()方法,指定静态资源的访问路径前缀以及静态资源所处路径:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//第一个方法设置访问路径前缀,第二个方法设置资源路径
registry.addResourceHandler("/resources/**","/public/**")
.addResourceLocations("classpath:/resources/","classpath:/public/");
}
然后在添加自定义拦截器时忽略静态资源的路径前缀:
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/","user/login","/index.html","/error.html")
.excludePathPatterns("/public/**","/resources/**");
}
最后,在访问静态资源的时候,加上资源所处的完整路径,例如
Spring boot1.0可以这样访问静态资源:
localhost:8080/11.png
那么Spring Boot2.0加上自定义拦截器就得这样了:
localhost:8080/public/11.png
、localhost:8080/resources/11.png
import java.io.IOException;
import java.util.Arrays;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
@Component
@WebFilter(urlPatterns="/**",filterName="loginFilter")
public class LoginFilter implements Filter{
//排除不拦截的url
private static final String[] excludePathPatterns = { "/stuInfo/getAllStuInfoA"};
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
// 获取请求url地址,不拦截excludePathPatterns中的url
String url = req.getRequestURI();
if (Arrays.asList(excludePathPatterns).contains(url)) {
//放行,相当于第一种方法中LoginInterceptor返回值为true
chain.doFilter(request, response);
}
System.out.println("开始拦截了................");
//业务代码
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
Filter和Interceptor二者都是AOP编程思想的体现,功能基本都可以实现
拦截器功能更强大些,Filter能做的事情它都能做
Filter在只在Servlet前后起作用,而Interceptor能够深入到方法前后、异常抛出前后等
依赖于Servlet容器既web应用中,而Interceptor不依赖于Servlet容器所以可以运行在多种环境
在接口调用的生命周期,Interceptor可以被多次调用,而Filter只能在容器初始化时调用一次。
Filter和Interceptor的执行顺序
过滤前->拦截前->action执行->拦截后->过滤后
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/weixin_43296313/article/details/120783039
内容来源于网络,如有侵权,请联系作者删除!