一、项目搭建

1、使用springboot搭建一个web工程

建web工程,不使用骨架创建maven的Java工程即可,不需要创建maven的web工程。

2、添加父工程坐标和添加web启动器

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

查看spring-boot-starter-web依赖,发现web模块默认使用了hibernate-validator:

3、创建启动类

@SpringBootApplication
public class MySpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class);
    }
}

二、对象校验

1、创建实体类Agent

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
public class Agent {
    /**
     * 代理人姓名
     */
    @NotNull(message = "姓名不能为空")
    private String name;
    /**
     * 联系人邮箱
     */
    @NotBlank(message = "邮箱不能为空")
    private String email;
}

注意:一定要加@Data注解,否则无法获取请求体中的值,即使请求体中参数不为空,也会校验失败

注意:如果使用@NotNull,如果是空字符串就不会报错。而用NotBlank,空字符串也会报错。

通过注释名即可推断出校验的内容,message用作校验失败时的提示信息。

2、编写controller

@RestController
public class TestController {
    @PostMapping( "/test")
    public String add(@RequestBody @Validated Agent agent) {
        return "你好";
    }
}

3、使用postman发起请求

结果如下:

{
    "timestamp": "2022-09-07T03:48:12.999+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "NotBlank.agent.email",
                "NotBlank.email",
                "NotBlank.java.lang.String",
                "NotBlank"
            ],
            "arguments": [
                {
                    "codes": [
                        "agent.email",
                        "email"
                    ],
                    "arguments": null,
                    "defaultMessage": "email",
                    "code": "email"
                }
            ],
            "defaultMessage": "邮箱不能为空",
            "objectName": "agent",
            "field": "email",
            "rejectedValue": "",
            "bindingFailure": false,
            "code": "NotBlank"
        }
    ],
    "message": "Validation failed for object='agent'. Error count: 1",
    "path": "/test"
}

三、统一异常处理

1、异常捕获类

经过对校验异常的debug发现,该异常为MethodArgumentNotValidException

import com.zwh.entity.RsData;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;


@ControllerAdvice
@RestController
public class ExceptionHandler {

    private String paramValid = "参数不合法:";

    /**
     * 用来处理validation异常,捕获post请求Body实体属性参数校验异常信息
     *
     * @param ex
     * @return
     */
    @org.springframework.web.bind.annotation.ExceptionHandler(MethodArgumentNotValidException.class)
    public RsData resolveMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        List<ObjectError> objectErrors = ex.getBindingResult().getAllErrors();
        if (!CollectionUtils.isEmpty(objectErrors)) {
            StringJoiner msgJoiner = new StringJoiner(",");
            Set<String> errors = new HashSet<>(objectErrors.size() / 2);
            for (ObjectError objectError : objectErrors) {
                errors.add(objectError.getDefaultMessage());
            }
            for (String error : errors) {
                msgJoiner.add(error);
            }
            String errorMessage = msgJoiner.toString();
            return RsData.fail(paramValid + errorMessage);
        }
        return RsData.fail(paramValid + ex.getMessage());
    }
}

2、返回的响应体类

@Data
public class RsData {

    private static final String SUCCESS = "0";
    private static final String FAIL = "1";

    private String code;

    private Object result;

    private String message;

    public static RsData success(String msg) {
        RsData rs = new RsData();
        rs.setCode(SUCCESS);
        rs.setMessage(msg);
        return rs;
    }

    public static RsData success(String msg, Object result) {
        RsData rs = new RsData();
        rs.setCode(SUCCESS);
        rs.setMessage(msg);
        rs.setResult(result);
        return rs;
    }

    public static RsData error(String msg) {
        RsData rs = new RsData();
        rs.setCode(FAIL);
        rs.setMessage(msg);
        return rs;
    }

    public static RsData error(String msg, Object result) {
        RsData rs = new RsData();
        rs.setCode(FAIL);
        rs.setMessage(msg);
        rs.setResult(result);
        return rs;
    }

