SpringBoot之异常处理示例

1.引入pom依赖

  • 主要几个异常注解都在web依赖中;
  • thymeleaf: 查看静态界面;
    <!--引入springboot父工程依赖-->
    <!--引入依赖作用:
    可以省去version标签来获得一些合理的默认配置
    -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
    </parent>

    <dependencies>

        <!--模板引擎 -用于查看界面-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>


        <!--引入提供Web开发场景依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>


        <!--两个用来做测试的jar包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>

    </dependencies>


2.application.yml配置

  • 主要是配置进行错误页面跳转时 springBoot可以自动携带错误信息
#    错误页面的异常信息都是在DefaultErrorAttributes类中进行封装的,
#     它有一个属性是includeException并且默认值是false,
#     在封装exception对象的时候,
#     它通过判断includeException是否为true来决定是否封装
server:
  error:
    include-exception: true #这里如果是false(默认是false) springboot就不会封装exception html页面也就拿不到数据



3.配置启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @创建人: Mhh
 * @创建时间: 2022/2/11
 * @描述: 异常处理测试
 *     SpringBoot默认的处理异常的机制:SpringBoot默认的已经提供一套处理异常的机制。
 *      一旦程序中出现了异常SpringBoot会像/error的url发送请求,在SpringBoot中提供了一个
 *      叫BasicExceptionController来处理/error请求,然后跳转到默认显示异常来展示异常信息。
 */
@SpringBootApplication
public class ExceptionHandlingApplication {
    public static void main(String[] args) {
        SpringApplication.run(ExceptionHandlingApplication.class, args);
    }
}



3. 异常使用实例


3.1 自定义错误异常

    创建自定义异常

  • 自定义异常类只需从Exception类或者它的子类派生一个子类即可。
  • 自定义异常类如果继承Exception类,则为受检查异常,必须对其进行处理;如果不想处理,可以让自定义异常类继承运行时异常RuntimeException类。
  • 习惯上,自定义异常类应该包含2个构造器:一个是默认的构造器,另一个是带有详细信息的构造器。
/**
 * @创建人: Mhh
 * @创建时间: 2022/2/11
 * @描述: 自定义异常
 */
public class CustomException extends Exception {
    public CustomException() {
    	super();
    }
    public CustomException(String s) {
        super(s);
    }
}



自定义异常测试结果:

  • 自定义异常的使用.
  • 这里的自定义异常继承的是Exception,为受检异常,所有需要throws抛出,如果继承的是RuntimeException运行时异常则就不用抛出.在这里插入图片描述

import com.it.mhh.exception.CustomException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @创建人: Mhh
 * @创建时间: 2022/2/11
 * @描述:
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class ExceptionHandling {


    /*
     * @explain : 自定义异常测试
     *
     * @Author Mhh
     * @param null :
     * @return
     * @Date 2022/2/11 16:10
     */

    @Test
    public void CustomExceptionTest() throws CustomException {
        throw new CustomException("自定义异常错误");
    }

}



3.2 @ExceptionHandler()局部针对某种异常的异常处理方法

  • 作用:用来定义针对某种异常的异常处理方法
  • 参数:定义该异常处理器捕获控制器里面出现的哪些异常;可传入集合。
  • 比如,传RuntimeException.class,该处理方法只会捕获RuntimeException异常进行处理。
  • 局限性:只对被定义在当前类中请求抛出的异常起作用,不具备捕获其它地方请求抛出异常的能力,其它请求报此错误不会进这个方法
import com.it.mhh.exception.CustomException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;

/**
 * @创建人: Mhh
 * @创建时间: 2022/2/11
 * @描述: 测试局部异常处理器
 */
@RestController
@RequestMapping("localExceptionHandling")
public class LocalExceptionHandlingController {



//-----------------------------------------------------------------------------------------------------

