springboot3使用validation进行参数验证

前言

  今天学习了使用validation整合springboot进行字段的校验,体验下来感觉很不错,有了validation可以省下一大堆控制器里面的数据校验,例如前端发送了一个请求到我们后端,请求中包含的数据字段一般情况下都是通过前端校验过的然后发送到后端进行处理,但是考虑到整体后端代码的可靠性和健壮性,不能100%得相信前端发送来的数据(万一某些前端数据来自一些闲的没事的人发来搞事情的呢),所以为了整体系统的可靠性后端也要对发来的数据进行校验,避免后期不必要的麻烦。

  那么言归正传,如果我们在控制器中加入大量的if进行数据校验,那么最终控制器(controller层)中的代码就会显得很臃肿,可读性降低,看起来也不够优雅,用validation就可以”优雅“地解决这个问题。

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.3'
    id 'io.spring.dependency-management' version '1.1.4'
}

apply from: './father.gradle'

group = 'org.example'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-validation'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    runtimeOnly 'com.mysql:mysql-connector-j'

    //MP
    // https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-spring-boot3-starter
    implementation 'com.baomidou:mybatis-plus-spring-boot3-starter:3.5.5'

    //druid
    // https://mvnrepository.com/artifact/com.alibaba/druid
    implementation 'com.alibaba:druid:1.2.21'
//swagger
    // https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui
    implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'

}

tasks.named('test') {
    useJUnitPlatform()
}

这个脚本中,我导入了 implementation 'org.springframework.boot:spring-boot-starter-validation' 其版本由springboot进行管理。maven导入:

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

下面是要用到的类:

点击查看代码Result类
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Result<T> {
    private int code;
    private String msg;
    private T data;

    public static <T> Result<T> success(T data) {
        return  new Result<>(Code.SUCCESS, "请求成功", data);
    }

    public static <T> Result<T> failed(String msg) {
        return  new Result<>(Code.FAILED, msg,null);
    }
}

点击查看代码code类
public class Code {
    public static  final int SUCCESS = 10100;
    public static  final int FAILED = 10101;
    public static  final int BUSY = 10102;
    public static  final int GRANT_ERR = 10103;
}

原本我们在校验前端发来的数据的时候需要在控制器中写很多if,现在我们可以这样写,这是dmeo:

@GetMapping("/get")

    public Result<User> getUserBy(@Pattern(regexp = "^\\d*$",message = "id不合法") @RequestParam String id) {

        return Result.success(userMapper.selectById(id));
    }

我们在字段前面加上 @Pattern(regexp = "^\\d*$",message = "id不合法") 我们用正则表达式进行参数的校验,当然这只是validation的其中一个注解,如果前端发来的参数可以成功匹配表达式,那么程序继续执行,如果不能,则会抛出异常,如果是在控制器中对参数进行校验会抛出HandlerMethodValidationException异常(实验得知),但如果是在实体类中的参数上面加上validation的注解,在请求体参数使用@Valid注解则会抛出MethodArgumentNotValidException异常,例如下面的方法会抛出MethodArgumentNotValidException异常:

@PostMapping("/save")
    public Result save(@Valid @RequestBody User user){
        userMapper.insert(user);
        return Result.success(null);
    }
点击查看代码User实体
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {

    @Size(min = 18, max = 18, message = "身份证长度不正确")
    private String idcard;

    @Size(min = 2,message = "姓名至少两个字")
    private String name;

    @Past(message =  "出生日期必须是过去时间")
    private java.sql.Date birth;

    @Pattern(regexp = "^[男女]$",message = "性别只能是男或女")
    private String sex;

    @Positive(message = "年龄必须是正整数")
    @Max(value = 120,message =  "年龄不能超过120岁")
    private Integer age;


    @TableId
    @Positive(message = "工号整数")
    private Integer worknum;


}

tips:validation注解一般用于controller层和实体类属性上

那如何处理未验证通过的请求呢?下面给出一个异常捕获器的处理方式,将message中的错误信息返回给前端:

@ExceptionHandler(MethodArgumentNotValidException.class)
    public Result exceptionHandler(MethodArgumentNotValidException exception){
        List<ObjectError> allErrors = exception.getAllErrors();
        StringBuilder stringBuilder=new StringBuilder();
        for (ObjectError error : allErrors) {
            stringBuilder.append(error.getDefaultMessage()).append("\n");
        }
        return Result.failed(stringBuilder.toString());
    }

这是MethodArgumentNotValidException异常处理器也就是异常信息由实体类属性校验产生(本人这么理解,如有错误望指正);HandlerMethodValidationException处理的代码几乎与以上一样;处理的方式可以多种样具体处理方式可以看业务的具体需求,当然也可以不给出那么详细的错误信息,校验失败直接抛给全局异常处理器返回BAD_REQUEST信息,这样也会减轻一些工作量。

posted @ 2024-03-17 22:48  lkhdaio  阅读(795)  评论(0编辑  收藏  举报