SpringMVC使用HandlerExceptionResolver实现全局异常处理器

在SpringMVC中,提供了一个全局异常处理器,用于对系统中出现的异常进行统一处理。在一般的系统中,DAO层、Service层及Controller层出现异常都以“throws Exception”的形式向上层抛出,最后都会有SpringMVC的前端控制器(DispatcherServlet)统一交由全局异常处理器进行异常处理。

1、HandlerExceptionResolver接口

在SpringMVC中提供的HandlerExceptionResolver接口可以实现全局异常处理器,该接口的源码如下:

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;

public interface HandlerExceptionResolver {
    @Nullable
    ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}

可以看到,HandlerExceptionResolver接口中定义了一个名为resolveException的方法,该方法主要用于处理Controller中的异常。参数“Exception ex”即为Controller或其下层抛出的异常。参数“Object handler”就是处理器适配器要执行的Handler对象。resolveException方法的返回值类型是ModelAndView,也就是说,可以通过这个返回值来设置发送异常时的显示页面。

2、综合实例

【实例】在SpringMVC项目中,使用使用HandlerExceptionResolver实现全局异常处理器。当抛出异常后,要有相应的符合用户体验的友好界面显示异常。

(1)创建自定义异常类的名称为OperationException,定义的代码如下:

package com.pjb.fms.exception;

/**
 * 自定义操作异常
 * 注意:如果继承的是Exception类,那么Spring的事务管理将会失效,
 * 只有继承RuntimeException类才使Spring的事务管理不会失效
 * @author pan_junbiao
 **/
public class OperationException extends RuntimeException
{
    private String errorMessage; //异常信息

    public OperationException(String errorMessage)
    {
        super(errorMessage);
        this.errorMessage = errorMessage;
    }

    public String getErrorMessage()
    {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage)
    {
        this.errorMessage = errorMessage;
    }
}

注意:该自定义异常类继承的是RuntimeException类,因为一般项目的Service层逻辑都会使用Spring提供的事务管理,当Service层需要抛出自定义异常时,如果该自定义异常继承的是Exception类,则Spring提供的事务管理将会失效,所以这里的自定义异常类继承的是RuntimeException类,这样才不会使Spring提供的事务管理失效。

Spring管理的事务,无论是声明式事务还是注解式事务默认是在抛出运行异常(RuntimeException异常)时,才会被Spring框架捕获到然后回滚。

(2)创建全局异常处理器OperationExceptionResolver类,该类继承HandlerExceptionResolver接口,并且实现resolveException方法,代码如下:

package com.pjb.fms.exception;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 全局异常处理器
 * @author pan_junbiao
 **/
public class OperationExceptionResolver implements HandlerExceptionResolver
{
    //日志对象
    private Logger logger = LogManager.getLogger(OperationExceptionResolver.class);

    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    {
        //1、解析出异常类型
        OperationException operationException = null;
        if(ex instanceof OperationException)
        {
            //2、如果该异常类型是自定义的操作异常,直接获取异常信息,在错误页面展示
            operationException = (OperationException)ex;
        }
        else
        {
            //3、如果该异常类型不是自定义的操作异常,构建一个自定义的操作异常类型
            operationException = new OperationException("系统错误,请联系管理员");
        }

        //错误信息
        String errorMessage = operationException.getErrorMessage();

        //记录异常日志
        logger.error(errorMessage);

        //返回错误页面
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("errorMessage",errorMessage);
        modelAndView.setViewName("/error.jsp");
        return modelAndView;
    }
}

(3)创建名称为error.jsp的页面,符合用户体验的友好界面,用于显示异常信息。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>操作失败</title>
    <meta name="author" content="pan_junbiao的博客">
</head>
<body>
<div align="center">
    <h1>操作失败</h1>
    <span style="color: red;">
        <%=request.getAttribute("errorMessage") == null ? "" : "失败原因:" + request.getAttribute("errorMessage")%>
    </span>
</div>
</body>
</html>

(4)然后在SpringMVC核心配置文件springmvc.xml中将定义的全局异常处理器配置进去:

<!-- 全局异常处理器 -->
<bean class="com.pjb.fms.exception.OperationExceptionResolver"></bean>

 (5)创建测试的Controller控制器方法,该方法抛出一个自定义异常。

/**
 * 用户登录
 * @author pan_junbiao
 */
@RequestMapping(value = "login", method = RequestMethod.POST)
public ModelAndView login() throws Exception
{
    throw new OperationException("账号或密码错误");
}

执行结果:

发布了354 篇原创文章 · 获赞 208 · 访问量 165万+

猜你喜欢

转载自blog.csdn.net/pan_junbiao/article/details/103937803