    public static RsData fail(String result) {
        RsData rs = new RsData();
        rs.setCode(FAIL);
        rs.setMessage("失败");
        rs.setResult(result);
        return rs;
    }
}

3、修改Controller

@RestController
public class TestController {
    @PostMapping( "/test")
    public RsData add(@RequestBody @Validated Agent agent) {
        return RsData.success("success");
    }
}

4、postman访问

四、对象集合校验

User实体类

@Data
public class User {
    @NotBlank(message = "姓名不能为空")
    private String name;

    @NotBlank(message = "性别不能为空")
    private String sex;
}

ListValidation类

/***
 * 由于Validator只能验证对象合法性,故数组方式需自定义处理,这是方式一
 * 也可直接在controller类上加@Validated注解
 * @param <E>
 */
public class ListValidation<E> implements List<E> {

    @Delegate
    @Valid
    public List<E> list = new ArrayList<>();

    @Override
    public String toString() {
        return list.toString();
    }
}

controller

@RestController
public class Demo1Controller {
    @PostMapping( "/test1")
    public String add(@RequestBody @Validated ListValidation<User> userList) {
        return "你好";
    }
}

修改异常捕获类,添加如下内容

// 将Spring DataBinder配置为使用直接字段访问
    @InitBinder
    private void activateDirectFieldAccess(DataBinder dataBinder) {
        dataBinder.initDirectFieldAccess();
    }

异常捕获类完整代码

@ControllerAdvice
@RestController
public class ExceptionHandler {

    private String paramValid = "参数不合法:";
    // 将Spring DataBinder配置为使用直接字段访问
    @InitBinder
    private void activateDirectFieldAccess(DataBinder dataBinder) {
        dataBinder.initDirectFieldAccess();
    }

    /**
     * 用来处理validation异常,捕获post请求Body实体属性参数校验异常信息
     *
     * @param ex
     * @return
     */
    @org.springframework.web.bind.annotation.ExceptionHandler(MethodArgumentNotValidException.class)
    public RsData resolveMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        List<ObjectError> objectErrors = ex.getBindingResult().getAllErrors();
        if (!CollectionUtils.isEmpty(objectErrors)) {
            StringJoiner msgJoiner = new StringJoiner(",");
            Set<String> errors = new HashSet<>(objectErrors.size() / 2);
            for (ObjectError objectError : objectErrors) {
                errors.add(objectError.getDefaultMessage());
            }
            for (String error : errors) {
                msgJoiner.add(error);
            }
            String errorMessage = msgJoiner.toString();
            return RsData.fail(paramValid + errorMessage);
        }
        return RsData.fail(paramValid + ex.getMessage());
    }
}
View Code

启动项目,postman请求

@Valid可以用在方法、构造函数、方法参数和成员属性(字段)上,支持嵌套检测。@Validated可以用在类型、方法和方法参数上,但是不能用在成员属性(字段)上,不支持嵌套检测。

五、分组校验

当我们遇到不同场景需要有不同的校验规则时候,我们可以使用分组校验。如:一个请求只校验姓名,一个请求只校验email

1、创建分组接口

名称自定义,也不需要实现,只是能做区分分组就行

FirstGroup.class

public interface FirstGroup {
}

SecondGroup.class

public interface SecondGroup {
}

2、实体类中使用分组

import javax.validation.constraints.NotBlank;
@Data
public class Agent {
    /**
     * 代理人姓名
     */
    @NotBlank(message = "姓名不能为空",groups = SecondGroup.class)
    private String name;
    /**
     * 联系人邮箱
     */
    @NotBlank(message = "邮箱不能为空",groups = FirstGroup.class)
    private String email;

}

注意:如果将email划入FirstGroup,将name划到SecondGroup,而@Validated注解不指定分组(默认为Default),

