SpringMVC全局异常处理有好几种方式,每种都有自己的应用场景,在这里做一个整理,仅供参考。
方式有两种,都是在web.xml
中配置。可以通过匹配http错误代码,来进行相应的处理:
<error-page>
<error-code>404error-code>
<location>/WEB-INF/velocity/template/404.vmlocation>
error-page>
<error-page>
<error-code>404error-code>
<location>/error/exception/404location>
error-page>
然后再在Controller
中加入以下代码,可以按需加入一些逻辑:
@RequestMapping("/error/exception/404")
public String return404Vm(HttpServletRequest request,Model model){
model.addAttribute("errorMsg", "404 not found,host:" + request.getRemoteAddr());
return "404";
}
最后,附上简易的404界面:
<div>
your page is 404.
detail: ${errorMsg}
div>
error-code方式配置简便,一目了然,适合处理一些固定的http的错误代码的异常。
@ExceptionHandler
可以对指定的异常或者所有异常编写特定的处理逻辑。
@ExceptionHandler
单独使用时,必须和要处理的方法在一个Controller类里面。
这种配置方式处理的优先级最高,可以返回多种类型数据。下面这个例子处理CustomException
,打印错误栈,并返回提示信息给客户端:
@ResponseBody
@ExceptionHandler({CustomException.class})
public String exception(CustomException e) {
e.printStackTrace();
return "ExceptionHandler has handled this " + e.getMessage();
}
下面的例子将会展示处理本Controller
内抛出的CustomException
和Custom2Exception
异常。
如果不指定@ExceptionHandler
的value,就处理所有Exception。
注意方法内的参数,指定多个异常类时需要包括value中的参数,否则不会生效。
@ResponseBody
@ExceptionHandler(value={CustomException.class,Custom2Exception.class})
public String exception(Exception e) {
e.printStackTrace();
return "ExceptionHandler has handled this " + e.getMessage();
}
@ExceptionHandler
单独使用时,必须与需要处理异常的方法处于同一个Controller
,代码侵入性高。
而且,只能处理当前Controller
中的异常,代码冗余度高。
但是,请牢记一点,这种用法的处理优先级是最高的。
这种配置方式可以在全局范围内处理异常,下面是示例代码。
@ControllerAdvice
public class GlobalControllerAdvice {
private static final Logger logger = LoggerFactory
.getLogger(AControllerAdvice.class);
/**
* 处理NullPointerException,并返回错误信息字符串
* @param ex
* @return
*/
@ExceptionHandler(NullPointerException.class)
@ResponseBody
public String handleIOException(NullPointerException ex) {
return ex.getMessage();
}
/**
* 处理IOException,并返回502错误, 即"Bad Gateway"
* @param ex
* @return
*/
@ExceptionHandler(IOException.class)
@ResponseStatus(HttpStatus.BAD_GATEWAY)
public void handleIOException(IOException ex) {
}
/**
* 处理Custom3Exception异常,并返回带指定错误消息的界面aca
* @param ex
* @return
*/
@ExceptionHandler(Custom3Exception.class)
public ModelAndView handleCustom3Exception(Custom3Exception ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("errorMsg", "Custom3Exception=" + ex.getMessage());
modelAndView.setViewName("aca");
return modelAndView;
}
/**
* 处理所有Exception类型异常
* 但请注意,如果该ControllerAdvice内已经有其他方法处理了指定异常,那就不会进入到该方法处理
* 比如发生Custom3Exception异常,那么只会在@ExceptionHandler(Custom3Exception.class)的方法中处理
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
public ModelAndView Exception(Exception e) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("errorMsg", "服务器处理发生错误,详细信息:" + e.getMessage());
modelAndView.setViewName("global-error");
return modelAndView;
}
}
请务必保证上述使用了@ControllerAdvice注解的类被Spring容器管理。
使用@ControllerAdvice的方式,优先级仅次于单独使用@ExceptionHandler方式。该方式可以全局处理异常,处理逻辑灵活,最为推荐。
必须实现HandlerExceptionResolver接口,重写resolveException方法,可以按需加入一些逻辑:
public class GlobalExceptionResolver implements HandlerExceptionResolver
{
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
{
ModelAndView modelAndView = new ModelAndView();
//设置默认错误界面
modelAndView.setViewName("/default-error");
//传入错误消息
modelAndView.addObject("errorMsg", ex);
//处理CustomException的url
if(ex instanceof CustomException){
modelAndView.setViewName("/custom-exception");
}
//处理Custom2Exception的url
if(ex instanceof Custom2Exception){
modelAndView.setViewName("/custom2-exception");
}
return modelAndView;
}
}
在applicationContext.xml中加入以下配置,向spring注册该类:
<bean class="com.chengc.demos.web.demo1.exception.resolver.GlobalExceptionResolver"/>
实现HandlerExceptionResolver接口,可以处理全局异常,配置简便。但请注意,该方法处理异常的匹配优先级最低。
Stackoverflow-what-are-the-advantages-of-controlleradvice-over-exceptionhandler-or-handlerex