如何优雅的处理SpringBoot接口中参数校验

相信我们在处理接口参数校验时,都不会使用大量的if,else 进行来处理,这样显得太繁琐,下面就来介绍一下如何能够简单而有效的处理方式:

一、使用注解来处理参数校验

1、实体类

package com.dongl.bean.mybean;


import com.dongl.utils.annotation.CheckField;
import lombok.Data;
import org.hibernate.validator.constraints.Range;

import javax.validation.constraints.NotNull;
import java.util.Date;
@Data
public class User { /**主键*/ private Long id; /**姓名*/ @NotNull private String name; /**性别*/ @CheckField(fieldValues = {"男", "女"}) private String sex; /**出生日期*/ private Date birthDay; /**年龄*/ @Range(min = 20 , max = 99) private Short age; /**详细地址*/ private String address; }

 

2、Controller层

package com.dongl.controller;

import com.dongl.bean.mybean.User;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

/**
 * @author D-L
 * @Classname AnnotationController
 * @Version 1.0
 * @Description   接口参数校验异常处理
 * @Date 2020/8/26
 */

@RestController
@RequestMapping("Annotation")
public class AnnotationController {

    @PostMapping(value = "user")
    public String test(@Validated @RequestBody User user  /*, BindingResult bindingResult*/) {
        System.out.println(user);
        return "do something you like ------";
    }
}

 

3、响应结果

测试参数:

{
    "name":"admin",
    "sex":"男",
    "age":120,
    "address":"杭州市西湖区"
}

response:

{
    "timestamp": "2020-08-26T07:25:45.547+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "Range.user.age",
                "Range.age",
                "Range.java.lang.Short",
                "Range"
            ],
            "arguments": [
                {
                    "codes": [
                        "user.age",
                        "age"
                    ],
                    "arguments": null,
                    "defaultMessage": "age",
                    "code": "age"
                },
                99,
                20
            ],
            "defaultMessage": "需要在20和99之间",
            "objectName": "user",
            "field": "age",
            "rejectedValue": 120,
            "bindingFailure": false,
            "code": "Range"
        }
    ],
    "message": "Validation failed for object='user'. Error count: 1",
    "trace": "org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public java.lang.String com.dongl.controller.AnnotationController.test(com.dongl.bean.mybean.User): [Field error in object 'user' on field 'age': rejected value [120]; codes [Range.user.age,Range.age,Range.java.lang.Short,Range]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.age,age]; arguments []; default message [age],99,20]; default message [需要在20和99之间]] \r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.lang.Thread.run(Thread.java:748)\r\n",
    "path": "/Annotation/user"
}

结论】:这样的响应结果显然有点不够优雅,太繁琐,有没有更好的处理方式,当然有,下面使用 BindResult 处理。

 

二、针对接口处理  Validator + BindResult进行校验

1、处理响应结果

package com.dongl.controller;

import com.dongl.bean.mybean.User;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @author D-L
 * @Classname AnnotationController
 * @Version 1.0
 * @Description   处理参数校验异常 
 * @Date 2020/8/24
 */

@RestController
@RequestMapping("Annotation")
public class AnnotationController {

    @PostMapping(value = "user")
    public String test(@Validated @RequestBody User user  , BindingResult bindingResult) {
        List<ObjectError> allErrors = bindingResult.getAllErrors();
        // 如果有参数校验失败,会将错误信息封装成对象组装在BindingResult里
        for(ObjectError error : allErrors){
            return error.getDefaultMessage();
        }
        System.out.println(user);
        return "do something you like ------";
    }
}

 

2、响应结果

需要在20和99之间

结论】当然这种方式已经解决了返回体繁琐的问题,但是每一处理接口参数都需要添加,还是有点不尽人意,有没有更好的解决方法,当然有,下面通过全局的方式处理。

 

三、全局异常处理  Validator + 自动抛出异常

1、全局处理响应结果

首先,我们需要新建一个类,在这个类上加上@ControllerAdvice或@RestControllerAdvice注解,这个类就配置成全局处理类了。(这个根据你的Controller层用的是@Controller还是@RestController来决定)

这里就以@RestController为例:

package com.dongl.utils.error;

import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @author D-L
 * @Classname ExceptionControllerAdvice
 * @Version 1.0
 * @Description   全局处理参数校验异常返回提示
 * @Date 2020/8/26
 */
@RestControllerAdvice
public class ExceptionControllerAdvice {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public String MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        // 从异常对象中拿到ObjectError对象
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        // 然后提取错误提示信息进行返回
        return objectError.getDefaultMessage();
    }
}

 

2、测试结果:

需要在20和99之间

注释】:这里说明一下如果你进行了全局的处理,但在接口上又进行了手动处理,这时命中的是接口上的,也就是全局配置不生效了。

posted @ 2020-08-26 15:57  AmourLee  阅读(2276)  评论(0编辑  收藏  举报