Spring Boot Validation 快速入门

spring-boot-starter-validation 是 Spring Boot 中用于支持数据验证的模块。它建立在 Java Validation API(JSR-380)之上,提供了一种方便的方式来验证应用程序中的数据。以下是使用 spring-boot-starter-validation 的基本方法:

快速入门

添加依赖:

在你的 Spring Boot 项目的 pom.xml 文件中,添加以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

如果你使用 Gradle,可以在 build.gradle 文件中添加:

implementation 'org.springframework.boot:spring-boot-starter-validation'

创建验证规则:

在需要进行数据验证的类中,使用 Java Validation API 中的注解标记字段,以定义验证规则。例如,使用 @NotBlank 来确保字段不为空:

public class MyRequest {
    @NotBlank
    private String name;

    /**
     *    1.@NotNull:不能为null,但可以为empty(""," ","   ")      
     *    2.@NotEmpty:不能为null,而且长度必须大于0 (" ","  ")
     *    3.@NotBlank:只能作用在String上,不能为null,而且调用trim()后,长度必须大于0("test")    即:必须有实际字符
     * 复制代码
     */
    @NotBlank(message="用户名不能为空")
    private String userName;

    @NotBlank(message="年龄不能为空")
    @Pattern(regexp="^[0-9]{1,2}$",message="年龄不正确")
    private String age;

    @AssertFalse(message = "必须为false")
    private Boolean isFalse;
    /**
     * 如果是空,则不校验,如果不为空,则校验
     */
    @Pattern(regexp="^\\d{4}(-)(1[0-2]|0?\\d)\\1([0-2]\\d|\\d|30|31)$",message="出生日期格式不正确")
    private String birthday;

    @Pattern(regexp = "^[M|F|U|m|f|u]{1}$")
    private String gender;

    @Pattern(regexp = "^(MS)?(MR)?(PRO)?(MRS)?(DOC)?$")
    private String civility;

    @Size(min = 1, message = "field names can't be empty")
    private List<String> names = new ArrayList();
    // Other fields and methods...
}

这只是一个简单的例子,Java Validation API 提供了许多其他注解,如 @NotNull@Min@Max@Email 等,以满足各种验证需求。

在控制器中使用验证:

在需要验证输入数据的地方,通常是在 Spring MVC 的控制器中,使用 @Valid 注解来启用验证:

@RestController
public class MyController {
    @PostMapping("/submit")
    public ResponseEntity<String> submit(@Valid @RequestBody MyRequest request) {
        // Process the validated request
        return ResponseEntity.ok("Request is valid");
    }
}

在上面的例子中,@Valid 注解用于告诉 Spring Boot 对 MyRequest 对象进行验证。如果验证失败,将会抛出 MethodArgumentNotValidException 异常。

处理验证错误:

若要处理验证错误,可以使用 BindingResult 对象。修改控制器方法以接受 BindingResult 参数,并检查是否有错误:

@RestController
public class MyController {
    @PostMapping("/submit")
    public ResponseEntity<String> submit(@Valid @RequestBody MyRequest request, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            // Handle validation errors
            return ResponseEntity.badRequest().body("Validation errors");
        }

        // Process the validated request
        return ResponseEntity.ok("Request is valid");
    }
}

这就是使用 spring-boot-starter-validation 的基本步骤。通过这种方式,你可以方便地在 Spring Boot 应用程序中进行数据验证,确保输入数据的合法性。

分组校验

在使用 Spring Boot Validation 进行分组校验时,你可以使用 Validation API 提供的 @GroupSequence 注解来定义校验顺序。下面是一个简单的示例,演示如何在 Spring Boot 中实现分组校验。

首先,假设你有一个包含分组信息的 Java Bean 类:

import javax.validation.GroupSequence;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

public class MyRequest {

    // 定义分组
    public interface FirstGroup {}

    public interface SecondGroup {}

    // 定义分组顺序
    @GroupSequence({FirstGroup.class, SecondGroup.class})
    public interface AllGroups {}

    // 分组校验示例
    @NotNull(message = "ID不能为空", groups = FirstGroup.class)
    private Long id;

    @NotBlank(message = "姓名不能为空", groups = SecondGroup.class)
    private String name;

    @NotNull(groups = {FirstGroup.class, SecondGroup.class}, message = "密码不能为空")
    private String password;

    // 省略其他字段和方法
}

在上述示例中,我们定义了两个分组 FirstGroupSecondGroup,然后使用 @GroupSequence 注解定义了它们的顺序。接着,在字段上使用 @NotNull@NotBlank 注解,并通过 groups 属性指定了校验时所属的分组。

接下来,在你的控制器或服务中,使用 @Validated 注解来指定使用哪个分组进行校验:

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.RestController;

@RestController
@Validated
public class MyController {

    @PostMapping("/submit")
    public String submit(@Validated(MyRequest.FirstGroup.class) @RequestBody MyRequest request) {
        // 处理请求
        return "Request is valid";
    }

    @PostMapping("/update")
    public String update(@Validated(MyRequest.SecondGroup.class) @RequestBody MyRequest request) {
        // 处理请求
        return "Request is valid";
    }
}

