Spring Boot中参数校验

这篇具有很好参考价值的文章主要介绍了Spring Boot中参数校验。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

为了保证数据的正确性、完整性,前后端都需要进行数据检验。作为一名后端开发工程师,不能仅仅依靠前端来校验数据,我们还需要对接口请求的参数进行后端的校验。最常见的做法就是通过if/else语句来对请求的每一个参数一一校验,当很多参数需要校验的时候,if/else语句就会比较长,写起来也比较麻烦,一点都不简洁、美观。所以,今天来和大家分享一下Spring Boot Validation。

spring-boot-starter-validation

Spring Boot 2.3 1 之后,spring-boot-starter-validation 已经不包括在了 spring-boot-starter-web 中,需要我们手动加上。

如下图所示,spring-boot-starter-web-2.2.6.RELEASE就包含了spring-boot-starter-validation,

Spring Boot中参数校验

而spring-boot-starter-web-2.5.7并没有spring-boot-starter-validation,需要自己手动加入依赖。

Spring Boot中参数校验

如下图所示,手动加入依赖spring-boot-starter-validation,实际上依赖了hibernate-validator。

Spring Boot中参数校验

@Valid和@Validated

@Valid所属包为javax.validation,不具备分组校验功能;可以用在方法、构造函数、方法参数和成员属性(field)上

说明:Java的JSR-303声明了@Valid这类接口,而hibernate-validator对其进行了实现。

JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation。

@Validated所属包为org.springframework.validation.annotation,属于spring的校验机制,具有分组校验功能;用在类型、方法和方法参数上。但不能用于成员属性(field)。

@Valid和@Validated注解可以结合使用,来实现嵌套验证。

Spring Boot中参数校验

 常用的注解如下:

Spring Boot中参数校验

简单使用

添加依赖

本文使用的是Spring Boot 2.5.7,具体依赖如下:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

实体类

@Data
@ToString
public class User {

    private Integer id;

    @NotBlank(message = "姓名不能为空")
    private String name;

    @Max(value = 100, message = "最大不超过100")
    private Integer age;
}    

Controller

@RestController
public class TestController {

    /**
    * post请求 实体类User 加上注解@Valid 
    */
    @PostMapping("/test")
    public String test(@Valid @RequestBody User user) {
        System.out.println(user);
        return "Hello World";
    }

    /**
    * get请求 实体类User 加上注解@Valid 
    * 测试:http://localhost:8080/query2?name=&age=101
    */    
    @GetMapping("/query2")
    public String queryUserInfo(@Valid User user) {
        System.out.println("query2");
        return user.getName();
    }
}
/**
* 【反面教材】验证不生效
*/
@RestController
public class Test3Controller {

    @GetMapping("/test3")
    public String test3(@NotEmpty(message = "name不能为空") String name,
                        @Max(value = 100, message = "请输入数字") Integer age) {
        System.out.println("是啥啊3");
        return name;
    }

    @GetMapping("/test4")
    @Validated
    public String test4(@NotEmpty(message = "name不能为空") String name,
                        @Max(value = 100, message = "请输入数字") Integer age) {
        System.out.println("是啥啊4");
        return name;
    }

    @GetMapping("/test5")
    public String test5(@Validated @NotEmpty(message = "name不能为空") String name,
                        @Valid @Max(value = 100, message = "请输入数字") Integer age) {
        System.out.println("是啥啊5");
        return name;
    }
}
/**
* 【正面教材】类上加注解@Validated,下面的验证生效
*/
@RestController
@Validated 
public class Test2Controller {

    @GetMapping("/query")
    public String queryUserInfo(@NotEmpty(message = "name不能为空") String name,
                                @Max(value = 100, message = "请输入数字") Integer age) {
        System.out.println("是啥啊");
        return name;
    }
}

全局异常处理类

/**
* 参数校验异常包括MethodArgumentNotValidException、BindException、ConstraintViolationException
*/
@RestControllerAdvice
public class ExceptionHandler {

