Spring Boot 统一参数校验、统一异常、统一响应,这才是优雅的处理方式

本文介绍了如何在Spring Boot中优雅地处理参数校验、异常和响应。通过统一状态码、封装ResultVo、利用@Validated进行参数校验、优化异常处理以及统一响应和异常处理,提升后端接口的规范性和易用性。内容包括Controller层参数接收、定义返回格式、使用枚举封装状态码、避免冗余的校验代码、处理BindException等异常,以及通过AOP实现统一响应和异常处理。
摘要由CSDN通过智能技术生成

前言

本篇主要要介绍的就是controller层的处理,一个完整的后端请求由4部分组成:

  1. 接口地址(也就是URL地址)

  2. 请求方式(一般就是get、set,当然还有put、delete)

  3. 请求数据(request,有head跟body)

  4. 响应数据(response)

本篇将解决以下3个问题:

  1. 当接收到请求时,如何优雅的校验参数

  2. 返回响应数据该如何统一的进行处理

  3. 接收到请求,处理业务逻辑时抛出了异常又该如何处理

一、Controller层参数接收(太基础了,可以跳过)

常见的请求就分为getpost2种

@RestController
@RequestMapping("/product/product-info")
public class ProductInfoController {

    @Autowired
    ProductInfoService productInfoService;

    @GetMapping("/findById")
    public ProductInfoQueryVo findById(Integer id) {
     ...
    }

    @PostMapping("/page")
    public IPage findPage(Page page, ProductInfoQueryVo vo) {
     ...
    }
}

1、@RestController:之前解释过,@RestController = @Controller + ResponseBody。加上这个注解,springboot就会吧这个类当成controller进行处理,然后把所有返回的参数放到ResponseBody

推荐一个 Spring Boot 基础实战教程:
https://github.com/javastacks/spring-boot-best-practice

2、@RequestMapping:请求的前缀,也就是所有该Controller下的请求都需要加上/product/product-info的前缀

3、@GetMapping("/findById"):标志这是一个get请求,并且需要通过/findById地址才可以访问到

4、@PostMapping("/page"):同理,表示是个post请求

5、参数:至于参数部分,只需要写上ProductInfoQueryVo,前端过来的json请求便会通过映射赋值到对应的对象中,例如请求这么写,productId就会自动被映射到vo对应的属性当中

size : 1
current : 1

productId : 1
productName : 泡脚

二、统一状态码

1. 返回格式

为了跟前端妹妹打好关系,我们通常需要对后端返回的数据进行包装一下,增加一下状态码状态信息,这样前端妹妹接收到数据就可以根据不同的状态码,判断响应数据状态,是否成功是否异常进行不同的显示。

当然这让你拥有了更多跟前端妹妹的交流机会,假设我们约定了1000就是成功的意思

如果你不封装,那么返回的数据是这样子的

{
  "productId": 1,
  "productName": "泡脚",
  "productPrice": 100.00,
  "productDescription": "中药泡脚加按摩",
  "productStatus": 0,
}

经过封装以后时这样子的

{
  "code": 1000,
  "msg": "请求成功",
  "data": {
    "productId": 1,
    "productName": "泡脚",
    "productPrice": 100.00,
    "productDescription": "中药泡脚加按摩",
    "productStatus": 0,
  }
}

2. 封装ResultVo

这些状态码肯定都是要预先编好的,怎么编呢?写个常量1000?还是直接写死1000?要这么写就真的书白读的了,写状态码当然是用枚举拉

1、首先先定义一个状态码的接口,所有状态码都需要实现它,有了标准才好做事

public interface StatusCode {
    public int getCode();
    public String getMsg();
}

2、然后去找前端妹妹,跟他约定好状态码(这可能是你们唯一的约定了)枚举类嘛,当然不能有setter方法了,因此我们不能在用@Data注解了,我们要用@Getter

@Getter
public enum ResultCode implements StatusCode{
    SUCCESS(1000, "请求成功"),
    FAILED(1001, "请求失败"),
    VALIDATE_ERROR(1002, "参数校验失败"),
    RESPONSE_PACK_ERROR(1003, "response返回包装失败");

    private int code;
    private String msg;

    ResultCode(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

3、写好枚举类,就开始写ResultVo包装类了,我们预设了几种默认的方法,比如成功的话就默认传入object就可以了,我们自动包装成success

@Data
public class ResultVo {
    // 状态码
    private int code;

    // 状态信息
    private String msg;

    // 返回对象
    private Object data;

    // 手动设置返回vo
    public ResultVo(int code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    // 默认返回成功状态码,数据对象
    public ResultVo(Object data) {
        this.code = ResultCode.SUCCESS.getCode();
        this.msg = ResultCode.SUCCESS.getMsg();
        this.data = data;
    }

    // 返回指定状态码,数据对象
    public ResultVo(StatusCode statusCode, Object data) {
        this.code = statusCode.getCode();
        this.msg = statusCode.getMsg();
        this.data = data;
    }

    // 只返回状态码
    public ResultVo(StatusCode statusCode) {
        this.code = statusCode.getCode();
        this.msg = statusCode.getMsg();
        this.data = null;
    }
}

4、使用,现在的返回肯定就不是return data;这么简单了,而是需要new ResultVo(data);

@PostMapping("/findByVo")
public Resu
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值