springboot学习第3期 - 参数校验

参数分为 路径参数、查询参数、请求体参数。

引入依赖

需要引入校验依赖:

xml 复制代码
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

常用的校验注解包含:

注解 作用类型 说明
@NotNull 所有引用类型 对象不能为null
@NotEmpty String 字符串不能为空字符串
@NotBlank String 字符串不能为空格和空字符串
@Length(min=,max=) String 字符串的长度限制
@Size(min=, max=) 集合类型 集合类型的元素个数限制
@Min / @Max Integer 数字的大小限制
@Pattern(regexp="") String 字符串正则匹配
@Email String 字符串为邮件格式

路径参数

校验路径参数,除了变量前面加校验注解外,类上还需要加 @Validated 注解,

java 复制代码
@RestController
@RequestMapping("/api/hello")
@Validated
public class HelloController {

    @GetMapping("/{name}")
    public ApiResponse<String> hello(@PathVariable @Length(min = 2, max = 10) String name) {
        return ApiResponse.success("Hello World!" + name);
    }

}

postman 接口调试:

后端异常信息:

查询参数

查询参数和路径参数一样。

同样是变量前面添加校验注解,类上添加 @Validated 注解。

java 复制代码
@RestController
@RequestMapping("/api/hello")
@Validated
public class HelloController {

    @GetMapping
    public ApiResponse<String> hello(@RequestParam @Length(min = 2, max = 10) String name) {
        return ApiResponse.success("Hello World!" + name);
    }

}

查询参数封装

这种形式类上不需要加 @Validated。

封装的对象前面需要添加 @Valid 注解,这里也可以换成 @Validated 注解,如果需要分组校验,则使用 @Validated 注解,但实际开发中,很少会使用分组校验。

java 复制代码
@RestController
@RequestMapping("/api/hello")
public class HelloController {

    @GetMapping
    public ApiResponse<String> hello(@Valid Param param) {
        return ApiResponse.success("Hello World!" + param.getName());
    }

}
java 复制代码
@Data
public class Param {
    @Length(min = 2, max = 50)
    private String name;
    private String age;
}

postman接口调试:

后端服务器异常信息:

请求体参数

请求体参数的校验和查询参数封装一样的。

java 复制代码
@RestController
@RequestMapping("/api/hello")
public class HelloController {

    @PostMapping
    public ApiResponse<String> hello(@Valid @RequestBody Request request) {
        return ApiResponse.success("Hello World!" + request.getName());
    }
}

而封装的属性前面,添加具体的校验注解:

java 复制代码
@Data
public class Request {

    @Length(min = 2, max = 100)
    private String name;

    @JsonProperty("my_age")
    private String myAge;
}

使用postman调试接口:

服务端抛出的异常信息,抛出的异常是 MethodArgumentNotValidException:

包含自定义对象属性

请求体对象包含自定义对象 Person, 并且 Person 属性包含校验注解。

则Person变量前面需要添加 @Valid 注解。

java 复制代码
@Data
public class Request {

    @Length(min = 2, max = 100)
    private String name;

    @Valid   // 关键
    private Person person;

//  集合嵌套自定义对象,也是如此
//    @Valid
//    private List<Person> person;

//  或者这种形式也是可以的
// 	  private List<@Valid Person> person;
}
java 复制代码
@Data
public class Person {

    @Length(min = 4, max = 10)
    private String name;
}

集合普通元素

java 复制代码
@Data
public class Request {

    @Length(min = 2, max = 100)
    private String name;

    private List<@Length(min=2) String> tags;
}

tags 的每个元素都会应用 @Length(min=2) 注解校验。

全局异常处理

通过前面的postman接口调试看出,即使校验不通过,响应信息晦涩难懂,客户端根本不知道是因为什么而接口调不通。这次通过全局异常处理机制,优化校验不通过的提示信息。

通过前面三种参数的校验,可以知道如果校验不通过,会返回两种类型的异常,MethodArgumentNotValidException 和 ConstraintViolationException,主要在响应之前全局拦截这两个异常,将异常信息提取出来,友好的返回给客户端即可。

全局异常处理器使用注解 @RestControllerAdvice + @ExceptionHandler,当程序中抛出指定的异常信息,就会被拦截到,经过自定义处理,然后返回给客户端。

java 复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<List<String>> handleValidException(MethodArgumentNotValidException ex) {
        List<String> errors = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.toList());
        return ApiResponse.error(400, "参数校验失败", errors);
    }

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<List<String>> handleViolationException(ConstraintViolationException ex) {
        List<String> errors = ex.getConstraintViolations()
                .stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.toList());
        return ApiResponse.error(400, "参数校验失败", errors);
    }
}

前面忘记提到,所有的校验注解都有个 message 属性, 当校验失败的时候,会提示 message 信息,而上述全局异常处理器,就是收集所有校验注解的message,返回给客户端

java 复制代码
@RestController
@RequestMapping("/api/hello")
@Validated
public class HelloController {

    @PostMapping("/{name}")
    public ApiResponse<String> hello(@PathVariable @Length(min = 2, max = 10, message = "Name length should be between 2 and 10") String name,
                                     @RequestParam @Min(value = 18, message = "Age should be between 0 and 100") String age) {
        return ApiResponse.success("Hello World!" + name);
    }

}

可以为参数校验失败设置特定的code, 比如 400001(400 + 001),然后前端响应拦截器判定到是400001,则展示所有的异常信息。关于响应码的设计,这是个大学问。

自定义校验注解

比如自定义一个校验电话号码的检验注解。

java 复制代码
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
    String message() default "手机号格式错误";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
java 复制代码
public class PhoneValidator implements ConstraintValidator<Phone, String> {
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return value != null && value.matches("^1[3-9]\\d{9}$");
    }
}

使用:

java 复制代码
@Data
public class Request {

    @Length(min = 2, max = 100, message = "name 长度应该在 2 到 100 之间")
    private String name;

    @Phone(message = "phone 格式不正确")
    private String phone;
}
相关推荐
布朗克1685 小时前
Spring Boot项目通过Feign调用三方接口的详细教程
java·spring boot·feign
鼠鼠我捏,要死了捏8 小时前
基于Spring Boot与gRPC的高性能微服务架构设计分享
spring boot·微服务·grpc
麦兜*9 小时前
Spring Boot调用优化版AI推理微服务 集成 NVIDIA NIM指南
java·人工智能·spring boot·后端·spring cloud·微服务·ai编程
paopaokaka_luck12 小时前
校园快递小程序(腾讯地图API、二维码识别、Echarts图形化分析)
vue.js·spring boot·后端·小程序·uni-app
北执南念13 小时前
如何在 Spring Boot 中设计和返回树形结构的组织和部门信息
java·spring boot·后端
邦杠15 小时前
最新SpringBoot上传Maven中央仓库,在其他项目直接引入依赖(github开源项目打包上传,不需要私服)
spring boot·后端·开源·github·maven
Co0kie_16 小时前
SpringAI报错:com.github.victools.jsonschema.generator.AnnotationHelper
jvm·spring boot·ai·ai编程
IT毕设实战小研18 小时前
Java毕业设计选题推荐 |基于SpringBoot的水产养殖管理系统 智能水产养殖监测系统 水产养殖小程序
java·开发语言·vue.js·spring boot·毕业设计·课程设计
小小深18 小时前
Spring进阶(八股篇)
java·spring boot·spring