SpringMVC 异常处理

目录

1、@ExceptionHandler-处理局部异常

2、HandlerExceptionResolver-处理全局异常

3、SimpleMappingExceptionResolver-处理全局异常

4、使用@ControllerAdvice+@ExceptionHandler


在 Spring MVC 应用的开发中,不管是操作底层数据库,还是业务层或控制层,都会不可避免地遇到各种可预知的、不可预知的异常。我们需要捕捉处理异常,才能保证程序不被终止。

Spring MVC 有以下 3 种处理异常的方式:

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

springmvc中,异常处理的思路

上图所示,系统的daoservicecontroller出现异常都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理。

springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。明白了springmvc中的异常处理机制,下面就开始分析springmvc中的异常处理。

1、@ExceptionHandler-处理局部异常

局部异常处理仅能处理指定 Controller 中的异常。

下面使用 @ExceptionHandler 注解实现。//注意:该注解不是加在产生异常的方法上,而是加在处理异常的方法上。

定义一个处理过程中可能会存在异常情况的 submit 方法,当 i=0 时会产生算术运算异常,在同一个类中定义处理异常的方法controllerExceptionHandler,捕获运算异常。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;

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

/**
 * @author swadian
 * @date 2022/2/21
 * @Version 1.0
 */
@Controller
@RequestMapping
public class ExceptionController {

    @RequestMapping("/submit") // 抛错方法
    public String submit(HttpServletRequest req,
                         HttpServletResponse resp) throws Exception {
        String num = req.getParameter("num");
        System.out.println(10 / Integer.valueOf(num));
        return "success";
    }

    @ExceptionHandler({ArithmeticException.class}) //捕获运算异常
    public String controllerExceptionHandler(Exception e) {
        System.out.println("打印错误信息 ===> ArithmeticException:" + e);
        // 跳转到指定页面
        return "error";
    }
}

异常页面 error.jsp 代码如下。

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!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>错误页面</title>
</head>
<body>
    发生算术运算异常,请重新输入数据!
</body>
</html>

工程中web.xml配置如下

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0"
         metadata-complete="true">

    <!--配置SpringMvc的核心控制器-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置DispatcherServlet的初始化參數:设置文件的路径和文件名称 -->
        <init-param>
            <param-name>contextConfigLocation</param-name> <!--名称不能动,DispatcherServlet固定读取key-->
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
        <!-- 配置 servlet 的对象的创建时间点:1-应用加载时创建。取值只能是非 0 正整数,表示启动顺序 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern> <!--拦截所有请求,.do/.action也可以,/方便支持restful风格-->
    </servlet-mapping>

</web-app>

工程中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 http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 启用注解,使用了<context:component-scan/> 后就可以将该配置移除。 -->
    <!--<context:annotation-config />-->
    <mvc:annotation-driven/>
    <!-- 设置使用注解的类所在的包 -->
    <context:component-scan base-package="com.springmvc.*"></context:component-scan>

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

整个项目的路径如下:

启动项目,访问submit方法,程序会进入到错误处理方法,最终跳转到错误页面

@ExceptionHandler 注解定义的方法优先级问题:例如发生的是 NullPointerException,但是声明的异常有 RuntimeException 和 Exception,这时候会根据异常的最近继承关系找到继承深度最浅的那个@ExceptionHandler 注解方法,即标记了 RuntimeException 的方法。

被 @ExceptionHandler 标记为异常处理方法,不能在方法中设置别的形参。但是可以使用 ModelAndView 向前台传递数据。

使用局部异常处理,仅能处理某个 Controller 中的异常,若需要对所有异常进行统一处理,可使用以下两种方法。

2、HandlerExceptionResolver-处理全局异常

Spring MVC 通过 HandlerExceptionResolver 处理程序异常,包括处理器异常、数据绑定异常以及控制器执行时发生的异常。HandlerExceptionResolver 仅有一个接口方法,源码如下。

public interface HandlerExceptionResolver {
    ModelAndView resolveException(HttpServletRequest var1, 
                                  HttpServletResponse var2, 
                                  Object var3, 
                                  Exception var4);
}

发生异常时,Spring MVC 会调用 resolveException() 方法,并转到 ModelAndView 对应的视图中,返回一个异常报告页面反馈给用户。

创建一个 HandlerExceptionResolver 接口的实现类 MyExceptionHandler,代码如下。

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * @author swadian
 * @date 2022/2/21
 * @Version 1.0
 */
@Component
public class MyExceptionHandler implements HandlerExceptionResolver {
    public ModelAndView resolveException(HttpServletRequest httpServletRequest,
                                         HttpServletResponse httpServletResponse,
                                         Object o,
                                         Exception e) {
        Map<String, Object> model = new HashMap<String, Object>();
        model.put("errorMessage", "程序运行出错");
        //根据不同错误转向不同页面(统一处理),即异常与View的对应关系
        if (e instanceof ArithmeticException) {
            return new ModelAndView("error", model);
        }
        return new ModelAndView("other_error", model);
    }
}

添加新的错误页面other_error.jsp如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!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>系统正忙页面</title>
</head>
<body>
    errorMessage:${errorMessage} <br />
    系统正忙,请稍后再试!
</body>
</html>

更改ExceptionController类,新增空指针异常

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

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

