springMVC提供的异常处理主要有两种方式,一种是直接实现自己的 HandlerExceptionResolver,当然这也包括使用Spring已经为我们提供好的 SimpleMappingExceptionResolver和DefaultHandlerExceptionResolver,另一种是使用注解的 方式实现一个专门用于处理异常的Controller——ExceptionHandler.
1.spring mvc 自己实现了SimpleMappingExceptionResolver 和 DefaultHandlerExceptionResolver.
DefaultHandlerExceptionResolver,该解析器只是对其中的一些比较典型的异常进行了拦截,然后返回对应的错误码.
public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
//......
@Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
try {
if (ex instanceof NoSuchRequestHandlingMethodException) {
return handleNoSuchRequestHandlingMethod((NoSuchRequestHandlingMethodException) ex, request, response,
handler);
}
else if (ex instanceof HttpRequestMethodNotSupportedException) {
return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, request,
response, handler);
}
else if (ex instanceof HttpMediaTypeNotSupportedException) {
return handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException) ex, request, response,
handler);
}
//......
}
catch (Exception handlerException) {
logger.warn("Handling of [" + ex.getClass().getName() + "] resulted in Exception", handlerException);
}
return null;
}
SimpleMappingExceptionResolver提供了通过异常类型 exceptionMappings来进行异常与视图之间的映射关系,提供了在发生异常时通过statusCodes来映射异常返回的视图名称和对应的 HttpServletResponse的返回码。而且可以通过defaultErrorView和defaultErrorCode来指定默认 值,defaultErrorView表示当没有在exceptionMappings里面找到对应的异常类型时就返回defaultErrorView 定义的视图,defaultErrorCode表示在发生异常时当没有在视图与返回码的映射关系statusCodes里面找到对应的映射时默认返回的返 回码。在使用SimpleMappingExceptionResolver时,当发生异常的时 候,SimpleMappingExceptionResolver将会把当前的异常对象放到自身属性exceptionAttribute中,当没有指 定exceptionAttribute时,exceptionAttribute就是用默认值exception。
public class SimpleMappingExceptionResolver extends AbstractHandlerExceptionResolver {
/** The default name of the exception attribute: "exception". */
public static final String DEFAULT_EXCEPTION_ATTRIBUTE = "exception";
//当发生异常时,与视图的映射
private Properties exceptionMappings;
private Class<?>[] excludedExceptions;
//默认的视图,表示当抛出异常但没有在exceptionMappings里面找到对应的异常时 返回//名叫exception的视图
private String defaultErrorView;
//定义在发生异常时视图跟返回码的对应关系
private Integer defaultStatusCode;
private Map<String, Integer> statusCodes = new HashMap<String, Integer>();
private String exceptionAttribute = DEFAULT_EXCEPTION_ATTRIBUTE;
在需要使用到SimpleMappingExceptionResolver来处理异常时,一般需在xml配置bean.
如:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="NumberFormatException">number</prop><!-- 表示当抛出NumberFormatException的时候就返回名叫number的视图 --> <prop key="NullPointerException">null</prop> </props> </property> <property name="defaultErrorView" value="exception"/><!-- 表示当抛出异常但没有在exceptionMappings里面找到对应的异常时 返回名叫exception的视图--> <property name="statusCodes"><!-- 定义在发生异常时视图跟返回码的对应关系 --> <props> <prop key="number">500</prop><!-- 表示在发生NumberFormatException时返回视图number,然后这里定义发生异常时视图number对应的HttpServletResponse的返回码是500 --> <prop key="null">503</prop> </props> </property> <property name="defaultStatusCode" value="404"/><!-- 表示在发生异常时默认的HttpServletResponse的返回码是多少,默认是200 --> </bean>
2.使用@ExceptionHandler进行处理
使用@ExceptionHandler进行处理有一个不好的地方是在同一个Controller里面需要同时有进行异常处理的方法与出错的方法.
如:
@Controller
public class GlobalController {
/**
* 用于处理异常的
* @return
*/
@ExceptionHandler({MyException.class})
public String exception(MyException e) {
System.out.println(e.getMessage());
e.printStackTrace();
return "exception";
}
@RequestMapping("test")
public void test() {
throw new MyException("出错了!");
}
}
这里在页面上访问test方法的时候就会报错,而拥有该test方法的Controller又拥有一个处理该异常的方法,这个时候处理异常的方法就会被调用.
但是,一般在实际中,采用注解@ExceptionHandler来处理异常,都会建立一个父类BaseController.
public abstract class BaseController {
@ExceptionHandler
public String exception(HttpServletRequest request, Exception e) {
//添加自己的异常处理逻辑,如日志记录
request.setAttribute("exceptionMessage", e.getMessage());
// 根据不同的异常类型进行不同处理
if(e instanceof SQLException)
return "testerror";
else
return "error";
}
}
TestExceptionController:
@Controller
@RequestMapping("/ex")
public class TestExceptionController extends BaseController{
@RequestMapping("/index")
public ModelAndView index() throws SQLException{
throw new SQLException("数据库异常");
}
}
最后,添加testerror.jsp视图来显示错误信息:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page isELIgnored="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>error!</title>
</head>
<body>
${exceptionMessage}
</body>
</html>
最后,测试访问,捕捉到异常.
这样只要把我们的其它的Controller全部继承于BaseController就能实现异常的集中捕捉和处理了