参数校验在 Web 开发中是一项必不可少的工作。它可以帮助开发人员在用户提交表单数据前对数据进行有效性验证,防止恶意攻击,同时也能提高用户体验。在 Spring MVC 中,我们可以使用 @Validated 和 @Valid 注解来进行校验操作。虽然它们都可以实现校验操作,但还是存在一些不同之处。下面我们分别来介绍一下。
注解的定义
@Validated
@Validated 是 Spring 的注解,是对 JSR-303 Bean Validation 的扩展。在spring-context包的org.springframework.validation.annotation路径下, 注解定义如下:
package org.springframework.validation.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {
Class<?>[] value() default {};
}
@Valid
@Valid 是 JSR-303/JSR-349 Bean Validation 的注解。它的作用是标注一个 Bean 对象需要校验其属性约束注解。在validation-api包的javax.validation路径下,定义如下:
package javax.validation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Valid {
}
注解的使用
@Validated
它支持分组校验,同时可以用在方法级别上。在 Spring MVC 中,我们同样可以使用 @Validated 注解进行校验操作。可以在 Controller 层方法中使用 @Validated 注解标记需要被校验的 Bean 对象,如下所示:
@PostMapping("/create")
public String createUser(@RequestBody @Validated User user) {
// 处理用户数据
}
需要注意的是,使用 @Validated 注解必须借助 Spring 的框架支持。在实际使用中,@Validated 注解一般用于 Controller 层方法参数的校验,可以标注在方法参数、方法上、类上定义验证规则,它的功能比 @Valid 更为强大,支持分组校验、级联校验等更高级的校验功能。
@Valid
在 Spring MVC 中,可以使用 @Valid 注解进行 Bean Validation 校验。具体来说,我们可以在 Controller 层方法中,使用 @Valid 注解标记需要被校验的 Bean 对象,如下所示:
@PostMapping("/create")
public String createUser(@RequestBody @Valid User user) {
// 处理用户数据
}
需要注意的是,@Valid 只能进行简单的约束条件校验,不能扩展实现逻辑包括分组校验等高级功能。在实际使用中,我们可以结合 Bean Validation 注解,实现复杂的校验逻辑。同样地,我们也可以使用 @Valid 注解对方法中的参数进行校验。
注解的区别
@Validated和@Valid的区别主要体现在3个方面:
分组
@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制。没有添加分组属性时,默认验证没有分组的验证属性。
@Valid:作为标准JSR-303规范,还没有吸收分组的功能。
注解地方
@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上
@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上 两者是否能用于成员属性(字段)上直接影响能否提供嵌套验证的功能。
嵌套验证
@Validated:用在方法入参上无法单独提供嵌套验证功能。不能用在成员属性(字段)上,也无法提示框架进行嵌套验证。能配合嵌套验证注解
@Valid进行嵌套验证。@Valid:用在方法入参上无法单独提供嵌套验证功能。能够用在成员属性(字段)上,提示验证框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。
示例
@Validated
@Validated 并不仅仅支持简单的 Bean 参数校验,还可以将其嵌套和分组,进行更复杂的校验。下面展示如何使用 @Validated 对嵌套对象、分组、属性进行验证。第一种,嵌套对象:
public class User {
@NotBlank(message = "用户名不能为空")
@Size(max = 10, message = "用户名不能超过10个字符")
private String username;
@NotBlank(message = "密码不能为空")
@Size(min = 6, max = 20, message = "密码必须在6到20个字符之间")
private String password;
@Valid
private Address address;
// 省略 getter 和 setter 方法
}
public class Address {
@NotBlank(message = "省份不能为空")
private String province;
@NotBlank(message = "城市不能为空")
private String city;
@NotBlank(message = "街道不能为空")
private String street;
// 省略 getter 和 setter 方法
}
第二种,分组:
public interface UserRegister {
}
public class User {
@NotBlank(message = "用户名不能为空", groups = {UserRegister.class})
@Size(max = 10, message = "用户名不能超过10个字符", groups = {UserRegister.class})
private String username;
@NotBlank(message = "密码不能为空", groups = {UserRegister.class})
@Size(min = 6, max = 20, message = "密码必须在6到20个字符之间", groups = {UserRegister.class})
private String password;
@Valid
private Address address;
// 省略 getter 和 setter 方法
}
controller层使用是相同的。
@RestController
@RequestMapping("/users")
public class UserController {
@PostMapping("/save")
public String createUser(@RequestBody @Validated User user) {
return "success";
}
}
@Valid
除不支持分组外,其他使用方式和@Validated类似
public class Address {
@NotBlank(message = "省份不能为空")
private String province;
@NotBlank(message = "城市不能为空")
private String city;
@NotBlank(message = "街道不能为空")
private String street;
// 省略 getter 和 setter 方法
}
public class User {
@NotNull(message = "用户 ID 不能为空")
private Integer userId;
@NotBlank(message = "用户名不能为空")
private String username;
@Valid
private Address address;
// getter 和 setter 方法省略
}
@Controller
@RequestMapping("/user")
public class UserController {
@PostMapping("/create")
public ResponseEntity createUser(@RequestBody @Valid User user ) {
// 保存用户信息
return ResponseEntity.ok("用户创建成功");
}
}
自定义注解验证
除了使用预定义的注解外,我们还可以自定义一个注解,例如验证用户名是否为手机号码。先定义一个手机号注解 @Phone,然后在 User 对象的 username 字段上使用它。
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
@Documented
public @interface Phone {
String message() default "请输入正确的手机号码格式";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class PhoneValidator implements ConstraintValidator<Phone, String> {
// 校验手机号码格式
public boolean isValid(String value, ConstraintValidatorContext context) {
...
}
}
public class User {
@NotNull(message = "用户 ID 不能为空")
private Integer userId;
@NotBlank(message = "用户名不能为空")
@Phone
private String username;
@Valid
private Address address;
// getter 和 setter 方法省略
}
@Controller
@RequestMapping("/user")
public class UserController {
@PostMapping("/create")
public ResponseEntity createUser(@RequestBody @Valid User user ) {
// 保存用户信息
return ResponseEntity.ok("用户创建成功");
}
}
另外
像@NotBlank、@NotNull、@Max、@Min、@Size都是Bean Validation注解,在 validation-api包里,maven坐标如下:
<!-- Bean Validation API -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
使用 Bean Validation API 时,还需要引入一个提供了具体实现的库,校验才会生效。常用的实现有 Hibernate Validator、Apache BVal 等。
<!-- Hibernate Validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.2.0.Final</version>
</dependency>
原文始发于微信公众号(小新成长之路):@Validated和@Valid
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/238585.html