Spring MVC Validation如何实现仅必填用户名或手机号两个字段其中一个
实现方案
有两种常用实现方式,可根据场景选择:
方案1:直接在Controller方法内加校验(快速实现,适合单个接口使用)
首先修正现有代码的隐藏问题:你将user-name标注为@PathVariable,但/users路径没有对应的{user-name}占位符,会直接启动报错,先统一调整为请求参数。
修改后代码如下:
@GetMapping("/users") @Operation(summary = "API to return users based on username or phone number") public ResponseEntity<List<UserResponseObject>> usersByNameOrNumber( @RequestParam(name = "phone-number", required = false) @Pattern(regexp = "^(\\d{5}|\\d{9})$") String userPhoneNumber, @RequestParam(name = "user-name", required = false) @Pattern(regexp = "^[a-zA-Z ]*$") String userName) { // 新增互斥校验逻辑 boolean isPhoneEmpty = userPhoneNumber == null || userPhoneNumber.isBlank(); boolean isNameEmpty = userName == null || userName.isBlank(); if (isPhoneEmpty && isNameEmpty) { return ResponseEntity.badRequest().body(null); // 可自定义返回错误提示 } if (!isPhoneEmpty && !isNameEmpty) { return ResponseEntity.badRequest().body(null); // 可自定义返回错误提示 } try { // 原有业务逻辑 } catch (Exception e) { // 原有异常处理 } }
注意:单个请求参数上的
@Pattern校验要生效,需要在Controller类上添加@Validated注解。
方案2:自定义校验注解(规范实现,适合多接口复用同类校验规则)
如果多个接口都有类似参数互斥需求,可通过JSR-380自定义校验注解实现,逻辑和业务代码解耦:
步骤1:定义自定义校验注解
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = MutexParamValidator.class) public @interface MutexParam { String message() default "仅允许传入互斥参数中的一个"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; // 指定互斥的两个字段名 String field1(); String field2(); }
步骤2:实现校验器逻辑
import org.springframework.beans.BeanWrapperImpl; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class MutexParamValidator implements ConstraintValidator<MutexParam, Object> { private String field1; private String field2; @Override public void initialize(MutexParam constraintAnnotation) { this.field1 = constraintAnnotation.field1(); this.field2 = constraintAnnotation.field2(); } @Override public boolean isValid(Object value, ConstraintValidatorContext context) { Object fieldValue1 = new BeanWrapperImpl(value).getPropertyValue(field1); Object fieldValue2 = new BeanWrapperImpl(value).getPropertyValue(field2); boolean field1Empty = fieldValue1 == null || (fieldValue1 instanceof String && ((String) fieldValue1).isBlank()); boolean field2Empty = fieldValue2 == null || (fieldValue2 instanceof String && ((String) fieldValue2).isBlank()); // 仅当其中一个非空时校验通过 return field1Empty ^ field2Empty; } }
步骤3:封装请求参数DTO
import javax.validation.constraints.Pattern; @MutexParam(field1 = "userPhoneNumber", field2 = "userName", message = "必须且仅能传入手机号或用户名其中一个参数") public class UserQueryDTO { @Pattern(regexp = "^(\\d{5}|\\d{9})$", message = "手机号仅允许5位或9位数字") private String userPhoneNumber; @Pattern(regexp = "^[a-zA-Z ]*$", message = "用户名仅允许英文字母和空格") private String userName; // 省略getter、setter }
步骤4:修改Controller代码
@GetMapping("/users") @Operation(summary = "API to return users based on username or phone number") public ResponseEntity<List<UserResponseObject>> usersByNameOrNumber(@Valid UserQueryDTO queryDTO) { try { // 原有业务逻辑,从queryDTO中取参数即可 } catch (Exception e) { // 原有异常处理 } }
校验失败时会自动抛出MethodArgumentNotValidException,可通过全局异常拦截统一返回错误提示即可。
内容的提问来源于stack exchange,提问作者Code Junkie
相关产品推荐
相关产品推荐