  @org.springframework.web.bind.annotation.ExceptionHandler(MethodArgumentNotValidException.class)
    public String handle(MethodArgumentNotValidException e) {
        e.printStackTrace();
        return e.getBindingResult().getFieldError().getDefaultMessage();
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(BindException.class)
    public String handle(BindException e) {
        e.printStackTrace();
        return e.getBindingResult().getFieldError().getDefaultMessage();
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(ConstraintViolationException.class)
    public String handle(ConstraintViolationException e) {
        e.printStackTrace();
        StringBuffer sb = new StringBuffer();
        for (ConstraintViolation<?> violation : e.getConstraintViolations()) {
            sb.append(violation.getMessage());
        }
        return sb.toString();
    }
}

进阶使用

分组校验

  • 约束注解上声明适用的分组信息groups
@Data
public class UserDTO {
 
    @Min(value = 10000000000000000L, groups = Update.class)
    private Long userId;
 
    @NotNull(groups = {Save.class, Update.class})
    @Length(min = 2, max = 10, groups = {Save.class, Update.class})
    private String userName;
 
    // 对于添加、修改都需要操作的公共属性,也可以不加groups标签,这时候,controller中入参需要写成@Validated({UserDTO.Update.class, Default.class}) 即可
    @NotNull(groups = {Save.class, Update.class})
    @Length(min = 6, max = 20, groups = {Save.class, Update.class})
    private String account;
 
    @NotNull(groups = {Save.class, Update.class})
    @Length(min = 6, max = 20, groups = {Save.class, Update.class})
    private String password;
 
    /**
     * 保存的时候校验分组
     */
    public interface Save {
    }
 
    /**
     * 更新的时候校验分组
     */
    public interface Update {
    }
}
  • @Validated注解上指定校验分组
@PostMapping("/save")
public Result saveUser(@RequestBody @Validated(UserDTO.Save.class) UserDTO userDTO) {
    // 校验通过,才会执行业务逻辑处理
    return Result.ok();
}
 
@PostMapping("/update")
public Result updateUser(@RequestBody @Validated(UserDTO.Update.class) UserDTO userDTO) {
    // 校验通过,才会执行业务逻辑处理
    return Result.ok();
}

嵌套校验

前面的示例中,DTO类里面的字段都是基本数据类型String类型。但是实际场景中,有可能某个字段也是一个对象,这种情况下,可以使用嵌套校验

比如,上面保存User信息的时候同时还带有Job信息。需要注意的是,此时DTO类的对应字段必须标记@Valid注解

@Data  
public class UserDTO {  
  
    @Min(value = 10000000000000000L, groups = Update.class)  
    private Long userId;  
  
    @NotNull(groups = {Save.class, Update.class})  
    @Length(min = 2, max = 10, groups = {Save.class, Update.class})  
    private String userName;  
  
    @NotNull(groups = {Save.class, Update.class})  
    @Length(min = 6, max = 20, groups = {Save.class, Update.class})  
    private String account;  
  
    @NotNull(groups = {Save.class, Update.class})  
    @Length(min = 6, max = 20, groups = {Save.class, Update.class})  
    private String password;  
  
    // job属性上添加@Valid注解
    @NotNull(groups = {Save.class, Update.class})  
    @Valid  
    private Job job;  
  
    @Data  
    public static class Job {  
  
        @Min(value = 1, groups = Update.class)  
        private Long jobId;  
  
        @NotNull(groups = {Save.class, Update.class})  
        @Length(min = 2, max = 10, groups = {Save.class, Update.class})  
        private String jobName;  
  
        @NotNull(groups = {Save.class, Update.class})  
        @Length(min = 2, max = 10, groups = {Save.class, Update.class})  
        private String position;  
    }  
  
    public interface Save {  
    }  
  
    public interface Update {  
    }  
}

自定义校验

  • 自定义注解

@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
// 指明使用那个校验器(类) 去校验使用了此标注的元素。
@Constraint(validatedBy = CaseUpperValidator.class)
@Documented
public @interface CaseUpper {

    String message() default "必须大写";

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

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

}
  • 实现ConstraintValidator接口编写约束校验器

public class CaseUpperValidator implements ConstraintValidator<CaseUpper, String> {

    // 提示信息
    private String message;

    // 实现校验逻辑的方法。value为当前需要进行校验的值,context可以给约束验证器时提供上下文数据和操作,比如设置错误信息等。
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        // 为空,返回失败
        boolean isValid = false;
        // value为空不校验;另外,value都是大写校验通过
        if (Objects.isNull(value) || value.equals(value.toUpperCase())) {
            isValid = true;
        }
        // 校验不通过,实现自定义错误信息
        if (!isValid) {
            //禁止默认消息返回
            context.disableDefaultConstraintViolation();
            //自定义返回消息
            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
        }
        return isValid;
    }

    // caseUpper为当前校验注解的实例,可以获取当前注解的属性值
    @Override
    public void initialize(CaseUpper caseUpper) {
        this.message = caseUpper.message();
    }
}
  • 使用注解@CaseUpper

@Data
@ToString
public class User {

    private Integer id;

    @NotBlank(message = "姓名不能为空")
    private String name;

    @Max(value = 100, message = "最大不超过100")
    private Integer age;

