springMVC-15 异常处理

发布于:2025-06-22 ⋅ 阅读:(17) ⋅ 点赞:(0)

异常处理-基本介绍

  • 基本介绍

1.Spring MVC通过HandlerExceptionResolver处理程序的异常,包括Handler映射、数据绑定以及目标方法执行时发生的异常。
2.主要处理Handler中用@ExceptionHandler注解定义的方法。
3.ExceptionHandlerMethodResolver内部若找不到@ExceptionHandler注解的话,会找@ControllerAdvice类的@ExceptionHandler注解方法,这样就相当于一个全局异常处理器

异常类型

1.局部异常

在注释了@Controller的处理器类Handler,内部写的异常处理,就是局部异常

需要使用注解@在其方法上进行标注

应用实例

处理原因:如果不处理异常,显示界面会非常的不友好

1.创建com/stein/springMVC/exception/MyExceptionHandler.java

注意:

        1)Handler要用@Component注入到容器中

        2)局部异常处理方法,用使用@ExceptionHandler进行注解

        3)@ExceptionHandler的参数,是填写异常类型,并且可以是数组的形式

@Controller
public class MyExceptionHandler {

    //一个正常的方法映射
    @RequestMapping("/arithmetic")
    public String exceptionDemo(Integer num){
        Integer result=100/num;
        System.out.println("result= "+result);
        return "success";
    }

    @ExceptionHandler({ArithmeticException.class, NullPointerException.class})
    public String exceptionHandler(Exception exception, HttpServletRequest request){
        System.out.println("exception= "+exception.getMessage());
        request.setAttribute("exception", exception.getMessage());
        return "exception_msg";
    }

}

2.创建操作页面 web/exception.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>exception</title>
</head>
<body>
    <h1>局部异常处理</h1>
    <a href="<%=request.getContextPath()%>/arithmetic?num=0">点击显示算数异常</a>
</body>
</html>

3.创建异常显示页面,web/WEB-INF/page/exception_msg.jsp

<body>
    <h1>出错啦>_<</h1>
    <h2>出错信息:<%=request.getAttribute("exception")%></h2>
</body>

4.测试

然后显示出错信息

Debug代码

        异常是通过ExceptionHandlerMethodResolver.java类来处理的,它的异常处理机制比较多。通过Ctrl+N找到

        通过形参exceptionType拿到异常,然后再拿到处理异常的method,最后通过反射调用。

        这一步是通过默认的方法查找异常处理方法,没有找到就返回null

Method method = (Method)this.exceptionLookupCache.get(exceptionType);

        然后找到了我写的MyExceptionHandler.exceptionHanler(exception,request)方法

       

        不出意外的,找到了我写的异常处理方法

        最终返回前端页面进行展示

2.全局异常

应用实例

        全局异常处理机制:

        如果在ExceptionHandlerMethodResolver内部找不到@ExceptionHandler注解的话,
        会去@ControllerAdvice类找@ExceptionHandler注解方法,这样就相当于一个全局异常处理器

1.创建全局异常类,com/stein/springMVC/exception/GlobalException.java

//加入这个注解后,就表示是一个全局异常
//全局异常就不管是哪个Handler抛出的异常,都可以捕获
//控制通知
@ControllerAdvice
public class GlobalException {

    //注解参数用于指定,需要捕获的异常类型
    //1. 模拟NumberFormatException
    //2. 在之前的局部异常中,没有对NumberFormatException异常进行涵盖
    //3. 所以就会来找全局异常处理
    @ExceptionHandler({NumberFormatException.class, ClassCastException.class})
    public String global(Exception ex, HttpServletRequest request) {
        System.out.println("全局异常信息:"+ex.getMessage());
        request.setAttribute("exception", ex.getMessage());
        return "exception_msg";
    }
}

2.增加出现转换异常的方法,com/stein/springMVC/exception/MyExceptionHandler.java

    @RequestMapping("/global")
    public String globalExceptionDemo(String num){
        int i = Integer.parseInt(num);
        return "success";
    }