/**
 * @author swadian
 * @date 2022/2/21
 * @Version 1.0
 */
@Controller
@RequestMapping
public class ExceptionController {
    @RequestMapping("/submit") // 抛错方法
    public String submit(HttpServletRequest req,
                         HttpServletResponse resp) throws Exception {
        String num = req.getParameter("num");
        System.out.println("输入的参数长度为:" + num.length());//空指针异常
        System.out.println(10 / Integer.valueOf(num));
        return "success";
    }
}

启动项目,访问submit方法,不输入参数,程序会进入到错误处理方法,最终跳转到其他错误页面

3、SimpleMappingExceptionResolver-处理全局异常

全局异常处理可使用 SimpleMappingExceptionResolver 来实现。它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。

在 springmvc-servlet.xml 中配置全局异常,代码如下。

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!-- 定义默认的异常处理页面,当该异常类型注册时使用 -->
        <property name="defaultErrorView" value="other_error"></property>
        <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
        <property name="exceptionAttribute" value="errorMessage"></property>
        <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页名作为值 -->
        <property name="exceptionMappings">
            <props>
                <prop key="ArithmeticException">error</prop>
                <!-- 在这里还可以继续扩展对不同异常类型的处理 -->
            </props>
        </property>
    </bean>

启动项目,访问submit方法,不输入参数,程序会进入到错误处理方法,最终跳转到其他错误页面

4、使用@ControllerAdvice+@ExceptionHandler

注意该方式需要开启注解支持

    <!-- 启用注解,使用了<context:component-scan/> 后就可以将该配置移除。 -->
    <!--<context:annotation-config />-->
    <mvc:annotation-driven/>
    <!-- 设置使用注解的类所在的包 -->
    <context:component-scan base-package="com.springmvc.*"></context:component-scan>

全局异常处理类:MyExceptionHandler.java

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

/**
 * @author swadian
 * @date 2022/2/21
 * @Version 1.0
 */
@ControllerAdvice
public class MyExceptionHandler {

    /**
     * 处理异常:捕获数据运算异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler({ArithmeticException.class}) //捕获所有异常 Exception.class
    @ResponseBody //返回字符串而非视图
    @ResponseStatus(HttpStatus.OK)
    public String arithmeticExceptionHandler(Exception e) {
        System.out.println("打印错误信息 ===> ArithmeticException:" + e);
        //返回错误信息
        return "错误信息:" + e.getMessage();
    }
}

测试类

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

/**
 * @author swadian
 * @date 2022/2/21
 * @Version 1.0
 */
@RestController
@RequestMapping
public class SubmitController {
    //计算
    @RequestMapping("/submit")
    public String submit(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String num = request.getParameter("num");
        Integer i = 10 / Integer.valueOf(num);
        return "计算成功,结果为:" + i;
    }
}

启动程序,参数输入为0,得到如下处理结果:

上文说到 @ ExceptionHandler 需要进行异常处理的方法必须与出错的方法在同一个 Controller里面。那么当代码加入了 @ControllerAdvice,则不需要必须在同一个controller 中了。

这也是 Spring 3.2 带来的新特性。从名字上可以看出大体意思是控制器增强。

也就是说,@controlleradvice + @ ExceptionHandler 也可以实现全局的异常捕捉。 请确保此WebExceptionHandle 类能被扫描到并装载进 Spring 容器中。

若在其他的由@Controller标记的Handler类中的Handle方法抛出异常,且没有在Handler类中定义@ExceptionHandler方法,则会去由@ControllerAdvice标记的类中去找,若也找不到,则在页面抛出异常。

问题:Tomcat方式启动和Application方式启动有什么区别呢?

https://www.jb51.net/article/211409.htm

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring MVC中,可以通过以下几种方式来处理异常: 1. 使用@ControllerAdvice注解和@ExceptionHandler注解: - 首先,创建一个全局的异常处理类,使用@ControllerAdvice注解标注,并在类中定义一个或多个带有@ExceptionHandler注解的方法,用于处理特定的异常类型。 - 在异常处理方法中,可以定义需要执行的逻辑,例如记录日志、返回自定义错误信息等。 - 这种方式可以捕获并处理控制器中抛出的异常,提供统一的异常处理机制。 2. 使用@ExceptionHandler注解: - 在控制器类中,可以使用@ExceptionHandler注解标注方法,用于处理特定的异常类型。 - 这种方式适合处理控制器中的异常,可以针对不同的异常类型定义不同的处理逻辑。 3. 使用HandlerExceptionResolver接口: - 可以实现HandlerExceptionResolver接口,并注册为Spring的bean。 - 通过实现该接口的resolveException方法,可以自定义异常处理逻辑。 - 这种方式可以自定义异常处理的策略,例如根据异常类型、请求路径等进行不同的处理。 4. 使用@ControllerAdvice注解和@ModelAttribute注解: - 在全局异常处理类中,可以使用@ModelAttribute注解定义一个方法,用于在异常处理方法执行前,向模型中添加一些通用的属性。 - 这种方式适合在异常处理前,向模型中添加一些额外的信息,以便在异常处理方法中使用。 以上是几种常见的Spring MVC异常处理方式,根据具体的需求和场景,选择适合的方式进行异常处理

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

swadian2008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值