优雅的使用Validated

本文详细介绍了Spring Boot中@Validated和@Valid的使用,包括简单的参数校验、分组校验和嵌套校验。通过示例展示了如何实现商品接口的参数验证,异常处理以及自定义注解的创建。同时,提到了正则表达式和特殊校验场景的应用,帮助开发者更好地理解和应用数据校验。
摘要由CSDN通过智能技术生成

前言

@Validation是一套帮助我们继续对传输的参数进行数据校验的注解,通过配置Validation可以很轻松的完成对数据的约束。
这个技术一直都想进行梳理了很多复杂校验不会使用,本章节用来进行梳理
validated 用于参数的校验,支持简单和复杂(分组/嵌套)校验

@Validated / @Valid 的区别

功能
	@validated 提供了分组能力而@Valid没有
位置
	@Valid作用于 方法\构造方法\方法参数\成员属性
	@Validdated作用于  类\方法\方法参数

注意事项

可能不生效的几个原因:
	1. @validate 默认将所有校验加入到了Default组中,如果指定了自定义组将不会校验Default组中的校验,如果需要校验默认组需要加上Default组,面对复杂的校验很有可能会搞混
	2. 如果需要使用分组,那么定义分组类型需要是接口类型,否则会报错~~
	3. 如果使用了正则校验查看 正则是否正确
	

注解

在这里插入图片描述

逻辑图

Validatad 工作机制描述
调用者发送请求后端 -> Validatad拦截器将请求体进行拦截后校验 
	-> 校验成功 -> 通过
	-> 校验失败 -> 抛出异常  -> 对异常进行处理(通过@RestControllerAdvice + @ExceptionHandler 注解进行异常处理)

在这里插入图片描述

依赖

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

校验

目前有关于商品的接口需要进行校验

异常的处理

import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.List;

@RestControllerAdvice
public class MyControllerAdvice {
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public String exceptionHandler(MethodArgumentNotValidException exception) {
        BindingResult result = exception.getBindingResult();
        StringBuilder stringBuilder = new StringBuilder();
        if (result.hasErrors()) {
            List<ObjectError> errors = result.getAllErrors();
            if (errors != null) {
                errors.forEach(p -> {
                    FieldError fieldError = (FieldError) p;
                    stringBuilder.append(fieldError.getDefaultMessage());
                });
            }
        }
        return stringBuilder.toString();
    }
}

简单校验

目前商品添加了一个新增接口需要进行校验
校验内容:
	商品的名称不能为空
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;

@Data
@Accessors(chain = true)
public class MyTestDTO {
    @NotEmpty(message = "产品名称不能为空")
    private String product;
}
@RestController
@RequestMapping("api")
public class MyController {
    @PostMapping("addProduct")
    public MyTestDTO addProduct(@RequestBody @Validated MyTestDTO myTestDTO) {
        return myTestDTO;
    }
}

在这里插入图片描述

分组校验

分组: 如果在Controller中设置了分组,那么校验的时候只会走对应的分组拦截器,默认没有分组的校验都在javax.validation.groups.Default.class组中

目前关于商品又增加了一个删除的接口原限制不变
	新增接口:
		产品名称不能为空
	修改接口:
		产品名称长度不能超过10位
//定义分组接口
public interface Group1 { //新增商品的分组
}
public interface Group2 { //修改商品的分组
}
import com.chen.advice.Group1;
import com.chen.advice.Group2;
import com.chen.pojo.MyTestDTO;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("api")
public class MyController {
    @PostMapping("addProduct")
    public MyTestDTO addProduct(@RequestBody @Validated(Group1.class) MyTestDTO myTestDTO) {
        return myTestDTO;
    }

    @PutMapping("putProduct")
    public MyTestDTO putProduct(@RequestBody @Validated(Group2.class) MyTestDTO myTestDTO) {
        return myTestDTO;
    }

}
import com.chen.advice.Group1;
import com.chen.advice.Group2;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;

@Data
@Accessors(chain = true)
public class MyTestDTO {
    @NotEmpty(message = "产品名称不能为空",groups = Group1.class)
    @Size(max = 10,message = "产品名称长度不能超过10位",groups = Group2.class)
    private String product;
}

在这里插入图片描述
在这里插入图片描述

嵌套校验

	注意事项:
		嵌套校验:  对象中的对象属性需要加上@valid的注解
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Data
@Accessors(chain = true)
public class MyTestDTO {
    @Size(max = 10,message = "产品名称长度不能超过10位")
    private String product;

    @Valid
    @NotNull(message = "医疗实体类不能为null")
    private YiLiaoDTO yiLiaoDTO;
}
import lombok.Data;
import javax.validation.constraints.Positive;

@Data
public class YiLiaoDTO {
    @Positive(message = "产品数量必须为正整数")
    private Integer count;

}
import com.chen.pojo.MyTestDTO;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("api")
public class MyController {
    @PostMapping("addProduct")
    public MyTestDTO addProduct(@RequestBody @Validated MyTestDTO myTestDTO) {
        return myTestDTO;
    }
}

在这里插入图片描述

注解的尝试

自定义注解校验

