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

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

相关推荐
爬虫程序猿5 分钟前
如何利用 Java 爬虫按关键字搜索 Amazon 商品:实战指南
java·开发语言·爬虫
AI+程序员在路上1 小时前
ABI与API定义及区别
c语言·开发语言·c++
风之旅人1 小时前
开发必备"节假日接口"
java·后端·开源
2201_753169471 小时前
implement用法
java·开发语言
云和恩墨2 小时前
国网某省电力借zDBM重构数据库容灾防线,400TB核心资产迈入分布式实时保护时代
数据库·分布式·重构
大千AI助手2 小时前
ER图:数据库设计的可视化语言 - 搞懂数据关系的基石
数据库
不会编程的阿成2 小时前
spring aop的概念与实战以及面试项目题
java·spring·面试
李强57627822 小时前
语法制导的语义计算(包含python源码)
java·数据库·python
企销客CRM2 小时前
企微CRM系统中的任务分配与效率提升技巧
大数据·数据库·人工智能·数据分析·企业微信