统一的异常处理
在springmvc的开发中,肯定会遇到各种各样的异常需要处理,如果每个异常都单独处理,系统的代码耦合性高,工作量大,维护困难。
Luckly,SpringMVC能将所有类型的异常从各层提取出来保障了相关处理过程的功能单一。
对于实现这种功能,SpringMVC有三种方法:
简单异常处理器SimpleMappingExceptionResolver:
1.首先在exception包中创建自定义异常类MyException为后面抛出自定义异常作准备:
@Repository("testExceptionDao") public class TestExceptionDao { public void daodb() throws Exception { throw new SQLException("Dao中数据异常"); } public void daomy() throws Exception { throw new MyException("Dao中自定义异常"); } public void daono() throws Exception { throw new Exception("Dao中未知异常"); } }
2.在service包中创建service的三种类型的异常,还有dao层的三种异常:
@Autowired private TestExceptionDao testExceptionDao; @Override public void servicemy() throws Exception { throw new MyException("Service中自定义异常"); } @Override public void servicedb() throws Exception { throw new SQLException("Service中数据库异常"); } @Override public void daomy() throws Exception { testExceptionDao.daomy(); } @Override public void daodb() throws Exception { testExceptionDao.daodb(); } @Override public void serviceno() throws Exception { throw new MyException("Service中未知异常"); } @Override public void daono() throws Exception { testExceptionDao.daono(); }
3.在控制器中映射各种dao层、service层、controller层的异常
4.创建各种jsp,对应各种异常:
主页index.jsp:
<body> <h1>所有的演示例子</h1> <h3><a href = "${pageContext.request.contextPath }/daodb">处理dao中的数据库异常</a></h3> <h3><a href = "${pageContext.request.contextPath }/daomy">处理dao中的自定义异常</a></h3> <h3><a href = "${pageContext.request.contextPath }/daono">处理dao中的未知异常</a></h3> <h3><a href = "${pageContext.request.contextPath }/servicedb">处理service中的数据库异常</a></h3> <h3><a href = "${pageContext.request.contextPath }/servicemy">处理service中的自定义异常</a></h3> <h3><a href = "${pageContext.request.contextPath }/serviceno">处理service中的未知异常</a></h3> <h3><a href = "${pageContext.request.contextPath }/db">处理controller中的数据库异常</a></h3> <h3><a href = "${pageContext.request.contextPath }/my">处理controller中的自定义异常</a></h3> <h3><a href = "${pageContext.request.contextPath }/no">处理controller中的未知异常</a></h3> <!-- 在web.xml中配置 --> <h3><a href = "${pageContext.request.contextPath }/404">404错误</a></h3> </body>
某种异常界面:
<body> <H1>数据库异常错误:</H1><%=exception %> <H2>错误内容:</H2> <% exception.printStackTrace(response.getWriter()); %> </body>
接下来就是最关键的Springmvc-servlet.xml的配置和web.xml的配置:
<!-- 配置异常类与View的对应关系 --> <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="exception.MyException">my-error</prop> <prop key="java.sql.SQLException">sql-error</prop> <!-- 在这里还可以扩展对不同异常类型的处理 --> </props> </property> </bean>
当然,还有一种就是很重要的404异常,就是找不到文件等问题,很烦。所以可以在创建相应的404.jsp以后在web.xml配置,如下:
<error-page> <error-code>404</error-code> <location>/WEB-INF/jsp/404.jsp</location> </error-page>
还有,要在浏览器上打开,eclipes打不开404界面(我也不懂为啥。)!
第二种更简单:HandlerExerptionResolver接口:
1.首先在原来的基础上,在exception包中创建这个接口的实现类MyExceptionHandler:
public class MyExceptionHandler implements HandlerExceptionResolver{ @Override public ModelAndView resolveException(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) { Map<String,Object> model = new HashMap<>(); model.put("ex", arg3); //根据不同错误转向不同页面,(统一处理)即异常与View对应 if(arg3 instanceof MyException) { //如果错误类型是MyException return new ModelAndView("my-error",model); } else if(arg3 instanceof SQLException) {//如果错误类型是SQLException return new ModelAndView("sql-error",model); } else { //如果错误类型是Exception return new ModelAndView("error",model); } } }
最后一步就只用把刚才上面springmvc-servlet中的对应关系删掉,换成下面的代码:
<!-- 托管MyExceptionHandler --> <bean class= "exception.MyExceptionHandler"/>
然后就大功告成!非常简单。
第三种@ExceptionHandler注解:
1.也在原来开的基础上修改:
在controller包中添加BaseController类,用注解声明:
public abstract class BaseController { //基于ExceptionHandler异常处理 @ExceptionHandler public String exception(HttpServletRequest request, Exception ex) { request.setAttribute("ex", ex); //根据不同错误转向不同页面,(统一处理)即异常与View对应 if(ex instanceof SQLException) { return "sql-error"; } else if(ex instanceof MyException) { return "my-error"; } else return "error"; } }
看起来跟上一种方法很相似。
2. 接下来就是将已经创建好的TestExceptionController继承这个抽象类,在后面加上extends BaseController就可以。
3. 最后一步 :因为@ExceptionHandler注解声明统一处理异常时,不需要配置任何信息,所以Springmvc-servlet.xml中保留视图解析器就行,其他删掉。
4. 这种方法具有集成简单、可扩展性好、不需要附加Spring配置等优点。
5. 但这个方法对已有的代码存在入侵性,使相关类继承BaseController。
最后做一个笔记,修改代码以后最好重新启动服务器,不然有时候没有修改成功。