    /*
     * @explain : 捕获捉住指定在@ExceptionHandler中的异常
     * @ExceptionHandler():局部 统一处理某一类异常(只会在当前请求出错起作用),
     * //                     后端调用报错还是报错 只是返回是封装了下错误而已;相当于被try()住,没有捕获,返回封装错误
     * //局限性:只对当前请求抛出的异常起作用,不具备捕获其它地方请求抛出异常的能力,其它请求报此错误不会进这个方法
     * @Author Mhh
     * @param request :会自动注入
     * @param e : 会将产生异常对象注入到方法中
     * @return java.lang.String
     * @Date 2022/2/12 13:42
     */
    @ExceptionHandler(RuntimeException.class)
    public String catchArithmeticException(HttpServletRequest request, Exception e, HandlerMethod handlerMethod) {
        e.printStackTrace();
        StackTraceElement stackTraceElement = e.getStackTrace()[0];// 得到异常棧的首个元素
//        System.out.println("File="+stackTraceElement.getFileName());// 打印文件名
//        System.out.println("Line="+stackTraceElement.getLineNumber());// 打印出错行号
//        System.out.println("Method="+stackTraceElement.getMethodName());// 打印出错方法
        return request.getRequestURI() + "请求<br/>" + "错误异常:     " + e + "<br/>错误类名为:    " + stackTraceElement.getFileName() + "<br/>错误方法名为:     " + stackTraceElement.getMethodName() + "<br/>错误java行号为:    " + stackTraceElement.getLineNumber();
    }
//-----------------------------------------------------------------------------------------------------

}



@ExceptionHandler()测试结果:

  • @ExceptionHandler()只对被定义在当前类中请求抛出的异常起作用,不具备捕获其它地方请求抛出异常的能力,其它请求报此错误不会进这个方法.
    在这里插入图片描述
import com.it.mhh.exception.CustomException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;

/**
 * @创建人: Mhh
 * @创建时间: 2022/2/11
 * @描述: 测试局部异常处理器
 */
@RestController
@RequestMapping("localExceptionHandling")
public class LocalExceptionHandlingController {



//-----------------------------------------------------------------------------------------------------


    /*
     * @explain :返回一个自定义异常,被@ExceptionHandler()注解捕获测试
     * @Author Mhh
     * @return void
     * @Date 2022/2/12 13:49
     */
    @GetMapping("tryReturnRuntimeException")
    public void tryReturnRuntimeException() throws CustomException {
        throw new RuntimeException("局部错误异常测试");
    }


    /*
     * @explain : 捕获捉住指定在@ExceptionHandler中的异常
     * @ExceptionHandler():局部 统一处理某一类异常(只会在当前请求出错起作用),
     * //                     后端调用报错还是报错 只是返回是封装了下错误而已;相当于被try()住,没有捕获,返回封装错误
     * //局限性:只对当前请求抛出的异常起作用,不具备捕获其它地方请求抛出异常的能力,其它请求报此错误不会进这个方法
     * @Author Mhh
     * @param request :会自动注入
     * @param e : 会将产生异常对象注入到方法中
     * @return java.lang.String
     * @Date 2022/2/12 13:42
     */
    @ExceptionHandler(RuntimeException.class)
    public String catchArithmeticException(HttpServletRequest request, Exception e, HandlerMethod handlerMethod) {
        e.printStackTrace();
        StackTraceElement stackTraceElement = e.getStackTrace()[0];// 得到异常棧的首个元素
//        System.out.println("File="+stackTraceElement.getFileName());// 打印文件名
//        System.out.println("Line="+stackTraceElement.getLineNumber());// 打印出错行号
//        System.out.println("Method="+stackTraceElement.getMethodName());// 打印出错方法
        return request.getRequestURI() + "请求<br/>" + "错误异常:     " + e + "<br/>错误类名为:    " + stackTraceElement.getFileName() + "<br/>错误方法名为:     " + stackTraceElement.getMethodName() + "<br/>错误java行号为:    " + stackTraceElement.getLineNumber();
    }
//-----------------------------------------------------------------------------------------------------

}



