IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> springboot+validation参数校验浅入浅出 -> 正文阅读

[Java知识库]springboot+validation参数校验浅入浅出

在spring开发中,对入参进行校验是一种常见且必须的需求,下面对springboot中引入validation组件实现校验进行简单的分析一下。
Java API 规范 JSR303 定义了 Bean 校验的标准,但没提供实现,而常用的hibernate validation则是对这个规范的实现,提供了校验注解@Min、@Max等。spring validation是对hibernate validation的二次封装,用于spirng中参数的校验。
若springboot版本低于2.3.时,spring-boot-starter-web会自动传入hibernate-validation依赖,若是版本高于2.3.,则需要手动引入hibernate-validation依赖。
示例如下图
在这里插入图片描述
在这里插入图片描述
对于web服务,为防止非法参数对业务造成影响,在controller层对http请求传递的参数进行校验分析。requestBody以json形式接收参数。
在http请求中,POST类型请求主要使用requestBody传递参数,后端使用*DTO对象接收参数,此时只须给DTO对象添加@Validated或@Valid注解,在DTO对象的字段上添加声明式约束注解,就能实现自动参数校验。其中Valid是java提供的javax.validation.Valid;,Validated是spring提供的org.springframework.validation.annotation.Validated;。
实例1

	@PostMapping("add")
    public Object addUser(@RequestBody @Valid UserDTO param){
        System.out.printf("save user id is %s", param.getUserId());
        return param;
    }

    @PostMapping("update")
    public Object updateUser(@RequestBody @Validated UserDTO param){
        System.out.printf("update user is %s", param.getUserId());
        return param;
    }
@Data
public class UserDTO {

    private Long userId;

    @NotNull
    @Length(min = 2, max = 10)
    private String userName;

    @NotNull
    @Length(min = 6, max = 20)
    private String account;

    @NotNull
    @Length(min = 6, max = 20)
    private String password;

}

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

在http请求中,GET类型请求主要使用requestParam/PathVariable传递参数,此时必须在controller类上标注@validated注解,在DTO对象的字段上添加声明式约束注解或在入参上添加声明式约束注解,完成参数校验。
实例2

返回
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果校验失败,会抛出MethodArgumentNotValidException或ConstraintViolationException异常,在实际工程中,通常通过统一异常处理来返回一个更友好的提示。
实例3

@RestControllerAdvice
public class CommonExceptionHandler {

    @ExceptionHandler({MethodArgumentNotValidException.class})
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        BindingResult bindingResult = ex.getBindingResult();
        StringBuilder sb = new StringBuilder("校验失败,");
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");
        }
        String msg = sb.toString();
        return ResponseData.fail(msg,400);
    }

    @ExceptionHandler({ConstraintViolationException.class})
    public Object handleConstraintViolationException(ConstraintViolationException ex) {
        return ResponseData.fail(ex.getMessage(), 400);
    }
}

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

如果有多个接口需要使用同一个DTO对象来接收参数,而不同的接口的校验规则是不一样的,通常通过分组校验来实现。
实例4

@Data
public class UserDTO {

    @NotNull(groups = Update.class)
    @Min(value = 1000L, groups = Update.class)
    private Long userId;

    @NotNull(groups = {Insert.class, Update.class})
    @Length(min = 2, max = 10, groups = {Insert.class, Update.class})
    private String userName;

    @NotNull(groups = {Insert.class, Update.class})
    @Length(min = 6, max = 20, groups = {Insert.class, Update.class})
    private String account;

    @NotNull(groups = {Insert.class, Update.class})
    @Length(min = 6, max = 20, groups = {Insert.class, Update.class})
    private String password;

}
public interface Insert {
}
public interface Update {
}
	@PostMapping("add3")
    public Object addUser3(@RequestBody @Validated(Insert.class) UserDTO param){
        System.out.printf("save user id is %s", param.getUserId());
        return param;
    }

    @PostMapping("update3")
    public Object updateUser3(@RequestBody @Validated(Update.class) UserDTO param){
        System.out.printf("update user is %s", param.getUserId());
        return param;
    }

返回
在这里插入图片描述
如果DTO对象里面的字段有基本数据类型,也出现了某个字段是一个对象,这时通过嵌套校验来实现。需要注意的是,此时DTO类的对应字段必须标记@Valid注解。
实例5

