package com.vincent.rsf.server.manager.utils; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.vincent.rsf.framework.common.Cools; import com.vincent.rsf.framework.common.SpringUtils; import com.vincent.rsf.server.common.service.RedisService; import com.vincent.rsf.server.common.domain.PageResult; import com.vincent.rsf.server.manager.entity.Companys; import com.vincent.rsf.server.manager.entity.Warehouse; import com.vincent.rsf.server.manager.entity.WarehouseAreas; import com.vincent.rsf.server.manager.service.*; import com.vincent.rsf.server.system.constant.DictTypeCode; import com.vincent.rsf.server.system.entity.DictData; import com.vincent.rsf.server.system.entity.User; import com.vincent.rsf.server.system.service.*; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; public class buildPageRowsUtils { private static final String USER_NAME_CACHE_FLAG = "PAGE_ROWS_USER_NAME"; private static final String WAREHOUSE_NAME_CACHE_FLAG = "PAGE_ROWS_WAREHOUSE_NAME"; private static final String COMPANY_NAME_CACHE_FLAG = "PAGE_ROWS_COMPANY_NAME"; private static final String DICT_LABEL_CACHE_FLAG = "PAGE_ROWS_DICT_LABEL"; private static final String ENTITY_FIELD_CACHE_FLAG = "PAGE_ROWS_ENTITY_FIELD"; private static final int NAME_CACHE_TTL_SECONDS = 300; private static final Consumer> NO_OP_ENRICHER = records -> { }; private static final List COMMON_ID_FIELD_MAPPINGS = List.of( new IdFieldMapping("tenantId", "tenantId$", TenantService.class, "name"), new IdFieldMapping("deptId", "deptId$", DeptService.class, "name"), new IdFieldMapping("dictTypeId", "dictTypeId$", DictTypeService.class, "name"), new IdFieldMapping("userId", "userId$", UserService.class, "nickname"), new IdFieldMapping("root", "root$", UserService.class, "username"), new IdFieldMapping("warehouseId", "warehouseId$", WarehouseService.class, "name"), new IdFieldMapping("warehouse", "warehouse$", WarehouseService.class, "name"), new IdFieldMapping("area", "area$", WarehouseAreasService.class, "name"), new IdFieldMapping("areaId", "areaId$", WarehouseAreasService.class, "name"), new IdFieldMapping("shipperId", "shipperId$", CompanysService.class, "name"), new IdFieldMapping("supplierId", "supplierId$", CompanysService.class, "name"), new IdFieldMapping("splrId", "splrId$", CompanysService.class, "name"), new IdFieldMapping("groupId", "groupId$", MatnrGroupService.class, "name"), new IdFieldMapping("locId", "locId$", LocService.class, "code"), new IdFieldMapping("locTypeId", "locTypeId$", LocTypeService.class, "name") ); private static final Map, Consumer>> SPECIAL_RECORD_ENRICHERS = createSpecialRecordEnrichers(); private static final Map, Consumer>> RESOLVED_ENRICHER_CACHE = new ConcurrentHashMap<>(); private static final Map, List> APPLICABLE_ID_FIELD_MAPPINGS_CACHE = new ConcurrentHashMap<>(); private static final Map, Map>> FIELD_CACHE = new ConcurrentHashMap<>(); private static final Map, Optional> ID_FIELD_CACHE = new ConcurrentHashMap<>(); private static final Map, Map> COLUMN_CACHE = new ConcurrentHashMap<>(); private static final Map, Optional>> SERVICE_CACHE = new ConcurrentHashMap<>(); public static T rowsMap(T data) { if (data == null) { return null; } if (data instanceof Page page) { rowsMapCollection(page.getRecords()); return data; } if (data instanceof PageResult pageResult) { rowsMapCollection(pageResult.getRecords()); return data; } if (data instanceof Collection collection) { rowsMapCollection(collection); return data; } if (data.getClass().isArray()) { int length = java.lang.reflect.Array.getLength(data); List records = new ArrayList<>(length); for (int i = 0; i < length; i++) { records.add(java.lang.reflect.Array.get(data, i)); } rowsMapCollection(records); return data; } rowsMapCollection(Collections.singletonList(data)); return data; } public static Map userNameMap(List records) { if (Cools.isEmpty(records)) { return Collections.emptyMap(); } Set userIds = records.stream() .filter(Objects::nonNull) .flatMap(item -> Stream.of( readLongId(item, "createBy"), readLongId(item, "updateBy") )) .filter(Objects::nonNull) .collect(Collectors.toSet()); Map userNameMap = loadUserNameMap(userIds); fillUserNameFields(records, userNameMap); return userNameMap; } public static void warehouseAreasRowsMap(List records) { if (Cools.isEmpty(records)) { return; } Set userIds = records.stream() .filter(Objects::nonNull) .flatMap(item -> Stream.of(item.getCreateBy(), item.getUpdateBy())) .filter(Objects::nonNull) .collect(Collectors.toSet()); Set warehouseIds = records.stream() .map(WarehouseAreas::getWarehouseId) .filter(Objects::nonNull) .collect(Collectors.toSet()); Set companyIds = records.stream() .filter(Objects::nonNull) .flatMap(item -> Stream.of( item.getShipperId(), item.getSupplierId() == null ? null : item.getSupplierId().longValue() )) .filter(Objects::nonNull) .collect(Collectors.toCollection(LinkedHashSet::new)); Set typeValues = records.stream() .map(WarehouseAreas::getType) .filter(type -> !Cools.isEmpty(type)) .collect(Collectors.toCollection(LinkedHashSet::new)); Map userNameMap = loadUserNameMap(userIds); Map warehouseNameMap = loadWarehouseNameMap(warehouseIds); Map companyNameMap = loadCompanyNameMap(companyIds); Map typeLabelMap = loadDictLabelMap(typeValues, DictTypeCode.SYS_WARE_AREAS_TYPE); records.stream() .filter(Objects::nonNull) .forEach(record -> { record.setCreateBy$(userNameMap.get(record.getCreateBy())); record.setUpdateBy$(userNameMap.get(record.getUpdateBy())); record.setWarehouseId$(warehouseNameMap.get(record.getWarehouseId())); record.setShipperId$(companyNameMap.get(record.getShipperId())); record.setSupplierId$(record.getSupplierId() == null ? null : companyNameMap.get(record.getSupplierId().longValue())); record.setType$(Cools.isEmpty(record.getType()) ? "" : typeLabelMap.get(record.getType())); }); } private static void rowsMapCollection(Collection sourceRecords) { if (Cools.isEmpty(sourceRecords)) { return; } Map, List> recordsByClass = new LinkedHashMap<>(); for (Object record : sourceRecords) { if (record == null) { continue; } recordsByClass.computeIfAbsent(record.getClass(), key -> new ArrayList<>()).add(record); } recordsByClass.forEach(buildPageRowsUtils::rowsMapByClass); } private static void rowsMapByClass(Class recordClass, List records) { if (recordClass == null || Cools.isEmpty(records) || isSimpleValueType(recordClass)) { return; } if (WarehouseAreas.class.isAssignableFrom(recordClass)) { warehouseAreasRowsMap(records.stream() .map(WarehouseAreas.class::cast) .collect(Collectors.toList())); return; } userNameMap(records); applyCommonIdFieldMappings(recordClass, records); Consumer> enricher = findSpecialRecordEnricher(recordClass); if (enricher != null) { enricher.accept(records); } fillUserRoleIds(records); } private static void applyCommonIdFieldMappings(Class recordClass, List records) { for (IdFieldMapping mapping : getApplicableIdFieldMappings(recordClass)) { fillFieldById(records, mapping.sourceField(), mapping.targetField(), mapping.serviceClass(), mapping.returnField()); } } private static Map, Consumer>> createSpecialRecordEnrichers() { Map, Consumer>> enrichers = new LinkedHashMap<>(); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.system.entity.SerialRule", records -> fillDictField(records, "reset", "reset$", "sys_rule_type")); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.system.entity.SerialRuleItem", records -> fillDictField(records, "wkType", "wkType$", "sys_rule_item_type")); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.AsnOrderLog", records -> { fillDictField(records, "exceStatus", "exceStatus$", DictTypeCode.DICT_ASN_EXCE_STATUS); fillDictField(records, "type", "type$", DictTypeCode.DICT_SYS_ORDER_TYPE); fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.BasContainer", records -> fillDictField(records, "containerType", "containerType$", "sys_container_type")); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.BasStation", records -> { fillDictField(records, "useStatus", "useStatus$", "sys_sta_use_stas"); fillDictIdsField(records, "containerType", "containerTypes$", "sys_container_type"); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.BasStationArea", records -> fillDictField(records, "useStatus", "useStatus$", "sys_sta_use_stas")); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.CheckDiff", records -> fillDictField(records, "exceStatus", "exceStatus$", DictTypeCode.SYS_CHECK_DIFF_EXCE_STATUS)); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.CheckDiffItem", records -> fillDictField(records, "exceStatus", "exceStatus$", DictTypeCode.SYS_CHECK_DIFF_EXCE_STATUS)); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Companys", records -> fillDictField(records, "type", "companys$", DictTypeCode.DICT_COMPANY_TYPE)); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Delivery", records -> { fillDictField(records, "exceStatus", "exceStatus$", DictTypeCode.SYS_PO_EXCE_STATUS); fillDictField(records, "type", "type$", DictTypeCode.DICT_SYS_ORDER_TYPE); fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.DeviceSite", records -> { fillDictField(records, "type", "type$", DictTypeCode.DICT_SYS_TASK_TYPE); fillDictField(records, "device", "device$", DictTypeCode.DICT_SYS_DEVICE_TYPE); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Loc", buildPageRowsUtils::fillLocTypeNamesField); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.LocAreaMatRela", records -> fillFieldById(records, "matnrId", "matnrId$", com.vincent.rsf.server.manager.service.MatnrService.class, "name")); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.LocItem", records -> { fillDictField(records, "type", "type$", DictTypeCode.DICT_SYS_ORDER_TYPE); fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.LocRevise", records -> fillDictField(records, "type", "type$", DictTypeCode.SYS_STOCK_REVISE_TYPE)); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.LocTypeRela", records -> fillFieldById(records, "locId", "areaId$", com.vincent.rsf.server.manager.service.LocService.class, "code")); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Purchase", records -> { fillDictField(records, "exceStatus", "exceStatus$", DictTypeCode.SYS_PO_EXCE_STATUS); fillDictField(records, "type", "type$", DictTypeCode.DICT_SYS_ORDER_TYPE); fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.QlyInspect", records -> { fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE); fillDictField(records, "isptStatus", "isptStatus$", DictTypeCode.DICT_QLY_INSPECT_STATUS); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.QlyIsptItem", records -> { fillDictField(records, "isptStatus", "isptStatus$", DictTypeCode.DICT_QLY_INSPECT_STATUS); fillDictField(records, "isptResult", "isptResult$", DictTypeCode.DICT_INSPECT_RESULT); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Stock", records -> { fillDictField(records, "type", "type$", DictTypeCode.DICT_SYS_ORDER_TYPE); fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.StockItem", records -> fillFieldById(records, "matnrId", "matnrId$", com.vincent.rsf.server.manager.service.MatnrService.class, "unit")); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Task", records -> { fillDictFieldWithValue(records, "taskStatus", "taskStatus$", DictTypeCode.DICT_SYS_TASK_STATUS); fillDictField(records, "warehType", "warehType$", DictTypeCode.DICT_SYS_DEVICE_TYPE); fillStationNameWithId(records, "orgSite", "orgSite$"); fillStationNameWithId(records, "targSite", "targSite$"); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.TaskItem", records -> { fillDictField(records, "orderType", "orderType$", DictTypeCode.DICT_SYS_ORDER_TYPE); fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE); fillDictField(records, "isptResult", "isptResult$", DictTypeCode.DICT_INSPECT_RESULT); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.TaskLog", records -> { fillDictField(records, "taskStatus", "taskStatus$", DictTypeCode.DICT_SYS_TASK_STATUS); fillDictField(records, "taskType", "taskType$", DictTypeCode.DICT_SYS_TASK_TYPE); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Transfer", records -> { fillDictField(records, "type", "type$", DictTypeCode.SYS_TRANSFER_TYPE); fillDictField(records, "exceStatus", "exceStatus$", DictTypeCode.DICT_ASN_EXCE_STATUS); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WaitPakin", records -> fillDictField(records, "ioStatus", "ioStatus$", DictTypeCode.SYS_ORDER_IN_STATUS)); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WaitPakinItem", records -> fillDictField(records, "isptResult", "isptResult$", DictTypeCode.DICT_INSPECT_RESULT)); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WaitPakinItemLog", records -> { fillFieldById(records, "pakinId", "pakinId$", com.vincent.rsf.server.manager.service.WaitPakinService.class, "id"); fillFieldById(records, "matnrId", "matnrId$", com.vincent.rsf.server.manager.service.MatnrService.class, "unit"); }); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WarehouseAreasItem", records -> fillDictField(records, "isptResult", "isptResult$", DictTypeCode.DICT_INSPECT_RESULT)); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Wave", records -> fillDictFieldWithValue(records, "exceStatus", "exceStatus$", DictTypeCode.SYS_WAVE_EXCE_STATUS)); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WaveItem", records -> fillDictFieldWithValue(records, "exceStatus", "exceStatus$", DictTypeCode.SYS_WAVE_ITEM_EXCE_STATUS)); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WaveRule", records -> fillDictField(records, "type", "type$", DictTypeCode.SYS_WAVE_RULE_CODE)); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WkOrder", buildPageRowsUtils::fillWkOrderRows); registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WkOrderItem", records -> fillDictField(records, "isptResult", "isptResult$", DictTypeCode.DICT_INSPECT_RESULT)); return enrichers; } private static void registerSpecialEnricher(Map, Consumer>> enrichers, String className, Consumer> enricher) { try { enrichers.put(Class.forName(className), enricher); } catch (ClassNotFoundException ignored) { } } private static Consumer> findSpecialRecordEnricher(Class recordClass) { Consumer> enricher = RESOLVED_ENRICHER_CACHE.computeIfAbsent(recordClass, buildPageRowsUtils::resolveSpecialRecordEnricher); return enricher == NO_OP_ENRICHER ? null : enricher; } private static Consumer> resolveSpecialRecordEnricher(Class recordClass) { for (Map.Entry, Consumer>> entry : SPECIAL_RECORD_ENRICHERS.entrySet()) { if (entry.getKey().isAssignableFrom(recordClass)) { return entry.getValue(); } } return NO_OP_ENRICHER; } private static void fillWkOrderRows(List records) { fillDictField(records, "checkType", "checkType$", DictTypeCode.SYS_CHECK_TYPE); fillDictField(records, "exceStatus", "exceStatus$", record -> Objects.equals(getStringFieldValue(record, "type"), com.vincent.rsf.server.manager.enums.OrderType.ORDER_CHECK.type) ? DictTypeCode.SYS_CHECK_EXCE_STATUS : DictTypeCode.DICT_ASN_EXCE_STATUS, false); fillComputedStringField(records, "wkType$", record -> com.vincent.rsf.server.manager.enums.OrderWorkType.getWorkDesc(getStringFieldValue(record, "wkType"))); } private static void fillComputedStringField(List records, String targetField, Function valueResolver) { if (Cools.isEmpty(records) || !hasField(records.get(0), targetField) || valueResolver == null) { return; } for (Object record : records) { writeStringField(record, targetField, valueResolver.apply(record)); } } private static void fillDictField(List records, String sourceField, String targetField, String dictTypeCode) { fillDictField(records, sourceField, targetField, record -> dictTypeCode, false); } private static void fillDictFieldWithValue(List records, String sourceField, String targetField, String dictTypeCode) { fillDictField(records, sourceField, targetField, record -> dictTypeCode, true); } private static void fillDictField(List records, String sourceField, String targetField, Function dictTypeResolver, boolean appendValue) { if (Cools.isEmpty(records) || !hasField(records.get(0), targetField) || dictTypeResolver == null) { return; } Map> valuesByType = new LinkedHashMap<>(); for (Object record : records) { String dictTypeCode = dictTypeResolver.apply(record); String value = normalizeStringValue(readFieldValue(record, sourceField)); if (Cools.isEmpty(dictTypeCode) || Cools.isEmpty(value)) { continue; } valuesByType.computeIfAbsent(dictTypeCode, key -> new LinkedHashSet<>()).add(value); } if (valuesByType.isEmpty()) { return; } Map> labelMapByType = new HashMap<>(); valuesByType.forEach((dictTypeCode, values) -> labelMapByType.put(dictTypeCode, loadDictLabelMap(values, dictTypeCode))); for (Object record : records) { String dictTypeCode = dictTypeResolver.apply(record); String value = normalizeStringValue(readFieldValue(record, sourceField)); if (Cools.isEmpty(dictTypeCode) || Cools.isEmpty(value)) { continue; } String label = labelMapByType.getOrDefault(dictTypeCode, Collections.emptyMap()).get(value); if (label == null) { continue; } writeStringField(record, targetField, appendValue ? value + "." + label : label); } } private static void fillDictIdsField(List records, String sourceField, String targetField, String dictTypeCode) { if (Cools.isEmpty(records) || !hasField(records.get(0), targetField)) { return; } Set values = new LinkedHashSet<>(); for (Object record : records) { Object sourceValue = readFieldValue(record, sourceField); if (sourceValue instanceof Collection collection) { collection.stream() .map(buildPageRowsUtils::normalizeStringValue) .filter(item -> !Cools.isEmpty(item)) .forEach(values::add); } } if (values.isEmpty()) { return; } List dictDataList = listEntitiesByFieldIn(DictDataService.class, DictData.class, "value", values, Map.of("dictTypeCode", dictTypeCode)); Map dictIdMap = new HashMap<>(); for (Object dictData : dictDataList) { String value = getStringFieldValue(dictData, "value"); Long id = getLongFieldValue(dictData, "id"); if (Cools.isEmpty(value) || id == null) { continue; } dictIdMap.put(value, id); } for (Object record : records) { Object sourceValue = readFieldValue(record, sourceField); if (!(sourceValue instanceof Collection collection)) { continue; } List ids = collection.stream() .map(buildPageRowsUtils::normalizeStringValue) .map(dictIdMap::get) .filter(Objects::nonNull) .toList(); if (!ids.isEmpty()) { writeField(record, targetField, ids); } } } private static void fillStationNameWithId(List records, String sourceField, String targetField) { if (Cools.isEmpty(records) || !hasField(records.get(0), targetField)) { return; } Set stationNames = records.stream() .map(record -> normalizeStringValue(readFieldValue(record, sourceField))) .filter(item -> !Cools.isEmpty(item)) .collect(Collectors.toCollection(LinkedHashSet::new)); if (stationNames.isEmpty()) { return; } List stations = listEntitiesByFieldIn( com.vincent.rsf.server.manager.service.BasStationService.class, com.vincent.rsf.server.manager.entity.BasStation.class, "stationName", stationNames, Collections.emptyMap() ); Map stationIdMap = new HashMap<>(); for (Object station : stations) { String stationName = getStringFieldValue(station, "stationName"); String stationId = getStringFieldValue(station, "stationId"); if (Cools.isEmpty(stationName) || Cools.isEmpty(stationId)) { continue; } stationIdMap.put(stationName, stationId); } for (Object record : records) { String stationName = normalizeStringValue(readFieldValue(record, sourceField)); if (Cools.isEmpty(stationName)) { continue; } String stationId = stationIdMap.get(stationName); writeStringField(record, targetField, Cools.isEmpty(stationId) ? stationName : stationName + "(" + stationId + ")"); } } private static void fillLocTypeNamesField(List records) { if (Cools.isEmpty(records) || !hasField(records.get(0), "typeIds$")) { return; } Map> parsedIdsByValue = new HashMap<>(); Set allIds = new LinkedHashSet<>(); for (Object record : records) { String value = normalizeStringValue(readFieldValue(record, "type")); if (Cools.isEmpty(value)) { continue; } List ids = parsedIdsByValue.computeIfAbsent(value, buildPageRowsUtils::parseLongIds); allIds.addAll(ids); } if (allIds.isEmpty()) { return; } Map nameMap = loadEntityFieldMap(com.vincent.rsf.server.manager.service.LocTypeService.class, allIds, "name"); for (Object record : records) { String value = normalizeStringValue(readFieldValue(record, "type")); List ids = value == null ? Collections.emptyList() : parsedIdsByValue.getOrDefault(value, Collections.emptyList()); if (ids.isEmpty()) { continue; } List names = ids.stream() .map(nameMap::get) .filter(item -> !Cools.isEmpty(item)) .toList(); if (!names.isEmpty()) { writeStringField(record, "typeIds$", String.join(",", names)); } } } private static List parseLongIds(String value) { if (Cools.isEmpty(value)) { return Collections.emptyList(); } return Stream.of(value.split(",")) .map(String::trim) .filter(item -> !item.isEmpty()) .map(item -> { try { return Long.parseLong(item); } catch (NumberFormatException ignored) { return null; } }) .filter(Objects::nonNull) .toList(); } private static String normalizeStringValue(Object value) { if (value == null) { return null; } String stringValue = String.valueOf(value).trim(); return stringValue.isEmpty() ? null : stringValue; } private static void fillUserRoleIds(List records) { if (Cools.isEmpty(records) || !hasField(records.get(0), "userRoleIds")) { return; } Set userIds = records.stream() .map(record -> readLongId(record, "id")) .filter(Objects::nonNull) .collect(Collectors.toCollection(LinkedHashSet::new)); if (userIds.isEmpty()) { return; } List userRoles = listEntitiesByFieldIn( com.vincent.rsf.server.system.service.UserRoleService.class, com.vincent.rsf.server.system.entity.UserRole.class, "userId", userIds, Collections.emptyMap() ); Map> userRoleMap = new HashMap<>(); for (Object userRole : userRoles) { Long userId = getLongFieldValue(userRole, "userId"); Long roleId = getLongFieldValue(userRole, "roleId"); if (userId == null || roleId == null) { continue; } userRoleMap.computeIfAbsent(userId, key -> new ArrayList<>()).add(roleId); } for (Object record : records) { Long userId = readLongId(record, "id"); List roleIds = userId == null ? Collections.emptyList() : userRoleMap.getOrDefault(userId, Collections.emptyList()); writeField(record, "userRoleIds", roleIds.toArray(Long[]::new)); } } private static void fillFieldById(List records, String sourceField, String targetField, Class serviceClass, String returnField) { if (Cools.isEmpty(records) || !hasField(records.get(0), targetField) || !hasField(records.get(0), sourceField)) { return; } Set ids = records.stream() .map(record -> readLongId(record, sourceField)) .filter(Objects::nonNull) .collect(Collectors.toCollection(LinkedHashSet::new)); if (ids.isEmpty()) { return; } Map valueMap = loadEntityFieldMap(serviceClass, ids, returnField); if (valueMap.isEmpty()) { return; } for (Object record : records) { writeStringField(record, targetField, valueMap.get(readLongId(record, sourceField))); } } private static Map loadEntityFieldMap(Class serviceClass, Set ids, String returnField) { if (serviceClass == null || Cools.isEmpty(ids) || Cools.isEmpty(returnField)) { return Collections.emptyMap(); } RedisService redisService = getRedisService(); String cacheFlag = buildEntityFieldCacheFlag(serviceClass, returnField); return loadValueMap( ids, id -> getCachedStringValue(redisService, id, cacheFlag), missingIds -> { IService service = getServiceBean(serviceClass); return service == null ? Collections.emptyList() : service.listByIds(new ArrayList<>(missingIds)); }, buildPageRowsUtils::readEntityId, entity -> normalizeStringValue(readFieldValue(entity, returnField)), loadedValueMap -> cacheStringValues(redisService, loadedValueMap, cacheFlag) ); } private static Long readEntityId(Object entity) { if (entity == null) { return null; } Field idField = getCachedIdField(entity.getClass()); if (idField != null) { Object value = readFieldValue(entity, idField.getName()); if (value instanceof Number number) { return number.longValue(); } } return getLongFieldValue(entity, "id"); } private static Long readLongId(Object record, String fieldName) { if (record == null || Cools.isEmpty(fieldName)) { return null; } Field field = getCachedField(record.getClass(), fieldName); if (field == null) { return null; } try { Object value = field.get(record); if (value instanceof Long) { return (Long) value; } if (value instanceof Number) { return ((Number) value).longValue(); } if (value instanceof String && !((String) value).trim().isEmpty()) { return Long.parseLong(((String) value).trim()); } } catch (IllegalAccessException | NumberFormatException ignored) { return null; } return null; } private static Map loadUserNameMap(Set userIds) { RedisService redisService = getRedisService(); UserService userService = getServiceBean(UserService.class, UserService.class); return loadValueMap( userIds, userId -> getCachedStringValue(redisService, userId, USER_NAME_CACHE_FLAG), missingUserIds -> userService == null ? Collections.emptyList() : userService.listByIds(missingUserIds), User::getId, User::getNickname, loadedUserNameMap -> cacheStringValues(redisService, loadedUserNameMap, USER_NAME_CACHE_FLAG) ); } private static Map loadWarehouseNameMap(Set warehouseIds) { RedisService redisService = getRedisService(); WarehouseService warehouseService = getServiceBean(WarehouseService.class, WarehouseService.class); return loadValueMap( warehouseIds, id -> getCachedStringValue(redisService, id, WAREHOUSE_NAME_CACHE_FLAG), missingIds -> warehouseService == null ? Collections.emptyList() : warehouseService.listByIds(missingIds), Warehouse::getId, Warehouse::getName, loadedNameMap -> cacheStringValues(redisService, loadedNameMap, WAREHOUSE_NAME_CACHE_FLAG) ); } private static Map loadCompanyNameMap(Set companyIds) { RedisService redisService = getRedisService(); CompanysService companysService = getServiceBean(CompanysService.class, CompanysService.class); return loadValueMap( companyIds, id -> getCachedStringValue(redisService, id, COMPANY_NAME_CACHE_FLAG), missingIds -> companysService == null ? Collections.emptyList() : companysService.listByIds(missingIds), Companys::getId, Companys::getName, loadedNameMap -> cacheStringValues(redisService, loadedNameMap, COMPANY_NAME_CACHE_FLAG) ); } private static Map loadDictLabelMap(Set values, String dictTypeCode) { if (Cools.isEmpty(values) || Cools.isEmpty(dictTypeCode)) { return Collections.emptyMap(); } RedisService redisService = getRedisService(); DictDataService dictDataService = getServiceBean(DictDataService.class, DictDataService.class); String cacheFlag = buildDictLabelCacheFlag(dictTypeCode); return loadValueMap( values, value -> getCachedStringValue(redisService, value, cacheFlag), missingValues -> { if (dictDataService == null) { return Collections.emptyList(); } return dictDataService.list( new LambdaQueryWrapper() .eq(DictData::getDictTypeCode, dictTypeCode) .in(DictData::getValue, missingValues) ); }, DictData::getValue, DictData::getLabel, loadedLabelMap -> cacheStringValues(redisService, loadedLabelMap, cacheFlag) ); } private static Map loadValueMap(Set keys, Function cacheGetter, Function, List> entityLoader, Function keyGetter, Function valueGetter, Consumer> cacheWriter) { if (Cools.isEmpty(keys)) { return Collections.emptyMap(); } List normalizedKeys = keys.stream() .filter(Objects::nonNull) .distinct() .toList(); if (normalizedKeys.isEmpty()) { return Collections.emptyMap(); } Map valueMap = new HashMap<>(); List missingKeys = new ArrayList<>(); for (K key : normalizedKeys) { String cachedValue = cacheGetter.apply(key); if (cachedValue == null) { missingKeys.add(key); continue; } valueMap.put(key, cachedValue); } if (missingKeys.isEmpty()) { return valueMap; } List loadedEntities = entityLoader.apply(missingKeys); if (loadedEntities == null) { return valueMap; } Map loadedValueMap = loadedEntities.stream() .filter(Objects::nonNull) .map(item -> new java.util.AbstractMap.SimpleEntry<>(keyGetter.apply(item), valueGetter.apply(item))) .filter(item -> item.getKey() != null && item.getValue() != null) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (left, right) -> left)); valueMap.putAll(loadedValueMap); cacheWriter.accept(loadedValueMap); return valueMap; } private static RedisService getRedisService() { try { return SpringUtils.getBean(RedisService.class); } catch (Exception ignored) { return null; } } private static IService getServiceBean(Class serviceClass) { if (serviceClass == null) { return null; } return SERVICE_CACHE.computeIfAbsent(serviceClass, key -> { try { Object bean = SpringUtils.getBean(key); return bean instanceof IService iService ? Optional.of(iService) : Optional.empty(); } catch (Exception ignored) { return Optional.empty(); } }).orElse(null); } private static T getServiceBean(Class serviceClass, Class targetType) { IService serviceBean = getServiceBean(serviceClass); return targetType != null && targetType.isInstance(serviceBean) ? targetType.cast(serviceBean) : null; } private static List listEntitiesByFieldIn(Class serviceClass, Class entityClass, String matchFieldName, Collection matchValues, Map extraConditions) { if (serviceClass == null || entityClass == null || Cools.isEmpty(matchFieldName) || Cools.isEmpty(matchValues)) { return Collections.emptyList(); } IService service = getServiceBean(serviceClass); if (service == null) { return Collections.emptyList(); } QueryWrapper queryWrapper = new QueryWrapper<>(); extraConditions.forEach((fieldName, value) -> queryWrapper.eq(resolveColumnName(entityClass, fieldName), value)); queryWrapper.in(resolveColumnName(entityClass, matchFieldName), matchValues); return service.list((Wrapper) queryWrapper); } private static String resolveColumnName(Class entityClass, String fieldName) { if (entityClass == null || Cools.isEmpty(fieldName)) { return fieldName; } return COLUMN_CACHE .computeIfAbsent(entityClass, key -> new ConcurrentHashMap<>()) .computeIfAbsent(fieldName, key -> resolveColumnNameInternal(entityClass, key)); } private static String resolveColumnNameInternal(Class entityClass, String fieldName) { Field field = getCachedField(entityClass, fieldName); if (field == null) { return camelToSnake(fieldName); } TableId tableId = field.getAnnotation(TableId.class); if (tableId != null && !Cools.isEmpty(tableId.value())) { return stripColumnQuotes(tableId.value()); } TableField tableField = field.getAnnotation(TableField.class); if (tableField != null && !Cools.isEmpty(tableField.value())) { return stripColumnQuotes(tableField.value()); } return camelToSnake(fieldName); } private static List getApplicableIdFieldMappings(Class recordClass) { if (recordClass == null) { return Collections.emptyList(); } return APPLICABLE_ID_FIELD_MAPPINGS_CACHE.computeIfAbsent(recordClass, key -> COMMON_ID_FIELD_MAPPINGS.stream() .filter(mapping -> hasField(key, mapping.sourceField()) && hasField(key, mapping.targetField())) .toList()); } private static String stripColumnQuotes(String column) { return column == null ? null : column.replace("`", ""); } private static String camelToSnake(String value) { if (Cools.isEmpty(value)) { return value; } StringBuilder builder = new StringBuilder(); for (int i = 0; i < value.length(); i++) { char current = value.charAt(i); if (Character.isUpperCase(current)) { if (i > 0) { builder.append('_'); } builder.append(Character.toLowerCase(current)); } else { builder.append(current); } } return builder.toString(); } private static String getStringFieldValue(Object entity, String fieldName) { Object value = readFieldValue(entity, fieldName); return value == null ? null : String.valueOf(value); } private static Long getLongFieldValue(Object entity, String fieldName) { Object value = readFieldValue(entity, fieldName); if (value instanceof Long longValue) { return longValue; } if (value instanceof Number number) { return number.longValue(); } if (value instanceof String stringValue && !stringValue.isBlank()) { try { return Long.parseLong(stringValue.trim()); } catch (NumberFormatException ignored) { return null; } } return null; } private static Object readFieldValue(Object entity, String fieldName) { if (entity == null || Cools.isEmpty(fieldName)) { return null; } Field field = getCachedField(entity.getClass(), fieldName); if (field == null) { return null; } try { return field.get(entity); } catch (IllegalAccessException ignored) { return null; } } private static String getCachedStringValue(RedisService redisService, Object key, String cacheFlag) { if (redisService == null || key == null || Cools.isEmpty(cacheFlag)) { return null; } try { String value = redisService.getValue(cacheFlag, String.valueOf(key)); return Cools.isEmpty(value) ? null : value; } catch (Exception ignored) { return null; } } private static void cacheStringValues(RedisService redisService, Map valueMap, String cacheFlag) { if (redisService == null || Cools.isEmpty(valueMap) || Cools.isEmpty(cacheFlag)) { return; } valueMap.forEach((key, value) -> { if (key == null || Cools.isEmpty(value)) { return; } try { redisService.setValue(cacheFlag, String.valueOf(key), value, NAME_CACHE_TTL_SECONDS); } catch (Exception ignored) { } }); } private static String buildDictLabelCacheFlag(String dictTypeCode) { return DICT_LABEL_CACHE_FLAG + "." + dictTypeCode; } private static String buildEntityFieldCacheFlag(Class serviceClass, String returnField) { return ENTITY_FIELD_CACHE_FLAG + "." + serviceClass.getName() + "." + returnField; } private static void fillUserNameFields(List records, Map userNameMap) { if (Cools.isEmpty(records) || Cools.isEmpty(userNameMap)) { return; } records.stream() .filter(Objects::nonNull) .forEach(record -> { writeStringField(record, "createBy$", userNameMap.get(readLongId(record, "createBy"))); writeStringField(record, "updateBy$", userNameMap.get(readLongId(record, "updateBy"))); }); } private static void writeStringField(Object record, String fieldName, String fieldValue) { if (record == null || Cools.isEmpty(fieldName) || fieldValue == null) { return; } writeField(record, fieldName, fieldValue); } private static void writeField(Object record, String fieldName, Object fieldValue) { if (record == null || Cools.isEmpty(fieldName) || fieldValue == null) { return; } Field field = getCachedField(record.getClass(), fieldName); if (field == null) { return; } try { field.set(record, fieldValue); } catch (IllegalAccessException ignored) { } } private static Field getCachedField(Class type, String fieldName) { if (type == null || Cools.isEmpty(fieldName)) { return null; } return FIELD_CACHE .computeIfAbsent(type, key -> new ConcurrentHashMap<>()) .computeIfAbsent(fieldName, key -> Optional.ofNullable(findField(type, key))) .orElse(null); } private static Field getCachedIdField(Class type) { if (type == null) { return null; } return ID_FIELD_CACHE.computeIfAbsent(type, key -> Optional.ofNullable(findIdField(key))).orElse(null); } private static Field findField(Class type, String fieldName) { Field field = Cools.getField(type, fieldName); if (field == null) { return null; } try { field.setAccessible(true); } catch (Exception ignored) { } return field; } private static Field findIdField(Class type) { for (Class current = type; current != null && !Object.class.equals(current); current = current.getSuperclass()) { for (Field field : current.getDeclaredFields()) { if (field.getAnnotation(TableId.class) == null) { continue; } try { field.setAccessible(true); } catch (Exception ignored) { } return field; } } return findField(type, "id"); } private static boolean hasField(Class recordClass, String fieldName) { return recordClass != null && !Cools.isEmpty(fieldName) && getCachedField(recordClass, fieldName) != null; } private static boolean hasField(Object record, String fieldName) { return record != null && hasField(record.getClass(), fieldName); } private static boolean isSimpleValueType(Class type) { return type != null && (type.isPrimitive() || Number.class.isAssignableFrom(type) || CharSequence.class.isAssignableFrom(type) || Boolean.class.isAssignableFrom(type) || Character.class.isAssignableFrom(type) || Enum.class.isAssignableFrom(type) || java.util.Date.class.isAssignableFrom(type) || java.time.temporal.Temporal.class.isAssignableFrom(type)); } private record IdFieldMapping(String sourceField, String targetField, Class serviceClass, String returnField) { } }