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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 04:10:39