【SpringBoot3】全局异常处理

【SpringBoot3】全局异常处理

在 Controller 处理请求过程中发生了异常,DispatcherServlet 将异常处理委托给异常处理器(处理异常的类)。实现 HandlerExceptionResolver 接口的都是异常处理类。

项目的异常一般集中处理,定义全局异常处理器。在结合框架提供的注解,诸如:@ExceptionHandler,@ControllerAdvice ,@RestControllerAdvice 一起完成异常的处理。@ControllerAdvice 与@RestControllerAdvice 区别在于:@RestControllerAdvice 加了@RepsonseBody。

一、全局异常处理器

  • 需求:应用计算两个数字相除,当用户被除数为 0 ,发生异常。使用自定义异常处理器代替默认的异常处理程序

step1:创建收入数字的页面

  • 在 static 目录下创建 input.html , static 目录下的资源浏览器可以直接访问
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="divide" method="post">
  除&nbsp;&nbsp;&nbsp;数:<input type="text" name="n1"> <br/>
  被除数:<input type="text" name="n2"> <br/>
  <input type="submit" value="计算">
</form>
</body>
</html>

step2:创建控制器,计算两个整数相除

java 复制代码
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class NumberController {
    @PostMapping("/divide")
    public String some(Integer n1,Integer n2){
        int result = n1/n2;
        return "n1/n2 = " + result;
    }
}

step3:创建自定义异常处理器

java 复制代码
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

//控制器增强
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler({ArithmeticException.class})
    public String handlerArtithmecticException(ArithmeticException e, Model model){
        String error = e.getMessage();
        model.addAttribute("error",error);
        return "exp";
    }

/*    @ExceptionHandler({ArithmeticException.class})
    @ResponseBody
    public Map<String,String> handlerArtithmecticException(ArithmeticException e){
        Map<String,String> errors = new HashMap<>();
        errors.put("msg",e.getMessage());
        errors.put("tips","被除数不能为0");
        return errors;
    }*/
}

step5:创建给用提示的页面

  • 在 resources/templates/ 创建 exp.html
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>显示异常信息:<div th:text = "${error}"></div> </h3>
</body>
</html>

step6:测试输入(10/0)


二、BeanValidator 异常处理

使用 JSR-303 验证参数时,我们是在 Controller 方法,声明BindingResult 对象获取校验结果。Controller 的方法很多,每个方法都加入 BindingResult 处理检验参数比较繁琐。 校验参数失败抛出异常给框架,异常处理器能够捕获到 MethodArgumentNotValidException,它是 BindException 的子类。

BindException 异常实现了 BindingResult 接口,异常类能够得到 BindingResult 对象,进一步获取 JSR303 校

验的异常信息。

  • 需求:全局处理 JSR-303 校验异常

step1:添加 JSR-303 依赖

xml 复制代码
   <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
   </dependency>

step2:创建 Bean 对象,属性加入 JSR-303 注解

java 复制代码
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.hibernate.validator.constraints.Range;

@Data
public class OrderVO {

    @NotBlank(message = "订单名称不能为空")
    private String name;
    @NotNull(message = "商品必须有数量")
    @Range(min = 1,max = 99,message = "一个订单商品数量在{min} -- {max}")
    private Integer amount;

    @NotNull(message = "用户不能为空")
    @Min(value = 1,message = "从1开始")
    private Integer userId;
}

step3:Controlller 接收请求

java 复制代码
import com.bjpowernode.exp.vo.OrderVO;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

    @PostMapping("/order/new")
    public String createOrder(@Validated @RequestBody OrderVO orderVO){
        return "订单信息:" + orderVO.toString();
    }
}

step4:创建异常处理器

java 复制代码
import org.springframework.ui.Model;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

//控制器增强
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler({ArithmeticException.class})
    public String handlerArtithmecticException(ArithmeticException e, Model model){
        String error = e.getMessage();
        model.addAttribute("error",error);
        return "exp";
    }

/*    @ExceptionHandler({ArithmeticException.class})
    @ResponseBody
    public Map<String,String> handlerArtithmecticException(ArithmeticException e){
        Map<String,String> errors = new HashMap<>();
        errors.put("msg",e.getMessage());
        errors.put("tips","被除数不能为0");
        return errors;
    }*/

    //处理JSR303 验证参数的异常
    //@ExceptionHandler({BindException.class})
    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseBody
    public Map<String,Object> handlerJSR303Exception(MethodArgumentNotValidException e){
        System.out.println("=============JSR303===========");
        Map<String,Object> map = new HashMap<>();
        BindingResult result = e.getBindingResult();
        if(result.hasErrors()){
            List<FieldError> fieldErrors = result.getFieldErrors();
            for (int i = 0; i < fieldErrors.size(); i++) {
                FieldError fieldError = fieldErrors.get(i);
                map.put(i + "-" + fieldError.getField(), fieldError.getDefaultMessage());
            }
        }
        return map;
    }
}
  • 核心代码:

step5:测试

java 复制代码
POST http://localhost:8080/order/new
Content-Type: application/json

{
  "name": "每日订单",
  "amount": 0,
  "userId": 0
}

显示:

{

"1-amount": "一个订单商品数量在1 -- 99",

"0-userId": "从1开始"

}

相关推荐
星辰云-32 分钟前
# 基于Spring Boot的德州特产扒鸡商城系统(毕设|源码|论文|演示视频)
spring boot·后端·课程设计
星辰云-42 分钟前
基于Spring Boot的旅游景点票务系统的设计与实现(毕设项目,附完整源码)
spring boot·后端·课程设计
十年Java程序媛2 小时前
JVM 基础与 GC 垃圾回收详解|可达性分析、分代模型、垃圾收集器、STW
java·开发语言·jvm·spring boot·后端·面试
她的男孩2 小时前
JAR 全对仍 checksum mismatch:Forge Admin 把 Flyway 从 filesystem 改成 classpath
java·数据库·spring boot
小蒜学长3 小时前
基于数据挖掘的京东商城商品推荐系统设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端·推荐系统·个性化推荐
IT研究室3 小时前
最新计算机毕业设计选题推荐-基于spring boot的医院体检管理系统-网站-文档指导-Java-springboot
java·spring boot·课程设计
长不大的杨瑞杰3 小时前
把 Spring Boot 接口变成 AI 工具:OpenAPI、参数映射与异常语义化实战
人工智能·spring boot·后端
RuoyiOffice3 小时前
Vue3+TypeScript 企业管理平台统一UI:新增一个模块,为什么还要重新调样式?
spring boot·typescript·vue3·组件化开发·企业管理软件·ruoyi office·统一ui
流烟默1 天前
SSE 实战:在 SpringBoot + Vue 项目中零依赖实现轻量级实时消息推送
vue.js·spring boot·后端·sse
ly76891 天前
Spring Boot 集成 PostgreSQL 的连接池调优:HikariCP、prepared statement 与服务器资源边界
spring boot·postgresql·hikaricp·连接池调优