springboot+mybatisPlus 开发 新增数据是进行是否重复校验

我们进行CRUD是经常需要判断新增数据是否重复,以下是校验工具类:

package com.minex.web.assets.util;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.IService;
import com.minex.common.exception.ExceptionFactory;
import com.minex.web.common.util.SecurityUtils;
import com.minex.web.tenant.service.TenantService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 资产名称重复校验工具类
 *
 * @author gch
 * @since 2025-05-06
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class AssetNameDuplicateChecker {

    private final TenantService tenantService;

    /**
     * 检查Excel中名称是否重复
     *
     * @param name 名称
     * @param excelNames Excel中的名称集合
     * @param rowIndex 当前行号
     * @return 错误信息,如果为null则表示没有重复
     */
    public String checkExcelDuplicate(String name, Set<String> excelNames, int rowIndex) {
        if (excelNames.contains(name)) {
            return String.format("第%d行名称[%s]在Excel中重复", rowIndex, name);
        }
        excelNames.add(name);
        return null;
    }

    /**
     * 检查数据库中名称是否重复
     *
     * @param name 名称
     * @param dbNames 数据库中的名称集合
     * @param rowIndex 当前行号
     * @return 错误信息,如果为null则表示没有重复
     */
    public String checkDbDuplicate(String name, Set<String> dbNames, int rowIndex) {
        if (dbNames.contains(name)) {
            return String.format("第%d行名称[%s]在数据库中已存在", rowIndex, name);
        }
        return null;
    }

    /**
     * 检查保存或更新时名称是否重复
     *
     * @param service        服务类
     * @param name           名称
     * @param id             主键ID(更新时使用)
     * @param assetType      资产类型(用于错误提示)
     * @param nameGetter     名称字段的getter方法引用
     * @param firmCodeGetter 公司编码字段的getter方法引用
     * @param idGetter       ID字段的getter方法引用
     * @param <T>            实体类型
     */
    public <T> void checkSaveOrUpdateDuplicate(IService<T> service, String name, Long id, String assetType,
                                               SFunction<T, String> nameGetter,
                                               SFunction<T, String> firmCodeGetter,
                                               SFunction<T, Long> idGetter, String firmCode) {
        LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(nameGetter, name)
                .eq(firmCodeGetter, firmCode);
        if (id != null) {
            wrapper.ne(idGetter, id);
        }
        if (service.count(wrapper) > 0) {
            throw ExceptionFactory.bizException(assetType + "名称已存在");
        }
    }

    /**
     * 校验保存或更新时是否存在重复数据(支持多个字段的“或”逻辑校验)
     *
     * @param service             服务接口
     * @param id                  ID(用于排除当前记录)
     * @param assetType           资产类型(用于异常提示)
     * @param firmCodeGetter      租户代码字段的 getter
     * @param idGetter            ID 字段的 getter
     * @param fieldMap            字段 Map(格式:字段 getter -> 字段值),支持“或”逻辑校验
     */
    public <T> void checkSaveOrUpdateDuplicate(
            IService<T> service,
            Long id,
            String assetType,
            SFunction<T, String> firmCodeGetter,
            SFunction<T, Long> idGetter,
            Map<SFunction<T, Object>, Object> fieldMap,
            String firmCode
    ) {
        // 构建查询条件
        LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();
        // 必须满足的租户条件
        wrapper.eq(firmCodeGetter, firmCode);
        // 添加额外字段的 OR 条件(包裹在同一个括号内)
        if (fieldMap != null && !fieldMap.isEmpty()) {
            wrapper.and(wrapper1 -> {
                for (Map.Entry<SFunction<T, Object>, Object> entry : fieldMap.entrySet()) {
                    wrapper1.or().eq(entry.getKey(), entry.getValue());
                }
            });
        }
        // 排除当前记录(更新场景)
        if (id != null) {
            wrapper.ne(idGetter, id);
        }
        // 校验是否存在重复数据
        if (service.count(wrapper) > 0) {
            throw ExceptionFactory.bizException(assetType + "信息已存在");
        }
    }

    /**
     * 初始化数据库中的名称集合
     *
     * @param service 服务类
     * @param nameGetter 名称字段的getter方法引用
     * @param firmCodeGetter 公司编码字段的getter方法引用
     * @param <T> 实体类型
     * @return 数据库中的名称集合
     */
    public <T> Set<String> initDbNames(IService<T> service,
            SFunction<T, String> nameGetter,
            SFunction<T, String> firmCodeGetter) {
        Set<String> dbNames = new HashSet<>();
        String firmCode = tenantService.getUserSelectedTenantInfo(SecurityUtils.getLoginUser()).getCode();
        Collection<T> list = service.lambdaQuery()
                .eq(firmCodeGetter, firmCode)
                .list();
        if (CollectionUtil.isNotEmpty(list)) {
            list.forEach(item -> {
                try {
                    String name = nameGetter.apply(item);
                    if (name != null) {
                        dbNames.add(name);
                    }
                } catch (Exception e) {
                    // 忽略异常
                    log.error("初始化数据库中的名称集合时发生异常", e);
                }
            });
        }
        return dbNames;
    }
}

 

调用 checkSaveOrUpdateDuplicate 方法进行多个字段校验

 

使用示例:

@Override
    public void validateAndSave(FaultIndicator info) {
        Map<SFunction<FaultIndicator, Object>, Object> fieldMap = new HashMap<>();
        fieldMap.put(FaultIndicator::getAssetsName, info.getAssetsName());
        if (StrUtil.isNotEmpty(info.getCode())) {
            fieldMap.put(FaultIndicator::getCode, info.getCode());
        }
        assetNameDuplicateChecker.checkSaveOrUpdateDuplicate(this,
                info.getId(),
                "故障指示器",
                FaultIndicator::getFirmCode,
                FaultIndicator::getId,
                fieldMap,
                tenantService.getUserSelectedTenantInfo(SecurityUtils.getLoginUser()).getCode());
        this.saveOrUpdate(info);
    }

 

posted @ 2025-06-11 16:09  官萧何  阅读(56)  评论(0)    收藏  举报