在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,系统的代码耦合度高,工作量大且不好统一,维护的工作量也很大。 那么,能不能将所有类型的异常处理从各处理过程解耦出来,这样既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护?答案是肯定的。下面将介绍使用Spring MVC统一处理异常的解决和实现过程。

spring aop 异常捕获事务回滚 spring 全局异常捕获_spring

 

  • 使用Spring MVC提供的SimpleMappingExceptionResolver
  • 实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器
  • 使用@ExceptionHandler注解实现异常处理

一. SimpleMappingExceptionResolver

使用这种方式具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,但该方法仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适用。

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.rz.mvc.web"})
public class WebMVCConfig extends WebMvcConfigurerAdapter{
 @Bean
 public SimpleMappingExceptionResolver simpleMappingExceptionResolver()
 {
 SimpleMappingExceptionResolver b = new SimpleMappingExceptionResolver();
 Properties mappings = new Properties();
 mappings.put("org.springframework.web.servlet.PageNotFound", "page-404");
 mappings.put("org.springframework.dao.DataAccessException", "data-access");
 mappings.put("org.springframework.transaction.TransactionException", "transaction-Failure");
 b.setExceptionMappings(mappings);
 return b;
 }
}

二. HandlerExceptionResolver

相比第一种来说,HandlerExceptionResolver能准确显示定义的异常处理页面,达到了统一异常处理的目标

1.定义一个类实现HandlerExceptionResolver接口

public class GlobalHandlerExceptionResolver implements HandlerExceptionResolver { 

     private static final Logger LOG = LoggerFactory.getLogger(GlobalHandlerExceptionResolver.class); 
 /** 
 * 在这里处理所有得异常信息 
 */ 
 @Override 
 public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse resp, 
      Object o, Exception ex) { 
     ex.printStackTrace(); 
     if (ex instanceof AthenaException) { 
         //AthenaException为一个自定义异常
           ex.printStackTrace(); 
           printWrite(ex.toString(), resp); 
           return new ModelAndView(); 
     } 

    //RspMsg为一个自定义处理异常信息的类 
    //ResponseCode为一个自定义错误码的接口
      RspMsg unknownException = null; 
     if (ex instanceof NullPointerException) { 
           unknownException = new RspMsg(ResponseCode.CODE_UNKNOWN, "业务判空异常", null);
     } else { 
           unknownException = new RspMsg(ResponseCode.CODE_UNKNOWN, ex.getMessage(), null); 
     } 
      printWrite(unknownException.toString(), resp); 
      return new ModelAndView(); 
 } 

 /** 
 * 将错误信息添加到response中 
 * 
 * @param msg 
 * @param response 
 * @throws IOException 
 */ 
 public static void printWrite(String msg, HttpServletResponse response) { 
   try { 
        PrintWriter pw = response.getWriter(); 
        pw.write(msg); 
        pw.flush(); 
        pw.close(); 
   } catch (Exception e) { 
        e.printStackTrace(); 
   } 
 }

}

这种方式实现的异常处理,可以针对不同的异常和自己定义的异常码进行翻译,然后输出到response中,在前端展示。

三 . ExceptionHandler

1.首先定义一个父类,实现一些基础的方法

public class BaseGlobalExceptionHandler { 

 protected static final Logger logger = null; 
 protected static final String DEFAULT_ERROR_MESSAGE = "系统忙,请稍后再试"; 
 protected ModelAndView handleError(HttpServletRequest req, HttpServletResponse rsp, Exception e, String viewName, HttpStatus status) throws Exception { 
 
	 if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) 
	 throw e; 
	 String errorMsg = e instanceof MessageException ? e.getMessage() : DEFAULT_ERROR_MESSAGE; 
	 String errorStack = Throwables.getStackTraceAsString(e); 
	 getLogger().error("Request: {} raised {}", req.getRequestURI(), errorStack); 
	 if (Ajax.isAjax(req)) { 
		 return handleAjaxError(rsp, errorMsg, status); 
	 } 
     return handleViewError(req.getRequestURL().toString(), errorStack, errorMsg, viewName); 
 } 
 
 protected ModelAndView handleViewError(String url, String errorStack, String errorMessage, String viewName) { 
	 ModelAndView mav = new ModelAndView(); 
	 mav.addObject("exception", errorStack); 
	 mav.addObject("url", url); 
	 mav.addObject("message", errorMessage); 
	 mav.addObject("timestamp", new Date()); 
	 mav.setViewName(viewName); 
	 return mav; 
 } 
 
 protected ModelAndView handleAjaxError(HttpServletResponse rsp, String errorMessage, HttpStatus status) throws IOException { 
	 rsp.setCharacterEncoding("UTF-8"); 
	 rsp.setStatus(status.value()); 
	 PrintWriter writer = rsp.getWriter();
	 writer.write(errorMessage); 
	 writer.flush(); 
	 return null; 
 } 
 
 public Logger getLogger() { 
     return LoggerFactory.getLogger(BaseGlobalExceptionHandler.class);
 } 
 
}

2.针对你需要捕捉的异常实现相对应的处理方式

@ControllerAdvice
public class GlobalExceptionHandler extends BaseGlobalExceptionHandler { 

	 //比如404的异常就会被这个方法捕获
	 @ExceptionHandler(NoHandlerFoundException.class) 
	 @ResponseStatus(HttpStatus.NOT_FOUND) 
	 public ModelAndView handle404Error(HttpServletRequest req, HttpServletResponse rsp, Exception e) throws Exception { 
	      return handleError(req, rsp, e, "error-front", HttpStatus.NOT_FOUND); 
	 } 
	 
	 //500的异常会被这个方法捕获
	 @ExceptionHandler(Exception.class) 
	 @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) 
	 public ModelAndView handleError(HttpServletRequest req, HttpServletResponse rsp, Exception e) throws Exception { 
	      return handleError(req, rsp, e, "error-front", HttpStatus.INTERNAL_SERVER_ERROR); 
	 } 
	 
	 //TODO 你也可以再写一个方法来捕获你的自定义异常
	 //TRY NOW!!!
	 @Override 
	 public Logger getLogger() { 
	      return LoggerFactory.getLogger(GlobalExceptionHandler.class); 
	 }
 }

另附:怎么优雅的处理Java异常?