如何在ControllerAdvice中获取Controller方法签名判断是否含@ResponseBody
结论
可以直接在@ExceptionHandler方法中获取到抛出异常的目标Controller方法的签名和注解信息。Spring MVC的异常处理方法支持自动注入HandlerMethod对象,该对象封装了目标请求处理方法的所有元数据,包含所属类信息、方法签名、方法及类上的注解等。
具体实现代码
你可以参考如下改造后的ControllerAdvice代码,实现你的需求:
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.method.HandlerMethod; import java.util.Map; @ControllerAdvice class SomeAdvice { // 去掉方法上的@ResponseBody注解,根据场景动态返回JSON或视图 @ExceptionHandler(Exception.class) public Object handle(Exception e, HandlerMethod handlerMethod) { // 优先判断方法上是否标注@ResponseBody boolean returnJson = handlerMethod.hasMethodAnnotation(ResponseBody.class); // 方法上没有的话再判断Controller类上是否标注@ResponseBody(@RestController自带@ResponseBody,也会被识别) if (!returnJson) { returnJson = handlerMethod.getBeanType().isAnnotationPresent(ResponseBody.class); } if (returnJson) { // 接口类型的请求,返回指定格式的JSON响应 return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(Map.of("message", "something happened")); } else { // 页面类型的请求,重定向到默认错误页面,也可直接返回视图名如"error" return "redirect:/error"; } } }
兼容边界场景
如果异常是在请求进入Controller方法前抛出的(比如路径不存在、过滤器/拦截器层面抛出异常),此时没有对应的HandlerMethod对象,会出现参数注入失败的问题,你可以调整参数做兼容:
@ExceptionHandler(Exception.class) public Object handle(Exception e, Object handler) { if (handler instanceof HandlerMethod handlerMethod) { boolean returnJson = handlerMethod.hasMethodAnnotation(ResponseBody.class); if (!returnJson) { returnJson = handlerMethod.getBeanType().isAnnotationPresent(ResponseBody.class); } if (returnJson) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(Map.of("message", "something happened")); } } // 非Controller方法抛出的异常统一走错误页面 return "redirect:/error"; }
内容的提问来源于stack exchange,提问作者FirePizza
相关产品推荐
相关产品推荐