@RestController
public class TestController {
    @PostMapping( "/test")
    public RsData add(@RequestBody @Validated Agent agent) {
        return RsData.success("success");
    }
}

此时由于Default分组没有要校验的属性,相当于不校验,结果如下:

{
    "code": "0",
    "result": null,
    "message": "success"
}

3、修改controller

(1)、当指定FirstGroup时:

@RestController
public class TestController {
    @PostMapping( "/test")
    public RsData add(@RequestBody @Validated(FirstGroup.class) Agent agent) {
        return RsData.success("success");
    }
}

结果如下:

{
    "code": "1",
    "result": "参数不合法:邮箱不能为空",
    "message": "失败"
}

(2)、当指定SecondGroup时

@RestController
public class TestController {
    @PostMapping( "/test")
    public RsData add(@RequestBody @Validated(SecondGroup.class) Agent agent) {
        return RsData.success("success");
    }
}

结果如下:

{
    "code": "1",
    "result": "参数不合法:姓名不能为空",
    "message": "失败"
}

(3)、当不指定分组时

当然不写时会有一个默认分组,所有不指定分组的属性都划到这个分组

实体类:

@Data
public class Agent {
    /**
     * 代理人姓名
     */
    @NotBlank(message = "姓名不能为空")
    private String name;
    /**
     * 联系人邮箱
     */
    @NotBlank(message = "邮箱不能为空")
    private String email;

}

controller

@RestController
public class TestController {
    @PostMapping( "/test")
    public RsData add(@RequestBody @Validated Agent agent) {
        return RsData.success("success");
    }
}

测试

{
    "code": "1",
    "result": "参数不合法:邮箱不能为空,姓名不能为空",
    "message": "失败"
}

修改实体类:

import javax.validation.constraints.NotBlank;
import javax.validation.groups.Default;

@Data
public class Agent {
    /**
     * 代理人姓名
     */
    @NotBlank(message = "姓名不能为空",groups = Default.class)
    private String name;
    /**
     * 联系人邮箱
     */
    @NotBlank(message = "邮箱不能为空",groups = Default.class)
    private String email;

}

修改controller

@RestController
public class TestController {
    @PostMapping( "/test")
    public RsData add(@RequestBody @Validated(Default.class) Agent agent) {
        return RsData.success("success");
    }
}

结果:

{
    "code": "1",
    "result": "参数不合法:邮箱不能为空,姓名不能为空",
    "message": "失败"
}

六、级联校验

使用Valid注解实现级联校验

新建Address实体类

@Data
public class Address {
    @NotBlank(message = "省不能为空")
    private String province;
    @NotBlank(message = "市不能为空")
    private String city;
    @NotBlank(message = "区不能为空")
    private String region;
}

修改Agent实体类

import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;

@Data
public class Agent {
    /**
     * 代理人姓名
     */
    @NotBlank(message = "姓名不能为空")
    private String name;
    /**
     * 联系人邮箱
     */
    @NotBlank(message = "邮箱不能为空")
    private String email;

    @Valid
    @NotNull(message = "地址不能为空")
    private List<Address> addressList;
}

controller

@RestController
public class TestController {
    @PostMapping( "/test")
    public RsData add(@RequestBody @Validated Agent agent) {
        return RsData.success("success");
    }
}

测试

七、JSR提供的校验注解API

注意:@NotEmpty 校验集合;@NotBlank 校验String类型;@NotNull 校验基本类型。

@Null   被注释的元素必须为 null    
@NotNull    被注释的元素必须不为 null    
@AssertTrue     被注释的元素必须为 true    
@AssertFalse    被注释的元素必须为 false    
@Min(value)     被注释的元素必须是一个数字,其值必须大于等于指定的最小值    
@Max(value)     被注释的元素必须是一个数字,其值必须小于等于指定的最大值    
@DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值    
@DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值    
@Size(max=, min=)   被注释的元素的大小必须在指定的范围内    
@Digits (integer, fraction)     被注释的元素必须是一个数字,其值必须在可接受的范围内    
@Past   被注释的元素必须是一个过去的日期    
@Future     被注释的元素必须是一个将来的日期    
@Pattern(regex=,flag=)  被注释的元素必须符合指定的正则表达式

