You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:17:01