开发过程中,后台的参数校验是必不可少的,本文关于 spring-boot-starter-validation
的学习笔记。
1 背景
开发过程中,后台的参数校验是必不可少的,本文关于 spring-boot-starter-validation
的学习笔记
2 示例
2.1 如何在pom.xml中引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.littlefxc</groupId> <artifactId>personal</artifactId> <version>1.0-snapshot</version> <packaging>jar</packaging>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties>
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.16.RELEASE</version> </parent>
<dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> </dependencies>
<repositories> <repository> <id>central</id> <name>central</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <layout>default</layout> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> </project>
|
2.2 Hibernate Validator 常用注解

2.3 创建自定义校验器
2.3.1 创建自定义注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.littlefxc.examples.validation; import javax.validation.Constraint; import javax.validation.Payload; import javax.validation.ReportAsSingleViolation; import javax.validation.constraints.Pattern; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Documented @Constraint(validatedBy = { }) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RUNTIME) @ReportAsSingleViolation@Pattern(regexp = "") public @interface IsPhone {
String message() default "{login.phone.invalid}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
|
2.3.2 实现ConstraintValidator
仅仅创建注解是没有任何意义的,必须与ConstraintValidator这个接口配合,才能使自定义注解生效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package com.littlefxc.examples.validation; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.util.regex.Pattern;
public class IsPhoneConstraintValidator implements ConstraintValidator<IsPhone, String> {
private Pattern pattern = Pattern.compile("^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$");
@Override public void initialize(IsPhone constraintAnnotation) { }
@Override public boolean isValid(String value, ConstraintValidatorContext context) { if (value == null || value.length() == 0) { return true; } return pattern.matcher(value).matches(); } }
|
2.3.3 组合验证:创建两个接口表示添加时和编辑时
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.littlefxc.examples.validation;
public interface ValidatorAdd { }
package com.littlefxc.examples.validation;
public interface ValidatorEdit { }
|
2.3.4 定义错误信息
Spring Boot Validation约定错误信息放在resources文件夹下的ValidationMessages.properties。
文件中key代表的是校验框架注解中的message属性。
1 2 3 4 5 6
| login.id.NotNull=id不能为空 login.username.NotBlank=用户名不能为空 login.username.Email=用户名必须是邮箱账号 login.password.NotBlank=密码不能为空 login.password.Length=密码长度至少为6位 login.phone.invalid="手机号格式不合法"
|
2.3.5 创建实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| package com.littlefxc.examples.model; import com.littlefxc.examples.validation.IsPhone; import com.littlefxc.examples.validation.ValidatorAdd; import com.littlefxc.examples.validation.ValidatorEdit; import lombok.Data; import org.hibernate.validator.constraints.Email; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotBlank; import javax.validation.constraints.NotNull;
@Datapublic class LoginVo {
@NotNull(message = "{login.id.NotNull}", groups = {ValidatorEdit.class}) private String id;
@NotBlank(message = "{login.username.NotBlank}", groups = {ValidatorAdd.class}) @Email(message = "{login.username.Email}", groups = {ValidatorAdd.class, ValidatorEdit.class}) private String username;
@NotBlank(message = "{login.password.NotBlank}", groups = {ValidatorAdd.class}) @Length(min = 6, message = "{login.password.Length}", groups = {ValidatorAdd.class, ValidatorEdit.class}) private String password;
@IsPhone(groups = {ValidatorAdd.class, ValidatorEdit.class}) private String phone; }
|
2.3.6 定义控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| package com.littlefxc.examples.controller; import com.littlefxc.examples.model.LoginVo; import com.littlefxc.examples.validation.ValidatorAdd; import com.littlefxc.examples.validation.ValidatorEdit; import org.springframework.validation.BindException; import org.springframework.validation.FieldError; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.UUID;
@RestControllerpublic class ValidatorController {
private static final HashMap<String, LoginVo> map = new HashMap<>();
@RequestMapping(value = "/save") public String save(@Validated({ValidatorAdd.class}) LoginVo loginVo) { loginVo.setId(UUID.randomUUID().toString().replace("-", "")); map.put(loginVo.getId(), loginVo); return "添加通过:" + loginVo.toString(); }
@RequestMapping(value = "/edit") public String edit(@Validated({ValidatorEdit.class}) LoginVo loginVo) { map.replace(loginVo.getId(), map.get(loginVo.getId()), loginVo); return "编辑通过:" + loginVo.toString(); }
@RequestMapping(value = "/list") public HashMap<String, LoginVo> edit() { return map; }
@ExceptionHandler(BindException.class) public String handleBindException(BindException ex) { StringBuilder sb = new StringBuilder(); for (FieldError fieldError : ex.getFieldErrors()) { sb.append(fieldError.getField()) .append(": ") hexo.append(fieldError.getDefaultMessage()) hexo.append(";"); } return "验证失败:" + sb.toString(); } }
|