在上述示例中,@Validated 注解用于标记控制器,然后在方法参数上使用 @Validated 注解来指定使用哪个分组进行校验。在 /submit 接口中使用了 FirstGroup 进行校验,而在 /update 接口中使用了 SecondGroup 进行校验。

这样,你就可以实现基于分组的校验。请注意,分组的顺序是在 @GroupSequence 注解中定义的。

@Validated与@Valid 的区别
@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制,这个网上也有资料,不详述。
@Valid:作为标准JSR-303规范,还没有吸收分组的功能。

常用注解说明

在 Spring Boot 中,用于数据验证的常用注解是来自 Java Validation API(JSR-380)的注解。以下是一些常用的注解:

  1. 通用注解
  • @NotNull: 验证注解的元素值不是 null。
  • @Null: 验证注解的元素值是 null。
  • @AssertTrue: 验证注解的元素值是 true
  • @AssertFalse: 验证注解的元素值是 false
  • @Min(value): 验证注解的元素值大于等于指定的值。
  • @Max(value): 验证注解的元素值小于等于指定的值。
  • @Size(max, min): 验证注解的元素值的大小在指定的范围内。
  • @Digits(integer, fraction): 验证注解的元素值的整数部分和小数部分的数字不超过指定的数值。
  1. 字符串验证
  • @NotBlank: 验证注解的元素值不为空(不为 null、去掉前后空格后长度大于0)。
  • @NotEmpty: 验证注解的元素值不为 null 且不为空。
  • @Email: 验证注解的元素值是一个有效的电子邮件地址。
  1. 数值验证
  • @Positive: 验证注解的元素值是正数。
  • @PositiveOrZero: 验证注解的元素值是非负数。
  • @Negative: 验证注解的元素值是负数。
  • @NegativeOrZero: 验证注解的元素值是非正数。
  1. 日期和时间验证
  • @Past: 验证注解的元素值是过去的日期或时间。
  • @PastOrPresent: 验证注解的元素值是过去或当前的日期或时间。
  • @Future: 验证注解的元素值是将来的日期或时间。
  • @FutureOrPresent: 验证注解的元素值是将来或当前的日期或时间。
  1. 自定义注解
  • 你还可以创建自定义的注解,通过实现 ConstraintValidator 接口来定义自己的验证逻辑,并使用 @Constraint 注解进行声明。

这些注解可以通过在 Java Bean 的字段上使用来进行数据验证。在 Spring Boot 中,通常与 @Valid@Validated 一起使用,以触发验证。在上述提到的示例中,已经展示了一些常用注解的使用方式。

示例:
以下是常用定义校验的注解及其使用示例:

  1. @NotNull:被注解的元素必须不为null。例如:
public class User {
    @NotNull(message = "姓名不能为空")
    private String name;
    // ...其他字段...
}
  1. @NotEmpty:被注释的对象必须不为空(数据:String,Collection,Map,arrays)。例如:
public class User {
    @NotEmpty(message = "角色列表不能为空")
    private List<Role> roles;
    // ...其他字段...
}
  1. @NotBlank:CharSequence子类型,验证注解的元素值不为空(包括不为null或去除首位空格后长度为0)。例如:
public class User {
    @NotBlank(message = "手机号码不能为空")
    private String phoneNumber;
    // ...其他字段...
}
  1. @Min:验证数字是否小于等于指定的最小值。例如:
public class User {
    @Min(value = 18, message = "年龄不能低于18岁")
    private int age;
    // ...其他字段...
}
  1. @Max:验证数字是否大于等于指定的最大值。例如:
public class User {
    @Max(value = 60, message = "年龄不能超过60岁")
    private int age;
    // ...其他字段...
}
  1. @Pattern:用于校验字符串是否符合指定的正则表达式。例如:
public class User {
    @Pattern(regexp = "^\\d{6}$", message = "身份证号码格式不正确")
    private String idCardNumber;
    // ...其他字段...
}
  1. @Size:用于限制字符序列(如String、Collection、Map等)的长度,支持min和max属性。例如:
public class User {
    @Size(min = 6, max = 18, message = "密码长度必须在6-18之间")
    private String password;
    // ...其他字段...
}
  1. @Email:用于校验邮箱地址。例如:
public class User {
    @Email(message = "请输入正确的邮箱地址")
    private String email;
    // ...其他字段...
}
  1. @Past:用于判断日期是否在过去。例如:
public class User {
    @Past(message = "生日不能晚于现在")
    private Date birthday;
    // ...其他字段...
}
  1. @Future:用于判断日期是否在未来。例如:
public class User {
    @Future(message = "截止日期必须在未来")
    private Date deadline;
    // ...其他字段...
}
  1. @DecimalMax:验证数字是否小于等于指定的最大值。例如:
public class User {
    @DecimalMax(value = "100.00", message = "金额不能超过100元")
    private double amount;
    // ...其他字段...
}
  1. @DecimalMin:验证数字是否大于等于指定的最小值。例如:
public class User {
    @DecimalMin(value = "1.00", message = "价格不能低于1元")
    private double price;
    // ...其他字段...
}

以上都是常见的数据校验注解,使用这些注解可以让我们的应用程序具有更强的健壮性,避免非法数据的输入。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容