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 捕捉异常内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • 排查Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl

    排查Failed to validate connection com.mysql.cj.jdbc.Connec

    这篇文章主要介绍了Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl问题排查,具有很好的参考价值,希望对大家有所帮助
    2023-02-02
  • springmvc之获取参数的方法(必看)

    springmvc之获取参数的方法(必看)

    下面小编就为大家带来一篇springmvc之获取参数的方法(必看)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • Java获取七牛云存储空间中图片外链

    Java获取七牛云存储空间中图片外链

    本文主要介绍了Java获取七牛云存储空间中图片外链,需要获取在七牛云中存储的所有图片,并返回外链地址,具有一定的参考价值,感兴趣的可以了解一下
    2023-10-10
  • 聊聊java中引用数据类型有哪些

    聊聊java中引用数据类型有哪些

    这篇文章主要介绍了java中引用数据类型有哪些,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • 关于Spring事务隔离、传播属性与@Transactional注解

    关于Spring事务隔离、传播属性与@Transactional注解

    这篇文章主要介绍了关于事务隔离、Spring传播属性与@Transactional注解,如果一组处理步骤或者全部发生或者一步也不执行,我们称该组处理步骤为一个事务,需要的朋友可以参考下
    2023-05-05
  • java写的伪微信红包功能示例代码

    java写的伪微信红包功能示例代码

    这篇文章主要介绍了java写的伪微信红包功能示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • 详解Java编程中final,finalize,finally的区别

    详解Java编程中final,finalize,finally的区别

    这篇文章主要介绍了详解Java编程中final,finalize,finally的区别,这个在Java面试题中简直是太常见了...需要的朋友可以参考下
    2015-11-11
  • 一篇文章带你深入了解Java类加载

    一篇文章带你深入了解Java类加载

    这篇文章主要介绍了Java中类加载过程全面解析,具有一定参考价值,需要的朋友可以了解下,希望能给你带来帮助
    2021-08-08
  • 详解Java动态字节码技术

    详解Java动态字节码技术

    Java字节码增强指的是在Java字节码生成之后,对其进行修改,增强其功能,可减少冗余代码,提高性能等。本文将详细介绍Java动态字节码技术。
    2021-05-05
  • javaweb上传下载实例完整版解析(上)

    javaweb上传下载实例完整版解析(上)

    这篇文章主要为大家详细解析了javaweb上传下载实例,本文重点在于文件上传功能的实现,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01

最新评论