一、概况
正常情况下,请求到达服务端,服务端处理完成后返回数据结果(RESTful前后端分离)或返回页面(传统jsp web工程),这样一次完整的流程就走完了。
异常情况下,如404/405/400/500/302/都是由容器或自定义页面返回给用户。在现在开发中(RESTful 接口),我们需要一个稳定的报文格式返回,包括异常请求情况,这就需要程序感知并处理所有的异常情况。SpringMVC就提供这个机制,统一处理Controller异常;这样对接口的使用者就非常友好,且提示信息明确,减少沟通成本(HEATOS)
异常处理之前返回的结果:
异常处理之后:
二、实现方式
注解@ExceptionHandler,用于异常处理,因所有的请求都需要进行异常处理,所以我们写一个抽象类让所有Controller继承;
public abstract class BaseController {
protected final Logger logger = LoggerFactory.getLogger(BaseController.class);
/** 异常处理 */
@ResponseBody
@ExceptionHandler(Exception.class)
public ResponseEntity<ModelMap> exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
ModelMap modelMap = new ModelMap();
ResponseEntity<ModelMap> result = null;
if (ex instanceof HttpRequestMethodNotSupportedException) {
result = setModelMap(modelMap, HttpStatus.METHOD_NOT_ALLOWED);
} else if (ex instanceof MissingServletRequestParameterException) {
result = setModelMap(modelMap, HttpStatus.BAD_REQUEST);
} else if (ex instanceof IllegalArgumentException) {
result = setModelMap(modelMap, HttpStatus.BAD_REQUEST);
} else {
result = setModelMap(modelMap, HttpStatus.INTERNAL_SERVER_ERROR);
logger.error("INTERNAL_SERVER_ERROR ", ex);
}
String message = ex.getMessage();
if (!StringUtils.isBlank(message)) {
modelMap.put("msg", message);
}
if (logger.isDebugEnabled()) {
logger.debug(ex.getMessage(), ex);
}
return result;
}
}
在ExceptionHandler上加上 @ResponseBody 注解,这样异常代码提示就可以直接返回到用户端了
上面的代码有一个问题:就是405的异常(HtttpRequestMethodNotSupportException)拦截不到,没有进入ExeptionHandler的处理逻辑中;原因:因为GET 没有相应的RequestMapping请求映射找不到相应的controller,就无法触发异常拦截;
解决:@ControllerAdvice注解,把使用@ExceptionHandler、@InitBinder、@ModelAttribute注解的方法应用到所有的 @RequestMapping注解的方法;