@Data
public class UserDTO {

    @NotNull(groups = Update.class)
    @Min(value = 1000L, groups = Update.class)
    private Long userId;

    @NotNull(groups = {Insert.class, Update.class})
    @Length(min = 2, max = 10, groups = {Insert.class, Update.class})
    private String userName;

    @NotNull(groups = {Insert.class, Update.class})
    @Length(min = 6, max = 20, groups = {Insert.class, Update.class})
    private String account;

    @NotNull(groups = {Insert.class, Update.class})
    @Length(min = 6, max = 20, groups = {Insert.class, Update.class})
    private String password;

    @NotNull(groups = {Insert.class, Update.class})
    @Valid
    private Job job;

    @Data
    public static class Job {

        @NotNull(groups = Update.class)
        @Min(value = 1, groups = Update.class)
        private Long jobId;

        @NotNull(groups = {Insert.class, Update.class})
        @Length(min = 2, max = 10, groups = {Insert.class, Update.class})
        private String jobName;

        @NotNull(groups = {Insert.class, Update.class})
        @Length(min = 2, max = 10, groups = {Insert.class, Update.class})
        private String position;
    }

}

返回
在这里插入图片描述
如果请求体直接传递了json数组到后端,并希望对数组中的每一项都进行参数校验,此时使用java.util.Collection下的list或set来接收数据,参数校验并不会生效,需要使用自定义的list集合来实现。
实例6

public class ValidationList<E> implements List<E> {

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

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

    public List<E> getList() {
        return list;
    }

    public void setList(List<E> list) {
        this.list = list;
    }
}
@PostMapping("/addList")
    public Object addList(@RequestBody @Validated(Insert.class) ValidationList<UserDTO> userList) {
        return ResponseData.ok(userList);
    }

返回
在这里插入图片描述
如果出现一些特殊的业务需求,此时可以通过自定义校验来实现。假设自定义加密字段校验(由数字或者a-f的字母组成,32-256长度)。
实例7

@Data
public class UserDTO implements Serializable {

    private static final long serialVersionUID = 1L;

    @NotNull(groups = Update.class)
    @Min(value = 1000L, groups = Update.class)
    private Long userId;

    @NotNull(groups = {Insert.class, Update.class})
    @Length(min = 2, max = 10, groups = {Insert.class, Update.class})
    private String userName;

    @NotNull(groups = {Insert.class, Update.class})
    @Length(min = 6, max = 20, groups = {Insert.class, Update.class})
    private String account;

    @Encrypt(groups = {Insert.class, Update.class})
    @NotNull(groups = {Insert.class, Update.class})
    @Length(min = 6, max = 20, groups = {Insert.class, Update.class})
    private String password;

    @NotNull(groups = {Insert.class, Update.class})
    @Valid
    private Job job;

    @Data
    public static class Job {

        @NotNull(groups = Update.class)
        @Min(value = 1, groups = Update.class)
        private Long jobId;

        @NotNull(groups = {Insert.class, Update.class})
        @Length(min = 2, max = 10, groups = {Insert.class, Update.class})
        private String jobName;

        @NotNull(groups = {Insert.class, Update.class})
        @Length(min = 2, max = 10, groups = {Insert.class, Update.class})
        private String position;
    }

}
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {EncryptValidator.class})
public @interface Encrypt {
    String message() default "加密格式错误";

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

    Class<? extends Payload>[] payload() default {};
}
public class EncryptValidator implements ConstraintValidator<Encrypt, String> {

    private static final Pattern PATTERN = Pattern.compile("^[a-f\\d]{32,256}$");

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value != null) {
            Matcher matcher = PATTERN.matcher(value);
            return matcher.find();
        }
        return true;
    }
}
	@PostMapping("update5")
    public Object updateUser(@RequestBody @Validated(Update.class) UserDTO param){
        System.out.printf("save user id is %s", param.getUserId());
        return param;
    }

返回
在这里插入图片描述
在spring-mvc中,RequestResponseBodyMethodProcessor是用于解析@RequestBody标注的参数以及处理@ResponseBody标注方法的返回值的。源码如下
在这里插入图片描述
参数校验还需不断的深入应用并理解其底层原理。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 11:04:09  更:2022-05-05 11:05:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:45:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码