3.3 @ExceptionHandler+@ControllerAdvice 全局异常处理方式

  • 该注解(@ControllerAdvice)可以把异常处理器(被@ExceptionHandler注解的方法)应用到所有的Controller,而不是单单的一个Controller类。
  • 全局异常处理的原理:在独立的一个类中,定义一套对各种异常的处理机制,然后用@ControllerAdvice注解该类,统一对不同位置的不同异常进行处理。
  • @RestControllerAdvice注解的 basePackages 和 basePackageClasses 属性 表示此全局处理器的作用域,不填则是全局
import com.it.mhh.exception.CustomException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;

/**
 * @创建人: Mhh
 * @创建时间: 2022/2/12
 * @描述: 全局性异常处理类
 */
//basePackages 和 basePackageClasses 属性 表示此全局处理器的作用域,不填则是全局
@RestControllerAdvice
public class GlobalExceptionAdviceHandling {

    //@RestControllerAdvice+@ExceptionHandler则就是全局性异常处理
    /*
     * @explain : 捕获捉住指定在@ExceptionHandler中的异常
     * @ExceptionHandler():局部 统一处理某一类异常(只会在当前请求出错起作用),
     * //                     后端调用报错还是报错 只是返回是封装了下错误而已;相当于被try()住,没有捕获,返回封装错误
     * //局限性:只对当前请求抛出的异常起作用,不具备捕获其它地方请求抛出异常的能力,其它请求报此错误不会进这个方法
     * @Author Mhh
     * @param request :会自动注入
     * @param e : 会将产生异常对象注入到方法中
     * @return java.lang.String
     * @Date 2022/2/12 13:42
     */
    @ExceptionHandler(CustomException.class)
    public String catchArithmeticException(HttpServletRequest request, Exception e, HandlerMethod handlerMethod) {
        e.printStackTrace();//在后台打印错误日志
        StackTraceElement stackTraceElement = e.getStackTrace()[0];// 得到异常棧的首个元素
//        System.out.println("File="+stackTraceElement.getFileName());// 打印文件名
//        System.out.println("Line="+stackTraceElement.getLineNumber());// 打印出错行号
//        System.out.println("Method="+stackTraceElement.getMethodName());// 打印出错方法
        return request.getRequestURI() + "请求<br/>" + "错误异常:     " + e + "<br/>错误类名为:    " + stackTraceElement.getFileName() + "<br/>错误方法名为:     " + stackTraceElement.getMethodName() + "<br/>错误java行号为:    " + stackTraceElement.getLineNumber();
    }


}



全局异常测试结果:

  • 不在存在@ExceptionHandler()注解的局限性,可以对全局指定的异常进行捕获
    在这里插入图片描述
import com.it.mhh.exception.CustomException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @创建人: Mhh
 * @创建时间: 2022/2/13
 * @描述: 测试全局异常处理器
 */
@RestController
@RequestMapping("adviceExceptionHandling")
public class AdviceExceptionHandlingController {

    /*
     * @explain :返回一个自定义异常,被@ExceptionHandler()注解捕获测试
     * @Author Mhh
     * @return void
     * @Date 2022/2/12 13:49
     */
    @GetMapping("tryReturnCustomExceptionAdvice")
    public void tryReturnCustomException() throws CustomException {
        throw new CustomException("自定义异常出错---");
    }
}



3.4 自定义错误页面

  • SpringBoot 默认的处理异常的机制:SpringBoot 默认的已经提供了一套处理异常的机制,一旦程序中出现了异常, SpringBoot 会像/error 的 url 发送请求.在 springBoot 中提供了一个叫 BasicExceptionController 来处理/error 请求,然后跳转到默认显示异常的页面来展示异常信息。
  • 如果我们需要将所有的异常统一跳转到自定义的错误页面,需要在src/main/resources/templates 目录下创建error.html 页面.注意:名称必须叫error.html