Hibernate Validator提供的校验注解

@NotBlank(message =)   验证字符串非null,且长度必须大于0    
@Email  被注释的元素必须是电子邮箱地址    
@Length(min=,max=)  被注释的字符串的大小必须在指定的范围内    
@NotEmpty   被注释的字符串的必须非空    
@Range(min=,max=,message=)  被注释的元素必须在合适的范围内

正则校验

  1 匹配首尾空格的正则表达式:(^\s*)|(\s*$)
  2 整数或者小数:^[0-9]+\.{0,1}[0-9]{0,2}$
  3 只能输入数字:"^[0-9]*$"4 只能输入n位的数字:"^\d{n}$"5 只能输入至少n位的数字:"^\d{n,}$"6 只能输入m~n位的数字:。"^\d{m,n}$"
  7 只能输入零和非零开头的数字:"^(0|[1-9][0-9]*)$"8 只能输入有两位小数的正实数:"^[0-9]+(.[0-9]{2})?$"9 只能输入有1~3位小数的正实数:"^[0-9]+(.[0-9]{1,3})?$"10 只能输入非零的正整数:"^\+?[1-9][0-9]*$"11 只能输入非零的负整数:"^\-[1-9][]0-9"*$。
 12 只能输入长度为3的字符:"^.{3}$"13 只能输入由26个英文字母组成的字符串:"^[A-Za-z]+$"14 只能输入由26个大写英文字母组成的字符串:"^[A-Z]+$"15 只能输入由26个小写英文字母组成的字符串:"^[a-z]+$"16 只能输入由数字和26个英文字母组成的字符串:"^[A-Za-z0-9]+$"17 只能输入由数字、26个英文字母或者下划线组成的字符串:"^\w+$"18 验证用户密码:"^[a-zA-Z]\w{5,17}$"正确格式为:以字母开头,长度在6~18之间,只能包含字符、数字和下划线。
 19 验证是否含有^%&',;=?$\"等字符:"[^%&',;=?$\x22]+"
 20 只能输入汉字:"^[\u4e00-\u9fa5]{0,}$"
 21 验证Email地址:"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"22 验证InternetURL:"^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$"23 验证电话号码:"^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$"正确格式为:"XXX-XXXXXXX""XXXX-XXXXXXXX""XXX-XXXXXXX""XXX-XXXXXXXX""XXXXXXX""XXXXXXXX"24 验证身份证号(15位或18位数字):"^\d{15}|\d{18}$"25 验证一年的12个月:"^(0?[1-9]|1[0-2])$"正确格式为:"01""09""1""12"26 验证一个月的31天:"^((0?[1-9])|((1|2)[0-9])|30|31)$"正确格式为;"01""09""1""31"27 匹配中文字符的正则表达式: [\u4e00-\u9fa5]
 28 匹配双字节字符(包括汉字在内):[^\x00-\xff]
 29 应用:计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)
 30 String.prototype.len=function(){return this.replace(/[^\x00-\xff]/g,"aa").length;}
 31 匹配空行的正则表达式:\n[\s| ]*\r
 32 匹配html标签的正则表达式:<(.*)>(.*)<\/(.*)>|<(.*)\/>
 33 仅允许输入1或2:^[12]$                                                                                                               34 大于0的正整数:^[1-9][0-9]*$
 35 大于1的正整数:^(([1-9]\d+)|([2-9]))$

校验日期格式:

(1)、日期格式:yyyy-MM-dd

@NotNull(message = "生产日期不为空")
    @Pattern(regexp = "^(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)$",message = "日期格式不正确!")
    private String produceDate;

