异常,异常。我们一定要捕获一切该死的异常,宁可错杀一千也不能放过一个!产品上线后的异常更要命,一定要屏蔽错误内容,以免暴露敏感信息!在用Spring MVC开发WEB应用时捕获全局异常的方法基本有两种:
WEB.XML,就是指定error-code和page到指定地址,这也是最传统和常见的做法
用Spring的全局异常捕获功能,这种相对可操作性更强一些,可根据自己的需要做一后善后处理,比如日志记录等。
SO,本文列出Spring-MVC做WEB开发时常用全局异常捕获的几种解决方案抛砖引玉,互相没有依赖,每个都可单独使用!
1、定义服务器错误WEB.XML整合Spring MVC
web.xml:
1
2 404
3 /404
4
5
6 500
7 /500
8
9
10
11
12 java.lang.Exception
13 /uncaughtException
14
applicationContext.xml:
1
2
3
4
2、Spring全局异常,Controller增强方式( Advising Controllers)
异常抛出:
1 @Controller2 public classMainController {3 @ResponseBody4 @RequestMapping("/")5 publicString main(){6 throw new NullPointerException("NullPointerException Test!");7 }8 }
异常捕获:
1 //注意使用注解@ControllerAdvice作用域是全局Controller范围,即必须与抛出异常的method在同一个controller2 //可应用到所有@RequestMapping类或方法上的@ExceptionHandler、@InitBinder、@ModelAttribute,在这里是@ExceptionHandler
3 @ControllerAdvice4 public classAControllerAdvice {5 @ExceptionHandler(NullPointerException.class)6 @ResponseStatus(HttpStatus.BAD_REQUEST)7 @ResponseBody8 publicString handleIOException(NullPointerException ex) {9 return ClassUtils.getShortName(ex.getClass()) +ex.getMessage();10 }11 }
为了确保@ResponseStatus标注的异常被Spring框架处理,可以这样编写全局异常处理类:
1 @ControllerAdvice2 classGlobalDefaultExceptionHandler {3 public static final String DEFAULT_ERROR_VIEW = "error";4
5 @ExceptionHandler(value = Exception.class)6 public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throwsException {7 //If the exception is annotated with @ResponseStatus rethrow it and let8 //the framework handle it - like the OrderNotFoundException example9 //at the start of this post.10 //AnnotationUtils is a Spring Framework utility class.
11 if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null)12 throwe;13
14 //Otherwise setup and send the user to a default error-view.
15 ModelAndView mav = newModelAndView();16 mav.addObject("exception", e);17 mav.addObject("url", req.getRequestURL());18 mav.setViewName(DEFAULT_ERROR_VIEW);19 returnmav;20 }21 }
3、Spirng全局异常,配置方式
异常抛出,同上!
异常捕获:
1
2
3
4
5 errors/500
6 errors/500
7
8
9
10
11 500
12
13
14
15
16
17
18
19
20
对应500错误的view jsp页面:
1
2
3
4
5
6
7
500 Error8
9
10
11
Exception:
12
13
14
15
4、Sping全局异常,自定义异常类和异常解析
自定义异常类:
1 public class CustomException extendsRuntimeException {2
3 publicCustomException(){4 super();5 }6
7 publicCustomException(String msg, Throwable cause){8 super(msg, cause);9 //Do something...
10 }11 }
抛出异常:
1 @ResponseBody2 @RequestMapping("/ce")3 publicString ce(CustomException e){4 throw new CustomException("msg",e);5 }
实现异常捕获接口HandlerExceptionResolver:
1 public class CustomHandlerExceptionResolver implementsHandlerExceptionResolver{2
3 @Override4 publicModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {5 Map model = new HashMap();6 model.put("e", e);7 //这里可根据不同异常引起类做不同处理方式,本例做不同返回页面。
8 String viewName =ClassUtils.getShortName(e.getClass());9 return newModelAndView(viewName, model);10 }11 }
新的的HandlerExceptionResolver实现类只需在配置文件中定义即可,可以配置优先级。DispatcherServlet初始化HandlerExceptionResolver的时候会自动寻找容器中实现了HandlerExceptionResolver接口的类,然后添加进来。配置Spring支持异常捕获:
1
5、Errors and REST
使用Restful的Controller可以使用@ResponseBody处理错误,首先定义一个错误:
1 public classErrorInfo {2 public finalString url;3 public finalString ex;4
5 publicErrorInfo(String url, Exception ex) {6 this.url =url;7 this.ex =ex.getLocalizedMessage();8 }9 }
通过一个@ResponseBody返回一个错误实例:
1 @ResponseStatus(HttpStatus.BAD_REQUEST)2 @ExceptionHandler(MyBadDataException.class)3 @ResponseBody ErrorInfo handleBadRequest(HttpServletRequest req, Exception ex) {4 return newErrorInfo(req.getRequestURL(), ex);5 }
6、参考: