| | |
| | | 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.UserService; |
| | | import com.vincent.rsf.server.system.service.*; |
| | | |
| | | import java.lang.reflect.Field; |
| | | import java.util.*; |
| | | 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 int USER_NAME_CACHE_TTL_SECONDS = 300; |
| | | 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<List<Object>> NO_OP_ENRICHER = records -> { |
| | | }; |
| | | private static final List<IdFieldMapping> 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<Class<?>, Consumer<List<Object>>> SPECIAL_RECORD_ENRICHERS = createSpecialRecordEnrichers(); |
| | | private static final Map<Class<?>, Consumer<List<Object>>> RESOLVED_ENRICHER_CACHE = new ConcurrentHashMap<>(); |
| | | private static final Map<Class<?>, List<IdFieldMapping>> APPLICABLE_ID_FIELD_MAPPINGS_CACHE = new ConcurrentHashMap<>(); |
| | | private static final Map<Class<?>, Map<String, Optional<Field>>> FIELD_CACHE = new ConcurrentHashMap<>(); |
| | | private static final Map<Class<?>, Optional<Field>> ID_FIELD_CACHE = new ConcurrentHashMap<>(); |
| | | private static final Map<Class<?>, Map<String, String>> COLUMN_CACHE = new ConcurrentHashMap<>(); |
| | | private static final Map<Class<?>, Optional<IService<?>>> SERVICE_CACHE = new ConcurrentHashMap<>(); |
| | | |
| | | public static <T> Map<Long, String> userNameMap(List<T> records){ |
| | | public static <T> 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<Object> 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 <T> Map<Long, String> userNameMap(List<T> records) { |
| | | if (Cools.isEmpty(records)) { |
| | | return Collections.emptyMap(); |
| | | } |
| | | Set<Long> collect = records.stream() |
| | | Set<Long> userIds = records.stream() |
| | | .filter(Objects::nonNull) |
| | | .flatMap(item -> Stream.of( |
| | | readUserId(item, "createBy"), |
| | | readUserId(item, "updateBy") |
| | | readLongId(item, "createBy"), |
| | | readLongId(item, "updateBy") |
| | | )) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toSet()); |
| | | |
| | | Map<Long, String> userNameMap = loadUserNameMap(collect); |
| | | Map<Long, String> userNameMap = loadUserNameMap(userIds); |
| | | fillUserNameFields(records, userNameMap); |
| | | return userNameMap; |
| | | } |
| | | |
| | | private static Long readUserId(Object record, String fieldName) { |
| | | public static void warehouseAreasRowsMap(List<WarehouseAreas> records) { |
| | | if (Cools.isEmpty(records)) { |
| | | return; |
| | | } |
| | | Set<Long> userIds = records.stream() |
| | | .filter(Objects::nonNull) |
| | | .flatMap(item -> Stream.of(item.getCreateBy(), item.getUpdateBy())) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toSet()); |
| | | Set<Long> warehouseIds = records.stream() |
| | | .map(WarehouseAreas::getWarehouseId) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toSet()); |
| | | Set<Long> 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<String> typeValues = records.stream() |
| | | .map(WarehouseAreas::getType) |
| | | .filter(type -> !Cools.isEmpty(type)) |
| | | .collect(Collectors.toCollection(LinkedHashSet::new)); |
| | | |
| | | Map<Long, String> userNameMap = loadUserNameMap(userIds); |
| | | Map<Long, String> warehouseNameMap = loadWarehouseNameMap(warehouseIds); |
| | | Map<Long, String> companyNameMap = loadCompanyNameMap(companyIds); |
| | | Map<String, String> 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<Class<?>, List<Object>> 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<Object> 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<List<Object>> enricher = findSpecialRecordEnricher(recordClass); |
| | | if (enricher != null) { |
| | | enricher.accept(records); |
| | | } |
| | | fillUserRoleIds(records); |
| | | } |
| | | |
| | | private static void applyCommonIdFieldMappings(Class<?> recordClass, List<Object> records) { |
| | | for (IdFieldMapping mapping : getApplicableIdFieldMappings(recordClass)) { |
| | | fillFieldById(records, mapping.sourceField(), mapping.targetField(), mapping.serviceClass(), mapping.returnField()); |
| | | } |
| | | } |
| | | |
| | | private static Map<Class<?>, Consumer<List<Object>>> createSpecialRecordEnrichers() { |
| | | Map<Class<?>, Consumer<List<Object>>> 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<Class<?>, Consumer<List<Object>>> enrichers, String className, Consumer<List<Object>> enricher) { |
| | | try { |
| | | enrichers.put(Class.forName(className), enricher); |
| | | } catch (ClassNotFoundException ignored) { |
| | | } |
| | | } |
| | | |
| | | private static Consumer<List<Object>> findSpecialRecordEnricher(Class<?> recordClass) { |
| | | Consumer<List<Object>> enricher = RESOLVED_ENRICHER_CACHE.computeIfAbsent(recordClass, buildPageRowsUtils::resolveSpecialRecordEnricher); |
| | | return enricher == NO_OP_ENRICHER ? null : enricher; |
| | | } |
| | | |
| | | private static Consumer<List<Object>> resolveSpecialRecordEnricher(Class<?> recordClass) { |
| | | for (Map.Entry<Class<?>, Consumer<List<Object>>> entry : SPECIAL_RECORD_ENRICHERS.entrySet()) { |
| | | if (entry.getKey().isAssignableFrom(recordClass)) { |
| | | return entry.getValue(); |
| | | } |
| | | } |
| | | return NO_OP_ENRICHER; |
| | | } |
| | | |
| | | private static void fillWkOrderRows(List<Object> 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<Object> records, String targetField, Function<Object, String> 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<Object> records, String sourceField, String targetField, String dictTypeCode) { |
| | | fillDictField(records, sourceField, targetField, record -> dictTypeCode, false); |
| | | } |
| | | |
| | | private static void fillDictFieldWithValue(List<Object> records, String sourceField, String targetField, String dictTypeCode) { |
| | | fillDictField(records, sourceField, targetField, record -> dictTypeCode, true); |
| | | } |
| | | |
| | | private static void fillDictField(List<Object> records, |
| | | String sourceField, |
| | | String targetField, |
| | | Function<Object, String> dictTypeResolver, |
| | | boolean appendValue) { |
| | | if (Cools.isEmpty(records) || !hasField(records.get(0), targetField) || dictTypeResolver == null) { |
| | | return; |
| | | } |
| | | Map<String, Set<String>> 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<String, Map<String, String>> 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<Object> records, String sourceField, String targetField, String dictTypeCode) { |
| | | if (Cools.isEmpty(records) || !hasField(records.get(0), targetField)) { |
| | | return; |
| | | } |
| | | Set<String> 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<String, Long> 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<Long> 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<Object> records, String sourceField, String targetField) { |
| | | if (Cools.isEmpty(records) || !hasField(records.get(0), targetField)) { |
| | | return; |
| | | } |
| | | Set<String> 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<String, String> 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<Object> records) { |
| | | if (Cools.isEmpty(records) || !hasField(records.get(0), "typeIds$")) { |
| | | return; |
| | | } |
| | | Map<String, List<Long>> parsedIdsByValue = new HashMap<>(); |
| | | Set<Long> allIds = new LinkedHashSet<>(); |
| | | for (Object record : records) { |
| | | String value = normalizeStringValue(readFieldValue(record, "type")); |
| | | if (Cools.isEmpty(value)) { |
| | | continue; |
| | | } |
| | | List<Long> ids = parsedIdsByValue.computeIfAbsent(value, buildPageRowsUtils::parseLongIds); |
| | | allIds.addAll(ids); |
| | | } |
| | | if (allIds.isEmpty()) { |
| | | return; |
| | | } |
| | | Map<Long, String> nameMap = loadEntityFieldMap(com.vincent.rsf.server.manager.service.LocTypeService.class, allIds, "name"); |
| | | for (Object record : records) { |
| | | String value = normalizeStringValue(readFieldValue(record, "type")); |
| | | List<Long> ids = value == null ? Collections.emptyList() : parsedIdsByValue.getOrDefault(value, Collections.emptyList()); |
| | | if (ids.isEmpty()) { |
| | | continue; |
| | | } |
| | | List<String> names = ids.stream() |
| | | .map(nameMap::get) |
| | | .filter(item -> !Cools.isEmpty(item)) |
| | | .toList(); |
| | | if (!names.isEmpty()) { |
| | | writeStringField(record, "typeIds$", String.join(",", names)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private static List<Long> 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<Object> records) { |
| | | if (Cools.isEmpty(records) || !hasField(records.get(0), "userRoleIds")) { |
| | | return; |
| | | } |
| | | Set<Long> 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<Long, List<Long>> 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<Long> roleIds = userId == null ? Collections.emptyList() : userRoleMap.getOrDefault(userId, Collections.emptyList()); |
| | | writeField(record, "userRoleIds", roleIds.toArray(Long[]::new)); |
| | | } |
| | | } |
| | | |
| | | private static void fillFieldById(List<Object> 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<Long> ids = records.stream() |
| | | .map(record -> readLongId(record, sourceField)) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toCollection(LinkedHashSet::new)); |
| | | if (ids.isEmpty()) { |
| | | return; |
| | | } |
| | | Map<Long, String> valueMap = loadEntityFieldMap(serviceClass, ids, returnField); |
| | | if (valueMap.isEmpty()) { |
| | | return; |
| | | } |
| | | for (Object record : records) { |
| | | writeStringField(record, targetField, valueMap.get(readLongId(record, sourceField))); |
| | | } |
| | | } |
| | | |
| | | private static Map<Long, String> loadEntityFieldMap(Class<?> serviceClass, Set<Long> 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 = Cools.getField(record.getClass(), fieldName); |
| | | Field field = getCachedField(record.getClass(), fieldName); |
| | | if (field == null) { |
| | | return null; |
| | | } |
| | | boolean accessible = field.isAccessible(); |
| | | try { |
| | | field.setAccessible(true); |
| | | Object value = field.get(record); |
| | | if (value instanceof Long) { |
| | | return (Long) value; |
| | |
| | | } |
| | | } catch (IllegalAccessException | NumberFormatException ignored) { |
| | | return null; |
| | | } finally { |
| | | field.setAccessible(accessible); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private static Map<Long, String> loadUserNameMap(Set<Long> userIds) { |
| | | if (Cools.isEmpty(userIds)) { |
| | | return Collections.emptyMap(); |
| | | } |
| | | List<Long> normalizedUserIds = userIds.stream() |
| | | .filter(Objects::nonNull) |
| | | .toList(); |
| | | if (normalizedUserIds.isEmpty()) { |
| | | 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<Long, String> loadWarehouseNameMap(Set<Long> 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<Long, String> loadCompanyNameMap(Set<Long> 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<String, String> loadDictLabelMap(Set<String> values, String dictTypeCode) { |
| | | if (Cools.isEmpty(values) || Cools.isEmpty(dictTypeCode)) { |
| | | return Collections.emptyMap(); |
| | | } |
| | | RedisService redisService = getRedisService(); |
| | | Map<Long, String> userNameMap = new HashMap<>(); |
| | | List<Long> missingUserIds = new ArrayList<>(); |
| | | for (Long userId : normalizedUserIds) { |
| | | String cachedUserName = getCachedUserName(redisService, userId); |
| | | if (cachedUserName == null) { |
| | | missingUserIds.add(userId); |
| | | 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<DictData>() |
| | | .eq(DictData::getDictTypeCode, dictTypeCode) |
| | | .in(DictData::getValue, missingValues) |
| | | ); |
| | | }, |
| | | DictData::getValue, |
| | | DictData::getLabel, |
| | | loadedLabelMap -> cacheStringValues(redisService, loadedLabelMap, cacheFlag) |
| | | ); |
| | | } |
| | | |
| | | private static <K, E> Map<K, String> loadValueMap(Set<K> keys, |
| | | Function<K, String> cacheGetter, |
| | | Function<List<K>, List<E>> entityLoader, |
| | | Function<E, K> keyGetter, |
| | | Function<E, String> valueGetter, |
| | | Consumer<Map<K, String>> cacheWriter) { |
| | | if (Cools.isEmpty(keys)) { |
| | | return Collections.emptyMap(); |
| | | } |
| | | List<K> normalizedKeys = keys.stream() |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .toList(); |
| | | if (normalizedKeys.isEmpty()) { |
| | | return Collections.emptyMap(); |
| | | } |
| | | Map<K, String> valueMap = new HashMap<>(); |
| | | List<K> missingKeys = new ArrayList<>(); |
| | | for (K key : normalizedKeys) { |
| | | String cachedValue = cacheGetter.apply(key); |
| | | if (cachedValue == null) { |
| | | missingKeys.add(key); |
| | | continue; |
| | | } |
| | | userNameMap.put(userId, cachedUserName); |
| | | valueMap.put(key, cachedValue); |
| | | } |
| | | if (missingUserIds.isEmpty()) { |
| | | return userNameMap; |
| | | if (missingKeys.isEmpty()) { |
| | | return valueMap; |
| | | } |
| | | UserService userService = SpringUtils.getBean(UserService.class); |
| | | Map<Long, String> loadedUserNameMap = userService.listByIds(missingUserIds) |
| | | .stream() |
| | | List<E> loadedEntities = entityLoader.apply(missingKeys); |
| | | if (loadedEntities == null) { |
| | | return valueMap; |
| | | } |
| | | Map<K, String> loadedValueMap = loadedEntities.stream() |
| | | .filter(Objects::nonNull) |
| | | .filter(user -> user.getId() != null && user.getNickname() != null) |
| | | .collect(Collectors.toMap(User::getId, User::getNickname, (left, right) -> left)); |
| | | userNameMap.putAll(loadedUserNameMap); |
| | | cacheUserNames(redisService, loadedUserNameMap); |
| | | return userNameMap; |
| | | .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() { |
| | |
| | | } |
| | | } |
| | | |
| | | private static String getCachedUserName(RedisService redisService, Long userId) { |
| | | if (redisService == null || userId == 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> T getServiceBean(Class<?> serviceClass, Class<T> 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<String, Object> 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<Object> 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<IdFieldMapping> 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 { |
| | | String value = redisService.getValue(USER_NAME_CACHE_FLAG, String.valueOf(userId)); |
| | | 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 cacheUserNames(RedisService redisService, Map<Long, String> userNameMap) { |
| | | if (redisService == null || Cools.isEmpty(userNameMap)) { |
| | | private static void cacheStringValues(RedisService redisService, Map<?, String> valueMap, String cacheFlag) { |
| | | if (redisService == null || Cools.isEmpty(valueMap) || Cools.isEmpty(cacheFlag)) { |
| | | return; |
| | | } |
| | | userNameMap.forEach((userId, userName) -> { |
| | | if (userId == null || Cools.isEmpty(userName)) { |
| | | valueMap.forEach((key, value) -> { |
| | | if (key == null || Cools.isEmpty(value)) { |
| | | return; |
| | | } |
| | | try { |
| | | redisService.setValue(USER_NAME_CACHE_FLAG, String.valueOf(userId), userName, USER_NAME_CACHE_TTL_SECONDS); |
| | | 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 <T> void fillUserNameFields(List<T> records, Map<Long, String> userNameMap) { |
| | |
| | | records.stream() |
| | | .filter(Objects::nonNull) |
| | | .forEach(record -> { |
| | | writeUserName(record, "createBy$", userNameMap.get(readUserId(record, "createBy"))); |
| | | writeUserName(record, "updateBy$", userNameMap.get(readUserId(record, "updateBy"))); |
| | | writeStringField(record, "createBy$", userNameMap.get(readLongId(record, "createBy"))); |
| | | writeStringField(record, "updateBy$", userNameMap.get(readLongId(record, "updateBy"))); |
| | | }); |
| | | } |
| | | |
| | | private static void writeUserName(Object record, String fieldName, String userName) { |
| | | if (record == null || Cools.isEmpty(fieldName) || userName == null) { |
| | | private static void writeStringField(Object record, String fieldName, String fieldValue) { |
| | | if (record == null || Cools.isEmpty(fieldName) || fieldValue == null) { |
| | | return; |
| | | } |
| | | Field field = Cools.getField(record.getClass(), fieldName); |
| | | if (field == null || !String.class.equals(field.getType())) { |
| | | writeField(record, fieldName, fieldValue); |
| | | } |
| | | |
| | | private static void writeField(Object record, String fieldName, Object fieldValue) { |
| | | if (record == null || Cools.isEmpty(fieldName) || fieldValue == null) { |
| | | return; |
| | | } |
| | | boolean accessible = field.isAccessible(); |
| | | 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); |
| | | field.set(record, userName); |
| | | } catch (IllegalAccessException ignored) { |
| | | } finally { |
| | | field.setAccessible(accessible); |
| | | } 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) { |
| | | } |
| | | } |