注解类 -- 模仿自带的注解类进行编写
@Constraint(validateBy = 指定配置类)
@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MyValidCheck.class)
public @interface MyValid {
    int min() default  0;
    String message() default "{javax.validation.constraints.Size.message}";

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

    Class<? extends Payload>[] payload() default {};
}
配置类
initalize() 初始化方法用于获取注解设置的值
isValid() 判断是否通过校验
import com.example.demo.annotation.MyValid;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class MyValidCheck implements ConstraintValidator<MyValid,Object> {
    int min ;
    @Override
    public void initialize(MyValid constraintAnnotation) {
         min = constraintAnnotation.min();
    }
    @Override
    public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
        if (o != null && o.toString().length() <= min) {
            return true;
        }
        return false;
    }
}
Controller类
@RestController
@RequestMapping("api")
public class MyController {
    @PostMapping("addProduct")
    public MyTestDTO addProduct(@RequestBody @Validated MyTestDTO myTestDTO) {
        return myTestDTO;
    }
}
import com.example.demo.annotation.MyValid;
import lombok.Data;

@Data
public class MyTestDTO {
    private String id;
    private String product;
    @MyValid(min =  10,message = "你小子不按规则走呀,输入10位以内")
    private Integer size;
}

正则校验

@Pattern(regexp = "^[A-Za-z0-9]+$",message = "不符合正则规定了哦小伙子")
private String name;

特殊校验

校验List<对象>
// 自行封装一个 List 没有经过尝试
@***Mapping("/**")
public *** apiName(@RequestBody @Validated(Add.class) ValidList<Bean> aObject)
package com.analog.greatbolderserver.config.valid;
 
import lombok.Data;
import lombok.NoArgsConstructor;
 
import javax.validation.Valid;
import java.util.*;
 
/**
 * @ClassName ValidList
 * @Description ValidList
 * @Author TY
 * @Date 2020/8/26 16:05
 * @Version 1.0
 **/
@Data
@NoArgsConstructor
public class ValidList<E> implements List<E> {
 
    @Valid
    private List<E> list = new LinkedList<>();
 
    public ValidList(List<E> paramList) {
        this.list = paramList;
    }
 
    @Override
    public int size() {
        return list.size();
    }
 
    @Override
    public boolean isEmpty() {
        return list.isEmpty();
    }
 
    @Override
    public boolean contains(Object o) {
        return list.contains(0);
    }
 
    @Override
    public Iterator<E> iterator() {
        return list.iterator();
    }
 
    @Override
    public Object[] toArray() {
        return list.toArray();
    }
 
    @Override
    public <T> T[] toArray(T[] a) {
        return list.toArray(a);
    }
 
    @Override
    public boolean add(E e) {
        return list.add(e);
    }
 
    @Override
    public boolean remove(Object o) {
        return list.remove(o);
    }
 
    @Override
    public boolean containsAll(Collection<?> c) {
        return list.containsAll(c);
    }
 
    @Override
    public boolean addAll(Collection<? extends E> c) {
        return list.addAll(c);
    }
 
    @Override
    public boolean addAll(int index, Collection<? extends E> c) {
        return list.addAll(index, c);
    }
 
    @Override
    public boolean removeAll(Collection<?> c) {
        return list.removeAll(c);
    }
 
    @Override
    public boolean retainAll(Collection<?> c) {
        return list.retainAll(c);
    }
 
    @Override
    public void clear() {
        list.clear();
    }
 
    @Override
    public E get(int index) {
        return list.get(index);
    }
 
    @Override
    public E set(int index, E element) {
        return list.set(index, element);
    }
 
    @Override
    public void add(int index, E element) {
        list.add(index, element);
    }
 
    @Override
    public E remove(int index) {
        return list.remove(index);
    }
 
    @Override
    public int indexOf(Object o) {
        return list.indexOf(o);
    }
 
    @Override
    public int lastIndexOf(Object o) {
        return list.lastIndexOf(o);
    }
 
    @Override
    public ListIterator<E> listIterator() {
        return list.listIterator();
    }
 
    @Override
    public ListIterator<E> listIterator(int index) {
        return list.listIterator(index);
    }
 
    @Override
    public List<E> subList(int fromIndex, int toIndex) {
        return list.subList(fromIndex, toIndex);
    }
}
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Validated是一个注解,用于参数的校验。它提供了分组的能力,可以对数据进行简单和复杂的校验,包括嵌套校验。@Validated可以作用于类、方法和方法参数。与之相比,@Valid注解只能作用于方法、构造方法、方法参数和成员属性。 Validated的工作机制是在调用者发送请求后被拦截,拦截器将请求体进行校验。如果校验成功,则通过,否则抛出异常。对于校验失败的情况,可以通过@RestControllerAdvice和@ExceptionHandler注解进行异常处理。 在上面的示例中,@Validated注解被用于MyTestDTO类,用来校验对象中的对象属性。具体来说,@Valid注解被用于YiLiaoDTO对象,用来校验产品数量必须为正整数。另外,@Size注解被用于product属性,用来校验产品名称长度不能超过10位。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span> #### 引用[.reference_title] - *1* *2* *3* [优雅使用Validated](https://blog.csdn.net/qq_41149775/article/details/126172137)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *4* [DateUtil.java](https://download.csdn.net/download/macy0122/9971035)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值