SpringMVC – 全局异常处理
前言
开发工程中,分很多环境,对于异常处理,不可暴露同时,如果每个模块都有单独的异常处理,可能会把异常暴露出来,增加耦合性,不好统一管理维护比例比较大。所以需要进行全局的异常处理;
处理办法
使用 Spring MVC 提供的简单异常处理器
- SimpleMappingExceptionResolver。
实现 Spring 的异常处理接口
- HandlerExceptionResolver 自定义自己的异常处理器。
使用
- @ExceptionHandler 注解实现异常处理
实践代码
创建一个自定义异常
public class MyException extends Exception {
private static final long serialVersionUID = 1L;
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
}
创建 Dao 层开始向上面抛出异常
import java.sql.SQLException;
import org.springframework.stereotype.Repository;
@Repository("TestExceptionDao")
public class TestExceptionDao {
public void daodb() throws Exception {
throw new SQLException("Dao中数据库异常");
}
public void daomy() throws Exception {
throw new SQLException("Dao中自定义异常");
}
public void daono() throws Exception {
throw new SQLException("Dao中未知异常");
}
}
分别向上面抛出了三个异常
Service 层向上抛出异常,三个向上抛出,三个调用dao出现异常向上抛出
接口
public interface TestExceptionService {
public void servicemy() throws Exception;
public void servicedb() throws Exception;
public void daomy() throws Exception;
public void daodb() throws Exception;
public void serviceno() throws Exception;
public void daono() throws Exception;
}
实现
import java.sql.SQLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import dao.TestExceptionDao;
import exception.MyException;
@Service("testExceptionService")
public class TestExceptionServiceImpl implements TestExceptionService {
@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 SQLException("Service中未知异常");
}
@Override
public void daono() throws Exception {
testExceptionDao.daono();
}
创建控制器
import java.sql.SQLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import service.TestExceptionService;
import exception.MyException;
@Controller
public class TestExceptionController {
@Autowired
private TestExceptionService testExceptionService;
@RequestMapping("/db")
public void db() throws Exception {
throw new SQLException("控制器中数据库异常");
}
@RequestMapping("/my")
public void my() throws Exception {
throw new MyException("控制器中自定义异常");
}
@RequestMapping("/no")
public void no() throws Exception {
throw new Exception("控制器中未知异常");
}
@RequestMapping("/servicedb")
public void servicedb() throws Exception {
testExceptionService.servicedb();
}
@RequestMapping("/servicemy")
public void servicemy() throws Exception {
testExceptionService.servicemy();
}
@RequestMapping("/serviceno")
public void serviceno() throws Exception {
testExceptionService.serviceno();
}
@RequestMapping("/daodb")
public void daodb() throws Exception {
testExceptionService.daodb();
}
@RequestMapping("/daomy")
public void daomy() throws Exception {
testExceptionService.daomy();
}
@RequestMapping("/daono")
public void daono() throws Exception {
testExceptionService.daono();
}
}
控制器异常,service异常,和调用dao,调用service出现的异常。
视图显示调用 index首页jsp更改
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!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>Insert title here</title>
</head>
<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>
<hr>
<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>
<hr>
<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>
<hr>
<!-- 在 web.xml中配置404 -->
<h3>
<a href="${pageContext.request.contextPath }/404">404 错误</a>
</h3>
</body>
</html>
调用404 是为了防止出现无页面异常。所以这个要注意一下
定义 404 页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!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>Insert title here</title>
</head>
<body>
资源已不在。
</body>
</html>
定义异常error.jsp,
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isErrorPage="true"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!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>Insert title here</title>
</head>
<body>
<H1>错误:</H1><%=exception %>
<H2>错误内容:</H2>
<%
exception.printStackTrace(response.getWriter());
%>
</body>
</html>
- excepton获取异常message信息。
- exception.printStackTrace(response.getWriter());打印错误信息
定义my-error.jsp自定义异常页面
<H1>自定义异常错误:</H1><%=exception %>
定义sql-error.jsp异常
<H1>数据库异常错误:</H1><%=exception %>
web.xml配置404异常
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/jsp/404.jsp</location>
</error-page>
springMVC 配置 SimpleMappingExceptionResolver 类统一处理异常
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 定义默认的异常处理页面,没有定义的异常全部到error.jsp页面 -->
<property name="defaultErrorView" value="error"></property>
<!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception 一般都定义为ex比较常用-->
<property name="exceptionAttribute" value="ex"></property>
<!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页名作为值 -->
<property name="exceptionMappings">
<props>
<!-- 定义自定义异常抛出显示的页面 -->
<prop key="com.springTest.exception.MyException">my-error</prop>
<!-- 定义sql异常抛出显示的页面 -->
<prop key="java.sql.SQLException">sql-error</prop>
<!-- 在这里还可以继续扩展对不同异常类型的处理 -->
</props>
</property>
</bean>
配置完成启动服务器效果如下
实现HandlerExceptionResolver异常处理器接口
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
public class MyExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o,
Exception excption) {
// 封装错误信息
Map<String, Object> map = new HashMap<String, Object>();
map.put("ex", excption);
// 根据不同错误转向不同页面(统一处理),即异常与View的对应关系
if (excption instanceof MyException) {
// 回传页面和信息
return new ModelAndView("my-error", map);
} else if (o instanceof SQLException) {
return new ModelAndView("sql-error", map);
} else {
return new ModelAndView("error", map);
}
}
}
springMVC加载bean
<!--托管MyExceptionHandler-->
<bean class="exception.MyExceptionHandler"/>
使用注解@ExceptionHandler
配置基础类
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.ExceptionHandler;
import exception.MyException;
public 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";
}
}
将所有需要异常处理的 Controller 都继承 BaseController 基类
@Controller
public class TestExceptionController extends BaseController{
...
}
使用注解不需要配置SpringMVC配置
总结
使用此三种方法都可以让异常向上抛出,然后进行处理。分别使用simpleMapperResolver。和使用handlerExceptionResolver。以及简单的注解ExceptionHandler
在开发环境下,配置simpleMapperResolver比较常见。使用springBoot后使用注解开发比较常见