过滤器Filter、拦截器Interceptor、参数解析器Resolver、Aop切面是我们应用开发中经常使用到的技术,到底该如何使用这些web附属功能, 本小节我们就分别介绍一下其各自的用法及其应用场景。
- 过滤器Filter是依赖于servlet存在的一种对web资源预处理的一种手段,不依赖于spring容器启动,是一种独立的web资源预处理器。能够对动静态资源统一拦截,统一过滤,springsecurity中就有用到过滤器的统一拦截功能,实现访问权限资源的控制。其是一种粗粒度的资源访问管理器,主要用来实现一些统一编码设置、用户访问控制等功能。
- 使用步骤
①创建一个过滤器并集成filter实现其接口,init()方法只会在项目启动时执行一次,doFilter()方法是拦截器具体实现对资源的处理过程,destroy()方法是在项目销毁时执行一次。
package com.yundi.atp.platform.filter; import lombok.extern.slf4j.Slf4j; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @Author: 北溟溟 * @Description: 过滤器:设置编码 * 优先级:过滤器>拦截器>AOP切面 * 粒度:过滤器<拦截器
②将filter注册到FilterRegistrationBean实例中
package com.yundi.atp.platform.config; import com.yundi.atp.platform.filter.ParamFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @Author: 北溟溟 * @Description: 过滤器注册:Servlet容器级别的过滤器 * @Date: 2022/1/25 18:38 * @Version: 1.0.0 */ @Configuration public class FilterConfiguration { @Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new ParamFilter()); registration.addUrlPatterns("/*"); registration.setName("paramFilter"); // 设置过滤器被调用的顺序 registration.setOrder(1); return registration; } }
- 拦截器是springmvc中对于web请求资源的处理手段之一,拦截器可以实现动态资源的拦截处理,主要用于登录认证,token校验,程序执行时间统计等等,是DispatcherServlet中对应用请求的预处理手段。能够获取到spring容器实例,实现拦截结果业务处理。
- 使用步骤
①创建一个auth注解,实现controller方法的拦截与放行,有auth注解的放行
package com.yundi.atp.platform.annotation; import java.lang.annotation.*; /** * @Author: 北溟溟 * @Description: 授权注解 * @Date: 2022/1/25 16:30 * @Version: 1.0.0 */ @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface Auth { }
②创建拦截器AuthHandlerInterceptor
package com.yundi.atp.platform.interceptor; import com.yundi.atp.platform.annotation.Auth; import com.yundi.atp.platform.module.sys.service.UserService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.core.NamedThreadLocal; import org.springframework.stereotype.Component; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @Author: 北溟溟 * @Description: 通过拦截器鉴权 * @Date: 2022/1/25 16:53 * @Version: 1.0.0 */ @Slf4j @Component public class AuthHandlerInterceptor implements HandlerInterceptor { private NamedThreadLocal
startTimeThreadLocal = new NamedThreadLocal ("StopWatch-StartTime"); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { //注入service UserService userService = this.getBean(UserService.class, request); log.info("注入service:" + userService); //设置当前时间 startTimeThreadLocal.set(System.currentTimeMillis()); log.info("【拦截器】方法在Controller方法执行前。。。"); if ((handler instanceof HandlerMethod) && (((HandlerMethod) handler).getMethodAnnotation(Auth.class) != null)) { return true; } return verifyToken(request); } private boolean verifyToken(HttpServletRequest request) { String token = request.getHeader("token"); if (StringUtils.isNotBlank(token)) { //todo 解析token,不通过返回false } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { log.info("【拦截器】方法在Controller方法执行结束后执行。。。"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { log.info("【拦截器】在view视图渲染完成后执行。。。"); log.info("【拦截器】spend total time:{}ms", System.currentTimeMillis() - startTimeThreadLocal.get()); } /** * 获取容器对象实例 * @param clazz * @param request * @param * @return */ private T getBean(Class clazz, HttpServletRequest request) { WebApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext()); return applicationContext.getBean(clazz); } } package com.yundi.atp.platform.config; import com.yundi.atp.platform.interceptor.AuthHandlerInterceptor; import com.yundi.atp.platform.resolver.AuthHandlerMethodArgumentResolver; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; /** * @Author: 北溟溟 * @Description: 添加静态资源文件,外部可以直接访问地址 * @Date: 2021/5/18 10:54 * @Version: 1.0.0 */ @Configuration public class MyWebMvcConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/"); registry.addResourceHandler("/tinymce/**").addResourceLocations("classpath:/tinymce/"); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthHandlerInterceptor()).addPathPatterns("/**").order(1); } @Override public void addArgumentResolvers(List
resolvers) { resolvers.add(new AuthHandlerMethodArgumentResolver()); } }
- 参数解析器HandlerMethodArgumentResolver将web请求中的参数解析为标准的数据并绑定到controller中接收,类似于@RequestBody注解,实现数据的统一处理。
- 使用步骤
①创建一个参数解析器注解
package com.yundi.atp.platform.annotation; import java.lang.annotation.*; /** * @Author: 北溟溟 * @Description: 授权注解 * @Date: 2022/1/25 16:30 * @Version: 1.0.0 */ @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface Param { }
②创建一个参数解析器ParamHandlerMethodArgumentResolver
package com.yundi.atp.platform.resolver; import com.yundi.atp.platform.annotation.Param; import lombok.extern.slf4j.Slf4j; import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; import javax.servlet.http.HttpServletRequest; /** * @Author: 北溟溟 * @Description: 参数解析器鉴权:其功能就是解析request请求参数并绑定数据到Controller的入参上 * @Date: 2022/1/25 17:47 * @Version: 1.0.0 */ @Slf4j @Component public class ParamHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter methodParameter) { log.info("【方法解析器】参数解析器鉴权2!"); return methodParameter.hasParameterAnnotation(Param.class); } @Override public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) { if (methodParameter.getParameterType().equals(String.class)) { HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class); String token = request.getHeader("token"); return token; } return null; } }
③注册参数解析器
/* * ****************************************************************************************************************************************** * Copyright (c) 2021 . * All rights reserved. * 项目名称:atp-platform * 项目描述:应用测试平台管理端 * 版权说明:本软件属云嘀科技有限公司所有,在未获得云嘀科技有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 * ******************************************************************************************************************************************* */ package com.yundi.atp.platform.config; import com.yundi.atp.platform.interceptor.AuthHandlerInterceptor; import com.yundi.atp.platform.resolver.ParamHandlerMethodArgumentResolver; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; /** * @Author: 北溟溟 * @Description: 添加静态资源文件,外部可以直接访问地址 * @Date: 2021/5/18 10:54 * @Version: 1.0.0 */ @Configuration public class MyWebMvcConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/"); registry.addResourceHandler("/tinymce/**").addResourceLocations("classpath:/tinymce/"); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthHandlerInterceptor()).addPathPatterns("/**").order(1); } @Override public void addArgumentResolvers(List
resolvers) { resolvers.add(new ParamHandlerMethodArgumentResolver()); } } ④绑定参数解析器到controller
@ApiOperation(value = "查询全部用户信息详情测试") @GetMapping(value = "/findAllUserInfoTest") public Result findAllUserInfoTest(@Param String id) { return Result.success(id); }
- aop切面是spring框架的重要组件之一,在项目应用中我们主要用来做操作日志的记录,它能够获取到方法级别的入参、出参,可用作低粒度级别的web资源处理器。
- 使用步骤
①创建切面注解
package com.yundi.atp.platform.annotation; import java.lang.annotation.*; /** * @Author: 北溟溟 * @Description: 日志注解 * @Date: 2022/1/25 16:30 * @Version: 1.0.0 */ @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface OperationLog { }
②创建日志切面OperationLogAspect
package com.yundi.atp.platform.aspect; import com.yundi.atp.platform.annotation.OperationLog; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.context.annotation.Configuration; /** * @Author: 北溟溟 * @Description: 通过切面鉴权 * @Date: 2022/1/25 16:34 * @Version: 1.0.0 */ @Aspect @Slf4j @Configuration public class OperationLogAspect { /** * 切点 */ @Pointcut("@annotation(com.yundi.atp.platform.annotation.OperationLog)") public void logPointCut() { } @Around(value = "logPointCut() && @annotation(operationLog)") public void operationLogStore(JoinPoint joinPoint, OperationLog operationLog) { //todo 日志处理 log.info("【切面】这是一个切面的使用!"); } }
③ 应用
@Auth @OperationLog @ApiOperation(value = "查询全部用户信息详情") @GetMapping(value = "/findAllUserInfo") public Result findAllUserInfo() { List
userList = userService.findAllUserInfo(); return Result.success(userList); }
OK,本期内容到这里就结束了,我们下期见。。。