如何区分处理@Controller与@RestController抛出的相同异常?
区分@Controller和@RestController抛出的相同自定义异常处理方案
不需要定义不同的自定义异常,Spring MVC提供了两种成熟的方案来实现根据异常来源控制器类型区分处理逻辑:
方案1:通过@ControllerAdvice/@RestControllerAdvice的注解筛选功能(推荐)
利用@ControllerAdvice和@RestControllerAdvice的annotations属性,直接指定各自负责处理的控制器类型,Spring会自动将异常路由到对应的处理器:
处理@Controller的异常处理器
@ControllerAdvice(annotations = Controller.class) public class ControllerGlobalExceptionHandler { @ExceptionHandler(CustomBizException.class) public ModelAndView handleControllerException(CustomBizException ex) { ModelAndView mav = new ModelAndView("error-page"); mav.addObject("errorCode", ex.getErrorCode()); mav.addObject("errorMsg", ex.getErrorMessage()); return mav; } }
处理@RestController的异常处理器
@RestControllerAdvice(annotations = RestController.class) public class RestGlobalExceptionHandler { @ExceptionHandler(CustomBizException.class) public ResponseEntity<ErrorResponse> handleRestException(CustomBizException ex) { ErrorResponse response = new ErrorResponse(ex.getErrorCode(), ex.getErrorMessage()); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); } }
原理:@ControllerAdvice(annotations = Controller.class)只会拦截标注了@Controller的控制器抛出的异常,@RestControllerAdvice(annotations = RestController.class)同理只会处理@RestController的异常,Spring会自动完成路由,代码清晰且符合Spring原生设计。
方案2:在单个异常处理器中判断控制器类型
如果需要在同一个方法中处理两种场景,可以通过获取当前请求对应的HandlerMethod,判断控制器类的注解类型:
@ControllerAdvice public class UnifiedGlobalExceptionHandler { @ExceptionHandler(CustomBizException.class) public Object handleException(CustomBizException ex, ServletWebRequest webRequest) { HandlerMethod handlerMethod = getCurrentHandlerMethod(webRequest); if (handlerMethod != null && handlerMethod.getBeanType().isAnnotationPresent(RestController.class)) { // 处理RestController场景:返回JSON响应 ErrorResponse response = new ErrorResponse(ex.getErrorCode(), ex.getErrorMessage()); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); } else { // 处理Controller场景:返回视图 ModelAndView mav = new ModelAndView("error-page"); mav.addObject("errorCode", ex.getErrorCode()); mav.addObject("errorMsg", ex.getErrorMessage()); return mav; } } private HandlerMethod getCurrentHandlerMethod(ServletWebRequest webRequest) { Object handler = webRequest.getRequest().getAttribute(DispatcherServlet.EXECUTION_ATTRIBUTE); return handler instanceof HandlerMethod ? (HandlerMethod) handler : null; } }
原理:通过DispatcherServlet.EXECUTION_ATTRIBUTE获取当前处理请求的HandlerMethod,进而判断控制器类是否标注了@RestController,以此分支处理逻辑。
内容的提问来源于stack exchange,提问作者Safvan P
相关产品推荐
相关产品推荐