3.修改页面,增加装换异常访问请求exception.jsp

<body>
    <h1>异常处理</h1>
    <a href="<%=request.getContextPath()%>/arithmetic?num=0">点击显示局部异常</a><br>
    <a href="<%=request.getContextPath()%>/global?num=hello">点击显示全局异常</a>
</body>

4.测试

        选择全局异常

        显示全局异常提示信息

5.postman测试

Debug处理流程

        依然点击全局异常

        断点不变,可以看到发生了数字格式化异常,这一步method没有找到处理异常方法,为null

        看到此时,method找不到在@Controller类中的局部异常处理方法,显示noMatchingExceptionHandler,没有匹配的异常处理

        找到了全局异常处理方法

         进入到处理方法

        最终成功显示异常信息

注意事项与细节

        异常处理时:局部异常优先级高于全局异常

        给局部异常处理添加上NumberFormatException.class后,局部异常优先处理

        局部异常exception= For input string: "hello"

3.自定义异常(类型)

        局部异常和全局异常,是通过作用范围来区分的。

        自定义异常,说的是自定义异常的类型。比如有ArithmeticException.class, NullPointerException.class,NumberFormatException.class这些异常了,我还需要自定义一个年龄异常AgeException.class

        通过@ResponseStatus注解,可以自定义该异常

        关系:那么自定义异常(类型),可以通过默认tomcat调用,或者局部异常、全局异常进行选择调用。像这样:

@ExceptionHandler({ArithmeticException.class, NullPointerException.class,NumberFormatException.class,ArithmeticException.class})
应用实例

1.创建自定义异常类型,com/stein/springMVC/exception/AgeException.java

//reason表示显示的错误原因
//value填写Http错误状态,是枚举类型的
@ResponseStatus(value = HttpStatus.BAD_REQUEST,reason = "年龄需要在1-120岁之间")
public class AgeException extends RuntimeException {
}

2.添加可能出现自定义异常的方法,MyExceptionHandler.java

    @RequestMapping("/age")
    public String age(int age){
        if(age>0 && age<120){
            return "success";
        }else {
            throw new AgeException();
        }
    }

3.添加访问链接,exception.jsp

<a href="<%=request.getContextPath()%>/age?age=121">点击显示自定义异常</a><br><br>

4.测试

        自定义异常(类型)

        返回结果


这个tomcat默认页面太生硬,想用自己页面显示

1.把AgeException.class添加到GlobalException.global()的注解中

@ExceptionHandler({NumberFormatException.class, ClassCastException.class,AgeException.class})

2.为了配合exception_msg.jsp的属性exception.getMessage()返回结果不为null,添加AgeException.java的构造器

@ResponseStatus(value = HttpStatus.BAD_REQUEST,reason = "年龄需要在1-120岁之间")
public class AgeException extends RuntimeException {
    public AgeException() {
    }

    public AgeException(String message) {
        super(message);
    }
}

3.业务代码中,完善message

    @RequestMapping("/age")
    public String age(int age){
        if(age>0 && age<120){
            return "success";
        }else {
            throw new AgeException("年龄需要在1-120岁之间");
        }
    }

4.再次测试

点击自定义异常后,出现了我们自己写的异常页面exception_msg.jsp

同样,这个自定义异常类型,添加到局部异常也可以生效,这儿就不演示了。

Debug处理流程

        跟全局异常Debug一样,参考走一遍即可。

统一处理异常信息

SimpleMappingExceptionResolver

  • 基本说明

1.如果希望对所有异常进行统一处理,可以使用SimpleMappingExceptionResolver
2.它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常
3.需要在ioc容器中配置

应用实例

1.配置SimpleMappingExceptionResolver

    <!--配置一个统一异常处理-->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!--这个属性用于设置异常映射,即当发生某种异常时,应该跳转到哪个视图。-->
        <property name="exceptionMappings">
            <!--它包含一个`<props>`标签,这是Spring配置中用于定义`java.util.Properties`类型属性的方式。每个`<prop>`标签表示一个键值对。-->
            <props>
                <!--键(key)是异常类的全限定名-->
                <!--值(value)是`arrEx`,是一个逻辑视图页面-->
                <prop key="ArrayIndexOutOfBoundsException">arrEx</prop>
            </props>
        </property>
    </bean>