(2)、日期格式:yyyy-MM-dd HH:mm:ss

public class demo {
    public static void main(String[] args) {
        String timeRegex = "^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))\\s+([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$";
        boolean flag = Pattern.matches(timeRegex, "2012-12-31 12:07:59");
        System.out.println(flag);
    }
}

结果为true

(3)、日期格式:yyyy/MM/dd

public class demo {
    public static void main(String[] args) {
        String timeRegex2 = "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})\\/(((0[13578]|1[02])\\/(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)\\/(0[1-9]|[12][0-9]|30))|(02\\/(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))\\/02\\/29)$";
        System.out.println(Pattern.matches(timeRegex2,"2018/12/31"));
    }
}

结果为true

(4)、日期格式:yyyy/MM/dd HH:mm:ss

public class demo {
    public static void main(String[] args) {
        String timeRegex3 = "^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})\\/(((0[13578]|1[02])\\/(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)\\/(0[1-9]|[12][0-9]|30))|(02\\/(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))\\/02\\/29))\\s([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$";
        System.out.println(Pattern.matches(timeRegex3,"2018/12/30 12:29:59"));
    }
}

结果为true

日期格式校验参考文档:https://blog.csdn.net/xingxiupaioxue/article/details/105998503

八、自定义校验器

案例一

1、自定义校验注解

import com.zwh.config.ListRangeValidatorForString;

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

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * 当前值必须在给定的列表中
 */
@Target({FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {ListRangeValidatorForString.class})
public @interface ListRange {

    String message() default "";

    Class<?>[] groups() default {};

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

    String[] value() default {};
}

2、校验器

import com.zwh.anno.ListRange;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.Objects;

public class ListRangeValidatorForString implements ConstraintValidator<ListRange, String> {

    private String[] range;

    @Override
    public void initialize(ListRange listRange) {
        this.range = listRange.value();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (Objects.isNull(value)) {
            return true;
        }
        return Arrays.asList(range).contains(value);
    }
}

3、使用注解:

@Data
public class Agent {
    /**
     * 代理人姓名
     */
    @NotBlank(message = "姓名不能为空")
    private String name;
    /**
     * 联系人邮箱
     */
    @NotBlank(message = "邮箱不能为空")
    private String email;

    @Valid
    @NotNull(message = "地址不能为空")
    private List<Address> addressList;

    @NotBlank(message = "性别不能为空")
    @ListRange(value = {"male", "female"}, message = "性别必须在[male,female]之间")
    private String gender;
}

4、测试

案例二:日期格式校验

1、自定义校验注解

@IsDate注解

/**
 * 日期类型校验
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {IsDateValidator.class}) // 指定自定义的校验器
public @interface IsDate {

    // 提示信息
    String message() default "日期格式不正确";
    String dateType() default "yyyy-MM-dd hh:mm:ss";
    // 不加这俩参数 error msg: contains Constraint annotation, but does not contain a groups parameter.
    // 必须包含这两个参数
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

@IsDatetime注解

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {IsDateTimeValidator.class}) // 指定自定义的校验器
public @interface IsDatetime {

    // 提示信息
    String message() default "日期格式不正确";
    String dateType() default "yyyy-MM-dd HH:mm:ss";
    // 不加这俩参数 error msg: contains Constraint annotation, but does not contain a groups parameter.
    // 必须包含这两个参数
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

2、校验器

IsDateValidator

import com.ljxx.common.util.DateUtil;

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

/**
 * 日期类型校验器
 */
public class IsDateValidator implements ConstraintValidator<IsDate, String> {

    private String dateType;
    
    @Override
    public void initialize(IsDate obj) {
        dateType = obj.dateType();
    }

    /**
     * 通过该方法,对参数进行验证,看是否通过。
     * @param value   修饰字段的值。
     * @param context 上下文
     * @return true:验证通过。 false:验证不通过。
     */
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return DateUtil.isvalidDate(value,dateType);
    }
}

