springboot-验证表单

后端 / 笔记 / 2021-10-17

springboot-验证表单

什么是 hibernate-validator

hibernate-validator是springboot自带的一个数据验证器,需要引入外部依赖。

常见注解

注解作用类型说明
@NotBlank(message=)字符串要求元素为非null,且长度必须大于0
@Email字符串要求元素电子邮箱
@Length(min=,max=)字符串要求元素在指定范围内,min最小,max最大
@NotEmpty字符串要求元素为非空
@NotEmptyPatter字符串在字符串不为空的情况下,是否匹配正则表达式
@DateValidator字符串验证日期格式,是否满足正则表达式
@DateFormatCheckPattern字符串验证日期格式化,是否满足正则表达式,local为手动指定
@CreditCardNumber字符串验证信用卡号码
@Range(min=,max=,message=)数值类型,字符串,字节验证数据是否在合理范围内
@Null任意要求元素必须为null
@NotNull任意要求元素必须不为null
@AssertTrue布尔值要求元素为true
@Min(value)数字要求元素必须为数字,且大于等于最小值
@Max(value)数字要求元素必须为数字,且小于等于最大值
@DecimalMin(value)数字要求元素必须为数字,且大于等于最小值
@DecimalMax(value)数字要求元素必须为数字,且小于等于最大值
@Size(max,min)数字要求元素在一个指定范围内,max最大,min最小
@Digits(integer,fraction)数字要求元素必须是一个数字,且在可接受范围内
@Past日期要求日期必须是一个过去的日期
@Future日期要求日期必须是一个将来的日期
@Pattern(regex=,flag=)正则表达式要求元素内容必须满足正则表达式规则
@ListStringPatternList<String>要求集合中字符串内容满足正则表达式

导入依赖

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

写一个验证逻辑

package com.lu.model;

import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import java.util.Date;

public class UserModel {
    @NotBlank(message = "用户名不可为空")
    @Length(min = 8,max = 32,message = "用户名在8-32位之间")
    private String userName;
    @NotNull(message="年龄不可为空")
    @Range(min = 18, max = 120, message = "请填写合理的人类寿命范围")
    private Integer userAge;
    @NotBlank(message = "邮箱不可为空")
    @Email(message = "请确保填入的是正确的邮箱地址")
    private String userEmail;
    @Past(message = "请确保,你出生在过去")
    private Date userBirth;

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setUserAge(Integer userAge) {
        this.userAge = userAge;
    }

    public void setUserEmail(String userEmail) {
        this.userEmail = userEmail;
    }

    public void setUserBirth(Date userBirth) {
        this.userBirth = userBirth;
    }


    @Override
    public String toString() {
        return "UserModel{" +
                "userName='" + userName + '\'' +
                ", userAge=" + userAge +
                ", userEmail='" + userEmail + '\'' +
                ", userBirth=" + userBirth +
                '}';
    }
}

package com.lu.controller;

import com.lu.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
@RequestMapping("/api/register")
public class RegisterController {
    @Autowired
    private MessageSource messageSource;

    @PostMapping("/validator")
    // JSON请求格式数据校验
    public String validator(@Valid @RequestBody UserModel userModel, BindingResult result) {
        System.out.println(userModel);
        StringBuilder builder = new StringBuilder();
        // 没有错误则直接返回成功
        if (!result.hasErrors()) {
            return "pass: " + userModel.toString();
        }
        // 检查错误
        for (ObjectError allError : result.getAllErrors()) {
            // 获取当前语言的错误
            String message = messageSource.getMessage(allError, LocaleContextHolder.getLocale());
            builder.append(message).append('\n');
        }
        return builder.toString();
    }

}

{
    "userName":"jack",
    "userAge":"-10",
}
邮箱不可为空
用户名在8-32位之间
请填写合理的人类寿命范围

具体实现过程如下

  • 首先定义model
  • 用注解约束model
  • 编写controller
  • @Valid 注解 标注model参数
  • BindingResult 用来接受错误信息
  • MessageSource 用来解析消息

自定义验证功能

虽然springboot的验证功能能满足绝大部分场景需求,但是如果要实现一些非常规验证,我们可以自定义规则。

流程

  • 自定义注解
    • @Constraint 标明验证器类
  • 写一个验证器类 实现 ConstraintValidator接口
    • 第一个参数: 自定义注解类型
    • 第二个参数: 要验证的数据类型
  • 把自定义注解添加到要验证的字段上即可

自定义注解

package com.lu.annotations;

import com.lu.validator.ProvinceConstraintValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 作用在字段上
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ProvinceConstraintValidator.class)
public @interface ProvinceConstraint {
    String message() default "请输入合法的城市名";
    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

需要注意的是,这里 Constraint注解标注对应验证器的类

编写验证器

package com.lu.validator;


import com.lu.annotations.ProvinceConstraint;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class ProvinceConstraintValidator implements ConstraintValidator<ProvinceConstraint, String> {
    @Override
    public void initialize(ProvinceConstraint constraintAnnotation) {
        ConstraintValidator.super.initialize(constraintAnnotation);
    }

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        return s.equals("山西省");
    }
}

第一个参数是验证器注解,第二个参数是要验证的数据类型

使用自定义注解

package com.lu.model;

import com.lu.annotations.ProvinceConstraint;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import java.util.Date;

public class UserModel {
    @NotBlank(message = "用户名不可为空")
    @Length(min = 8,max = 32,message = "用户名在8-32位之间")
    private String userName;
    @NotNull(message="年龄不可为空")
    @Range(min = 18, max = 120, message = "请填写合理的人类寿命范围")
    private Integer userAge;
    @NotBlank(message = "邮箱不可为空")
    @Email(message = "请确保填入的是正确的邮箱地址")
    private String userEmail;
    @Past(message = "请确保,你出生在过去")
    private Date userBirth;
    @ProvinceConstraint(message = "请输入合理的省份")
    private String province;

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setUserAge(Integer userAge) {
        this.userAge = userAge;
    }

    public void setUserEmail(String userEmail) {
        this.userEmail = userEmail;
    }

    public void setUserBirth(Date userBirth) {
        this.userBirth = userBirth;
    }

    public String getUserName() {
        return userName;
    }

    public Integer getUserAge() {
        return userAge;
    }

    public String getUserEmail() {
        return userEmail;
    }

    public Date getUserBirth() {
        return userBirth;
    }

    @Override
    public String toString() {
        return "UserModel{" +
                "userName='" + userName + '\'' +
                ", userAge=" + userAge +
                ", userEmail='" + userEmail + '\'' +
                ", userBirth=" + userBirth +
                '}';
    }
}

编写接口

实现 ConstraintValidator 接口

package com.lu.controller;

import com.lu.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.validation.Valid;

@RestController
@RequestMapping("/api/register")
public class RegisterController {
    @Autowired
    private MessageSource messageSource;
    @PostMapping("/valid")
    // JSON请求格式数据校验
    public String validator(@Valid @RequestBody UserModel userModel, BindingResult result, RedirectAttributes attr) {
        if (result.hasErrors()){
            for (ObjectError allError : result.getAllErrors()) {
                return allError.getDefaultMessage();
            }
        }
        return "success";
    }
}

测试接口

{
    "userName":"luzhenfang",
    "userEmail":"1223@qq.com",
    "userAge":"22",
    "province":"山西"
}
请输入合理的省份