package com.smartor.service.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.google.gson.Gson; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.http.HttpUtils; import com.smartor.domain.Icd10; import com.smartor.mapper.Icd10Mapper; import com.smartor.service.IIcd10Service; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.*; import java.util.stream.Collectors; /** * 疾病Service业务层处理 * * @author ruoyi * @date 2023-12-21 */ @Slf4j @Service public class Icd10ServiceImpl implements IIcd10Service { @Autowired private Icd10Mapper icd10Mapper; @Value("${sltd_pub_path}") private String sltdPubPath; @Value("${lwl_app_key}") private String APP_KEY; /** * 固定 orgId */ private static final long ORG_ID = 20001001L; /** * 每页拉取条数(接口最大允许 1000) */ private static final int PAGE_SIZE = 1000; /** * 批量写入单批最大条数 */ private static final int BATCH_SIZE = 500; /** * 查询疾病 * * @param icdid 疾病主键 * @return 疾病 */ @Override public Icd10 selectIcd10ByIcdid(Long icdid) { return icd10Mapper.selectIcd10ByIcdid(icdid); } /** * 查询疾病列表 * * @param icd10 疾病 * @return 疾病 */ @Override public List selectIcd10List(Icd10 icd10) { return icd10Mapper.selectIcd10List(icd10); } /** * 新增疾病 * * @param icd10 疾病 * @return 结果 */ @Override public int insertIcd10(Icd10 icd10) { icd10.setCreateTime(DateUtils.getNowDate()); return icd10Mapper.insertIcd10(icd10); } /** * 修改疾病 * * @param icd10 疾病 * @return 结果 */ @Override public int updateIcd10(Icd10 icd10) { icd10.setUpdateTime(DateUtils.getNowDate()); return icd10Mapper.updateIcd10(icd10); } /** * 批量删除疾病 * * @param icdids 需要删除的疾病主键 * @return 结果 */ @Override public int deleteIcd10ByIcdids(Long[] icdids) { return icd10Mapper.deleteIcd10ByIcdids(icdids); } /** * 删除疾病信息 * * @param icdid 疾病主键 * @return 结果 */ @Override public int deleteIcd10ByIcdid(Long icdid) { return icd10Mapper.deleteIcd10ByIcdid(icdid); } /** * 从远程接口(来未来)分页拉取并增量写入 icd10 表。 *

* 优化要点: * 1. 每页最大拉取 1000 条,减少请求次数。 * 2. 每页把当前页所有 icdcode 用一条 IN SQL 一次批量查库,避免循环 N 次单条查询。 * 3. 将不存在的记录收集后分批(每批 500 条)批量插入。 *

* * @return 本次运行新增总条数 */ @Override public int queryAddIcd10() { int totalInserted = 0; long current = 1; long totalPages = 1; // 首次循环前先执行一次 log.info("[开始] 从来未来拉取 ICD10 增量数据,orgId={}", ORG_ID); do { // 构建请求体 Map requestBody = new HashMap<>(); requestBody.put("orgId", ORG_ID); requestBody.put("searchText", ""); requestBody.put("size", PAGE_SIZE); requestBody.put("current", current); String responseStr; try { Map headers = buildRequestHeaders(); responseStr = HttpUtils.sendPostByHeader(sltdPubPath + "/hbos-thirdparty-integration/standard/base/dtc/pageDiagnosisDict", new Gson().toJson(requestBody), headers); } catch (Exception e) { log.error("[第{}页] 请求来未来接口失败", current, e); break; } if (responseStr == null || responseStr.isEmpty()) { log.warn("[第{}页] 接口返回空,停止采集", current); break; } JSONObject resp = JSON.parseObject(responseStr); if (resp == null || !Boolean.TRUE.equals(resp.getBoolean("success"))) { log.error("[第{}页] 接口返回失败:{}", current, responseStr); break; } JSONObject data = resp.getJSONObject("data"); if (data == null) { break; } // 计算总页数 long total = data.getLongValue("total"); long pageSize = data.getLongValue("size"); if (pageSize <= 0) { break; } totalPages = (total + pageSize - 1) / pageSize; JSONArray records = data.getJSONArray("records"); if (records == null || records.isEmpty()) { break; } log.info("[第{}/{}页] 获取 {} 条记录,总{}条", current, totalPages, records.size(), total); // 解析当前页数据 List pageNames = new ArrayList<>(); List pageList = new ArrayList<>(); for (int i = 0; i < records.size(); i++) { JSONObject rec = records.getJSONObject(i); String icdCode = rec.getString("icdCode"); if (icdCode == null || icdCode.isEmpty()) { continue; } String icdName = StringUtils.isEmpty(rec.getString("name")) ? null : rec.getString("name").trim(); if (icdName == null || icdName.isEmpty()) { continue; } pageNames.add(icdName); Icd10 icd10 = new Icd10(); icd10.setIcdcode(icdCode); icd10.setIcdname(icdName); icd10.setIcdpym(rec.getString("pinyin")); icd10.setHisIcdid(rec.getString("his_icdid")); icd10.setOrgid(String.valueOf(ORG_ID)); icd10.setDelFlag("0"); icd10.setCreateTime(DateUtils.getNowDate()); pageList.add(icd10); } if (pageNames.isEmpty()) { current++; continue; } // 一次 IN 查库,获取已存在的 icdname(核心去重优化点)南华附一的icdname不会重复,icd10code会重复 Set existingNames = new HashSet<>(icd10Mapper.selectExistingIcdcodes(pageNames)); // 过滤出不存在的记录 List newList = pageList.stream().filter(item -> !existingNames.contains(item.getIcdname())).collect(Collectors.toList()); log.info("[第{}/{}页] 当前页共 {} 条,已存在 {} 条,需新入库 {} 条", current, totalPages, pageList.size(), existingNames.size(), newList.size()); // 分批批量插入 int inserted = batchInsert(newList); totalInserted += inserted; current++; } while (current <= totalPages); log.info("[完成] ICD10 增量采集结束,本次共新增 {} 条", totalInserted); return totalInserted; } /** * 分批批量插入,每批最大 BATCH_SIZE 条 */ private int batchInsert(List list) { if (list == null || list.isEmpty()) { return 0; } int total = 0; int size = list.size(); for (int start = 0; start < size; start += BATCH_SIZE) { int end = Math.min(start + BATCH_SIZE, size); total += icd10Mapper.batchIcd10(list.subList(start, end)); } return total; } private Map buildRequestHeaders() { Map headers = new HashMap<>(); headers.put("Content-Type", "application/json"); headers.put("app-key", APP_KEY); return headers; } }