Spring Boot中的数据校验 Validation

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/starexplode/article/details/81198703

Spring Boot中的数据校验

我们可能会经常需要对传入的参数进行校验,如果数据比较少的时候还比较容易处理,但当数据比较多的时候会显得比较麻烦,而且处理不当的时候,还会代码重复。这时候就需要Spring Boot对参数进行校验了。
这时候就需要使用使用Validation对数据进行校验了。

在Spring Boot中使用Validation

有如下的一段代码:

@RestController
public class BookController {
    @PostMapping("/book")
    public Book getBook(Book book) {
        // ...
        return book;
    }
}

可以看到请求传入了一个Book,Book类如下:

public class Book {
    private Integer id;
    private String bookName;
    private String bookAuthor;
    // 省略get和set方法
}

现在需要对book中的属性进行校验,如果使用if else 进行校验会显得很麻烦。这时候可以在Book中的属性上添加Validation注解,如下:

public class Book {
    private Integer id;
    @NotBlank
    private String bookName;
    @NotBlank
    private String bookAuthor;
    // 省略get和set方法
}

其中的NotBlank注解指的是属性值不能为空。
然后还需要在Controller中的方法的需要校验的字段上加上@Valid注解,表明这个参数需要校验,如下:

@RestController
public class BookController {
    @PostMapping("/book")
    public Book getBook(@Valid Book book) {
        // ...
        return book;
    }
}

这时候假如bookName和bookAuthor为空,那么就会出现400的响应码。
这里写图片描述
Spring Boot这时的返回为:

{
    "timestamp": "2018-07-25T01:21:53.644+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "NotBlank.book.bookAuthor",
                "NotBlank.bookAuthor",
                "NotBlank.java.lang.String",
                "NotBlank"
            ],
            "arguments": [
                {
                    "codes": [
                        "book.bookAuthor",
                        "bookAuthor"
                    ],
                    "arguments": null,
                    "defaultMessage": "bookAuthor",
                    "code": "bookAuthor"
                }
            ],
            "defaultMessage": "不能为空",
            "objectName": "book",
            "field": "bookAuthor",
            "rejectedValue": "",
            "bindingFailure": false,
            "code": "NotBlank"
        },
        {
            "codes": [
                "NotBlank.book.bookName",
                "NotBlank.bookName",
                "NotBlank.java.lang.String",
                "NotBlank"
            ],
            "arguments": [
                {
                    "codes": [
                        "book.bookName",
                        "bookName"
                    ],
                    "arguments": null,
                    "defaultMessage": "bookName",
                    "code": "bookName"
                }
            ],
            "defaultMessage": "不能为空",
            "objectName": "book",
            "field": "bookName",
            "rejectedValue": "",
            "bindingFailure": false,
            "code": "NotBlank"
        }
    ],
    "message": "Validation failed for object='book'. Error count: 2",
    "path": "/book"
}

因为使用的是测试工具,所以Spring Boot返回的是Json串。
上面的是Spring Boot的默认返回,我们肯定不希望返回这样的一个东西给前端。所以就需要自定义错误信息和错误处理。

自定义校验信息和错误处理

Validation注解中都有一个message的属性可以通过这个属性自定义错误信息。如下:

public class Book {
    private Integer id;
    @NotBlank(message = "书名不能为空")
    private String bookName;
    @NotBlank(message = "作者不能为空")
    private String bookAuthor;
    // 省略get和set方法
}

Spring Boot的Controller方法中可以传一个BindingResult或者Errors类型的参数,值得注意的一点是这个参数的位置必须是参数列表的被@Valid注解修饰的参数紧跟着的(也就是被@Valid修饰的下一个参数)后面,如果在前面,会出现下面的错误,如果不是下一个,那么这个参数将不起作用

{
    "timestamp": "2018-07-25T01:49:10.742+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the @RequestBody or the @RequestPart arguments to which they apply: public top.mcwebsite.demo.domain.Book top.mcwebsite.demo.web.controller.BookController.getBook(org.springframework.validation.BindingResult,top.mcwebsite.demo.domain.Book,javax.servlet.http.HttpServletResponse)",
    "path": "/book"
}

下面的代码是如何进行自定义错误处理:

@RestController
public class BookController {
    @PostMapping("/book")
    public Book getBook(@Valid Book book, BindingResult result, HttpServletResponse response) {
        if (result.hasErrors()) {
            result.getAllErrors().forEach((error) -> {
                FieldError fieldError = (FieldError) error;
                // 属性
                String field = fieldError.getField();
                // 错误信息
                String message = fieldError.getDefaultMessage();
                System.out.println(field + ":" + message);
            });

        }
        // ...
        return book;
    }
}

结果:
这里写图片描述
这里的错处处理只是简单的打印。

这里的错误消息也可以做成国际化的,具体做法可以自己取研究。

当需要校验的Bean比较多的时候这样也会显得比较麻烦,所以这时候就可以使用Spring Boot的异常处理机制了。

Spring Boot的异常处理+Bean Validation

Spring Boot 中有一个专门处理错误信息的一个类叫做ResponseEntityExceptionHandler。其中有很多关于400的错误处理,也就是参数错误的处理,其中就有一个专门用来处理没有通过校验的参数的方法。我们重写这个类的这个方法即可。

@ControllerAdvice   // Spring 的异常处理的注解
public class BadRequestExceptionHandler extends ResponseEntityExceptionHandler {

    private Logger logger = LoggerFactory.getLogger(getClass());


    @Override
    protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

        Map<String, String> messages = new HashMap<>();
        BindingResult result = ex.getBindingResult();
        if (result.hasErrors()) {
            List<ObjectError> errors = result.getAllErrors();
            for (ObjectError error : errors) {
                FieldError fieldError = (FieldError) error;
                messages.put(fieldError.getField(), fieldError.getDefaultMessage());
            }
            logger.error(messages.toString());
        }
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(messages);
    }
}

这时候controller中的方法中就不需要BindingResult或者Errors类型的参数了。

一些常用的Validation注解

注解 作用
@NotNull 值不能为空
@Null 值必须为空
@Pattern(regex=) 字符串必须匹配正则表达式
@Size(min, max) 集合元素的数量必须在min和max之间
@CreditCardNumber(ignoreNonDigitCharacters=) 字符串必须是信用卡号,按找美国的标准验证
@Email 字符串必须是Email地址
@Length(min, max) 检查字符串的长度
@NotBlank 字符串不能为空串
@NotEmpty 字符串不能为null, 集合必须有元素
@Range(min, max) 数字必须大于min, 小于max
@SafeHtml 字符串必须是安全的html
@URL 字符串必须是合法的URL
@AssertFalse 值必须是false
@AssertTrue 值必须是true
@DecimalMax(value=, inclusive=) 值必须小于等于(inclusive=true)/小于(inclusive=false)属性指定的值,也可以注释在字符串类型的属性上。
@DecimalMin(value=, inclusive=) 值必须大于等于(inclusive=true)/小于(inclusive=false)属性指定的值,也可以注释在字符串类型的属性上。
@Digist(integer=,fraction=) 数字格式检查。integer指定整数部分的最大长度,fraction指定小数部分的最大长度
@Future 时间必须是未来的
@Past 事件必须是过去的
@Max(value=) 值必须小于等于value指定的值。不能注解在字符串类型属性上。
@Min(value=) 值必须小于等于value指定的值。不能注解在字符串类型属性上。

猜你喜欢

转载自blog.csdn.net/starexplode/article/details/81198703
今日推荐