Spring关联请求参数校验咨询:纬度非空时经度需非空
如何校验Spring MVC中关联请求参数的非空依赖?
问题场景
我有一个Spring MVC接口:
@RequestMapping(value = "/test") @ResponseBody public Object test(@RequestParam("latitude") String latitude, @RequestParam("longitude") String longitude) { }
需求是:如果latitude参数非空,那么longitude参数必须也非空。想请教这类关联请求参数的校验该怎么实现?有没有开箱即用的方案,还是得手动写校验逻辑?
解决方案
其实Spring原生的Validation注解(比如@NotNull、@NotBlank)都是针对单个字段的校验,没办法直接处理这种参数间的关联依赖,所以得根据场景选择不同的实现方式:
1. 手动校验(最快上手,适合简单场景)
这是最直接的方式,直接在接口方法开头加入校验逻辑,不需要额外依赖:
@RequestMapping(value = "/test") @ResponseBody public Object test(@RequestParam(value = "latitude", required = false) String latitude, @RequestParam(value = "longitude", required = false) String longitude) { // 核心关联校验逻辑 if (latitude != null && !latitude.trim().isEmpty()) { if (longitude == null || longitude.trim().isEmpty()) { // 可以抛出异常,或者返回自定义的错误响应体 throw new IllegalArgumentException("当latitude参数非空时,longitude参数不能为空"); } } // 后续业务逻辑 return "success"; }
优点:代码直观,零额外配置;缺点:校验逻辑和业务代码耦合,没办法复用。
2. 自定义校验注解(推荐,适合多接口复用场景)
如果这种关联校验在多个接口都需要用到,自定义校验注解会更优雅,能把校验逻辑和业务代码解耦。
步骤1:定义自定义校验注解
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; @Documented @Constraint(validatedBy = LatLonPairValidator.class) @Target({ElementType.PARAMETER, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface ValidLatLonPair { // 校验失败时的提示信息 String message() default "当latitude非空时,longitude不能为空"; // 分组校验用,可选 Class<?>[] groups() default {}; // 负载信息,可选 Class<? extends Payload>[] payload() default {}; }
步骤2:实现校验器逻辑
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class LatLonPairValidator implements ConstraintValidator<ValidLatLonPair, Object[]> { @Override public boolean isValid(Object[] values, ConstraintValidatorContext context) { // 确保参数是两个字符串类型 if (values == null || values.length != 2) { return true; // 交给其他校验规则处理,比如@NotBlank } String latitude = (String) values[0]; String longitude = (String) values[1]; // 核心校验:latitude非空时,longitude必须非空 if (latitude != null && !latitude.trim().isEmpty()) { return longitude != null && !longitude.trim().isEmpty(); } // latitude为空时,longitude可以为空,直接通过校验 return true; } }
步骤3:在接口中使用
注意必须在控制器类上加上@Validated注解,开启Spring的方法参数校验功能:
@RestController @Validated // 这个注解一定要加,否则自定义校验不生效 public class TestController { @RequestMapping(value = "/test") @ResponseBody public Object test(@ValidLatLonPair @RequestParam(value = "latitude", required = false) String latitude, @RequestParam(value = "longitude", required = false) String longitude) { // 业务逻辑 return "success"; } }
更推荐的做法是把参数封装成DTO类,这样校验逻辑更灵活,也方便扩展其他字段的校验:
@ValidLatLonPair public class LocationDTO { private String latitude; private String longitude; // getter、setter方法 }
然后接口改成接收DTO参数:
@RequestMapping(value = "/test") @ResponseBody public Object test(@Valid @RequestBody LocationDTO locationDTO) { // 业务逻辑 return "success"; }
3. 分组校验(适合复杂多场景校验)
如果你的业务有更复杂的校验场景(比如不同接口对参数的校验规则不同),可以结合Spring Validation的分组功能,但对于这种简单的关联校验,自定义注解已经足够好用了。
总结
- 没有开箱即用的原生注解能直接处理这种参数间的关联校验,因为原生注解都是针对单个字段的;
- 简单场景直接用手动校验,快速实现;
- 多接口复用场景推荐自定义校验注解,解耦且可复用。
内容的提问来源于stack exchange,提问作者Combo
相关产品推荐
相关产品推荐