    @NotBlank(message = "englishName不能为空")
    @CaseUpper(message = "englishName必须大写")
    private String englishName;
}

参考链接:

SpringBoot 实现各种参数校验,非常实用!_枫哥和java的博客-CSDN博客

Spring Validation最佳实践及其实现原理,参数校验没那么简单! - 掘金文章来源地址https://www.toymoban.com/news/detail-415193.html

到了这里,关于Spring Boot中参数校验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 参数校验: spring-boot-starter-validation

    2024年01月21日
    浏览(51)
  • 如何在Spring Boot中优雅地进行参数校验

    在平时的开发工作中,我们通常需要对接口进行参数格式验证。当参数个数较少(个数小于3)时,可以使用 if ... else ... 手动进行参数验证。当参数个数大于3个时,使用 if ... else ... 进行参数验证就会让代码显得臃肿,这个时候推荐使用注解来进行参数验证。 在Java中,注解

    2024年01月17日
    浏览(43)
  • Spring Boot使用 Hibernate-Validator校验参数时的长度校验

    今天在使用Validator框架数据验证的时候碰到了三个类似的注解,都是用来限制长度,但是用法上有区别:  @Size是一个Bean验证注释,用于验证关联的String具有的长度受最小值和最大值限制的值.  @Length是一个Hibernate特定的注释,与@Size具有相同的含义; 两者的区别: ​ 用@length限

    2024年02月14日
    浏览(41)
  • Spring Boot中使用JSR-303实现请求参数校验

    JSR-303是Java中的一个规范,用于实现请求参数校验。它定义了一组注解,可以应用于JavaBean的字段上,用于验证输入参数的合法性。下面是一些常用的JSR-303注解及其介绍: @NotNull :用于验证字段值不能为null。 @NotEmpty :用于验证字符串字段不能为空。 @NotBlank :用于验证字符

    2024年02月08日
    浏览(39)
  • Spring Boot 中自定义数据校验注解

    在 Spring Boot 中,我们可以使用 JSR-303 数据校验规范来校验表单数据的合法性。JSR-303 提供了一些常用的数据校验注解,例如 @NotNull 、 @NotBlank 、 @Size 等。但是,在实际开发中,我们可能需要自定义数据校验注解来满足特定的需求。本文将介绍如何在 Spring Boot 中自定义数据校

    2024年02月10日
    浏览(53)
  • 从零开始学Spring Boot系列-前言

    在数字化和信息化的时代,Java作为一种成熟、稳定且广泛应用的编程语言,已经成为构建企业级应用的首选。而在Java生态系统中,Spring框架无疑是其中最为耀眼的一颗明星。它提供了全面的编程和配置模型,用于构建企业级应用。随着Spring Boot的出现,这一框架变得更加易于

    2024年02月22日
    浏览(59)
  • 使用Win10自带的PowerShell命令校验文件和镜像文件的Hash值(MD5、SHA1/256等)正确性

    通常为了保证我们从网上下载的文件的完整性和可靠性,我们把文件下载下来以后都会校验一下MD5值或SHA1值(例如验证下载的Win10 ISO镜像是否为原始文件),这一般都需要借助专门的MD5检验工具来完成。但其实使用Windows系统自带的Windows PowerShell运行命令即可进行文件MD5、S

    2024年02月16日
    浏览(42)
  • Spring Boot 统一功能处理(拦截器实现用户登录权限的统一校验、统一异常返回、统一数据格式返回)

    目录 1. 用户登录权限校验 1.1 最初用户登录权限效验 1.2 Spring AOP 用户统⼀登录验证 1.3 Spring 拦截器 (1)创建自定义拦截器 (2)将自定义拦截器添加到系统配置中,并设置拦截的规则 1.4 练习:登录拦截器 (1)实现 UserController 实体类 (2)返回的登录页面:login.html (3)实

    2024年02月12日
    浏览(50)
  • spring参数校验@Validated及嵌套校验

    本文介绍项目中校验 @Validated的使用,主要分参数对象属性校验,嵌套校验,集合在对象属性中校验,集合作为参数校验。 controller层 测试输入 输出 这里作为参数,如果使用List接收是不起作用的,必须用ValidList,这个类中有标记 @Valid @Valid private ListE list = new ArrayList(); 如果在

    2024年02月09日
    浏览(49)
  • Spring boot Websocket 添加授权校验(校验Header)

            最近需要用到websocket,并且确认是在登录成功的情况下才能连接,看了下,websocket 5.8以上已经支持校验了,但是由于我项目是spring boot 2.7.9,为了兼容,只能考虑通过在websocket 的header中带上验证信息,进行校验,详细如下 1.首先往spring boot pom 内加入 websocket的依赖

    2024年02月07日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包