SpringMVC统一异常处理

Posted nuist__NJUPT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMVC统一异常处理相关的知识,希望对你有一定的参考价值。

SpringMVC统一异常处理

在SpringMVC应用开发中,不管是对底层数据库的操作,还是对业务层或者控制层的操作,都不可避免的会遇到各种可预知的和不可预知的异常需要处理。如果每个过程都要单独处理异常,那么系统的代码耦合度高,工作量大且不好统一,以后维护的工作量也很大,如果能将所有类型的异常从各层中解耦出来,这样既能保证相关处理过程的功能单一,又实现了异常信息的统一处理和维护。
SpringMVC框架提供了3种异常处理方式:
1-简单异常处理SimpleMappingExceptionResolver;
2-实现HandlerExceptionResolver接口的自定义异常;
3-实现@ExceptionHandler注解实现异常处理

为了验证SpringMVC框架的3种异常处理的效果,需要开发一个测试应用,从Dao层,Service层,Controller层分别抛出不同的异常,然后分别集成3种方式进行异常处理,进而比较优缺点。

3种异常处理方式的相似部分有dao层,Service层,View层,MyException,TestExceptionControler以及web.xml
1-在IDEA中创建web应用ch16-1,并在WEB-INF目录下创建lib目录,在lib目录下导入SpringMVC相关jar包。

2-创建自定义异常类,在src目录下创建exception包,并在该包中创建自定义异常类MyException,具体代码如下:

public class MyException extends Exception {
    private static final long serialVersionID = 1L;
    public MyException(){
        super() ;
    }
    public MyException(String message){
        super(message) ;
    }
}

3-创建Dao层,在src目录下创建dao包,并在该包中创建TestExceptionDao类,在该类中分别定义三个方法,分别抛出“数据库异常”,“自定义异常”,“未知异常”。

import java.sql.SQLException;

/**
 * dao层中类中定义三个方法,分别抛出数据库异常,自定义异常,未知异常
 */
@Repository
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 MyException("Dao中未知的异常") ;
    }
}

4-创建Service层,在src目录下创建TestExceptionService接口和TestExceptionServiceImpl实现类,该接口中定义了6个方法,其中,3个方法是Service层的方法,3个方法是调用Dao层的方法,Service层的方法是为了演示Service层的“数据库异常”,“自定义异常”,“未知异常”而定义的。

TestExceptionService接口:

/**
 * 该接口中定义了6个接口方法,其中,3个方法定义了Dao层的方法,有3个方法是Service层的方法
 * Service层方法是为了演示Service层的数据库异常,自定义异常和未知异常
 */
public interface TestExceptionService {
    public void servicemy() throws Exception ;
    public void servicedb() throws Exception ;
    public void serviceno() throws Exception ;
    public void daomy() throws Exception ;
    public void daodb() throws Exception ;
    public void daono() throws Exception ;
}

TestExceptionServiceImpl实现类:


import exception.MyException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
@Service
public class TestExceptionServiceImpl implements TestExceptionService {
    @Autowired
    private TestExceptionService testExceptionService ;
    @Override
    public void servicemy() throws Exception {
        throw new MyException("Service中自定义的异常") ;
    }

    @Override
    public void servicedb() throws Exception {
        throw new SQLException("Service中的数据库异常") ;
    }

    @Override
    public void serviceno() throws Exception {
        throw new Exception("Service中的未知异常") ;
    }

    @Override
    public void daomy() throws Exception {
        testExceptionService.daomy();
    }

    @Override
    public void daodb() throws Exception {
        testExceptionService.daodb();
    }

    @Override
    public void daono() throws Exception {
        testExceptionService.daono();
    }
}

5-创建控制器类,在src目录下创建controller包,在controller包中创建控制器类TestExceptionController,代码如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import service.TestExceptionService;

import java.sql.SQLException;

@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 Exception("控制器中的自定义异常") ;
    }
    @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();
    }
}

6-创建View层,View层共5个JSP页面。
分别为测试应用首页面index.jsp,还有在WEB-INF目录下创建jsp目录,并在该目录中创建404.jsp,error.jsp,my-error.jsp,sql-error.jsp.

