SpringBoot优雅捕捉异常的两种方法小结

 更新时间:2024年08月09日 09:34:16   作者:wx59bcc77095d22  
SpringBoot框架对异常的处理提供了几种很强大的方法,我们可以通过@ControllerAdvice和@ExceptionHandler注解实现全局异常的处理,下面就来介绍一下这两种方法的实现,感兴趣的可以了解一下

一、前言

SpringBoot框架对异常的处理提供了几种很强大的方法,我们可以通过@ControllerAdvice和@ExceptionHandler注解实现全局异常的处理,也可以通过实现HandlerExceptionResolve接口来完成全局异常的处理。

二、全局异常处理方式一

通过@ControllerAdvice和@ExceptionHandler注解实现全局异常拦截,它可以拦截controller层请求方法抛出的异常信息,同时外加@ ResponseBody注解,可以实现响应类型为json格式。或者直接使用@RestControllerAdvice和@ExceptionHandler注解的方式实现响应类型为json格式的数据。

1.添加依赖

<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

2.自定义异常类

package com.example.dataproject.exception;

/**
 * @author qx
 * @date 2024/8/8
 * @des 自定义异常
 */
public class ServiceException extends RuntimeException {

    private Integer code;

    public Integer getCode() {
        return code;
    }

    public ServiceException(String message, Integer code) {
        super(message);
        this.code = code;
    }
}

3.全局异常处理类

包含对自定义异常和空指针异常的处理。

package com.example.dataproject.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

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

/**
 * @author qx
 * @date 2024/8/8
 * @des 全局异常处理类
 */
@RestControllerAdvice
@Slf4j
public class GlobalException {


    @ExceptionHandler(value = {Exception.class})
    public Map<String, Object> exceptionHandler(HttpServletRequest request, Exception e) {
        log.info("未知异常,请求地址:{},错误信息:{}", request.getRequestURI(), e.getMessage());
        Map<String, Object> map = new HashMap<>();
        map.put("code", 999);
        map.put("message", e.getMessage());
        return map;
    }

    @ExceptionHandler(value = {ServiceException.class})
    public Map<String, Object> serviceExceptionHandler(HttpServletRequest request, ServiceException e) {
        log.info("自定义异常,请求地址:{},错误信息:{}", request.getRequestURI(), e.getMessage());
        Map<String, Object> map = new HashMap<>();
        map.put("code", e.getCode());
        map.put("message", e.getMessage());
        return map;
    }

    @ExceptionHandler(value = {NullPointerException.class})
    public Map<String, Object> nullPointExceptionHandler(HttpServletRequest request, NullPointerException e) {
        log.info("空指针异常,请求地址:{},错误信息:{}", request.getRequestURI(), e.getMessage());
        Map<String, Object> map = new HashMap<>();
        map.put("code", 500);
        map.put("message", e.getMessage());
        return map;
    }

}

4.创建控制层测试

package com.example.dataproject.controller;

import com.example.dataproject.exception.ServiceException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author qx
 * @date 2024/8/8
 * @des 测试
 */
@RestController
public class IndexController {


    @GetMapping("/null")
    public String testNull() {
        String s = null;
        //抛出空指针异常 全局异常中的空指针异常处理会捕获到这个异常
        if (true) {
            throw new NullPointerException("空指针异常");
        }
        return "null success";
    }

    @GetMapping("/service")
    public String testService() {
        if (true) {
            //抛出自定义异常 全局异常中的自定义异常处理会捕获到这个异常
            throw new ServiceException("自定义服务异常", 888);
        }
        return "service success";
    }

    @GetMapping("/exception")
    public String testException() {
        if (true) {
            throw new RuntimeException("其他异常");
        }
        return "exception success";
    }

}

5.启动程序并访问请求进行测试

测试空指针异常

测试自定义服务异常

其他异常

6.404异常特殊处理

默认情况下,@ExceptionHandler注解无法捕捉到 404 异常,比如请求一个无效的地址,返回信息如下:

如果想要捕捉到这种异常,可以在application.properties文件中添加如下配置来实现。

# 如果没有找到请求地址,抛异常
spring.mvc.throw-exception-if-no-handler-found=true
# 关闭默认的静态资源路径映射
spring.web.resources.add-mappings=false

启动服务,再次发起地址请求,结果如下:

7.自定义异常页面的实现

某些场景下,当发生异常时希望跳转到自定义的异常页面,如何实现呢?

首先,这里基于thymeleaf模板引擎来开发页面,在templates目录下创建一个异常页面error.html。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>错误</title>
</head>
<body>
出错啦,请与管理员联系<br>
错误详情:<span th:text="${message}"></span>
</body>
</html>

我们重新修改一下全局异常处理类,让异常返回结果到页面中。

package com.example.dataproject.exception;

import lombok.extern.slf4j.Slf4j;
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.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;

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

/**
 * @author qx
 * @date 2024/8/8
 * @des 全局异常处理类
 */
@ControllerAdvice
@Slf4j
public class GlobalException {


