参数实体,规范化+校验

本文详细介绍了Java后端参数实体的验证,包括时间类型的处理、嵌套实体的校验、自定义验证注解的创建与应用、正则表达式校验以及@Valid和@Validated的区别。此外,还探讨了校验信息的返回和异常处理策略。
摘要由CSDN通过智能技术生成

目录

引入

用法

常用的注解校验

时间类型

嵌套实体

自定义验证注解

正则校验

校验字段顺序

@Valid和@Validated区别

分组

作用地方

来源

关于验证信息的返回,异常处理


引入

 <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
</dependency>
 
<dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
</dependency>

用法

两方面:controller加注解@Validated或@Valid【加哪个由内部注解的包决定】,配合DTO中的属性注解实现

//controller
public class controller{
    //controller中,方法参数前面要加注解
    public void edit(@Validated DTO dto){
    
    }
}
//实体类
public class DTO{
    @NotNull(message="id不能为null")
    private Integer id;
}

常用的注解校验

@NotBlank(message = "XX不能为空")
@Email(message="邮箱填写不规范")

时间类型

①后端向前端返回的值规范

@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
 //规范时间格式,时区采用北京东八区,默认的标准时区少8个小时

②前端向后端传入的值规范【注:只能用于url拼接的参数,放在实体中并没作用】

请求URL : http://localhost:9999/put?date=2020-03-07 13:13:13

@PostMapping("put")
public User put(@DateTimeFormat(pattern = "yyyy-MM-dd HH") @RequestParam Date  date){
System.out.println(date); // Sat Mar 07 13:00:00 CST 2020  // 可以看到分和秒都被忽略了。
}

嵌套实体

//实体类
public class DTO{
    @Valid
    @Size(min=1,message="至少要有一个")
    private List<AreaDTO> areaDTOList;
}

//内部嵌套类
publica class AreaDTO{
    @NotBlank(message="不能为空")
    private String code;
}

注:内部实体中要加@Valid的注解,实体内部的注解才能生效

自定义验证注解

以上的验证注解可能不够用,所以有了自定义验证注解。下面我们以枚举为例,不过最好不要用枚举类入参,因为不太好校验准确性;可以使用枚举类中的某个属性作为参数入参,配合自定义注解和实现。

①最终定义

public class DTO{   
  //枚举参数
  @EnumVaildator(clazz= myEnum.class, message="枚举值不存在",method="getCode")
  private Integer areaEnum;
}

②创建自定义验证注解

自定义验证注解:定义方法

@Constraint注解配合自定义验证注解,是此注解的实现方法类。内部是去找指定枚举中的指定字段,遍历查询跟入参字段对比是否存在

实现类和验证注解的定义可分成两个文件实现,下图是一个文件实现的

package com.hyj.annotation;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author huyujie
 * 枚举值入参检验注解
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = EnumValidator.EnumValidatorClass.class)
public @interface EnumValidator {
    String message() default "入参值不在正确枚举中";

    Class<?>[] groups() default {}; //这个方法要加上,不然会抛异常

    Class<? extends Payload>[] payload() default {}; //这个方法要加上,不然会抛异常

    Class<?> clazz(); //验证枚举类型

    String method(); //验证枚举类方法

    class EnumValidatorClass implements ConstraintValidator<EnumValidator, Object> {
        private final List<Object> values = new ArrayList<>();

        @Override
        public void initialize(EnumValidator enumValidator) {
            Class<?> clz = enumValidator.clazz();
            Object[] objects = clz.getEnumConstants();
            try {
                Method method = clz.getMethod(enumValidator.method());
                for (Object obj : objects) {
                    values.add(method.invoke(obj));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
            return Objects.isNull(value) || values.contains(value);
        }
    }
}

正则校验

 @NotBlank
    @Pattern(regexp = "[a-zA-Z0-9]", message = "只允许输入数字和字母")
    private String strValue;

校验字段顺序

①字段上存在多个注解时,是按注解从上至下的顺序进行校验的

②@GroupSequence使用在group接口上。如下update方法,先校验group属于id.class的字段

其次是strValue

public interface TestValidGroup {

    @GroupSequence(value = {StrValue.class})
    interface Insert {

    }

    @GroupSequence(value = {Id.class, StrValue.class})
    interface Update {

    }

    interface Id {

    }

    interface StrValue {

    }
}

此时controller是这样用,跟之前不一样

//正确用法
@NotBlank(message = "ID不能为空", groups = {TestValidGroup.Id.class})
private String id;

//错误用法
@NotBlank(message = "ID不能为空", groups = {TestValidGroup.Update.class})
private String id;

下面说点干货:

@Valid和@Validated区别

分组

@Validated有分组,可以根据不同的分组用不同的机制

换句话说,增、改、查,可以定义一套DTO通过控制注解来实现参数校验

//controller
public class controller{
    public void save(@Validated({TestValidGroup.Insert.class}) DTO dto){}

    public void edit(@Validated({TestValidGroup.Update.class}) DTO dto){}
}
//实体类
public class DTO{
    @NotNull(message="id不能为空",groups={Update.class})
    private Ingeter id;
}
//建个空的就行
public interface TestValidGroup {

    interface Insert {

    }

    interface Update {

    }
}

作用地方

@Validated作用于:类型、方法、方法参数

@Valid作用于:方法、构造函数、方法参数、成员属性字段

所以,嵌套类的类内部注解实现,必须只能在嵌套类上加注解@Valid,而不是另外一个

来源

@Validated是Spring Validator提供的校验机制

@Valid是 Hibernate validation提供,需要引入下面的pom

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

关于验证信息的返回,异常处理

/**
 * 全局异常处理
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 参数校验全局异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handlerValidator(MethodArgumentNotValidException e) {
        BindingResult result = e.getBindingResult();
        List<ObjectError> allErrors = result.getAllErrors();
        return Result.myError(allErrors);
    }
}

@ExceptionHandler:用于指定异常处理方法。当与@RestControllerAdvice配合使用时,用于全局处理控制器里的异常;RestControllerAdvice = ControllerAdvice + ResponseBody

@Valid和@Validated详解 - 浪迹天涯的派大星 - 博客园在实际的项目开发中,经常会遇到对参数进行校验的场景,最常见的就是后端需要对前端传过来的数据进行校验。 我理解的数据校验大致分为两类: 一类是对数据本身进行校验,不涉及与数据库交互的,比如正则校验、非空https://www.cnblogs.com/zhaodalei/p/16377549.html#go8它写的很全

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值