全局异常统一处理

全局异常统一处理

在 JavaEE 项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,系统的代码耦合度高,工作量大且不好统一,维护的工作量也很大。

SpringMVC 对于异常处理这块提供了支持,通过 SpringMVC 提供的全局异常处理机制,能够将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。

全局异常实现方式 Spring MVC 处理异常有 3 种方式:

  1. 使用 Spring MVC 提供的简单异常处理器 SimpleMappingExceptionResolver
  2. 实现 Spring 的异常处理接口 HandlerExceptionResolver 自定义自己的异常处理器
  3. 使用 @ExceptionHandler 注解实现异常处理

全局异常处理方式一

配置简单异常处理器

配置 SimpleMappingExceptionResolver 对象

    <!-- 配置全局异常统一处理的 Bean (简单异常处理器) -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> 
        <!-- 页面在转发时出现异常,设置默认的错误页面 (error代表的是一个视图) -->
        <property name="defaultErrorView" value="error"></property> 
        <!-- 异常发生时,设置异常的变量名 -->
        <property name="exceptionAttribute" value="ex"></property>
    </bean>

可以在处理异常的页面获取异常信息

${
    
    ex}

使用自定义异常

参数异常

/*** 自定义异常:参数异常 */
public class ParamsException extends RuntimeException {
    
    
    private Integer code = 300;
    private String msg = "参数异常!";

    public ParamsException() {
    
    
        super("参数异常!");
    }

    public ParamsException(String msg) {
    
    
        super(msg);
        this.msg = msg;
    }

    public ParamsException(Integer code) {
    
    
        super("参数异常!");
        this.code = code;
    }

    public ParamsException(Integer code, String msg) {
    
    
        super(msg);
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
    
    
        return code;
    }

    public void setCode(Integer code) {
    
    
        this.code = code;
    }

    public String getMsg() {
    
    
        return msg;
    }

    public void setMsg(String msg) {
    
    
        this.msg = msg;
    }
}

业务异常

/*** 自定义异常:业务异常 */
public class BusinessException extends RuntimeException {
    
    
    private Integer code = 400;
    private String msg = "业务异常!";

    public BusinessException() {
    
    
        super("业务异常!");
    }

    public BusinessException(String msg) {
    
    
        super(msg);
        this.msg = msg;
    }

    public BusinessException(Integer code) {
    
    
        super("业务异常!");
        this.code = code;
    }

    public BusinessException(Integer code, String msg) {
    
    
        super(msg);
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
    
    
        return code;
    }

    public void setCode(Integer code) {
    
    
        this.code = code;
    }

    public String getMsg() {
    
    
        return msg;
    }

    public void setMsg(String msg) {
    
    
        this.msg = msg;
    }
}

设置自定义异常与页面的映射

    <!-- 设置自定义异常与页面的映射 -->
    <property name="exceptionMappings">
        <props> <!-- key:自定义异常对象的路径; 标签中设置具体的处理页面的视图名-->
            <prop key="com.xxxx.ssm.exception.BusinessException">buss_error</prop>
            <prop key="com.xxxx.ssm.exception.ParamsException">params_error</prop>
        </props>
    </property>

使用 SimpleMappingExceptionResolver 进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,但该方法仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适用。

全局异常处理方式二(推荐)

实现 HandlerExceptionResolver 接口

/*** 全局异常统一处理 */
@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver {
    
    
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception ex) {
    
    
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("ex", "默认错误信息");
        return mv;
    }
}

自定义异常处理

/*** 全局异常统一处理 */
@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver {
    
    
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception ex) {
    
    
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("ex", "默认错误信息");
        // 判断是否是自定义异常
        if (ex instanceof ParamsException) {
    
    
            mv.setViewName("params_error");
            ParamsException e = (ParamsException) ex;
            mv.addObject("ex", e.getMsg());
        }
        if (ex instanceof BusinessException) {
    
    

            mv.setViewName("business_error");
            BusinessException e = (BusinessException) ex;
            mv.addObject("ex", e.getMsg());
        }
        return mv;
    }
}
        

使用实现 HandlerExceptionResolver 接口的异常处理器进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,同时,在异常处理时能获取导致出现异常的对象,有利于提供更详细的异常处理信息。

全局异常处理方式三

页面处理器继承 BaseController

public class BaseController {
    
    
    @ExceptionHandler
    public String exc(HttpServletRequest request, HttpServletResponse response, Exception ex) {
    
    
        request.setAttribute("ex", ex);
        if (ex instanceof ParamsException) {
    
    
            return "error_param";
        }
        if (ex instanceof BusinessException) {
    
    
            return "error_business";
        }
        return "error";
    }
}

使用 @ExceptionHandler 注解实现异常处理,具有集成简单、有扩展性好(只需要将要异常处理的Controller 类继承于 BaseController 即可)、不需要附加Spring 配置等优点,但该方法对已有代码存在入侵性(需要修改已有代码,使相关类继承于 BaseController),在异常处理时不能获取除异常以外的数据。

未捕获异常的处理

对于 Unchecked Exception 而言,由于代码不强制捕获,往往被忽略,如果运行期产生了Unchecked Exception,而代码中又没有进行相应的捕获和处理,则我们可能不得不面对尴尬的 404、500……等服务器内部错误提示页面。

此时需要一个全面而有效的异常处理机制。目前大多数服务器也都支持在 web.xml 中通过(Websphere/Weblogic)或者(Tomcat)节点配置特定异常情况的显示页面。修改 web.xml 文件,增加以下内容:

    <!-- 出错页面定义 -->
    <error-page>
        <exception-type>java.lang.Throwable</exception-type>
        <location>/500.jsp</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/500.jsp</location>
    </error-page>
    <error-page>
        <error-code>404</error-code>
        <location>/404.jsp</location>
    </error-page>

Guess you like

Origin blog.csdn.net/lln1540295459/article/details/121251555