2.按配置创建异常视图,web/WEB-INF/page/arrEx.jsp

<h1>朋友,当前页面异常>_<,如有疑问,可以联系管理员</h1>

3.增加出现数组越界的映射方法,MyExceptionHandler

@RequestMapping("/array")
public String array(){
    //两种写法都可以
    int[] ints = {1, 3, 6, 12};
    //int[] ints =new int[]{1,3,6,12};
    //越界异常
    System.out.println("ints[5]="+ints[5]);
    return "success";
}

4.添加访问页面的链接,exception.jsp

    <a href="<%=request.getContextPath()%>/array">点击测试统一异常处理</a><br><br>

5.测试

对未知异常统一处理

        异常的情况有很多,当无法对每一种异常都进行单独配置的时候,需要一种兜底的方案,就是对其他异常的统一处理。

应用实例

1.使用SimpleMappingExceptionResolver进行配置,web/WEB-INF/springMVC-servlet.xml

    <!--配置一个统一异常处理-->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!--这个属性用于设置异常映射,即当发生某种异常时,应该跳转到哪个视图。-->
        <property name="exceptionMappings">
            <!--它包含一个`<props>`标签,这是Spring配置中用于定义`java.util.Properties`类型属性的方式。每个`<prop>`标签表示一个键值对。-->
            <props>
                <!--键(key)是异常类的全限定名-->
                <!--值(value)是`arrEx`,是一个逻辑视图页面-->
                <prop key="java.lang.ArrayIndexOutOfBoundsException">arrEx</prop>
                <!--两种写法都可以,但是推荐上面一种,避免重名-->
                <!--<prop key="ArrayIndexOutOfBoundsException">arrEx</prop>-->
                <!--配置其他的未知异常-->
                <!--key配置的是所有异常Exception-->
                <!--响应的页面名称是allEx-->
                <prop key="java.lang.Exception">allEx</prop>
            </props>
        </property>
    </bean>

2.创建响应页面,web/WEB-INF/page/allEx.jsp

    <h1>哎呀,发生了未知异常>_<</h1>

3.添加未知异常映射方法,MyExceptionHandler.java

        这是一个字符串越界异常

    @RequestMapping("/unknown")
    public String unknownException(){
        String str="hello";
        System.out.println("str.charAt[5]="+str.charAt(5));
        return "success";
    }

4.添加访问链接,exception.jsp

    <a href="<%=request.getContextPath()%>/unknown">配置统一的未知异常处理</a><br><br>

5.测试

哎呀,发生了未知异常>_<

异常处理的优先级

       

 局部异常 > 全局异常 > SimpleMappingExceptionResolver > tomcat默认机制

1.对比测试局部异常、全局异常、SimpleMappingExceptionResolver的优先级,他们3个的范围都加上ArrayIndexOutOfBoundsException.class,然后进行数组越界异常测试。

        结果响应的只有局部异常:

局部异常exception= 5

2.接下来取消局部异常的参赛资格,取消其ArrayIndexOutOfBoundsException.class的设置,将剩下2个的进行对比。然后进行数组越界异常测试。

        此时,响应的是全局异常

全局异常信息:5

3.然后全局异常退出,删除其越界异常的设置,只保留SimpleMappingExceptionResolver的设置,进行越界测试。

        结果是按照SimpleMappingExceptionResolver配置的arrEx.jsp进行了响应

朋友,当前页面异常>_<,如有疑问,可以联系管理员

4.将SimpleMappingExceptionResolver的设置也取消,包括越界异常和所有异常。进行越界测试

        结果,Tomcat默认的异常机制开始生效了

        综上,确认了他们的优先级排序。


网站公告

今日签到

点亮在社区的每一天
去签到