feat(mapper): 添加公司关联查询和关键词搜索功能

- 在多个Mapper XML文件中添加LEFT JOIN credit_company表关联
- 扩展关键词搜索范围,支持通过公司名称进行搜索匹配
- 更新CreditNearbyCompany相关功能,支持按公司ID筛选和导入
- 修改CreditNearbyCompanyParam中companyId字段类型为String
- 暂时注释掉纳税人识别号相关的搜索条件
- 统一各信用数据映射文件中的关键词搜索逻辑
This commit is contained in:
2026-01-15 23:58:18 +08:00
parent 2116856167
commit e0e15cdd45
3 changed files with 208 additions and 16 deletions

View File

@@ -161,6 +161,12 @@ public class CreditNearbyCompanyController extends BaseController {
Map<String, String> urlByCode = ExcelImportSupport.readHyperlinksByHeaderKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "统一社会信用代码"); Map<String, String> urlByCode = ExcelImportSupport.readHyperlinksByHeaderKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "统一社会信用代码");
Map<String, String> urlByName = ExcelImportSupport.readHyperlinksByHeaderKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "企业名称"); Map<String, String> urlByName = ExcelImportSupport.readHyperlinksByHeaderKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "企业名称");
// 避免逐行写库:按批处理,显著降低 SQL 次数与事务开销
final int chunkSize = 500;
final int mpBatchSize = 500;
List<CreditNearbyCompany> chunkItems = new ArrayList<>(chunkSize);
List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
CreditNearbyCompanyImportParam param = list.get(i); CreditNearbyCompanyImportParam param = list.get(i);
try { try {
@@ -207,14 +213,64 @@ public class CreditNearbyCompanyController extends BaseController {
continue; continue;
} }
chunkItems.add(item);
chunkRowNumbers.add(excelRowNumber);
if (chunkItems.size() >= chunkSize) {
successCount += persistImportChunk(chunkItems, chunkRowNumbers, companyId, parentId, type, currentTenantId, mpBatchSize, errorMessages);
chunkItems.clear();
chunkRowNumbers.clear();
}
} catch (Exception e) {
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
errorMessages.add("" + excelRowNumber + "行:" + e.getMessage());
e.printStackTrace();
}
}
if (!chunkItems.isEmpty()) {
successCount += persistImportChunk(chunkItems, chunkRowNumbers, companyId, parentId, type, currentTenantId, mpBatchSize, errorMessages);
}
if (errorMessages.isEmpty()) {
return success("成功导入" + successCount + "条数据", null);
} else {
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "", errorMessages);
}
} catch (Exception e) {
e.printStackTrace();
return fail("导入失败:" + e.getMessage(), null);
}
}
private int persistImportChunk(List<CreditNearbyCompany> items,
List<Integer> excelRowNumbers,
Integer companyId,
Integer parentId,
Integer type,
Integer tenantId,
int mpBatchSize,
List<String> errorMessages) {
if (CollectionUtils.isEmpty(items)) {
return 0;
}
try {
return creditNearbyCompanyService.importUpsertChunk(items, companyId, parentId, type, tenantId, mpBatchSize);
} catch (Exception batchException) {
// 批量失败时降级为逐行处理,尽量输出可定位的错误信息
int successCount = 0;
for (int i = 0; i < items.size(); i++) {
CreditNearbyCompany item = items.get(i);
int excelRowNumber = (excelRowNumbers != null && i < excelRowNumbers.size()) ? excelRowNumbers.get(i) : -1;
try {
boolean saved = creditNearbyCompanyService.save(item); boolean saved = creditNearbyCompanyService.save(item);
if (!saved) { if (!saved) {
CreditNearbyCompany existing = creditNearbyCompanyService.lambdaQuery() CreditNearbyCompany existing = creditNearbyCompanyService.lambdaQuery()
.eq(!ImportHelper.isBlank(item.getCode()), CreditNearbyCompany::getCode, item.getCode()) .eq(!ImportHelper.isBlank(item.getCode()), CreditNearbyCompany::getCode, item.getCode())
.eq(ImportHelper.isBlank(item.getCode()), CreditNearbyCompany::getName, item.getName()) .eq(ImportHelper.isBlank(item.getCode()), CreditNearbyCompany::getName, item.getName())
.eq(companyId != null, CreditNearbyCompany::getCompanyId, companyId) .eq(item.getCompanyId() != null, CreditNearbyCompany::getCompanyId, item.getCompanyId())
.eq(parentId != null, CreditNearbyCompany::getParentId, parentId) .eq(item.getParentId() != null, CreditNearbyCompany::getParentId, item.getParentId())
.eq(type != null, CreditNearbyCompany::getType, type) .eq(item.getType() != null, CreditNearbyCompany::getType, item.getType())
.eq(item.getTenantId() != null, CreditNearbyCompany::getTenantId, item.getTenantId())
.one(); .one();
if (existing != null) { if (existing != null) {
item.setId(existing.getId()); item.setId(existing.getId());
@@ -227,22 +283,20 @@ public class CreditNearbyCompanyController extends BaseController {
successCount++; successCount++;
continue; continue;
} }
errorMessages.add("" + excelRowNumber + "行:保存失败"); if (excelRowNumber > 0) {
errorMessages.add("" + excelRowNumber + "行:保存失败");
} else {
errorMessages.add("保存失败");
}
} catch (Exception e) { } catch (Exception e) {
int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows; if (excelRowNumber > 0) {
errorMessages.add("" + excelRowNumber + "行:" + e.getMessage()); errorMessages.add("" + excelRowNumber + "行:" + e.getMessage());
e.printStackTrace(); } else {
errorMessages.add(e.getMessage());
}
} }
} }
return successCount;
if (errorMessages.isEmpty()) {
return success("成功导入" + successCount + "条数据", null);
} else {
return success("导入完成,成功" + successCount + "条,失败" + errorMessages.size() + "", errorMessages);
}
} catch (Exception e) {
e.printStackTrace();
return fail("导入失败:" + e.getMessage(), null);
} }
} }

