本文共 6778 字,大约阅读时间需要 22 分钟。
Spring MVC处理异常有3种方式:
(1)使用@ExceptionHandler注解实现异常处理;
(2)使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver;
(3)实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器;
BusinessException和SystemException为自定义异常类,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | package com.twosnail.exception; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ExceptionHandler; @Controller public class BasicExController { /** * 基于@ExceptionHandler异常处理基类 * @return */ @ExceptionHandler public String exception( HttpServletRequest request , Exception ex ) { // 根据不同错误转向不同页面 if ( ex instanceof BusinessException ) { return "business-error" ; } else if ( ex instanceof SystemException ) { return "system-error" ; } else { return "error" ; } } } |
1 | public class DemoController extends BasicExController {} |
然而,Dao层、Service层、Controller层抛出的异常(BusinessException、SystemException和其它异常)都能准确显示定义的异常处理页面,达到了统一异常处理的目标。
总结:使用@ExceptionHandler注解实现异常处理,具有集成简单、有扩展性好(只需要将要异常处理的Controller类继承于BasicExController即可)、不需要附加Spring配置等优点,但该方法对已有代码存在入侵性(需要修改已有代码,使继承于BasicExController),在异常处理时不能获取除异常以外的数据。
SimpleMappingExceptionResolver有两种配置方式,可以按自己需求而定,配置代码如下:
在这里,可以设置跳转相应页面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | < bean class = "org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" > <!-- 定义默认的异常处理页面,当该异常类型的注册时使用 --> < property name = "defaultErrorView" value = "error" ></ property > <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception --> < property name = "exceptionAttribute" value = "ex" ></ property > <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常也页名作为值 --> < property name = "exceptionMappings" > < props > < prop key = "com.twosnail.exception.BusinessException" >business-error</ prop > < prop key = "com.twosnail.exception.SystemException" >system-error</ prop > </ props > </ property > <!-- 相关状态码对应的错误页面 --> < property name = "statusCodes" > < props > < prop key = "errors/500" >500</ prop > < prop key = "errors/404" >404</ prop > </ props > </ property > <!-- 设置日志输出级别,不定义则默认不输出警告等错误日志信息 --> < property name = "warnLogCategory" value = "WARN" /> <!-- 默认HTTP状态码 --> < property name = "defaultStatusCode" value = "500" /> </ bean > |
然后在Spring的配置。代码如下:
1 2 3 4 5 6 7 8 9 | < bean id = "exceptionResolver" class = "com.twosnail.exception.MyselfSimpleMappingExceptionResolver" > < property name = "exceptionMappings" > < props > < prop key = "com.twosnail.exception.SystemException" >error/500</ prop > < prop key = "com.twosnail.exception.BusinessException" >error/errorpage</ prop > < prop key = "java.lang.exception" >error/500</ prop > </ props > </ property > </ bean > |
java类代码如下,在这里可以处理相应逻辑,如下,分别处理了jsp页面和json数据:
1 2 3 4 5 6 7 8 9 10 11 1 3 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | package com.twosnail.exception; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; public class MyselfSimpleMappingExceptionResolver extends SimpleMappingExceptionResolver { @Override protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { // Expose ModelAndView for chosen error view. String viewName = determineViewName(ex, request); if (viewName != null ) { // JSP格式返回 if (!(request.getHeader( "accept" ).indexOf( "application/json" ) > - 1 || (request .getHeader( "X-Requested-With" ) != null && request .getHeader( "X-Requested-With" ).indexOf( "XMLHttpRequest" ) > - 1 ))) { // 如果不是异步请求 // Apply HTTP status code for error views, if specified. // Only apply it if we're processing a top-level request. Integer statusCode = determineStatusCode(request, viewName); if (statusCode != null ) { applyStatusCodeIfPossible(request, response, statusCode); } return getModelAndView(viewName, ex, request); } else { // JSON格式返回 try { PrintWriter writer = response.getWriter(); writer.write(ex.getMessage()); writer.flush(); } catch (IOException e) { e.printStackTrace(); } return null ; } } else { return null ; } } } |
总结:使用SimpleMappingExceptionResolver进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,但方法1仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适用。
1 | < bean id = "exceptionHandler" class = "com.twosnail.exception.MyExceptionHandler" /> |
在这里,单独打印出了异常路径,便于在日志中查看,在对SystemException异常进行了特殊处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 5 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | package com.twosnail.exception; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.View; import org.springframework.web.servlet.view.RedirectView; public class MyExceptionHandler implements HandlerExceptionResolver { public ModelAndView resolveException( HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception ) { System.out.println( "【抛出异常】--异常路径为:" + request.getServletPath() + "\n【异常信息】--" + exception.getMessage() ) ; //如果不是抛出的action业务异常则不处理 if ( !( exception instanceof SystemException ) ) { return null ; } final SystemException actionE = (SystemException) exception; ModelAndView model = null ; if ( actionE.getForwardType() == SystemException.FORWARD ) { //进入页面渲染 model = new ModelAndView( actionE.getModelPath(), actionE.getAttributes()); } else if ( actionE.getForwardType() == SystemException.REDIRECT ) { model = new ModelAndView( new RedirectView( actionE.getModelPath(), true )); } else { //直接返回页面内容 model = new ModelAndView( new View() { @Override public void render(Map<String, ?> arg0, HttpServletRequest arg1, HttpServletResponse arg2) throws Exception { arg2.setContentType( "text/html" ); arg2.setCharacterEncoding( actionE.getEncode() ); if ( actionE.getResponseBody() != null ) { arg2.getWriter().print( actionE.getResponseBody() ); } } @Override public String getContentType() { return "text/html; charset=utf-8" ; } } ); } return model; } } |
总结:从上面的集成过程可知,使用实现HandlerExceptionResolver接口的异常处理器进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点。在异常处理时能获取导致出现异常的对象,有利于提供更详细的异常处理信息。而SimpleMappingExceptionResolver就是HandlerExceptionResolver的默认实现类
转载地址:http://jdjdi.baihongyu.com/