SpringBoot处理(Controller、interceptor、filter)全局异常
Posted on 2022-02-22 11:12 FLGB 阅读(643) 评论(0) 编辑 收藏 举报## 1、Controller层的全局异常处理
通过对Controller添加注释@ControllerAdvice可以实现Controller层的全局异常处理
统一的拦截异常处理类AppExceptionHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | @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); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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注释的异常处理类捕获的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | (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 返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | @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内部抛出异常)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix