@ControllerAdvice中能否为同一异常配置适配不同请求的多个@ExceptionHandler
问题原因
Spring MVC 的 @ExceptionHandler 注解仅根据异常类型完成匹配映射,不会参考方法入参中除异常外的其他参数类型。你定义的两个方法都声明处理WebServiceContactException类型异常,Spring 启动时无法区分两个方法的映射规则,就会抛出歧义异常。
可行实现方案
方案1:单处理方法兼容多请求类型(最推荐)
直接在同一个异常处理方法中判断请求类型,既满足日志取值需求,也不会出现映射冲突。@ExceptionHandler 方法支持直接注入当前请求的请求体对象,用Object接收后做类型判断即可:
@EnableWebMvc @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(WebServiceContactException.class) @ResponseStatus(value = HttpStatus.PRECONDITION_FAILED) @ResponseBody public MyResponse dealWebServiceContactException(WebServiceContactException e, Object request) { int errorCode = HttpStatus.PRECONDITION_FAILED.value(); String functionalId = null; // 判断请求类型取值 if (request instanceof AddRequest addRequest) { functionalId = addRequest.getFunctionalId(); } else if (request instanceof DeleteRequest deleteRequest) { functionalId = deleteRequest.getFunctionalId(); } LOGGER.error("Failed to contact service for " + functionalId, e); auditTrail.reportFailureInfo(e.getMessage()); return MyResponse.Builder.newBuilder(errorCode) .setDescription(Constants.EXECUTION_FAILED) .build(); } }
如果你的请求参数不是直接作为请求体传入,也可以注入HttpServletRequest/WebRequest对象,从中获取对应参数值。
方案2:自定义异常携带请求信息
抛出自定义异常时,直接把当前请求对象作为入参传入异常构造方法,处理时直接从异常中取所需字段即可:
首先修改自定义异常类:
public class WebServiceContactException extends RuntimeException { private final Object request; public WebServiceContactException(String message, Object request) { super(message); this.request = request; } // 省略getter方法 }
控制器抛异常时传入当前请求:
// Add接口中抛异常示例 throw new WebServiceContactException("调用服务失败", addRequest);
异常处理方法就不需要额外接收请求参数,直接从异常对象取值即可。
方案3:拆分多份ControllerAdvice指定作用范围
如果确实要拆分不同的处理方法,可以定义两个不同的@ControllerAdvice类,分别指定生效的控制器范围,每个类中各写一个异常处理方法,避免冲突:
// 仅处理Add相关控制器的异常 @ControllerAdvice(assignableTypes = AddController.class) public class AddExceptionHandler { @ExceptionHandler(WebServiceContactException.class) @ResponseStatus(value = HttpStatus.PRECONDITION_FAILED) @ResponseBody public MyResponse dealAddException(WebServiceContactException e, AddRequest request) { // 对应处理逻辑 } } // 仅处理Delete相关控制器的异常 @ControllerAdvice(assignableTypes = DeleteController.class) public class DeleteExceptionHandler { @ExceptionHandler(WebServiceContactException.class) @ResponseStatus(value = HttpStatus.PRECONDITION_FAILED) @ResponseBody public MyResponse dealDeleteException(WebServiceContactException e, DeleteRequest request) { // 对应处理逻辑 } }
内容的提问来源于stack exchange,提问作者Bhupesh_decoder
相关产品推荐
相关产品推荐

