Spring boot 参数校验
发布日期:2021-05-10 09:25:31 浏览次数:21 分类:精选文章

本文共 6709 字,大约阅读时间需要 22 分钟。

文章目录

Spring boot 参数校验

上一节 Spring boot crud 和 swagger使用

源码


springboot web模板已经自动集成了 hibernate-validator; 所以我们引入 spring-boot-starter-web 即可使用;

简介

java 参数校验;是遵循JSR-303 规范,对这种规范实现支持最好的就是 Hibernate Validator; spring 底层也是使用的hibernate validator。简化了 我们在硬编码对参数和bean的校验。

基本数据类型参数校验(包括string,以及基本数据类型的包装类)

请求只接受一个基本类型参数的时候(包括string)不是一个bean;

我们需要在类上加@Validated 然后在方法参数上加上对应的校验注解

我们以String 类型参数为例

使用@Length对string 长度的校验

// 类上加注解 @Validated@Validatedpublic class ProductController {   // 参数中使用校JSR303  bean校验注解@GetMapping("product")public Product getProduct(@Length(max = 32, min = 32) @RequestParam String id) throws Exception {   ...}}

通过swagger 调用; 上面我们限制了 id的长度为32, 我们输入一个错误的长度

在这里插入图片描述
我们输入长度为1 的id; 校验生效 提示 长度需要在32到32之间;这是框架自动给我们返回的
当然我们也可以指定message来设置消息;例如:
@Length(max = 32, min = 32, message = “id长度必须为32位”),其他的基本类型使用基本一样;
例如 int , long 值可以使用 @Max @Min 等注解修饰;具体参考, 不同类型使用不同的校验方式。

实体参数校验

对参数bean进行校验。我们在实体类上使用注解

例如 :
- @NotBlank 不能为null以及空白字符
- @Max 最大值
- @Min 最小值