    @ExceptionHandler(value = {Exception.class})
    public ModelAndView exceptionHandler(HttpServletRequest request, Exception e) {
        log.info("未知异常,请求地址:{},错误信息:{}", request.getRequestURI(), e.getMessage());
      /*  Map<String, Object> map = new HashMap<>();
        map.put("code", 999);
        map.put("message", e.getMessage());
        return map;*/
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error");
        modelAndView.addObject("message", e.getMessage());
        return modelAndView;
    }

    @ExceptionHandler(value = {ServiceException.class})
    @ResponseBody
    public Map<String, Object> serviceExceptionHandler(HttpServletRequest request, ServiceException e) {
        log.info("自定义异常,请求地址:{},错误信息:{}", request.getRequestURI(), e.getMessage());
        Map<String, Object> map = new HashMap<>();
        map.put("code", e.getCode());
        map.put("message", e.getMessage());
        return map;
    }

    @ExceptionHandler(value = {NullPointerException.class})
    @ResponseBody
    public Map<String, Object> nullPointExceptionHandler(HttpServletRequest request, NullPointerException e) {
        log.info("空指针异常,请求地址:{},错误信息:{}", request.getRequestURI(), e.getMessage());
        Map<String, Object> map = new HashMap<>();
        map.put("code", 500);
        map.put("message", e.getMessage());
        return map;
    }

}

我们重新请求刚才不存在的访问时,这个时候跳转到了页面,并在页面中显示了异常的信息。

三、全局异常处理方式二

在 Spring Boot 中,除了通过@ControllerAdvice和@ExceptionHandler注解实现全局异常处理外,还有一种通过实现HandlerExceptionResolver接口来完成全局异常的处理。

具体实现示例如下:

package com.example.dataproject.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

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

/**
 * @author qx
 * @date 2024/8/8
 * @des 全局异常处理
 */
@Component
@Slf4j
public class GlobalExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
        log.error("接口请求出现异常,请求地址:{},错误信息:{}", request.getRequestURI(), e.getMessage());
        if (e instanceof NullPointerException) {
            // 设置响应类型为json格式
            ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
            mv.addObject("code", 500);
            mv.addObject("msg", e.getMessage());
            return mv;
        } else {
            // 设置响应类型为错误页面
            ModelAndView mv = new ModelAndView();
            mv.addObject("message", e.getMessage());
            mv.setViewName("error");
            return mv;
        }
    }
}

如果是空指针异常的话会返回json数据格式,如果是其他异常会在页面上显示异常的信息。

其他异常

空指针异常

虽然这种方式能够处理全局异常,但是 Spring 官方不推荐使用它;同时实测过程中发现它无法拦截 404 错误,当请求错误地址时,会优先被DefaultHandlerExceptionResolver默认异常处理类拦截,自定义的异常处理类无法捕捉。

到此这篇关于SpringBoot优雅捕捉异常的两种方法小结的文章就介绍到这了,更多相关SpringBoot 捕捉异常内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • java解析多层嵌套json字符串问题

    java解析多层嵌套json字符串问题

    这篇文章主要介绍了java解析多层嵌套json字符串问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • Java rmi远程方法调用基本用法解析

    Java rmi远程方法调用基本用法解析

    这篇文章主要介绍了Java rmi远程方法调用基本用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • Sleuth+logback 设置traceid 及自定义信息方式

    Sleuth+logback 设置traceid 及自定义信息方式

    这篇文章主要介绍了Sleuth+logback 设置traceid 及自定义信息方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Spring通过配置文件和注解实现属性赋值

    Spring通过配置文件和注解实现属性赋值

    这篇文章主要介绍了Spring通过配置文件和注解实现属性赋值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • SpringBoot环境下junit单元测试速度优化方式

    SpringBoot环境下junit单元测试速度优化方式

    这篇文章主要介绍了SpringBoot环境下junit单元测试速度优化方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Spring框架实现文件上传功能

    Spring框架实现文件上传功能

    这篇文章主要为大家详细介绍了Spring框架实现文件上传功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • Spring整合ehCache全过程

    Spring整合ehCache全过程

    这篇文章主要介绍了Spring整合ehCache全过程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • SpringBoot实现发送邮件、发送微信公众号推送功能

    SpringBoot实现发送邮件、发送微信公众号推送功能

    这篇文章主要介绍了SpringBoot实现发送邮件、发送微信公众号推送功能,这里对成员变量JavaMailSender使用了@Resource注解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • 浅析Bean Searcher 与 MyBatis Plus 区别介绍

    浅析Bean Searcher 与 MyBatis Plus 区别介绍

    Bean Searcher号称任何复杂的查询都可以一行代码搞定,但 Mybatis Plus 似乎也有类似的动态查询功能,最近火起的 Bean Searcher 与 MyBatis Plus 倒底有啥区别?带着这个问题一起通过本文学习下吧
    2022-05-05
  • Java主线程捕获子线程异常的实现

    Java主线程捕获子线程异常的实现

    本文主要介绍了Java主线程捕获子线程异常的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-04-04

最新评论