java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot 捕捉异常

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

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

您可能感兴趣的文章:
阅读全文