public class Product {       @ApiModelProperty(required = true, value = "商品名称")    @NotBlank    @Length(min = 1, max = 500)    private String name;    @ApiModelProperty(required = true, value = "商品id")    @NotBlank    @Length(max = 32, min = 32)    private String id;    @ApiModelProperty(required = true, value = "商品价格,以分为单位", dataType = "java.lang.Long", example = "1000")    @Max(Integer.MAX_VALUE)    @Min(0)    private Long price;

上面对实体类Product 进行了name的长度和不能为空白的校验以及id长度限制,price最大值最小值

请求方法添加@Validated 开启校验

@ApiOperation(value = "添加商品信息", httpMethod = "POST")    @PostMapping("product")    public String addProduct(@Validated Product product) throws Exception {           return product.getId();    }

使用swagger 调用; 返回400,并且是一组json格式的校验信息很不友好;下个章节对全局异常的处理,设置返回我们自己封装的信息。更加友好简短的返回体

{     "timestamp": "2021-03-31T08:47:28.158+0000",  "status": 400,  "error": "Bad Request",  "errors": [    {         "codes": [        "Length.product.id",        "Length.id",        "Length.java.lang.String",        "Length"      ],      "arguments": [        {             "codes": [            "product.id",            "id"          ],          "arguments": null,          "defaultMessage": "id",          "code": "id"        },        32,        32      ],      "defaultMessage": "长度需要在32和32之间",      "objectName": "product",      "field": "id",      "rejectedValue": "111",      "bindingFailure": false,      "code": "Length"    }  ],  "message": "Validation failed for object='product'. Error count: 1",  "path": "/validator/product"}

分组校验

@Validated 是spring 提供的注解,支持分组校验;通过groups 属性进行分组

例如: @Length(min = 32, max = 32, message = "orderId 长度为32", groups = OrderGroup.class) 通过 属性groups 进行指定是那个组,不指定默认spring提供了javax.validation.groups.Default 分组
  1. 创建自定义分组
public interface OrderGroup {   }
  1. 需要校验得实体bean上进行分组指定 orderGroup
@ApiModel(description = "订单信息描述")public class OrderEntity {       @ApiModelProperty(required = true, value = "订单编号")    @Length(min = 32, max = 32, message = "orderId 长度为32", groups = OrderGroup.class)    @NotBlank(message = "orderId 必填")    private String orderId;...
  1. 请求指定分组校验
@ApiOperation(value = "添加订单", httpMethod = "POST", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)    @PostMapping("order")    public String addOrder(@Validated({   Default.class, OrderEntity.OrderGroup.class}) @RequestBody OrderEntity orderEntity) throws Exception {           return orderEntity.getOrderId();    }

通过@validated value 可以指定多个分组同时生效,Default.class 为默认分组,若不指定则默认Default.class分组。

示例代码中 属性orderId 同时使用了@Length 和 @NotBlank校验注解; 并且同时指定了分组default 和orderGroup,

所以@Length 和 @NotBlank 都会生效;若不指定分组则默认 @NotBlank 生效;也可以指定多个同时生效。

嵌套校验

使用@Valid 进行实体的嵌套校验。

@Valid 是java自带的校验注解;支持属性嵌套参数校验; 主要是 对实体bean的级联校验;

在实体的属性上添加@Valid

@ApiModel(description = "订单信息描述")public class OrderEntity {   ...    @ApiModelProperty(required = true, value = "订单详情")    @NotNull    @Valid    private OrderInfo orderInfo;    ...

OrderInfo 是 OrderEntity 的一个属性; OrderInfo 的属性也添加校验注解,则 对属性 OrderEntity.orderInfo.orderSorce 的校验也生效

@ApiModel(description = "订单扩展详情")    public class OrderInfo {           @ApiModelProperty(value = "订单来源", required = true)        @Length(max = 32, min = 1)        @NotBlank        private String orderSource;

常用校验注解

注解 说明 备注
@AssertFalse 断言为false JSR303
@AssertTrue 断言为true JSR303
@DecimalMax 必须为一个数字,值必须小于或者等于指定的值 JSR303
@DecimalMin 必须为一个数字,值必须大于或者等于指定的值 JSR303
@Digits 元素必须是可接受范围内的数字 JSR303
@Email email格式 JSR303
@Future 标注在时间类型上,必须是一个未来的时间 JSR303
@FutureOrPresent 标注在时间类型上,必须是一个未来的时间或者当前 JSR303
@Max 最大值 JSR303
@Min 最小值 JAR303
@Negative 元素必须是严格的负数 JSR303
@NegativeOrZero 负数或者0 JSR303
@NotBlank 不能为null和空白 JSR303
@NotEmpty 不能为null和空字符 JSR303
@NotNull not null JSR303
@Null 必须为null JSR303
@Past 标注在时间类型上,必须为一个过去的时间 JSR303
@PastOrPresent 标注在时间类型上,为一个过去或者现在的时间 JSR303
@Pattern 是否匹配正则 JSR303
@Positive 正数,不包括0 JSR303
@PositiveOrZero 正数,或者0 JSR303
@Size 集合大小或者字符串长度限制 JSR303
@Length 校验字符串长度 Hibernate 提供
@Range 值得范围 Hibernate 提供
@URL 合法url Hibernate 提供

自定义校验

通过 @Constraint 指定具体的校验器

示例:

  1. 自定义注解 @FileSufixx 校验文件后缀
@Target({   METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})@Documented@Repeatable(value = FileSufixx.List.class)@Retention(RetentionPolicy.RUNTIME)@Constraint(validatedBy = ValidatedFileSufixx.class)public @interface FileSufixx {       String value() default "docx";    String message() default "上传的文件类型不对,请检查";    Class
[] groups() default { }; Class
[] payload() default { }; @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE}) @Documented @Retention(RetentionPolicy.RUNTIME) @interface List { FileSufixx[] value(); }}

通过@Constraint(validatedBy = ValidatedFileSufixx.class) 指定校验器

2. 编写校验器
在方法isValid 进行文件后缀名称的判断

public class ValidatedFileSufixx implements ConstraintValidator
{ private String fileSufixx; @Override public boolean isValid(MultipartFile value, ConstraintValidatorContext context) { if (fileSufixx == null || fileSufixx.trim().equals("")) return true; String originalFilename = value.getOriginalFilename(); if (originalFilename.contains(".")) { if (originalFilename.substring(originalFilename.lastIndexOf(".") + 1).equals(fileSufixx)) { return true; } } return false; } @Override public void initialize(FileSufixx constraintAnnotation) { fileSufixx = constraintAnnotation.value(); }}
  1. 请求中使用
    上传文件,会走我们自定义的校验器进行文件后缀的校验
@ApiOperation(value = "上传", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)    public void upload(@RequestPart("file") @FileSufixx MultipartFile file) {           System.out.println(file.getOriginalFilename());    }

下一节 Spring boot 异常配置

上一篇:Spring boot 异常配置
下一篇:动态数组的封装(泛型)

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2025年04月26日 11时31分49秒