一、异常解析器应该具有的功能:
1、既然使用异常解析器,那么就不必在Controller中对异常进行处理,抛出即可,简化开发,异常统一控制。
2、ajax请求(有@ResponseBody的Controller)发生错误,输出JSON。
3、页面请求(无@ResponseBody的Controller)发生错误,输出错误页面。
4、 它需要与AnnotationMethodHandlerAdapter使用同一个messageConverters
5、异常处理细节可控制。
二、SpringMVC异常机制总体思想:
(1)普通页面出错后可以跳到统一的错误处理页面,但是ajax就不行了,ajax的本意就是不让当前页面发生跳转,仅局部刷新,从而改善用户体验,基本思路是:把异常转换成json数据返回,这样ajax的回调函数,就能解析出错误原因。(对于仅仅提供json接口发生异常,可以输出异常json信息)
(2)普通界面与json数据出错跳入错误界面,需要重写异常解析器。
(3)单地统一配置异常,使得发生普通错误指定到固定的页面,ajax发生错直接通过js获取,展现给用户。
三、SpringMVC框架中常用的异常处理办法:
(1)
Dao层:直接抛出异常即可
Service层:直接抛出异常即可
Controller层: 访问页面时出现异常即可跳入错误页面
Ajax请求:出现异常时提醒异常,不跳出界面
(2)在项目中Controller中的异常配置:
Web.xml:
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500.html</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
Spring-servlet.xml:
<!-- 覆盖org.springframework.web.servlet.handler.SimpleMappingExceptionResolver,实现普通请求和ajax请求的异常处理 -->
<bean id="exceptionResolver" class="xyt.first.web.exception.CustomSimpleMappingExceptionResolver">
<!-- 异常信息变量名
配置异常的属性值为ex,那么在错误页面中可以通过 ${ex} 来获取异常的信息
如果不配置这个属性,它的默认值为exception-->
<property name="exceptionAttribute" value="ex"></property>
<!--需要做特殊处理的异常,用类名或者完全路径作为key,异常页面作为值 -->
<property name="exceptionMappings">
<props>
<!-- 表示当抛出NumberFormatException异常时,会跳入commons/number界面 -->
<prop key="NumberFormatException">commons/number</prop>
<prop key="NullPointerException">commons/null</prop>
<prop key="java.lang.ArrayIndexOutOfBoundsException">commons/error</prop>
</props>
</property>
<!-- 定义发生异常时 视图与返回码对应关系 -->
<property name="statusCodes">
<props>
<!-- 表示在发生NumberFormatException时返回视图number,然后这里定义发生异常时视图number对应的HttpServletResponse的返回码是500 -->
<prop key="commons/number">500</prop>
<prop key="commons/null">503</prop>
</props>
</property>
<!-- 设置日志输出级别,不定义则默认不输出警告等错误日志信息 -->
<property name="warnLogCategory" value="WARN"></property>
<!-- 发生异常时默认返回码404 -->
<property name="defaultStatusCode" value="500"/>
<!-- 表示抛出异常时没有在exceptionMappings找到对应的异常时返回error视图 -->
<property name="defaultErrorView" value="commons/error"/>
</bean>
实现普通异常和ajax异常的处理
观察SimpleMappingExceptionResolver,我们可以复写其doResolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)方法,通过修改该方法实现普通异常和ajax异常的处理,代码如下:
public class CustomSimpleMappingExceptionResolver 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))) {
// 如果不是异步请求
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;
}
}