SpringBoot处理(Controller、interceptor、filter)全局异常
Posted on 2022-02-22 11:12 FLGB 阅读(554) 评论(0) 编辑 收藏 举报## 1、Controller层的全局异常处理
通过对Controller添加注释@ControllerAdvice可以实现Controller层的全局异常处理
统一的拦截异常处理类AppExceptionHandler
@Slf4j @RestControllerAdvice public class AppExceptionHandler { @Autowired protected MessageSource messageSource; @ExceptionHandler({UserLoginException.class}) @ResponseStatus(HttpStatus.FORBIDDEN) public Result handleUserLoginException(final UserLoginException userLoginException) { log.error("LiveAppExceptionHandler->UserLoginException={}", userLoginException); return Result.error(userLoginException.getCode(), userLoginException.getMessage()); } @ExceptionHandler({UrlException.class}) @ResponseStatus(HttpStatus.OK) public Result handleChanceException(final UrlException urlException) { log.error("【UrlException】:", UrlException); return Result.error(urlException.getCode(), urlException.getMessage()); } @ExceptionHandler({Exception.class}) @ResponseStatus(HttpStatus.OK) public Result handleException(final Exception exception) { log.error("【exception】:", exception); return Result.error(AdminErrorCodeEnum.A0001); } }
Result 统一封装的返回类 @Data public class Result<T> { private int code; private T data; private String msg; public static <T> Result<T> success(T response) { Result<T> result = new Result<>(); result.setCode(0); result.setData(response); return result; } public static Result error(int code, String message) { Result result = new Result(); result.setCode(code); result.setMsg(message); return result; } public static Result error(AppErrorCodeEnum errorCodeEnum) { Result result = new Result(); result.setCode(errorCodeEnum.getCode()); result.setMsg(errorCodeEnum.getMessage()); return result; } public static Result error(AppErrorCodeEnum errorCodeEnum, MessageSource messageSource, Object... params) { Result jsonResult = new Result(); jsonResult.setCode(errorCodeEnum.getCode()); jsonResult.setMsg(messageSource.getMessage(String.valueOf(errorCodeEnum.getCode()), params, errorCodeEnum.getMessage(), Locale.SIMPLIFIED_CHINESE)); return jsonResult; } }
## 2、Interceptor异常统一处理
Interceptor是基于SpringMVC框架的,有时候我们需要拦截器中进行逻辑处理时(比如:tonken登陆验证)需要抛出异常,那么这里抛出的异常是可以被@ControllerAdvice注释的异常处理类捕获的。
InterceptorConfig 配置类,将具体的拦截器类注册到InterceptorConfig 中 ```bash @Configuration public class InterceptorConfig implements WebMvcConfigurer { @Autowired SessionInterceptor userLoginInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { InterceptorRegistration interceptorRegistration = registry.addInterceptor(userLoginInterceptor); interceptorRegistration.addPathPatterns("/**"); interceptorRegistration.excludePathPatterns( "/login/**" ); } ``` 实际的业务拦截器类SessionInterceptor ```bash @Slf4j @Component public class SessionInterceptor implements HandlerInterceptor { @Autowired RedisTemplate redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String token = request.getHeader("token"); if (StringUtils.isEmpty(token)){ log.error("传入token参数值为空={},请先登录",token); throw new UserLoginException(AppErrorCodeEnum.A0003.getCode(),AppErrorCodeEnum.A0003.getMessage() ); } //从redis中获取token LiveTokenDTO liveTokenDTO = (LiveTokenDTO) redisTemplate.opsForValue().get(token); if(ObjectUtil.isNotEmpty(liveTokenDTO)){ return true; } else { log.error("SessionInterceptor->userToken用户会话解析为空"); throw new UserLoginException(AppErrorCodeEnum.A0003.getCode(),AppErrorCodeEnum.A0003.getMessage() ); } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } ``` 异常类 ```bash @data public class UserLoginException extends RuntimeException{ int code; String message; } ``` 枚举类 ```bash @Getter public enum AppErrorCodeEnum { A0000(10000, "参数校验失败"), A0001(10001, "系统繁忙,请稍后再试"), A0002(10002, "登录失败"), A0003(10003, "token失效,请重新登录"); private int code; private String message; private String subCode; private String subMessage; AppErrorCodeEnum(int code, String message) { this.code = code; this.message = message; } public void setSubCodeAndSubMessage(String subCode, String subMessage) { setSubCode(subCode); setSubMessage(subMessage); } private void setSubCode(String subCode) { this.subCode = subCode; } private void setSubMessage(String subMessage) { this.subMessage = subMessage; } }
## 3、Filter异常统一处理
过滤器Filter和基于Servlet框架编写的,抛出的异常是不可以被@ControllerAdvice注释的异常处理类捕获的,常见的异常处理的方法有两种:
(1)通过请求转发到特定的异常处理controller中进行处理
(1)通过请求转发到特定的异常处理controller中进行处理 定义一个filter异常处理的Controller ```bash @Slf4j @RestController @RequestMapping("/filter") public class FilterExceptionController { @RequestMapping("exception") public void handleException() { throw new UrlException(AppErrorCodeEnum.A0003.getCode(), AppErrorCodeEnum.A0003.getMessage()); } } ``` 请求url路径过滤器 ```bash @Slf4j @Component public class RequestUrlFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { String path = ((HttpServletRequest) servletRequest).getRequestURI(); if (!path.contains("/app")) { // throw new UrlException(401, "filter内部抛出异常");//AppExceptionHandler 全局异常捕获不到 //转发给filter异常处理的Controller,controller中直接抛出异常,AppExceptionHandler全局异常就可已捕获到了 servletRequest.getRequestDispatcher("/filter/exception").forward(servletRequest,servletResponse); } filterChain.doFilter(servletRequest, servletResponse); } }
(2)、SpringBoot 提供了 ErrorController 这个接口能力;其内置了一个 BasicErrorController 对异常进行统一的处理,当在 Controller 发生异常的时候会自动把请求 forward 到 /error 这个请求 path 下(/error 是 SpringBoot 提供的一个默认的mapping)。BasicErrorController 提供两种返回错误:1、页面返回;2、json 返回。
@RestController public class UrlErrorController extends BasicErrorController { public UrlErrorController() { super(new DefaultErrorAttributes(), new ErrorProperties()); } @Override @RequestMapping(produces = {MediaType.APPLICATION_JSON_VALUE}) public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL)); HttpStatus status = getStatus(request); return new ResponseEntity((String) body.get("message"), status); } } ``` 将filter异常直接抛出 @Slf4j @Component public class RequestUrlFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { String path = ((HttpServletRequest) servletRequest).getRequestURI(); if (!path.contains("/app")) { throw new UrlException(401, "filter内部抛出异常"); } filterChain.doFilter(servletRequest, servletResponse); } }
返回:java.lang.RuntimeException: UrlException(code=401, message=filter内部抛出异常)