IsDatetimeValidator

import com.ljxx.common.util.DateUtil;
import org.apache.commons.lang3.StringUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class IsDateTimeValidator implements ConstraintValidator<IsDatetime, String> {

    private String dateType;

    @Override
    public void initialize(IsDatetime obj) {
        dateType = obj.dateType();
    }

    /**
     * 通过该方法,对参数进行验证,看是否通过。
     *
     * @param value   修饰字段的值。
     * @param context 上下文
     * @return true:验证通过。 false:验证不通过。
     */
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if(StringUtils.isNotEmpty(value)){
            return DateUtil.isvalidDate(value,dateType);
        }
        return true;
    }
}

3、使用注解:

@IsDatetime(message = "开始时间格式不正确")
@NotBlank(message = "开始时间不能为空")
private String beginTime;
//过期时间
@IsDate(message = "过期时间格式不正确", dateType = "yyyy-MM-dd")
private String expireDate;

案例三:校验值是否在数据字典中

1、自定义校验注解

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

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * 当前值必须在给定的列表中
 */
@Target({FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {DictTypeRangeValidatorForString.class})
public @interface DictTypeRange {
    String message() default "";

    String[] value() default {};

    Class<?>[] groups() default {};

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

2、校验器

import com.ljxx.client.DictServiceClient;
import com.ljxx.model.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.*;

public class DictTypeRangeValidatorForString implements ConstraintValidator<DictTypeRange, String> {
//    private String[] range;
    private String[] dictCodes;
    @Autowired
    private DictServiceClient dictServiceClient;

    @Override
    public void initialize(DictTypeRange dictTypeRange) {
        this.dictCodes = dictTypeRange.value();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
        if (Objects.isNull(value)) {
            return true;
        }
        // 先查询数据字典获取所有的出库类型
        List<String> dictCodeList = Arrays.asList(this.dictCodes);
        if (CollectionUtils.isEmpty(dictCodeList)) {
            return false;
        }
        Result result1 = dictServiceClient.queryDictByDictTypeCode(dictCodeList.get(0));
        List<Map> list1 = (List<Map>) result1.getData();
        List<String> dictTypeList = new ArrayList<>(); //局部变量:随着方法的调用而存在,随着方法的调用完毕而消失。
        list1.forEach(map -> {
            String dictCode = (String) map.get("dictCode");
            dictTypeList.add(dictCode);

        });
        return dictTypeList.contains(value);
    }
}

3、使用注解:

@NotBlank(message = "出库单据类型编码不能为空")
@DictTypeRange(value = {"OUTSTORE_TYPE"},message = "出库类型错误")
private String orderType;

案例四:validator校验List集合的合法性

import lombok.experimental.Delegate;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;

/***
 * 由于Validator只能验证对象合法性,故数组方式需自定义处理,这是方式一
 * 也可直接在controller类上加@Validated注解
 * @param <E>
 */
public class ValidationList<E> implements List<E> {

    @Delegate
    @Valid
    public List<E> list = new ArrayList<>();

    @Override
    public String toString() {
        return list.toString();
    }
}

Controller

@PostMapping("/xxxxxx")
    @ResponseBody
    public Result2 push(@RequestBody @Validated ValidationList<CtsProPushVO> ctsProPushVOS, HttpServletRequest request) {
        return regService.push(ctsProPushVOS,request);
    }

注意:ctsProPushVOS为List<CtsProPushVO>。

CtsProPushVOS

@Data
public class CtsProPushVO {
    @NotBlank(message = "编码不能为空")
    private String code;
    @NotBlank(message = "是否监管不能为空")
    @ListRange(value = {"1", "0"}, message = "是否监管的值必须为0或1")
    private String monitor;

}

 

posted on 2022-09-07 12:31  周文豪  阅读(391)  评论(0编辑  收藏  举报