如何在Spring的GET请求中实现@RequestParam参数的复杂校验规则
GET请求@RequestParam复杂参数校验实现方案
首先确认项目已引入校验依赖,SpringBoot 2.3+版本需手动引入:
<!-- Maven依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
方案1:单个参数直接加校验注解(适合参数少的场景)
该方案无需封装请求类,直接在@RequestParam参数上加校验注解,步骤如下:
- 在Controller类上标注
@Validated注解,触发单个参数的校验逻辑:
import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; @RestController @Validated // 必填注解,缺省会导致单参数校验不生效 public class TicketController { // 接口示例 @GetMapping("/query") public String queryTicket( @RequestParam(value = "departureDate") @DateTimeFormat(pattern = "dd.MM.yyyy") // 自定义校验注解,你也可以用JSR自带的@NotNull、@Future等注解 @DateRange(min = 0, max = 90, message = "出发日期需在今天起90天范围内") LocalDate departureDate ) { return "查询成功"; } }
- 自定义复杂校验注解(以日期范围校验为例)
首先定义注解类:
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; @Target({ElementType.PARAMETER, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = DateRangeValidator.class) public @interface DateRange { // 校验失败提示信息 String message() default "日期不在允许范围内"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; // 自定义规则:距离今天最小天数 int min() default 0; // 自定义规则:距离今天最大天数 int max() default 30; }
然后实现校验逻辑类:
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.time.LocalDate; public class DateRangeValidator implements ConstraintValidator<DateRange, LocalDate> { private int min; private int max; @Override public void initialize(DateRange constraintAnnotation) { this.min = constraintAnnotation.min(); this.max = constraintAnnotation.max(); } @Override public boolean isValid(LocalDate date, ConstraintValidatorContext context) { // 空值校验逻辑可按需求调整,若允许空可直接返回true if (date == null) return false; LocalDate minDate = LocalDate.now().plusDays(min); LocalDate maxDate = LocalDate.now().plusDays(max); return !date.isBefore(minDate) && !date.isAfter(maxDate); } }
方案2:GET参数封装为DTO类校验(适合多参数场景)
即使是GET请求,也可以把所有请求参数封装到普通POJO类中,直接作为方法参数加@Valid注解即可触发校验,用法和POST请求的DTO校验完全一致:
- 定义参数封装DTO类,加对应校验注解:
import org.springframework.format.annotation.DateTimeFormat; import javax.validation.constraints.NotBlank; import java.time.LocalDate; public class TicketQueryDTO { @DateTimeFormat(pattern = "dd.MM.yyyy") @DateRange(min = 0, max = 90, message = "出发日期需在今天起90天范围内") private LocalDate departureDate; @NotBlank(message = "出发城市不能为空") private String fromCity; @NotBlank(message = "到达城市不能为空") private String toCity; // 此处省略getter、setter }
- Controller方法直接接收DTO参数:
@GetMapping("/query") public String queryTicket(@Valid TicketQueryDTO queryDTO) { return "查询成功"; }
该方案无需在Controller类上加@Validated注解,参数较多时更易维护,还可以直接复用POST请求已有的校验规则。
全局异常捕获
校验失败会抛出ConstraintViolationException,可以通过全局异常处理器统一返回错误信息:
import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import javax.validation.ConstraintViolationException; import java.util.HashMap; import java.util.Map; @ControllerAdvice public class ValidationExceptionHandler { @ExceptionHandler(ConstraintViolationException.class) public ResponseEntity<Map<String, String>> handleValidationError(ConstraintViolationException e) { Map<String, String> errorMap = new HashMap<>(); e.getConstraintViolations().forEach(violation -> { String param = violation.getPropertyPath().toString(); String msg = violation.getMessage(); errorMap.put(param, msg); }); return ResponseEntity.badRequest().body(errorMap); } }
内容的提问来源于stack exchange,提问作者Raccoon21
相关产品推荐
相关产品推荐

