SpringBoot自定义校验器实现地址字段唯一性校验逻辑
Spring Boot 地址唯一性自定义校验器实现指南
1. 基础实现(新增场景)
通过构造函数注入数据访问层Repository,查询数据库判断地址是否重复,实现核心校验逻辑:
package com.assessment.crud.validate; import com.assessment.crud.repository.AddressRepository; import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; public class AddressValidator implements ConstraintValidator<AddressValid, String> { private final AddressRepository addressRepository; // 构造函数注入Repository(Spring推荐方式,避免空指针问题) public AddressValidator(AddressRepository addressRepository) { this.addressRepository = addressRepository; } @Override public boolean isValid(String address, ConstraintValidatorContext context) { // 空地址处理:根据业务规则放行,此处允许空地址跳过唯一性校验 if (address == null || address.trim().isEmpty()) { return true; } // 数据库查询,存在相同地址则校验不通过(返回false) return !addressRepository.existsByAddress(address.trim()); } }
2. 必备前置组件
(1)定义校验注解AddressValid
校验器需要绑定到自定义注解上,示例代码:
package com.assessment.crud.validate; import jakarta.validation.Constraint; import jakarta.validation.Payload; import java.lang.annotation.*; @Documented @Constraint(validatedBy = AddressValidator.class) @Target({ElementType.FIELD, ElementType.PARAMETER}) // 作用于字段或参数 @Retention(RetentionPolicy.RUNTIME) public @interface AddressValid { // 校验失败提示信息 String message() default "地址已存在,请更换"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
(2)Repository添加查询方法
确保AddressRepository包含判断地址是否存在的方法:
package com.assessment.crud.repository; import com.assessment.crud.entity.Address; import org.springframework.data.jpa.repository.JpaRepository; public interface AddressRepository extends JpaRepository<Address, Long> { // 判断指定地址是否已存在 boolean existsByAddress(String address); }
3. 扩展:支持更新场景
如果需要在更新实体时排除当前记录(避免自身地址重复触发校验),修改校验器支持类级校验:
(1)更新注解定义
package com.assessment.crud.validate; import jakarta.validation.Constraint; import jakarta.validation.Payload; import java.lang.annotation.*; @Documented @Constraint(validatedBy = AddressValidator.class) @Target({ElementType.TYPE}) // 改为作用在实体类上 @Retention(RetentionPolicy.RUNTIME) public @interface AddressValid { String message() default "地址已存在,请更换"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; // 指定实体中ID字段的名称(默认id) String idField() default "id"; // 指定实体中地址字段的名称(默认address) String addressField() default "address"; }
(2)更新校验器逻辑
package com.assessment.crud.validate; import com.assessment.crud.repository.AddressRepository; import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeanWrapperImpl; public class AddressValidator implements ConstraintValidator<AddressValid, Object> { private final AddressRepository addressRepository; private String idField; private String addressField; public AddressValidator(AddressRepository addressRepository) { this.addressRepository = addressRepository; } @Override public void initialize(AddressValid constraintAnnotation) { this.idField = constraintAnnotation.idField(); this.addressField = constraintAnnotation.addressField(); } @Override public boolean isValid(Object entity, ConstraintValidatorContext context) { BeanWrapper beanWrapper = new BeanWrapperImpl(entity); Object id = beanWrapper.getPropertyValue(idField); String address = (String) beanWrapper.getPropertyValue(addressField); if (address == null || address.trim().isEmpty()) { return true; } boolean exists; if (id == null) { // 新增场景:直接校验地址是否存在 exists = addressRepository.existsByAddress(address.trim()); } else { // 更新场景:排除当前ID,校验其他记录是否存在相同地址 exists = addressRepository.existsByAddressAndIdNot(address.trim(), (Long) id); } return !exists; } }
(3)Repository添加更新场景的查询方法
// 在AddressRepository中添加 boolean existsByAddressAndIdNot(String address, Long id);
(4)实体类使用注解
直接在实体类上添加@AddressValid注解:
@AddressValid public class Address { private Long id; private String address; // 其他字段、getter/setter }
内容的提问来源于stack exchange,提问作者Abdullaah
相关产品推荐
相关产品推荐

