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

如何为@UniqueConstraint和@Column(unique = true)配置自定义错误返回消息

实现方案

@Column(unique = true) 是数据库层面的约束,不会触发Bean Validation的校验流程,所以没法直接被你控制器里的validator.validate方法捕获,需要按以下步骤实现自定义校验:

步骤1:自定义唯一校验注解

首先创建自定义校验注解@UniqueCNPJ:

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Documented
@Constraint(validatedBy = UniqueCnpjValidator.class)
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface UniqueCNPJ {
    String message() default "该CNPJ已存在,请更换后重试";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

步骤2:实现校验逻辑类

创建对应的校验器,注入你的DAO/Repository层逻辑查询CNPJ是否已存在:

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.springframework.beans.factory.annotation.Autowired;
// 导入你的UnityRepository
import com.yourpackage.repository.UnityRepository;

public class UniqueCnpjValidator implements ConstraintValidator<UniqueCNPJ, String> {

    @Autowired
    private UnityRepository unityRepository;

    @Override
    public boolean isValid(String cnpj, ConstraintValidatorContext context) {
        // 空值不做校验,由@NotNull负责
        if (cnpj == null) {
            return true;
        }
        // 查询数据库中是否存在该CNPJ
        return !unityRepository.existsByCnpj(cnpj);
    }
}

你需要提前在UnityRepository中添加查询方法:

boolean existsByCnpj(String cnpj);

步骤3:给字段添加注解

将@UniqueCNPJ注解放到UnityDTO类的cnpj字段上(因为你控制器层校验的是DTO对象):

@CNPJ(message = "O CNPJ é inválido")
@NotNull(message = "Preencha o campo CNPJ")
@UniqueCNPJ(message = "CNPJ já cadastrado no sistema")
private String cnpj;

此时你控制器里的validator.validate方法就可以自动捕获到CNPJ重复的错误,和@NotNull的错误一起返回。

步骤4:添加兜底异常处理(可选但推荐)

为了避免并发场景下,校验通过后、数据插入前其他请求插入了相同CNPJ导致数据库抛出唯一约束异常,建议添加异常捕获,处理数据库层面的唯一约束冲突:
你可以直接在控制器原有逻辑中添加异常捕获:

if (constraintViolations.isEmpty()) {
    try {
        UnityDTO unityDTOPersisted = unityMapper.unityToUnityDTO(unityService.save(unityDTO));
        return Response.fromResponse(createdResponse(unityDTOPersisted.getId(), UnityEndpoint.class)).entity(unityDTOPersisted).build();
    } catch (PersistenceException e) {
        // 判断是否是CNPJ唯一约束冲突,替换为你的实际唯一约束名即可
        if (e.getMessage().contains("unity_cnpj_unique")) {
            Set<String> errors = Set.of("CNPJ já cadastrado no sistema");
            return Response.status(Response.Status.BAD_REQUEST).entity(errors).build();
        }
        throw e;
    }
} else {
    Set<String> errors = constraintViolations.stream().map(ConstraintViolation::getMessage).collect(Collectors.toSet());
    return Response.status(Response.Status.BAD_REQUEST).entity(errors).build();
}

内容的提问来源于stack exchange,提问作者Vitor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 10:30:03