如何为@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
相关产品推荐
相关产品推荐

