关于过滤器和拦截器
看一下过滤器,过滤器我们可以分两步:
1.配置自定义过滤器
2.过滤器注册
这样它才会生效,拦截器也如此
先配置:
@RequiredArgsConstructor
public class UserTransmitFilter implements Filter {
private final StringRedisTemplate stringRedisTemplate;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String requestURI = httpServletRequest.getRequestURI();
//如果不是登录路径 要验证
if(!Objects.equals(requestURI,"/api/short-link/v1/user/login")) {
String username = httpServletRequest.getHeader("username");
String token = httpServletRequest.getHeader("token");
Object JsonStrUserDO = stringRedisTemplate.opsForHash().get("login_" + username, token);
UserDO userInfoJsonstr = JSONUtil.toBean((String) JsonStrUserDO, UserDO.class);
if (userInfoJsonstr != null) {
UserInfoDTO userInfoDTO = BeanUtil.copyProperties(userInfoJsonstr,UserInfoDTO.class);
userInfoDTO.setUserId(userInfoJsonstr.getId().toString());
UserContext.setUser(userInfoDTO);
}
}
try {
filterChain.doFilter(servletRequest, servletResponse);
} finally {
UserContext.removeUser();
}
}
}
再注册:
@Configuration
public class UserConfiguration {
/**
* 用户信息传递过滤器
*/
@Bean
public FilterRegistrationBean<UserTransmitFilter> globalUserTransmitFilter(StringRedisTemplate stringRedisTemplate) {
FilterRegistrationBean<UserTransmitFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new UserTransmitFilter(stringRedisTemplate));
registration.addUrlPatterns("/*");
registration.setOrder(0);
return registration;
}
}
我们也可以这样注册:
@RequiredArgsConstructor
@Configuration
public class UserConfigurationMvc extends WebMvcConfigurationSupport {
private final StringRedisTemplate stringRedisTemplate;
@Bean
public FilterRegistrationBean<UserTransmitFilter> globalUserTransmitFilter(StringRedisTemplate stringRedisTemplate) {
FilterRegistrationBean<UserTransmitFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new UserTransmitFilter(stringRedisTemplate));
registration.addUrlPatterns("/*");
registration.setOrder(0);
return registration;
}
}
这两种方式都可以用来注册过滤器,但是它们放在不同的配置类中,作用域和目的有所不同:
-
第一个配置类UserConfiguration:
- 在这里直接定义了一个
FilterRegistrationBean
的Bean,用于注册UserTransmitFilter
过滤器。 - 由于没有明确指出这是一个MVC配置类,这个过滤器将会在整个应用程序范围内生效,不仅仅局限于Spring MVC相关的HTTP请求。
- 在这里直接定义了一个
-
第二个配置类UserConfigurationMvc:
- 这个配置类继承自
WebMvcConfigurationSupport
,表明它是专门针对Spring MVC的定制配置类。 - 在这个类中同样定义了一个同名的
FilterRegistrationBean
的Bean,用于注册UserTransmitFilter
过滤器。 - 因为它是一个MVC相关的配置类,所以这里的过滤器主要应用于Spring MVC处理的HTTP请求。
- 这个配置类继承自
拦截器如此:
拦截器实现HandlerInterceptor接口,重写preHandle方法,放行就return true 不然就返回false
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {
@Autowired
private JwtProperties jwtProperties;
/**
* 校验jwt
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断当前拦截到的是Controller的方法还是其他资源
if (!(handler instanceof HandlerMethod)) {
//当前拦截到的不是动态方法,直接放行
return true;
}
//1、从请求头中获取令牌
String token = request.getHeader(jwtProperties.getAdminTokenName());
//2、校验令牌
try {
log.info("jwt校验:{}", token);
Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
log.info("当前员工id:{}", empId);
BaseContext.setCurrentId(empId);
//3、通过,放行
return true;
} catch (Exception ex) {
//4、不通过,响应401状态码
response.setStatus(401);
return false;
}
}
}
然后注册拦截器:
@Configuration
@Slf4j
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
@Autowired
private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;
/**
* 注册自定义拦截器
*
* @param registry
*/
protected void addInterceptors(InterceptorRegistry registry) {
log.info("开始注册自定义拦截器...");
registry.addInterceptor(jwtTokenAdminInterceptor)
.addPathPatterns("/admin/**")
.excludePathPatterns("/admin/employee/login");
}
WebMvcConfigurationSupport是 Spring Framework 提供的一个类,它主要用于提供基础的 Spring MVC 配置支持。在 Spring Boot 中,Spring Boot 自动配置了大量的 Spring MVC 组件,但是如果开发者需要进行更细粒度的自定义配置,例如自定义拦截器、过滤器、视图解析器、消息转换器等,就可以通过扩展WebMvcConfigurationSupport 类来达到目的。
关于全局异常拦截器
全局异常拦截器是一种用于捕获应用程序中所有未被处理的异常的技术。通过使用全局异常拦截器,我们可以捕获应用程序中的所有未被处理的异常,并在拦截器中统一处理这些异常。这样可以避免因未处理的异常导致的程序崩溃,提高程序的稳定性和可靠性。
自定义异常处理:
自定义异常类通常继承RuntimeException或者Exception。通过自定义异常,更准确的表达错误情况。
1.比如这样(自定义异常):
public class BaseException extends RuntimeException {
public BaseException() {
}
public BaseException(String msg) {
super(msg);
}
}
2.可以再定义异常类去基础它来,更加详细的描述:
2.1比如这个密码错误的异常
public class PasswordErrorException extends BaseException {
public PasswordErrorException(String msg) {
super(msg);
}
}
2.2这个删除异常:
public class DeletionNotAllowedException extends BaseException {
public DeletionNotAllowedException(String msg) {
super(msg);
}
}
3.然后全局异常处理去处理它:
/**
* 全局异常处理器,处理项目中抛出的业务异常
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 捕获业务异常
* @param ex
* @return
*/
@ExceptionHandler(BaseException.class)
public Result exceptionHandler(BaseException ex){
log.error("异常信息:{}", ex.getMessage());
return Result.error(ex.getMessage());
}
}
第二步,为了标准的表达,自己写的话,当然是方便可以省略啦!
当然,开发还有更规范的异常定义处理