SpringBoot 三种拦截http请求方式Filter,interceptor和aop

SpringBoot 三种拦截http请求方式Filter,interceptor和aop

SpringBoot 三种拦截http请求方式Filter,interceptor和aop。

这三种拦截方式的拦截顺序是:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller;

这三种方式的区别:1.过滤器

过滤器拦截web访问url地址。 严格意义上讲,filter只是适用于web中,依赖于Servlet容器,利用Java的回调机制进行实现。Filter过滤器:和框架无关,可以控制最初的http请求,但是更细一点的类和方法控制不了。过滤器可以拦截到方法的请求和响应(ServletRequest request, ServletResponse response),并对请求响应做出像响应的过滤操作,比如设置字符编码,鉴权操作等

2.拦截器Interceptor

拦截器拦截以 .action结尾的url,拦截Action的访问。 Interfactor是基于Java的反射机制(APO思想)进行实现,不依赖Servlet容器。拦截器可以在方法执行之前(preHandle)和方法执行之后(afterCompletion)进行操作,回调操作(postHandle),可以获取执行的方法的名称,请求(HttpServletRequest)Interceptor:可以控制请求的控制器和方法,但控制不了请求方法里的参数(只能获取参数的名称,不能获取到参数的值)(用于处理页面提交的请求响应并进行处理,例如做国际化,做主题更换,过滤等)。

3.切片Aspect,既然Spring那么支持AOP

只能拦截Spring管理Bean的访问(业务层Service)。 具体AOP详情参照 Spring AOP:原理、 通知、连接点、切点、切面、表达式实际开发中,AOP常和事务结合:Spring的事务管理:声明式事务管理(切面)AOP操作可以对操作进行横向的拦截,最大的优势在于他可以获取执行方法的参数( ProceedingJoinPoint.getArgs() ),对方法进行统一的处理。Aspect : 可以自定义切入的点,有方法的参数,但是拿不到http请求,可以通过其他方式如RequestContextHolder获得( ServletRequestAttributes servletRequestAttributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); )。常见使用日志,事务,请求参数安全验证等

第一种方式:Filter

实现Filter接口

/**

* 自定义Filter

* 对请求的header 过滤token

*

* 过滤器Filter可以拿到原始的HTTP请求和响应的信息,

* 但是拿不到你真正处理请求方法的信息,也就是方法的信息

*

* @Component 注解让拦截器注入Bean,从而让拦截器生效

* @WebFilter 配置拦截规则

*

* 拦截顺序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller

*

*/

@Slf4j

@Component

@WebFilter(urlPatterns = {"/**"},filterName = "tokenAuthorFilter")

public class TokenFilter implements Filter {

@Override

public void init(FilterConfig filterConfig) throws ServletException {

log.info("TokenFilter init {}",filterConfig.getFilterName());

}

@Override

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

log.info("TokenFilter doFilter 我拦截到了请求");

// log.info("TokenFilter doFilter",((HttpServletRequest)request).getHeader("token"));

chain.doFilter(request,response);//到下一个链

}

@Override

public void destroy() {

log.info("TokenFilter destroy");

}

}

第二种方式:拦截器 Interceptor

实现 HandlerInterceptor 接口,然后配置进Spring。

/**

* 自定义拦截器

* 自定义拦截器后,需要配置进Spring

*

* 拦截器Interceptor可以拿到原始的HTTP请求和响应的信息,

* 也可以拿到你真正处理请求方法的信息,但是拿不到传进参数的那个值。

*

*拦截顺序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller

*/

@Slf4j

@Component

public class TokenInterceptor implements HandlerInterceptor {

/**

* 在访问Controller某个方法之前这个方法会被调用。

* @param request

* @param response

* @param handler

* @return false则表示不执行postHandle方法,true 表示执行postHandle方法

* @throws Exception

*/

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

log.info("Token Interceptor preHandle {}","");

String token = request.getHeader("token");

log.info("Token Interceptor preHandle token :{}",token);

log.info("Token Interceptor preHandle uri {}",request.getRequestURL().toString());

//spring boot 2.0对静态资源也进行了拦截,当拦截器拦截到请求之后,

// 但controller里并没有对应的请求时,该请求会被当成是对静态资源的请求。

// 此时的handler就是 ResourceHttpRequestHandler,就会抛出上述错误。

if (handler instanceof HandlerMethod){

HandlerMethod handlerMethod = (HandlerMethod) handler;

Method method = handlerMethod.getMethod();

log.info("Token Interceptor preHandle getMethod {}",method.getName());

}else if(handler instanceof ResourceHttpRequestHandler){//静态资源

ResourceHttpRequestHandler resourceHttpRequestHandler = (ResourceHttpRequestHandler) handler;

log.info("Token Interceptor preHandle getMethod {}",resourceHttpRequestHandler.getMediaTypes());

}

//false则表示不执行postHandle方法,不执行下一步chain链,直接返回response

return true;

}