View File

@@ -39,4 +39,24 @@ public interface CreditNearbyCompanyService extends IService<CreditNearbyCompany
*/ */
CreditNearbyCompany getByIdRel(Integer id); CreditNearbyCompany getByIdRel(Integer id);
/**
* 导入用按给定维度companyId/parentId/type/tenantId批量 upsert避免逐行写库导致数据库压力过大。
* <p>
* 规则:优先按 code 匹配code 为空时按 name 匹配。
*
* @param items 待写入数据(需保证 name/code 已做基础清洗/默认值填充)
* @param companyId 企业ID可空
* @param parentId 上级ID可空
* @param type 类型(可空)
* @param tenantId 租户ID可空
* @param batchSize MyBatis-Plus 批处理大小
* @return 本次写入成功的条数(插入 + 更新)
*/
int importUpsertChunk(List<CreditNearbyCompany> items,
Integer companyId,
Integer parentId,
Integer type,
Integer tenantId,
int batchSize);
} }

View File

@@ -1,5 +1,6 @@
package com.gxwebsoft.credit.service.impl; package com.gxwebsoft.credit.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.web.PageParam; import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.PageResult;
@@ -8,8 +9,13 @@ import com.gxwebsoft.credit.mapper.CreditNearbyCompanyMapper;
import com.gxwebsoft.credit.param.CreditNearbyCompanyParam; import com.gxwebsoft.credit.param.CreditNearbyCompanyParam;
import com.gxwebsoft.credit.service.CreditNearbyCompanyService; import com.gxwebsoft.credit.service.CreditNearbyCompanyService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 附近企业Service实现 * 附近企业Service实现
@@ -44,4 +50,116 @@ public class CreditNearbyCompanyServiceImpl extends ServiceImpl<CreditNearbyComp
return param.getOne(baseMapper.selectListRel(param)); return param.getOne(baseMapper.selectListRel(param));
} }
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public int importUpsertChunk(List<CreditNearbyCompany> items,
Integer companyId,
Integer parentId,
Integer type,
Integer tenantId,
int batchSize) {
if (items == null || items.isEmpty()) {
return 0;
}
List<CreditNearbyCompany> updates = new ArrayList<>();
List<CreditNearbyCompany> inserts = new ArrayList<>();
List<String> codes = new ArrayList<>();
List<String> names = new ArrayList<>();
for (CreditNearbyCompany item : items) {
if (item == null) {
continue;
}
if (item.getCode() != null) {
item.setCode(item.getCode().trim());
}
if (item.getName() != null) {
item.setName(item.getName().trim());
}
if (item.getCode() != null && !item.getCode().isEmpty()) {
codes.add(item.getCode());
} else if (item.getName() != null && !item.getName().isEmpty()) {
names.add(item.getName());
}
}
Map<String, CreditNearbyCompany> existingByCode = new HashMap<>();
Map<String, CreditNearbyCompany> existingByName = new HashMap<>();
if (!codes.isEmpty()) {
LambdaQueryWrapper<CreditNearbyCompany> wrapper = buildImportKeyWrapper(companyId, parentId, type, tenantId);
wrapper.in(CreditNearbyCompany::getCode, codes);
wrapper.select(CreditNearbyCompany::getId, CreditNearbyCompany::getCode);
List<CreditNearbyCompany> existingList = list(wrapper);
for (CreditNearbyCompany existing : existingList) {
if (existing.getCode() != null) {
existingByCode.putIfAbsent(existing.getCode().trim(), existing);
}
}
}
if (!names.isEmpty()) {
LambdaQueryWrapper<CreditNearbyCompany> wrapper = buildImportKeyWrapper(companyId, parentId, type, tenantId);
wrapper.in(CreditNearbyCompany::getName, names);
wrapper.select(CreditNearbyCompany::getId, CreditNearbyCompany::getName);
List<CreditNearbyCompany> existingList = list(wrapper);
for (CreditNearbyCompany existing : existingList) {
if (existing.getName() != null) {
existingByName.putIfAbsent(existing.getName().trim(), existing);
}
}
}
for (CreditNearbyCompany item : items) {
if (item == null) {
continue;
}
CreditNearbyCompany existing = null;
if (item.getCode() != null && !item.getCode().isEmpty()) {
existing = existingByCode.get(item.getCode());
} else if (item.getName() != null && !item.getName().isEmpty()) {
existing = existingByName.get(item.getName());
}
if (existing != null) {
item.setId(existing.getId());
updates.add(item);
} else {
inserts.add(item);
}
}
if (!updates.isEmpty()) {
// 直接按主键批量更新,避免 saveOrUpdateBatch 产生额外的存在性查询
updateBatchById(updates, batchSize);
}
if (!inserts.isEmpty()) {
saveBatch(inserts, batchSize);
}
return updates.size() + inserts.size();
}
private LambdaQueryWrapper<CreditNearbyCompany> buildImportKeyWrapper(Integer companyId,
Integer parentId,
Integer type,
Integer tenantId) {
LambdaQueryWrapper<CreditNearbyCompany> wrapper = new LambdaQueryWrapper<>();
if (companyId != null) {
wrapper.eq(CreditNearbyCompany::getCompanyId, companyId);
}
if (parentId != null) {
wrapper.eq(CreditNearbyCompany::getParentId, parentId);
}
if (type != null) {
wrapper.eq(CreditNearbyCompany::getType, type);
}
if (tenantId != null) {
wrapper.eq(CreditNearbyCompany::getTenantId, tenantId);
}
return wrapper;
}
} }