Java修改接口 校验一个或多个字段不可重复(自定义注解)

|---------------------|
| 🎈边走、边悟🎈迟早会好 |

根据业务需求,将修改校验服务,使其支持动态校验一个或多个字段的组合唯一性。以下是改进后的代码实现:

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博客

|--------------------|
| 🎈众口难调🎈从心就好 |

相关推荐
lixzest几秒前
C++ Lambda 表达式详解
服务器·开发语言·c++·算法
丶小鱼丶7 分钟前
链表算法之【合并两个有序链表】
java·算法·链表
沉默媛23 分钟前
如何安装python以及jupyter notebook
开发语言·python·jupyter
TDengine (老段)28 分钟前
TDengine 数据库建模最佳实践
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
张先shen35 分钟前
Elasticsearch RESTful API入门:全文搜索实战(Java版)
java·大数据·elasticsearch·搜索引擎·全文检索·restful
Elastic 中国社区官方博客38 分钟前
Elasticsearch 字符串包含子字符串:高级查询技巧
大数据·数据库·elasticsearch·搜索引擎·全文检索·lucene
_Chipen1 小时前
C++基础问题
开发语言·c++
Gauss松鼠会1 小时前
GaussDB应用场景全景解析:从金融核心到物联网的分布式数据库实践
数据库·分布式·物联网·金融·database·gaussdb
天河归来1 小时前
springboot框架redis开启管道批量写入数据
java·spring boot·redis
止观止1 小时前
JavaScript对象创建9大核心技术解析
开发语言·javascript·ecmascript