|---------------------|
| 🎈边走、边悟🎈迟早会好 |
根据业务需求,将修改校验服务,使其支持动态校验一个或多个字段的组合唯一性。以下是改进后的代码实现:
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@Service
public class UniqueValidatorService {
@PersistenceContext
private EntityManager entityManager;
/**
* 校验多个字段的组合在数据库中是否唯一
* @param tableName 表名
* @param uniqueFields 需校验唯一性的字段名和值的映射
* @return 如果唯一返回true,否则返回false
*/
@Transactional(readOnly = true)
public boolean validateUnique(String tableName, Map<String, Object> uniqueFields) {
if (!StringUtils.hasText(tableName) || uniqueFields == null || uniqueFields.isEmpty()) {
throw new IllegalArgumentException("表名和校验字段不能为空");
}
// 构建动态查询语句
StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM ").append(tableName);
StringBuilder whereClause = new StringBuilder(" WHERE ");
Map<String, Object> parameters = new HashMap<>();
int index = 0;
for (Map.Entry<String, Object> entry : uniqueFields.entrySet()) {
String field = entry.getKey();
Object value = entry.getValue();
if (!StringUtils.hasText(field) || value == null) {
throw new IllegalArgumentException("字段名和值不能为空");
}
if (index > 0) {
whereClause.append(" AND ");
}
whereClause.append(field).append(" = :").append(field.replace(".", "_"));
parameters.put(field.replace(".", "_"), value);
index++;
}
sql.append(whereClause);
try {
Long count = entityManager.createNativeQuery(sql.toString(), Long.class)
.unwrap(org.hibernate.query.NativeQuery.class)
.setParameterMapping(parameters)
.getSingleResult();
return count == 0;
} catch (NoResultException e) {
return true; // 没有结果表示唯一
} catch (Exception e) {
// 记录日志并处理异常
throw new RuntimeException("唯一性校验失败", e);
}
}
}
使用示例
java
@RestController
@RequestMapping("/api")
public class MyController {
@Autowired
private UniqueValidatorService validatorService;
@PostMapping("/data")
public ResponseEntity<?> createData(@RequestBody MyData data) {
// 校验字段A和字段B的组合是否唯一
Map<String, Object> uniqueFields = new HashMap<>();
uniqueFields.put("field_a", data.getFieldA());
uniqueFields.put("field_b", data.getFieldB());
// 可根据需要添加更多字段
// uniqueFields.put("field_c", data.getFieldC());
boolean isUnique = validatorService.validateUnique("my_table", uniqueFields);
if (!isUnique) {
return ResponseEntity.badRequest().body("字段组合已存在");
}
// 保存数据的逻辑
return ResponseEntity.ok().build();
}
}
自定义注解增强版(可选)
为了让校验更加简洁优雅,可以创建支持多字段的自定义注解:
java
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueFieldsValidator.class)
@Documented
public @interface UniqueFields {
String message() default "字段组合不唯一";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String tableName();
String[] fields();
}
java
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class UniqueFieldsValidator implements ConstraintValidator<UniqueFields, Object> {
@Autowired
private UniqueValidatorService validatorService;
private String tableName;
private String[] fields;
@Override
public void initialize(UniqueFields constraintAnnotation) {
this.tableName = constraintAnnotation.tableName();
this.fields = constraintAnnotation.fields();
}
@Override
public boolean isValid(Object obj, ConstraintValidatorContext context) {
if (obj == null) {
return true;
}
Map<String, Object> uniqueFields = new HashMap<>();
for (String fieldName : fields) {
try {
Field field = getField(obj.getClass(), fieldName);
if (field != null) {
field.setAccessible(true);
uniqueFields.put(fieldName, field.get(obj));
}
} catch (Exception e) {
throw new RuntimeException("获取字段值失败", e);
}
}
return validatorService.validateUnique(tableName, uniqueFields);
}
private Field getField(Class<?> clazz, String fieldName) {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && !superClass.equals(Object.class)) {
return getField(superClass, fieldName);
}
return null;
}
}
}
实体类使用注解
java
@Entity
@Table(name = "my_table")
@UniqueFields(tableName = "my_table", fields = {"fieldA", "fieldB"})
public class MyData {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "field_a")
private String fieldA;
@Column(name = "field_b")
private String fieldB;
// getters and setters
}
这个改进后的实现可以灵活支持校验一个或多个字段的组合唯一性,通过 Map 参数动态指定需要校验的字段,同时提供了自定义注解的高级用法,使代码更加简洁和类型安全。
🌟感谢支持 听忆.-CSDN博客
|--------------------|
| 🎈众口难调🎈从心就好 |