error.html视图配置:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>错误页面提示</title>
</head>
<body>
<h2 align="center" style="color: red">系统出错 请联系--Mhh</h2>
<h4 align="center" th:text="'status: '+${status}"></h4>
<h4 align="center" th:text="'timestamp: '+${timestamp}"></h4>
<h4 align="center" th:text="'exception: '+${exception}"></h4>
<h4 align="center" th:text="'error: '+${error}"></h4>
<h4 align="center" th:text="'message: '+${message}"></h4>
<h4 align="center" th:text="'detail: '+${detail}"></h4>
<h4 align="center" th:text="'path: '+${path}"></h4>
<!--
错误页面最终能获取到信息有如下:
timestamp:时间戳
status:状态码
error:错误提示
exception:异常对象
message:异常信息
errors:JSR303数据校验都在这里

-->
</body>
</html>


自定义错误页面:

  • 只有异常没有被捕获或被处理的前提下才会进错误页面
    在这里插入图片描述

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

/**
 * @创建人: Mhh
 * @创建时间: 2022/2/11
 * @描述: 测试进入自定义错误页面
 */
@RestController
@RequestMapping("errorExceptionHandling")
public class ErrorExceptionHandlingController {


    /*http://localhost:8080/exceptionHandling/tryReturnArrayIndexOutOfBoundsException
     * @explain :出现错误异常走自定义错误页面
     *
     * @Author Mhh
     * @return void
     * @Date 2022/2/12 10:08
     */
    @GetMapping("tryReturnArrayIndexOutOfBoundsException")
    public void tryReturnArrayIndexOutOfBoundsException() {
        int[] a = new int[3];
        int i = a[4];
    }
}



3.5 配置 SimpleMappingExceptionResolver 全局处理异常

SimpleMappingExceptionResolver 配置:

  • SimpleMappingExceptionResolver只能简单的处理异常
  • 当发生异常的时候,根据发生的异常类型跳转到指定的页面来显示异常信息
  • 以异常全路径名和视图名称进行绑定 来确认 报什么异常走什么视图
  • 注意: 实现HandlerExceptionResolver 接口类全局处理异常优先级比SimpleMappingExceptionResolver 全局处理异常高

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import java.util.Properties;

/**
 * 通过 SimpleMappingExceptionResolver 做全局异常映射视图处理(其局限性传递不了异常信息,只是简单的 具体错误映射到具体视图界面)
 * @创建人: Mhh
 * @创建时间: 2022/2/12
 * @描述: 是通过简单映射关系来决定由哪个错误视图来处理当前的异常信息。它提供了多种映射关系可以使用
 */
@Configuration
public class GlobalExceptionSimpleMappingExceptionResolver {

    @Bean
    public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
        Properties properties = new Properties();

        /**
         * 如果找不到视图 那么就是走的error视图
         * 参数一:异常的类型,注意必须是异常类型的全名
         * 参数二:视图名称
         */
        properties.put("java.lang.NullPointerException","nullPointerException");
//        properties.put("java.lang.ArithmeticException","arithmeticException");
        //设置异常与视图映射信息
        simpleMappingExceptionResolver.setExceptionMappings(properties);
        simpleMappingExceptionResolver.setExceptionAttribute("exception");
        return simpleMappingExceptionResolver;
    }
}



nullPointerException.html视图配置:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <title>NullPointerException</title>
</head>
<body>
<h1 style="color: red">NullPointerException异常界面</h1>
<h4  th:text="'message: '+${exception.message}"></h4>
<h4  th:text="'exception: '+${exception}"></h4>
<h4  th:text="'fileName: '+${exception.stackTrace[0].fileName}"></h4>
<h4  th:text="'methodName: '+${exception.stackTrace[0].methodName}"></h4>
<h4  th:text="'lineNumber: '+${exception.stackTrace[0].lineNumber}"></h4>
</body>
</html>


SimpleMappingExceptionResolver 全局处理异常测试结果:

  • 只能返回简单的错误异常信息.
    在这里插入图片描述
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @创建人: Mhh
 * @创建时间: 2022/2/13
 * @描述: 测试SimpleMappingExceptionResolver方法(具体错误映射到具体视图界面)
 */
@RestController
@RequestMapping("nullPointerExceptionHandling")
public class NullPointerExceptionHandlingController {

