refactor(wms): 优化钢卷list查询速度应对大量itemId
- 引入 CollectionUtils 工具类用于集合判空 - 优化用户昵称映射逻辑,减少不必要的查询 - 使用 EXISTS 子查询替代原有的 IN 查询方式,提升性能 - 重构 item_id 筛选条件组合逻辑,支持更灵活的查询需求 - 新增 buildOrLikeClause 方法统一处理多值模糊匹配条件 - 移除冗余的 queryMatchedItemIds 方法,简化代码结构 - 增强 SQL 注入防护,使用参数化查询替代字符串拼接
This commit is contained in:
@@ -21,6 +21,7 @@ import com.klp.domain.vo.*;
|
||||
import com.klp.mapper.WmsDeliveryPlanMapper;
|
||||
import com.klp.system.service.ISysUserService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.klp.domain.WmsMaterialCoil;
|
||||
@@ -297,28 +298,31 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
|
||||
Page<WmsMaterialCoilVo> result = baseMapper.selectVoPagePlus(pageQuery.build(), qw);
|
||||
|
||||
List<WmsMaterialCoilVo> records = result.getRecords();
|
||||
if (records == null || records.isEmpty()) {
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
Set<String> userNames = records.stream()
|
||||
.flatMap(v -> java.util.stream.Stream.of(v.getCreateBy(), v.getUpdateBy()))
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Map<String, String> nickMap = Collections.emptyMap();
|
||||
if (!userNames.isEmpty()) {
|
||||
Map<String, String> nickMap = userService.selectNickNameMapByUserNames(records.stream()
|
||||
.flatMap(v -> java.util.stream.Stream.of(v.getCreateBy(), v.getUpdateBy()))
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.distinct()
|
||||
.collect(Collectors.toList()));
|
||||
records.forEach(item -> {
|
||||
if (StringUtils.isNotBlank(item.getCreateBy())) {
|
||||
item.setCreateByName(nickMap.getOrDefault(item.getCreateBy(), item.getCreateBy()));
|
||||
}
|
||||
if (StringUtils.isNotBlank(item.getUpdateBy())) {
|
||||
item.setUpdateByName(nickMap.getOrDefault(item.getUpdateBy(), item.getUpdateBy()));
|
||||
}
|
||||
});
|
||||
nickMap = userService.selectNickNameMapByUserNames(new ArrayList<>(userNames));
|
||||
}
|
||||
|
||||
// 从联查结果中构建产品和原材料对象(避免单独查询)
|
||||
for (WmsMaterialCoilVo vo : result.getRecords()) {
|
||||
// 单次遍历:填充创建/更新人昵称,并构建物料/产品对象
|
||||
for (WmsMaterialCoilVo vo : records) {
|
||||
if (!nickMap.isEmpty()) {
|
||||
if (StringUtils.isNotBlank(vo.getCreateBy())) {
|
||||
vo.setCreateByName(nickMap.getOrDefault(vo.getCreateBy(), vo.getCreateBy()));
|
||||
}
|
||||
if (StringUtils.isNotBlank(vo.getUpdateBy())) {
|
||||
vo.setUpdateByName(nickMap.getOrDefault(vo.getUpdateBy(), vo.getUpdateBy()));
|
||||
}
|
||||
}
|
||||
// 从联查结果中构建产品和原材料对象(避免单独查询)
|
||||
buildItemObjectFromJoin(vo);
|
||||
}
|
||||
|
||||
@@ -348,28 +352,14 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
|
||||
}
|
||||
}
|
||||
|
||||
// 组合 item_id 条件:selectType 细粒度筛选 与 显式 itemIds/itemId 的并行支持
|
||||
List<Long> matchedItemIds = null; // 来自 selectType + 多字段筛选
|
||||
if (StringUtils.isNotBlank(bo.getSelectType())) {
|
||||
boolean hasAnyItemFilter = StringUtils.isNotBlank(bo.getItemMaterial())
|
||||
|| StringUtils.isNotBlank(bo.getItemManufacturer())
|
||||
|| StringUtils.isNotBlank(bo.getItemSurfaceTreatmentDesc())
|
||||
|| StringUtils.isNotBlank(bo.getItemZincLayer())
|
||||
|| StringUtils.isNotBlank(bo.getItemName())
|
||||
|| StringUtils.isNotBlank(bo.getItemSpecification());
|
||||
|
||||
if (hasAnyItemFilter) {
|
||||
try {
|
||||
matchedItemIds = queryMatchedItemIds(bo.getSelectType(), bo);
|
||||
} catch (Exception e) {
|
||||
Log.error("筛选产品/原材料ID失败", e);
|
||||
matchedItemIds = Collections.emptyList();
|
||||
}
|
||||
if (matchedItemIds != null) {
|
||||
matchedItemIds = matchedItemIds.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
// 组合 item_id 条件:改为使用 EXISTS 子查询,替代预查询 + IN
|
||||
boolean hasSelectType = StringUtils.isNotBlank(bo.getSelectType());
|
||||
boolean hasAnyItemFilter = StringUtils.isNotBlank(bo.getItemMaterial())
|
||||
|| StringUtils.isNotBlank(bo.getItemManufacturer())
|
||||
|| StringUtils.isNotBlank(bo.getItemSurfaceTreatmentDesc())
|
||||
|| StringUtils.isNotBlank(bo.getItemZincLayer())
|
||||
|| StringUtils.isNotBlank(bo.getItemName())
|
||||
|| StringUtils.isNotBlank(bo.getItemSpecification());
|
||||
|
||||
// 解析显式 itemIds 或单个 itemId
|
||||
List<Long> explicitItemIds = null;
|
||||
@@ -390,25 +380,55 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
|
||||
explicitItemIds = Collections.singletonList(bo.getItemId());
|
||||
}
|
||||
|
||||
// 合并最终 item_id 条件:若两者都有则取交集;仅一者存在则使用那一者
|
||||
List<Long> finalItemIds = null;
|
||||
if (matchedItemIds != null && explicitItemIds != null) {
|
||||
// 交集
|
||||
Set<Long> set = new HashSet<>(explicitItemIds);
|
||||
finalItemIds = matchedItemIds.stream().filter(set::contains).collect(Collectors.toList());
|
||||
} else if (matchedItemIds != null) {
|
||||
finalItemIds = matchedItemIds;
|
||||
} else if (explicitItemIds != null) {
|
||||
finalItemIds = explicitItemIds;
|
||||
// 使用 EXISTS 针对 selectType 的细粒度筛选(使用参数占位符防注入)
|
||||
if (hasSelectType && hasAnyItemFilter) {
|
||||
StringBuilder existsSql = new StringBuilder();
|
||||
List<Object> existsArgs = new ArrayList<>();
|
||||
if ("product".equals(bo.getSelectType())) {
|
||||
existsSql.append(" EXISTS (SELECT 1 FROM wms_product p WHERE p.del_flag = 0 AND p.product_id = mc.item_id");
|
||||
String clause;
|
||||
clause = buildOrLikeClause("p.product_name", bo.getItemName(), existsArgs);
|
||||
if (!clause.isEmpty()) existsSql.append(" AND ").append(clause);
|
||||
clause = buildOrLikeClause("p.material", bo.getItemMaterial(), existsArgs);
|
||||
if (!clause.isEmpty()) existsSql.append(" AND ").append(clause);
|
||||
clause = buildOrLikeClause("p.manufacturer", bo.getItemManufacturer(), existsArgs);
|
||||
if (!clause.isEmpty()) existsSql.append(" AND ").append(clause);
|
||||
clause = buildOrLikeClause("p.surface_treatment_desc", bo.getItemSurfaceTreatmentDesc(), existsArgs);
|
||||
if (!clause.isEmpty()) existsSql.append(" AND ").append(clause);
|
||||
clause = buildOrLikeClause("p.zinc_layer", bo.getItemZincLayer(), existsArgs);
|
||||
if (!clause.isEmpty()) existsSql.append(" AND ").append(clause);
|
||||
clause = buildOrLikeClause("p.specification", bo.getItemSpecification(), existsArgs);
|
||||
if (!clause.isEmpty()) existsSql.append(" AND ").append(clause);
|
||||
existsSql.append(")");
|
||||
} else if ("raw_material".equals(bo.getSelectType())) {
|
||||
existsSql.append(" EXISTS (SELECT 1 FROM wms_raw_material r WHERE r.del_flag = 0 AND r.raw_material_id = mc.item_id");
|
||||
String clause;
|
||||
clause = buildOrLikeClause("r.raw_material_name", bo.getItemName(), existsArgs);
|
||||
if (!clause.isEmpty()) existsSql.append(" AND ").append(clause);
|
||||
clause = buildOrLikeClause("r.material", bo.getItemMaterial(), existsArgs);
|
||||
if (!clause.isEmpty()) existsSql.append(" AND ").append(clause);
|
||||
clause = buildOrLikeClause("r.manufacturer", bo.getItemManufacturer(), existsArgs);
|
||||
if (!clause.isEmpty()) existsSql.append(" AND ").append(clause);
|
||||
clause = buildOrLikeClause("r.surface_treatment_desc", bo.getItemSurfaceTreatmentDesc(), existsArgs);
|
||||
if (!clause.isEmpty()) existsSql.append(" AND ").append(clause);
|
||||
clause = buildOrLikeClause("r.zinc_layer", bo.getItemZincLayer(), existsArgs);
|
||||
if (!clause.isEmpty()) existsSql.append(" AND ").append(clause);
|
||||
clause = buildOrLikeClause("r.specification", bo.getItemSpecification(), existsArgs);
|
||||
if (!clause.isEmpty()) existsSql.append(" AND ").append(clause);
|
||||
existsSql.append(")");
|
||||
}
|
||||
if (existsSql.length() > 0) {
|
||||
qw.apply(existsSql.toString(), existsArgs.toArray());
|
||||
}
|
||||
}
|
||||
|
||||
if (finalItemIds != null) {
|
||||
if (finalItemIds.isEmpty()) {
|
||||
qw.apply("1 = 0");
|
||||
return qw;
|
||||
}
|
||||
// 显式 itemId 条件:与 EXISTS 共存时,语义为交集
|
||||
if (CollectionUtils.isNotEmpty(explicitItemIds)) {
|
||||
qw.isNotNull("mc.item_id");
|
||||
qw.in("mc.item_id", finalItemIds);
|
||||
qw.in("mc.item_id", explicitItemIds);
|
||||
} else if (explicitItemIds != null && explicitItemIds.isEmpty()) {
|
||||
qw.apply("1 = 0");
|
||||
return qw;
|
||||
}
|
||||
// 添加coilIds查询条件,支持逗号分隔的多个coilId查询
|
||||
if (StringUtils.isNotBlank(bo.getCoilIds())) {
|
||||
@@ -454,236 +474,29 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
|
||||
return qw;
|
||||
}
|
||||
|
||||
public List<Long> queryMatchedItemIds(String selectType, WmsMaterialCoilBo bo) {
|
||||
List<Long> result = new ArrayList<>();
|
||||
if ("product".equals(selectType)) {
|
||||
QueryWrapper<WmsProduct> pq = new QueryWrapper<>();
|
||||
pq.eq("del_flag", 0);
|
||||
if (StringUtils.isNotBlank(bo.getItemName())) {
|
||||
String[] vals = bo.getItemName().split(",");
|
||||
if (vals.length == 1) {
|
||||
pq.like("product_name", vals[0].trim());
|
||||
} else {
|
||||
pq.and(wrapper -> {
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
String v = vals[i].trim();
|
||||
if (v.isEmpty()) continue;
|
||||
if (i == 0) {
|
||||
wrapper.like("product_name", v);
|
||||
} else {
|
||||
wrapper.or().like("product_name", v);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getItemMaterial())) {
|
||||
String[] vals = bo.getItemMaterial().split(",");
|
||||
if (vals.length == 1) {
|
||||
pq.like("material", vals[0].trim());
|
||||
} else {
|
||||
pq.and(wrapper -> {
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
String v = vals[i].trim();
|
||||
if (v.isEmpty()) continue;
|
||||
if (i == 0) {
|
||||
wrapper.like("material", v);
|
||||
} else {
|
||||
wrapper.or().like("material", v);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getItemManufacturer())) {
|
||||
String[] vals = bo.getItemManufacturer().split(",");
|
||||
if (vals.length == 1) {
|
||||
pq.like("manufacturer", vals[0].trim());
|
||||
} else {
|
||||
pq.and(wrapper -> {
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
String v = vals[i].trim();
|
||||
if (v.isEmpty()) continue;
|
||||
if (i == 0) {
|
||||
wrapper.like("manufacturer", v);
|
||||
} else {
|
||||
wrapper.or().like("manufacturer", v);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getItemSurfaceTreatmentDesc())) {
|
||||
String[] vals = bo.getItemSurfaceTreatmentDesc().split(",");
|
||||
if (vals.length == 1) {
|
||||
pq.like("surface_treatment_desc", vals[0].trim());
|
||||
} else {
|
||||
pq.and(wrapper -> {
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
String v = vals[i].trim();
|
||||
if (v.isEmpty()) continue;
|
||||
if (i == 0) {
|
||||
wrapper.like("surface_treatment_desc", v);
|
||||
} else {
|
||||
wrapper.or().like("surface_treatment_desc", v);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getItemZincLayer())) {
|
||||
String[] vals = bo.getItemZincLayer().split(",");
|
||||
if (vals.length == 1) {
|
||||
pq.like("zinc_layer", vals[0].trim());
|
||||
} else {
|
||||
pq.and(wrapper -> {
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
String v = vals[i].trim();
|
||||
if (v.isEmpty()) continue;
|
||||
if (i == 0) {
|
||||
wrapper.like("zinc_layer", v);
|
||||
} else {
|
||||
wrapper.or().like("zinc_layer", v);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getItemSpecification())) {
|
||||
String[] specs = bo.getItemSpecification().split(",");
|
||||
if (specs.length == 1) {
|
||||
pq.like("specification", specs[0].trim());
|
||||
} else {
|
||||
pq.and(wrapper -> {
|
||||
for (int i = 0; i < specs.length; i++) {
|
||||
if (i == 0) {
|
||||
wrapper.like("specification", specs[i].trim());
|
||||
} else {
|
||||
wrapper.or().like("specification", specs[i].trim());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
result = productMapper.selectList(pq).stream()
|
||||
.map(WmsProduct::getProductId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
} else if ("raw_material".equals(selectType)) {
|
||||
QueryWrapper<WmsRawMaterial> rq = new QueryWrapper<>();
|
||||
rq.eq("del_flag", 0);
|
||||
if (StringUtils.isNotBlank(bo.getItemName())) {
|
||||
String[] vals = bo.getItemName().split(",");
|
||||
if (vals.length == 1) {
|
||||
rq.like("raw_material_name", vals[0].trim());
|
||||
} else {
|
||||
rq.and(wrapper -> {
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
String v = vals[i].trim();
|
||||
if (v.isEmpty()) continue;
|
||||
if (i == 0) {
|
||||
wrapper.like("raw_material_name", v);
|
||||
} else {
|
||||
wrapper.or().like("raw_material_name", v);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getItemMaterial())) {
|
||||
String[] vals = bo.getItemMaterial().split(",");
|
||||
if (vals.length == 1) {
|
||||
rq.like("material", vals[0].trim());
|
||||
} else {
|
||||
rq.and(wrapper -> {
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
String v = vals[i].trim();
|
||||
if (v.isEmpty()) continue;
|
||||
if (i == 0) {
|
||||
wrapper.like("material", v);
|
||||
} else {
|
||||
wrapper.or().like("material", v);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getItemManufacturer())) {
|
||||
String[] vals = bo.getItemManufacturer().split(",");
|
||||
if (vals.length == 1) {
|
||||
rq.like("manufacturer", vals[0].trim());
|
||||
} else {
|
||||
rq.and(wrapper -> {
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
String v = vals[i].trim();
|
||||
if (v.isEmpty()) continue;
|
||||
if (i == 0) {
|
||||
wrapper.like("manufacturer", v);
|
||||
} else {
|
||||
wrapper.or().like("manufacturer", v);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getItemSurfaceTreatmentDesc())) {
|
||||
String[] vals = bo.getItemSurfaceTreatmentDesc().split(",");
|
||||
if (vals.length == 1) {
|
||||
rq.like("surface_treatment_desc", vals[0].trim());
|
||||
} else {
|
||||
rq.and(wrapper -> {
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
String v = vals[i].trim();
|
||||
if (v.isEmpty()) continue;
|
||||
if (i == 0) {
|
||||
wrapper.like("surface_treatment_desc", v);
|
||||
} else {
|
||||
wrapper.or().like("surface_treatment_desc", v);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getItemZincLayer())) {
|
||||
String[] vals = bo.getItemZincLayer().split(",");
|
||||
if (vals.length == 1) {
|
||||
rq.like("zinc_layer", vals[0].trim());
|
||||
} else {
|
||||
rq.and(wrapper -> {
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
String v = vals[i].trim();
|
||||
if (v.isEmpty()) continue;
|
||||
if (i == 0) {
|
||||
wrapper.like("zinc_layer", v);
|
||||
} else {
|
||||
wrapper.or().like("zinc_layer", v);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getItemSpecification())) {
|
||||
String[] specs = bo.getItemSpecification().split(",");
|
||||
if (specs.length == 1) {
|
||||
rq.like("specification", specs[0].trim());
|
||||
} else {
|
||||
rq.and(wrapper -> {
|
||||
for (int i = 0; i < specs.length; i++) {
|
||||
if (i == 0) {
|
||||
wrapper.like("specification", specs[i].trim());
|
||||
} else {
|
||||
wrapper.or().like("specification", specs[i].trim());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
result = rawMaterialMapper.selectList(rq).stream()
|
||||
.map(WmsRawMaterial::getRawMaterialId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
/**
|
||||
* 构建 OR 连接的 LIKE 子句,使用 MyBatis-Plus apply 的 {index} 占位符并将参数加入 args。
|
||||
* 例如:column = "p.product_name", values = "A,B" -> 返回 "(p.product_name LIKE {0} OR p.product_name LIKE {1})"
|
||||
* 同时往 args 追加 "%A%", "%B%"。
|
||||
*/
|
||||
private String buildOrLikeClause(String column, String csvValues, List<Object> args) {
|
||||
if (StringUtils.isBlank(csvValues)) {
|
||||
return "";
|
||||
}
|
||||
return result;
|
||||
String[] vals = csvValues.split(",");
|
||||
List<String> parts = new ArrayList<>();
|
||||
for (String raw : vals) {
|
||||
if (raw == null) continue;
|
||||
String v = raw.trim();
|
||||
if (v.isEmpty()) continue;
|
||||
int idx = args.size();
|
||||
parts.add(column + " LIKE {" + idx + "}");
|
||||
args.add('%' + v + '%');
|
||||
}
|
||||
if (parts.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return '(' + String.join(" OR ", parts) + ')';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user