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;
}
相关推荐
计算机学姐4 小时前
基于微信小程序的高校班务管理系统【2026最新】
java·vue.js·spring boot·mysql·微信小程序·小程序·mybatis
摇滚侠9 小时前
Spring Boot 3零基础教程,WEB 开发 Thymeleaf 核心语法 笔记39
spring boot·笔记·后端·thymeleaf
九丶弟9 小时前
SpringBoot的cache使用说明
java·spring boot·spring·cache
lang2015092811 小时前
打造专属Spring Boot Starter
java·spring boot·后端
lang2015092813 小时前
Spring Boot RSocket:高性能异步通信实战
java·spring boot·后端
蹦跑的蜗牛14 小时前
Spring Boot使用Redis实现消息队列
spring boot·redis·后端
凤山老林15 小时前
SpringBoot 如何实现零拷贝:深度解析零拷贝技术
java·linux·开发语言·arm开发·spring boot·后端
Chan1617 小时前
流量安全优化:基于 Nacos 和 BloomFilter 实现动态IP黑名单过滤
java·spring boot·后端·spring·nacos·idea·bloomfilter
YUELEI11818 小时前
Springboot WebSocket
spring boot·后端·websocket
小蒜学长18 小时前
springboot基于JAVA的二手书籍交易系统的设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端