【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开始"

}

相关推荐
程序猿乐锅4 小时前
【黑马点评 | 第八篇】Redisson分布式锁
java·数据库·spring boot·redis·分布式·spring·缓存
需要8266 小时前
分布式事务:Seata AT/TCC/SAGA 的取舍与踩坑
java·spring boot·分布式·spring·spring cloud
m0_587383006 小时前
深圳24小时自助健身房解决方案实战:从系统架构到部署指南
java·人工智能·spring boot·spring·系统架构·需求分析
小马哥程序开发8 小时前
[点赞收藏免费领取 · 项目源码]57105基于Spring Boot的充电桩管理系统的设计与实现
java·spring boot·源码·课程设计·毕设·大作业·课设
卓怡学长10 小时前
w202springboot基于B_S架构的图书信息管理系统
java·spring boot·spring·intellij-idea
走到天涯海角10 小时前
用springBoot写几个简单的接口
java·spring boot·intellij-idea
xcl092511 小时前
西安同城货运系统源码开发实战 核心功能实现与部署全指南
java·spring boot
ym hyd 11112 小时前
慢性病精细化管理平台源码 Java+SpringBoot+Vue3 前后分离
java·vue.js·spring boot·毕设
RuoyiOffice12 小时前
SpringBoot3+Vue3 低代码业务表单:从拖拽设计、独立建表到审批与数据查询
spring boot·vue3·数据建模·flowable·版本管理·低代码表单·ruoyi office
需要82612 小时前
MySQL MVCC 与事务隔离级别:从一条 update 看版本链
java·数据库·spring boot·mysql·spring cloud