今天翻看项目发现异常类中有一个CommonExceptionHandler,却在配置文件中找不到任何有配置的地方,于是搜了一把资料,整理一下。
Spring3.0中有两种异常处理机制,一种是实现HandlerExceptionResolver接口,一种是在Controller类中使用@ExceptionHandler注解,第一种方法可以实现全局异常控制,第二种方法更加灵活,个性化,但是不统一,我之前看的项目中就是用的第一种方法。
1. 基于HandlerExceptionResolver接口的异常处理:
使用这种方法只需要复写 resolveException方法就可以了,该方法返回一个ModelAndView对象,该方法内部对异常的类型做判断,然后返回合适的ModelAndView对象,如果该方法返回了null,则spring会继续寻找其他实现了HandlerExceptionResolver接口的bean,就是说spring会搜索所有注册在其环境中的实现了HandlerExceptionResolver接口的Bean,逐个执行,直到返回了一个ModelAndView对象。(注意该自定义全局异常类一般用注解 @Component,表示模糊不好分层的注入,或者在配置文件xml中使用<bean/>结点声明。)
举例:
@Component
public class CommonExceptionHandler implements HandlerExceptionResolver {
private static final Logger logger = LoggerFactory.getLogger(CommonExceptionHandler.class);
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
try {
response.reset();
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
if (ex instanceof UnAuthenticatedException || ex instanceof NoAuthorityException
|| ex instanceof TimeoutException || ex instanceof ServiceException) {
logger.warn("hander Exception:{}, Message is {}", ex.getClass(), ex.getMessage());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
writer.print(ex.getMessage());
} else if (ex instanceof SystemShutDownException) {
logger.warn("hander Exception:{}, Message is {}", ex.getClass(), ex.getMessage());
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
writer.print(ex.getMessage());
} else {
// 其他异常,返回500状态码
logger.error(ex.getMessage(), ex);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
writer.print("System error");
}
} catch (Exception e) {
//logger.error(e.getMessage(), e);
return null;
}
return new ModelAndView();
}
}
这种写法,错误码直接返回到前台,前台jsp页面获取到之后,进行相应的判断,给出相对应的提示,如果前台页面没有相应的判断,则会直接输入相应的错误信息在页面上。
也可以用一下写法,出现异常之后跳转到一个写好的提示页面:
public class CustomExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object object, Exception exception) {
if(exception instanceof IOException){
return new ModelAndView("errors/ioException");
}else if(exception instanceof SQLException){
return new ModelAndView("errors/sqlException");
}
return null;
}
}
其中 errors/ioException 和 errors/sqlException 都是jsp页面。
spring 默认也提供了一个全局异常处理类SimpleMappingExceptionResolver,它也是HandlerExceptionResolver的实现类,如果要使用,只需要在xml中配置即可。
例如:
<span style="color:#3333FF;"> <!-- 全局异常配置 start 控制器异常处理-->
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.Exception">errors/webException</prop>
<prop key="java.lang.Throwable">errors/rmsException</prop>
</props>
</property>
<property name="statusCodes">
<props>
<prop key="errors/webException">500</prop>
<prop key="errors/rmsException">404</prop>
</props>
</property>
<!-- 设置日志输出级别,不定义则默认不输出警告等错误日志信息 -->
<property name="warnLogCategory" value="WARN"></property>
<!-- 默认错误页面,当找不到上面mappings中指定的异常对应视图时,使用本默认配置 -->
<property name="defaultErrorView" value="errors/error"></property>
<!-- 默认HTTP状态码 -->
<property name="defaultStatusCode" value="500"></property>
</bean>
<!-- 全局异常配置 end --> </span>
<span style="color:#3333FF;"><html>
<head><title>Exception!</title></head>
<body>
<% Exception ex = (Exception)request.getAttribute("exception"); %>
<H2>Exception: <%= ex.getMessage();%></H2>
<P/>
<% ex.printStackTrace(new java.io.PrintWriter(out)); %>
</body>
</html> </span>
exception 实在SimpleMappingExceptionResolver 被存放到request中的,具体可以查看源代码。
如果SimpleMappingExceptionResolver无法满足异常处理的需要,我们可以针对
HandlerExceptionResolver接口实现自己异常处理类,这同样非常简单(只需要实现一个
resolveException方法)。
如果有ViewResolver,则制定的jsp页面必须在那个页面下,到时候如果找不到页面,可以根据错误提示再调整页面路径
2..基于@ExceptionHandler的异常处理:
该方法需要定义在Controller内部,然后创建一个方法并用@ExceptionHandler注解来修饰用来处理异常,这个方法基本和 @RequestMapping修饰的方法差不多,只是可以多一个类型为Exception的参数,@ExceptionHandler中可以添加一个或多个异常的类型,如果为空的话则认为可以触发所有的异常类型错误。
示例:
<span style="color:#3333FF;">@Controller
public class ExceptionHandlerController {
@ExceptionHandler(value={IOException.class,SQLException.class})
public String exp(Exception ex,HttpServletRequest request) {
request.setAttribute("exception", ex);
return "/error.jsp";
}
</span>