index.jsp页面:

<%--
  Created by IntelliJ IDEA.
  User: nuist__NJUPT
  Date: 2021/8/14
  Time: 11:24
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</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>

未知异常error.jsp页面:

<%--
  Created by IntelliJ IDEA.
  User: nuist__NJUPT
  Date: 2021/8/14
  Time: 12:22
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<H1>未知错误:</H1> <%=exception%>>
<H2>错误内容:</H2>
<%
    exception.printStackTrace(response.getWriter());
%>
</body>
</html>

自定义异常页面my-error.jsp:

<%--
  Created by IntelliJ IDEA.
  User: nuist__NJUPT
  Date: 2021/8/14
  Time: 12:25
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java"  isErrorPage="true" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<H1>自定义异常错误:</H1> <%=exception%>
<H2>错误内容:</H2>
<%
    exception.printStackTrace(response.getWriter());
%>
</body>
</html>

SQL异常对应页面sql-error.jsp:

<%--
  Created by IntelliJ IDEA.
  User: nuist__NJUPT
  Date: 2021/8/14
  Time: 12:27
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<H1>数据库异常错误:</H1> <%=exception%>
<H2>错误内容:</H2>
<%
    exception.printStackTrace(response.getWriter());
%>
</body>
</html>

7-在web.xml部署DispatcherServlet,配置 CharacterEncodingFilter解决中文乱码问题对于UncheckedException而言,由于代码不强制捕获,往往被忽略,如果运行时候产生UncheckedException,而代码中又没有进行相应的捕获和处理,则可能不得不面对404,500等服务器内部错误提示页面,所以还需要在web.xml文件中添加全局异常404处理。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         id = "WebApp_ID" version="4.0">
    <!--部署DispatcherServlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>WEB-INF/springmvc-servlet.xml</param-value>
        </init-param>
        <!--表示容器启动时加载的servlet-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <!--任意的请求都通过DispatcherServlet-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- 配置 CharacterEncodingFilter解决中文乱码问题-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

        <!-- 配置编码格式为UTF-8 -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <error-page>
        <error-code>404</error-code>
        <location>/WEB-INF/jsp/404.jsp</location>
    </error-page>
</web-app>

从上述Dao层,Service层,Controller层的代码中看出,它们只管通过thow和throws抛储异常,并不处理。

SimpleMappingExceptionResolver类:
1-使用该类处理异常时候需要在配置文件中提前配置异常类和View的关系,配置文件springmvc-servlet.xml的具体代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">

    <!--使用扫描机制,扫描控制器类,使得注解生效-->
    <context:component-scan base-package="controller"/>
    <context:component-scan base-package="service"/>
    <context:component-scan base-package="dao"/>

    <!--配置视图解析器-->
    <bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver" id = "internalResourceViewResolver">
        <!--前缀-->
        <property name = "prefix" value = "/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name = "suffix" value = ".jsp"/>
    </bean>

    <!--配置SimpleMappingExceptionResolver,异常类与View的对应关系-->
    <bean class = "org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!--定义默认异常处理页面,当该异常类型注册时候使用-->
        <property name = "defaultErrorView" value="error"></property>
        <!--定义异常处理页面来获取异常信息的变量名,默认名为exception-->
        <property name = "exceptionAttribute" value="ex"/>
        <!--定义需要进行特殊处理的异常,用类名或者完全路径名作为key,异常网页作为值-->
        <property name = "exceptionMappings">
            <props>
                <prop key = "exception.MyException">my-error</prop>
                <prop key = "java.sql.SQLException"以上是关于SpringMVC统一异常处理的主要内容,如果未能解决你的问题,请参考以下文章

开发之统一异常处理

javaweb异常提示信息统一处理(使用springmvc,附源码)

Spring MVC学习—项目统一异常处理机制详解与使用案例

SpringMVC统一异常处理(返回异常数据而不是跳转到某个页面的方法)

springmvc统一异常处理

SpringMvc,Springboot统一校验自定义异常全局异常处理