    /*http://localhost:8080/nullPointerExceptionHandling/tryReturnNullPointerException
     * @explain :出现错误异常走自定义错误页面(异常没有被捕获或被处理的前提下)
     *
     * @Author Mhh
     * @return void
     * @Date 2022/2/12 10:08
     */
    @GetMapping("tryReturnNullPointerException")
    public void tryReturnNullPointerException() {
        String s = null;
        s.toString();
    }
}



3.6 配置 实现HandlerExceptionResolver 接口 全局处理异常

实现HandlerExceptionResolver 接口配置:

  • 当发生异常的时候,根据发生的异常类型跳转到指定的页面来显示自定义异常信息
  • 需要实现 resolveException 方法,该方法返回一个 ModelAndView 对象,在方法内部对异常的类型进行判断,然后返回合适的 ModelAndView 对象,如果该方法返回了 null,则 Spring 会继续寻找其他的实现了 HandlerExceptionResolver 接口的 Bean。换句话说,Spring 会搜索所有注册在其环境中的实现了 HandlerExceptionResolver 接口的 Bean,逐个执行,直到返回了一个 ModelAndView 对象。
  • 比SimpleMappingExceptionResolver 全局处理异常的优势在于可以传递自定义参数,其它没区别

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;

/**
 * @创建人: Mhh
 * @创建时间: 2022/2/12
 * @描述: 通过实现 HandlerExceptionResolver 接口做全局异常(可以传递异常信息,只是简单的 具体错误映射到具体视图界面)
 */
@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        StackTraceElement stackTraceElement = e.getStackTrace()[0];// 得到异常棧的首个元素

        //根据返回错误异常 指定视图
//        if (e instanceof NullPointerException)
//            modelAndView.setViewName("nullPointerException");
        if (e instanceof ArithmeticException)
            modelAndView.setViewName("arithmeticException");

        modelAndView.addObject("status", httpServletResponse.getStatus());//状态码
        modelAndView.addObject("exception",e);//异常错误类型
        modelAndView.addObject("uri",httpServletRequest.getRequestURI());//错误请求地址
        modelAndView.addObject("fileName", stackTraceElement.getFileName());//错误地方类名
        modelAndView.addObject("methodName", stackTraceElement.getMethodName());//错误方法名
        modelAndView.addObject("lineNumber", stackTraceElement.getLineNumber());//错误行号
        return modelAndView;
    }
}



arithmeticException.html视图配置:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <title>ArithmeticException</title>
</head>
<body>
<h1 style="color: red" >ArithmeticException异常界面</h1>
<h4  th:text="'status: '+${status}"></h4>
<h4  th:text="'exception: '+${exception}"></h4>
<h4  th:text="'uri: '+${uri}"></h4>
<h4  th:text="'fileName: '+${fileName}"></h4>
<h4  th:text="'methodName: '+${methodName}"></h4>
<h4  th:text="'lineNumber: '+${lineNumber}"></h4>
</body>
</html>


现HandlerExceptionResolver 接口 全局处理异常测试结果:

  • 比SimpleMappingExceptionResolver 全局处理异常优点在于可以自定义数据返回到视图界面上.
    在这里插入图片描述
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @创建人: Mhh
 * @创建时间: 2022/2/13
 * @描述: 实现HandlerExceptionResolver接口测试类
 */
@RestController
@RequestMapping("arithmeticExceptionHandling")
public class ArithmeticExceptionHandlingController {

    /*http://localhost:8080/arithmeticExceptionHandling/tryReturnArithmeticException
     * @explain :出现错误异常走自定义错误页面(异常没有被捕获或被处理的前提下)
     *
     * @Author Mhh
     * @return void
     * @Date 2022/2/12 10:08
     */
    @GetMapping("tryReturnArithmeticException")
    public void tryReturnArithmeticException() {
        int i = 1/0;
    }
}









链接:SpringBoot之异常处理示例 源代码下载地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

孟浩浩

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

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

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

打赏作者

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

抵扣说明:

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

余额充值