/**

* 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)

* preHandle方法处理之后这个方法会被调用,如果控制器Controller出现了异常,则不会执行此方法

* @param request

* @param response

* @param handler

* @param modelAndView

* @throws Exception

*/

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

log.info("Token Interceptor postHandle");

}

/**

* 不管有没有异常,这个afterCompletion都会被调用

* @param request

* @param response

* @param handler

* @param ex

* @throws Exception

*/

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

log.info("Token Interceptor afterCompletion");

}

}

配置进spring

/**

* TokenInterceptor 自定义拦截器后,需要配置进Spring

* 也可以mapping,跨域设置

*/

@Slf4j

@Configuration

public class TokenConfig implements WebMvcConfigurer {

@Autowired

TokenInterceptor tokenInterceptor;

/**

* 添加拦截器

* @param registry

*/

@Override

public void addInterceptors(InterceptorRegistry registry) {

log.info("TokenConfig addInterceptors tokenInterceptor");

registry.addInterceptor(tokenInterceptor)

.addPathPatterns("/**")//指定该类拦截的url

.excludePathPatterns( "/static/**");//过滤静态资源

}

/**

* 如果实现了Filter跨域拦截,这个跨域无效

* 拦截器实现 跨域支持

* @param registry

*/

@Override

public void addCorsMappings(CorsRegistry registry) {

log.info("TokenConfig addInterceptors addCorsMappings");

registry.addMapping("/**")

.allowedOrigins("*")

.allowCredentials(true)

.allowedMethods("GET", "POST", "DELETE", "PUT","OPTIONS","HEAD")

.allowedHeaders("*")

.maxAge(3600);

}

}

第三种方式 : aop拦截

pom.xml 添加Aop支持

org.springframework.boot

spring-boot-starter-aop

/**

* pom.xml 添加Aop支持

*

* org.springframework.boot

* spring-boot-starter-aop

*

*

* 切片Aspect,既然Spring那么支持AOP,可以拿到原始的HTTP请求和响应的信息,

* 也可以拿到你真正处理请求方法的信息,也可以传进参数的那个值。

*

* 拦截顺序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller

*/

@Slf4j

@Component //表示它是一个Spring的组件

@Aspect //表示它是一个切面

public class HttpAspect {

/**

* 通过ProceedingJoinPoint对象的getArgs()我们可以得到传进来的参数。

* 通过ProceedingJoinPoint对象的proceed()我们可以得到拿到切面方法返回值的对象。

* @param pjp

* @return

* 环绕通知 首先是:包名 然后是: 类名 然后是方法名:方法名 括号内是:参数

*/

@Around("execution(* com.learn.jwttoken.controller.*.*(..))")

public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {

log.info("HttpAspect handleControllerMethod filter start");

//原始的HTTP请求和响应的信息

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

HttpServletRequest request = attributes.getRequest();

HttpServletResponse response = attributes.getResponse();

Signature signature = pjp.getSignature();

MethodSignature methodSignature = (MethodSignature)signature;

//获取当前执行的方法

Method targetMethod = methodSignature.getMethod();

log.info("当前执行的方法:{}",targetMethod.getName());

//获取参数

Object[] objs = pjp.getArgs();

for (Object obj:objs){

log.info("参数:"+obj);

}

//获取返回对象

Object object = pjp.proceed();

log.info("获得返回对象 :{}",object);

log.info("HttpAspect handleControllerMethod filter end");

return pjp.proceed();//代理方法的返回值

}

}

相关推荐

土狗王北车这一讽刺称谓到底从何而来 土狗狗王有什么特点
现代 Android 应用架构
o365邮箱登录

现代 Android 应用架构

📅 08-11 👁️ 3752
梦幻西游平民力天宫加点攻略:任务与战斗全解析
365bet体育在线15

梦幻西游平民力天宫加点攻略:任务与战斗全解析

📅 07-03 👁️ 6168
使用渐变工具创建渐变颜色混合
o365邮箱登录

使用渐变工具创建渐变颜色混合

📅 06-28 👁️ 2992
带圣字好听的名字大全
365bet体育在线15

带圣字好听的名字大全

📅 08-21 👁️ 2975
北方地区进入供暖季,季节性用能高峰期到来 加强能源供应 保障温暖过冬