stream目标库创建trigger无效

今天在stream目标库上的一张表上创建了一个trigger,编译都通过,但是目标表就是没有数据:
最后执行一下一个包就ok了,记录如下:
 
begin
   EXEC DBMS_DDL.SET_TRIGGER_FIRING_PROPERTY('schema_name', 'trigger_name', FALSE);
end;
/
 
 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/25618347/viewspace-713154/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/25618347/viewspace-713154/

package com.hikvision.building.cloud.inspect.common.utils.excel; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.hikvision.building.cloud.gaia.common.exception.BusinessException; import com.hikvision.building.cloud.util.common.ObjectUtils; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; import java.io.File; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; /** * @author: chenzhuo9 * @since: 2025年09月01日16:51 */ @RunWith(MockitoJUnitRunner.class) @Slf4j public class DeviceAIAbilityExcelTest { private final static String AI_JSON_PATH = "E:\\工作\\AI\\算法LED配置相关文件\\json\\"; private final static String IPC_G5_J40189120 = "IPC_G5_J40189120"; private final static String IPC_H7_C87513270 = "IPC_H7_C87513270"; private final static String IPC_H8_K96568605 = "IPC_H8_K96568605"; private final static String IPC_H9_AZ0730868 = "IPC_H9_AZ0730868"; private final static String NVR_KT2_J42839102 = "NVR_KT2_J42839102"; private final static String NVR_KT4_FV6903374 = "NVR_KT4_FV6903374"; private final static List<String> DEVICE_LIST = List.of(IPC_G5_J40189120, IPC_H7_C87513270, IPC_H8_K96568605, IPC_H9_AZ0730868, NVR_KT2_J42839102, NVR_KT4_FV6903374); private final static String IPC_G5_JSON = AI_JSON_PATH + IPC_G5_J40189120 +".json"; private final static String IPC_H7_JSON = AI_JSON_PATH + IPC_H7_C87513270 +".json"; private static ObjectMapper objectMapper = new ObjectMapper(); @Test public void generateExcel() throws IOException { String path = AI_JSON_PATH + "device_ai_ability_"+ System.currentTimeMillis()+".xlsx"; ExcelWriter excelWriter = EasyExcel.write(path).build(); DEVICE_LIST.forEach(device->{ JsonNode rootNode = null; try { rootNode = objectMapper.readTree(new File(AI_JSON_PATH + device + ".json")); } catch (IOException e) { log.info("device:{}", device); throw new RuntimeException(e); } List<DeviceAIAbilityTestResultDTO> resultDTOList = convertJsonNode(rootNode); excelWriter.write(resultDTOList, createSheet(device, resultDTOList)); }); excelWriter.finish(); } private WriteSheet createSheet(String device, List<DeviceAIAbilityTestResultDTO> resultDTOList){ WriteSheet sheet1 = EasyExcel.writerSheet(device) .head(DeviceAIAbilityTestResultDTO.class) // 设置表头类 .registerWriteHandler(new SafePrecomputedMergeStrategy( 1, // 标题行数 resultDTOList, "taskType", "modelType" // 要合并的字段 )) .build(); return sheet1; } private List<DeviceAIAbilityTestResultDTO> convertJsonNode(JsonNode aiJson) { if (ObjectUtils.isEmpty(aiJson)) { throw new BusinessException(400, "aiJson不能为空"); } JsonNode ruleRelatedCaps = aiJson.path("ruleRelatedCaps"); if (ObjectUtils.isEmpty(ruleRelatedCaps)) { throw new BusinessException(400, "ruleRelatedCaps不能为空"); } List<DeviceAIAbilityTestResultDTO> resultList = new ArrayList<>(); processJsonNodeTask(ruleRelatedCaps, resultList); return resultList; } // private List<DeviceAIAbilityTestResultDTO> convert(AIJsonTestDTO aiJson) { // if (ObjectUtils.isEmpty(aiJson)) { // throw new BusinessException(400, "aiJson不能为空"); // } // if (ObjectUtils.isEmpty(aiJson.getRuleRelatedCaps())) { // throw new BusinessException(400, "ruleRelatedCaps不能为空"); // } // List<DeviceAIAbilityTestResultDTO> resultList = new ArrayList<>(); // proce(aiJson, resultList); // return resultList; // } private void processJsonNodeTask(JsonNode ruleRelatedCaps, List<DeviceAIAbilityTestResultDTO> resultList){ processVideoTask(ruleRelatedCaps.path("videoTask"), resultList, TaskTypeEnum.VIDEO_TASK); // processVideoPollingAnalysisTask(ruleRelatedCaps.path("videoPollingAnalysisTask"), resultList, TaskTypeEnum.VIDEO_POLLING_ANALYSIS_TASK); // processPicturePollingAnalysisTask(ruleRelatedCaps.path("picturePollingAnalysisTask"), resultList, TaskTypeEnum.PICTURE_POLLING_ANALYSIS_TASK); } private void processVideoTask(JsonNode taskDTO, List<DeviceAIAbilityTestResultDTO> resultList, TaskTypeEnum taskTypeEnum){ if (ObjectUtils.isNotEmpty(taskDTO)) { JsonNode detect = taskDTO.path("detect"); if (ObjectUtils.isNotEmpty(detect)) { Map<TriggerTypeEnum, JsonNode> triggerTypeEnumRuleConfigDTOMap = Map.of( TriggerTypeEnum._$1073774593, detect.path("1073774593"), TriggerTypeEnum._$1073758209, detect.path("1073758209"), TriggerTypeEnum._$1073758211, detect.path("1073758211"), TriggerTypeEnum._$1073758212, detect.path("1073758212"), TriggerTypeEnum._$1073758213, detect.path("1073758213"), TriggerTypeEnum._$1073758217, detect.path("1073758217") ); processModelType(triggerTypeEnumRuleConfigDTOMap, resultList, taskTypeEnum, ModelTypeEnum.DETECT); } JsonNode classify = taskDTO.path("classify"); if (ObjectUtils.isNotEmpty(classify)) { Map<TriggerTypeEnum, JsonNode> triggerTypeEnumRuleConfigDTOMap = Map.of( TriggerTypeEnum._$1073774593, classify.path("1073774593"), TriggerTypeEnum._$1073758210, classify.path("1073758210") ); processModelType(triggerTypeEnumRuleConfigDTOMap, resultList, taskTypeEnum, ModelTypeEnum.CLASSIFY); } JsonNode mixed = taskDTO.path("mixed"); if (ObjectUtils.isNotEmpty(mixed)) { Map<TriggerTypeEnum, JsonNode> triggerTypeEnumRuleConfigDTOMap = Map.of( TriggerTypeEnum._$1073774593, mixed.path("1073774593"), TriggerTypeEnum._$1073758209, mixed.path("1073758209"), TriggerTypeEnum._$1073758211, mixed.path("1073758211"), TriggerTypeEnum._$1073758212, mixed.path("1073758212"), TriggerTypeEnum._$1073758213, mixed.path("1073758213") ); processModelType(triggerTypeEnumRuleConfigDTOMap, resultList, taskTypeEnum, ModelTypeEnum.MIXED); } JsonNode ocr = taskDTO.path("ocr"); if (ObjectUtils.isNotEmpty(ocr)) { Map<TriggerTypeEnum, JsonNode> triggerTypeEnumRuleConfigDTOMap = Map.of( TriggerTypeEnum._$1073758217, ocr.path("1073758217")); processModelType(triggerTypeEnumRuleConfigDTOMap, resultList, taskTypeEnum, ModelTypeEnum.OCR); } } } // private void processVideoPollingAnalysisTask(AIJsonTestDTO.RuleRelatedCapsDTO.VideoPollingAnalysisTaskDTO taskDTO, // List<DeviceAIAbilityTestResultDTO> resultList, // TaskTypeEnum taskTypeEnum){ // if (ObjectUtils.isNotEmpty(taskDTO)) { // AIJsonTestDTO.RuleRelatedCapsDTO.VideoPollingAnalysisTaskDTO.DetectDTO detect = taskDTO.getDetect(); // if (ObjectUtils.isNotEmpty(detect)) { // Map<TriggerTypeEnum, AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO> triggerTypeEnumRuleConfigDTOMap = // Map.of( TriggerTypeEnum._$1073774593, taskDTO.getDetect().get_$1073774593(), // TriggerTypeEnum._$1073758209, taskDTO.getDetect().get_$1073758209(), // TriggerTypeEnum._$1073758211, taskDTO.getDetect().get_$1073758211(), // TriggerTypeEnum._$1073758212, taskDTO.getDetect().get_$1073758212(), // TriggerTypeEnum._$1073758213, taskDTO.getDetect().get_$1073758213() // ); // processModelType(triggerTypeEnumRuleConfigDTOMap, resultList, taskTypeEnum, ModelTypeEnum.DETECT); // } // if (ObjectUtils.isNotEmpty(taskDTO.getClassify())) { // Map<TriggerTypeEnum, AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO> triggerTypeEnumRuleConfigDTOMap = // Map.of( TriggerTypeEnum._$1073774593, taskDTO.getClassify().get_$1073774593(), // TriggerTypeEnum._$1073758210, taskDTO.getClassify().get_$1073758210() // ); // processModelType(triggerTypeEnumRuleConfigDTOMap, resultList, taskTypeEnum, ModelTypeEnum.CLASSIFY); // } // if (ObjectUtils.isNotEmpty(taskDTO.getMixed())) { // Map<TriggerTypeEnum, AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO> triggerTypeEnumRuleConfigDTOMap = // Map.of( TriggerTypeEnum._$1073774593, taskDTO.getMixed().get_$1073774593(), // TriggerTypeEnum._$1073758209, taskDTO.getMixed().get_$1073758209(), // TriggerTypeEnum._$1073758211, taskDTO.getMixed().get_$1073758211(), // TriggerTypeEnum._$1073758212, taskDTO.getMixed().get_$1073758212(), // TriggerTypeEnum._$1073758213, taskDTO.getMixed().get_$1073758213() // ); // processModelType(triggerTypeEnumRuleConfigDTOMap, resultList, taskTypeEnum, ModelTypeEnum.MIXED); // } // if (ObjectUtils.isNotEmpty(taskDTO.getOcr())) { // Map<TriggerTypeEnum, AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO> triggerTypeEnumRuleConfigDTOMap = // Map.of( TriggerTypeEnum._$1073758217, taskDTO.getOcr().get_$1073758217()); // processModelType(triggerTypeEnumRuleConfigDTOMap, resultList, taskTypeEnum, ModelTypeEnum.OCR); // } // } // } // private void processPicturePollingAnalysisTask(AIJsonTestDTO.RuleRelatedCapsDTO.PicturePollingAnalysisTaskDTO taskDTO, // List<DeviceAIAbilityTestResultDTO> resultList, // TaskTypeEnum taskTypeEnum){ // if (ObjectUtils.isNotEmpty(taskDTO)) { //// if (ObjectUtils.isNotEmpty(taskDTO.getClassify())) { //// Map<TriggerTypeEnum, AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO> triggerTypeEnumRuleConfigDTOMap = //// Map.of( TriggerTypeEnum._$1073774593, taskDTO.getDetect().get_$1073774593(), //// TriggerTypeEnum._$1073758209, taskDTO.getDetect().get_$1073758209(), //// TriggerTypeEnum._$1073758211, taskDTO.getDetect().get_$1073758211(), //// TriggerTypeEnum._$1073758212, taskDTO.getDetect().get_$1073758212(), //// TriggerTypeEnum._$1073758213, taskDTO.getDetect().get_$1073758213() //// ); //// processModelType(triggerTypeEnumRuleConfigDTOMap, resultList, taskTypeEnum, ModelTypeEnum.DETECT); //// } // if (ObjectUtils.isNotEmpty(taskDTO.getClassify())) { // Map<TriggerTypeEnum, AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO> triggerTypeEnumRuleConfigDTOMap = // Map.of( // TriggerTypeEnum._$1073758210, taskDTO.getClassify().get_$1073758210() // ); // processModelType(triggerTypeEnumRuleConfigDTOMap, resultList, taskTypeEnum, ModelTypeEnum.CLASSIFY); // } // } // } private void processModelType(Map<TriggerTypeEnum, JsonNode> triggerTypeEnumJsonNodeMap, List<DeviceAIAbilityTestResultDTO> resultList, TaskTypeEnum taskTypeEnum, ModelTypeEnum modelTypeEnum){ if (ObjectUtils.isNotEmpty(triggerTypeEnumJsonNodeMap)) { triggerTypeEnumJsonNodeMap.forEach((triggerTypeEnum, jsonNode) -> { if (!jsonNode.isEmpty()) { AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO ruleConfigDTO = null; try { ruleConfigDTO = objectMapper.treeToValue(jsonNode, AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO.class); } catch (JsonProcessingException e) { throw new RuntimeException(e); } resultList.add(convertRuleConfig(taskTypeEnum.desc,triggerTypeEnum, modelTypeEnum.desc, ruleConfigDTO)); } }); } } private void processDetect(AIJsonTestDTO.RuleRelatedCapsDTO.VideoTaskDTO videoTask, List<DeviceAIAbilityTestResultDTO> resultList, TaskTypeEnum taskTypeEnum, ModelTypeEnum modelTypeEnum){ if (ObjectUtils.isNotEmpty(videoTask.getDetect())) { AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO _$1073758209 = videoTask.getDetect().get_$1073758209(); if (ObjectUtils.isNotEmpty(_$1073758209)) { resultList.add(convertRuleConfig(taskTypeEnum.desc,TriggerTypeEnum._$1073758209, modelTypeEnum.desc, _$1073758209)); } AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO _$1073758211 = videoTask.getDetect().get_$1073758211(); if (ObjectUtils.isNotEmpty(_$1073758211)) { resultList.add(convertRuleConfig(taskTypeEnum.desc,TriggerTypeEnum._$1073758211,modelTypeEnum.desc, _$1073758211)); } AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO _$1073758212 = videoTask.getDetect().get_$1073758212(); if (ObjectUtils.isNotEmpty(_$1073758212)) { resultList.add(convertRuleConfig(taskTypeEnum.desc,TriggerTypeEnum._$1073758212,modelTypeEnum.desc, _$1073758212)); } AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO _$1073758213 = videoTask.getDetect().get_$1073758213(); if (ObjectUtils.isNotEmpty(_$1073758213)) { resultList.add(convertRuleConfig(taskTypeEnum.desc,TriggerTypeEnum._$1073758213,modelTypeEnum.desc, _$1073758213)); } AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO _$1073758217 = videoTask.getDetect().get_$1073758217(); if (ObjectUtils.isNotEmpty(_$1073758217)) { resultList.add(convertRuleConfig(taskTypeEnum.desc,TriggerTypeEnum._$1073758217,modelTypeEnum.desc, _$1073758217)); } AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO _$1073774593 = videoTask.getDetect().get_$1073774593(); if (ObjectUtils.isNotEmpty(_$1073774593)) { resultList.add(convertRuleConfig(taskTypeEnum.desc,TriggerTypeEnum._$1073774593,modelTypeEnum.desc, _$1073774593)); } } } private DeviceAIAbilityTestResultDTO convertRuleConfig(String taskType, TriggerTypeEnum triggerTypeEnum, String modelType, AIJsonTestDTO.RuleRelatedCapsDTO.RuleConfigDTO ruleConfigDTO) { DeviceAIAbilityTestResultDTO dto = new DeviceAIAbilityTestResultDTO(); dto.setTaskType(taskType); dto.setTriggerTypeStr(triggerTypeEnum.desc); dto.setTriggerType(triggerTypeEnum.code); dto.setModelType(modelType); dto.setRegionType(RegionTypeEnum.getInstanceBySplit(ruleConfigDTO.getRegionType())); dto.setTargetType(ruleConfigDTO.getTriggerType()); dto.setTargetStatus(ruleConfigDTO.getTargetStatus()); dto.setSubTargetNumberCondition(ruleConfigDTO.getSubTargetNumberCondition()); dto.setNumberCondition(ruleConfigDTO.getNumberCondition()); dto.setDuration(ruleConfigDTO.getDuration()); dto.setSubDuration(ruleConfigDTO.getSubDuration()); dto.setDurationSensitive(ruleConfigDTO.getDurationSensitive()); dto.setTriggerInterval(ruleConfigDTO.getTriggerInterval()); dto.setSensitive(ruleConfigDTO.getSensitive()); dto.setMaxTriggerTimes(ruleConfigDTO.getMaxTriggerTimes()); dto.setCountInterval(ruleConfigDTO.getCountInterval()); dto.setAlertConfThreshold(ruleConfigDTO.getAlertConfThreshold()); dto.setFilterParam(ruleConfigDTO.getFilterParam()); dto.setOOSDInfo(ruleConfigDTO.getOOSDInfo()); dto.setSizeFilter(ruleConfigDTO.getSizeFilter()); dto.setOSensorInfo(ruleConfigDTO.getOSensorInfo()); dto.setRelationAnalysis(ruleConfigDTO.getRelationAnalysis()); dto.setOverlapRatio(ruleConfigDTO.getOverlapRatio()); dto.setStillFilterParam(ruleConfigDTO.getStillFilterParam()); dto.setShieldArea(ruleConfigDTO.getShieldArea()); dto.setMaxCmpNum(ruleConfigDTO.getMaxCmpNum()); dto.setTopN(ruleConfigDTO.getTopN()); dto.setLibInfo(ruleConfigDTO.getLibInfo()); dto.setUploadSuccess(ruleConfigDTO.getUploadSuccess()); dto.setUploadFailed(ruleConfigDTO.getUploadFailed()); dto.setTriggerMode(ruleConfigDTO.getTriggerMode()); dto.setRuleOverlayEnable(ruleConfigDTO.getRuleOverlayEnable()); dto.setTargetOverlayEnable(ruleConfigDTO.getTargetOverlayEnable()); dto.setRuleNameInfo(ruleConfigDTO.getRuleNameInfo()); dto.setRatioCondition(ruleConfigDTO.getRatioCondition()); dto.setTargetInfoOverlayEnable(ruleConfigDTO.getTargetInfoOverlayEnable()); dto.setTargetAttrOverlayEnable(ruleConfigDTO.getTargetAttrOverlayEnable()); dto.setTargetAreaOverlayEnable(ruleConfigDTO.getTargetAreaOverlayEnable()); dto.setTargetConfidenceOverlayEnable(ruleConfigDTO.getTargetConfidenceOverlayEnable()); dto.setTargetIDOverlayEnable(ruleConfigDTO.getTargetIDOverlayEnable()); return dto; } protected enum TaskTypeEnum { VIDEO_TASK("videoTask", "实时视频"), VIDEO_POLLING_ANALYSIS_TASK("videoPollingAnalysisTask", "轮询视频"), PICTURE_POLLING_ANALYSIS_TASK("picturePollingAnalysisTask", "定时抓图"); private String code; private String desc; TaskTypeEnum(String code, String desc) { this.code = code; this.desc = desc; } public static TaskTypeEnum getInstance(String taskType) { if (ObjectUtils.isEmpty(taskType)) { throw new BusinessException(400, "taskType不能为空"); } return Arrays.stream(TaskTypeEnum.values()).filter(e -> e.code.equals(taskType)).findFirst() .orElseThrow(() -> new BusinessException(400, "无效的taskType")); } } protected enum ModelTypeEnum { DETECT("detect", "检测"), CLASSIFY("classify", "分类"), MIXED("mixed", "混合"), OCR("ocr", "OCR"), DIFF("diff", "diff"), RETRIEVAL("retrieval", "retrieval"); private String code; private String desc; ModelTypeEnum(String code, String desc) { this.code = code; this.desc = desc; } public static ModelTypeEnum getInstance(String modelType) { if (ObjectUtils.isEmpty(modelType)) { throw new BusinessException(400, "modelType不能为空"); } return Arrays.stream(ModelTypeEnum.values()).filter(e -> e.code.equals(modelType)).findFirst() .orElseThrow(() -> new BusinessException(400, "无效的modelType")); } } protected enum TriggerTypeEnum { _$1073758209("1073758209", "区域目标异常状态检测"), _$1073774593("1073774593", "全分析规则"), _$1073758210("1073758210", "区域异常状态检测"), _$1073758211("1073758211", "跨线目标检测"), _$1073758212("1073758212", "跨线目标统计"), _$1073758213("1073758213", "区域目标数统计"), _$1073758214("1073758214", "区域交叠比统计"), _$1073758215("1073758215", "区域交叠比异常检测"), _$1073758216("1073758216", "OCR触发抓拍"), _$1073758217("1073758217", "区域状态变化检测(图像比对,相对背景)"), // _$1073754112("1073754112", "区域状态变化检测(图像比对,相对背景)") ; private String field; private String code; private String desc; TriggerTypeEnum(String code, String desc) { this.code = code; this.desc = desc; } public static TriggerTypeEnum getInstance(String triggerType) { if (ObjectUtils.isEmpty(triggerType)) { throw new BusinessException(400, "triggerType不能为空"); } return Arrays.stream(TriggerTypeEnum.values()).filter(e -> e.code.equals(triggerType)).findFirst() .orElseThrow(() -> new BusinessException(400, "无效triggerType")); } } protected enum RegionTypeEnum { RECT("Rect", "矩形"), AREA("Area", "多边形"), LINE_CROSS("LineCross", "线"); private String code; private String desc; RegionTypeEnum(String code, String desc) { this.code = code; this.desc = desc; } public static RegionTypeEnum getInstance(String regionType) { if (ObjectUtils.isEmpty(regionType)) { throw new BusinessException(400, "regionType不能为空"); } return Arrays.stream(RegionTypeEnum.values()).filter(e -> e.code.equals(regionType)).findFirst() .orElseThrow(() -> new BusinessException(400, "无效的regionType:"+regionType)); } public static String getInstanceBySplit(String regionType) { if (ObjectUtils.isEmpty(regionType)) { throw new BusinessException(400, "regionType不能为空"); } return Arrays.stream(regionType.split(",")) .map(rType -> getInstance(rType).desc) // 获取枚举的code .collect(Collectors.joining(",")); } } public static class SafePrecomputedMergeStrategy implements SheetWriteHandler { private final Map<Integer, List<CellRangeAddress>> mergeRegions = new HashMap<>(); private final int titleRowCount; private final List<?> dataList; private final List<String> mergeFields; private CellStyle centerStyle; /** * @param titleRowCount 标题行数(通常是1) * @param dataList 要写入的DTO列表 * @param mergeFields 需要合并的字段名(如:["taskType", "modelType"]) */ public SafePrecomputedMergeStrategy(int titleRowCount, List<?> dataList, String... mergeFields) { this.titleRowCount = titleRowCount; this.dataList = dataList; this.mergeFields = Arrays.asList(mergeFields); // 预先计算所有合并区域 precomputeMergeRegions(); } private void precomputeMergeRegions() { Map<String, Integer> fieldToIndex = new HashMap<>(); // 通过反射获取字段在DTO中的索引位置 if (!dataList.isEmpty()) { Object firstItem = dataList.get(0); java.lang.reflect.Field[] fields = firstItem.getClass().getDeclaredFields(); for (int i = 0; i < fields.length; i++) { fieldToIndex.put(fields[i].getName(), i); } } // 为每个合并字段计算合并区域 for (String field : mergeFields) { Integer colIndex = fieldToIndex.get(field); if (colIndex != null) { mergeRegions.put(colIndex, calculateRegionsForColumn(colIndex)); } } } private List<CellRangeAddress> calculateRegionsForColumn(int colIndex) { List<CellRangeAddress> regions = new ArrayList<>(); if (dataList.isEmpty()) return regions; int startRow = titleRowCount; // 数据起始行 Object lastValue = getFieldValue(dataList.get(0), colIndex); for (int i = 1; i < dataList.size(); i++) { Object currentValue = getFieldValue(dataList.get(i), colIndex); // 值变化时记录合并区域 if (!Objects.equals(lastValue, currentValue)) { if (i - 1 >= startRow) { // 至少2行相同 regions.add(new CellRangeAddress( startRow, titleRowCount + i - 1, colIndex, colIndex )); } startRow = titleRowCount + i; } lastValue = currentValue; } // 处理最后一段区域 if (dataList.size() - (startRow - titleRowCount) > 1) { regions.add(new CellRangeAddress( startRow, titleRowCount + dataList.size() - 1, colIndex, colIndex )); } return regions; } private Object getFieldValue(Object dto, int fieldIndex) { try { java.lang.reflect.Field[] fields = dto.getClass().getDeclaredFields(); if (fieldIndex < fields.length) { fields[fieldIndex].setAccessible(true); return fields[fieldIndex].get(dto); } } catch (Exception e) { // 忽略异常 } return null; } @Override public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { // 创建居中样式(在创建工作表前初始化) Workbook workbook = writeWorkbookHolder.getWorkbook(); this.centerStyle = workbook.createCellStyle(); // 设置水平居中 centerStyle.setAlignment(HorizontalAlignment.LEFT); // 设置垂直居中 centerStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 设置边框(可选) centerStyle.setBorderTop(BorderStyle.THIN); centerStyle.setBorderBottom(BorderStyle.THIN); centerStyle.setBorderLeft(BorderStyle.THIN); centerStyle.setBorderRight(BorderStyle.THIN); } @Override public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { Sheet sheet = writeSheetHolder.getSheet(); // 应用合并区域并设置样式 for (Map.Entry<Integer, List<CellRangeAddress>> entry : mergeRegions.entrySet()) { int columnIndex = entry.getKey(); for (CellRangeAddress region : entry.getValue()) { try { // 添加合并区域 sheet.addMergedRegion(region); // 设置合并区域样式为居中 applyCenterStyle(sheet, region, columnIndex); } catch (Exception e) { System.err.println("合并区域失败: " + region.formatAsString() + " 原因: " + e.getMessage()); } } } } /** * 为合并区域的所有单元格应用居中样式 */ private void applyCenterStyle(Sheet sheet, CellRangeAddress region, int columnIndex) { for (int rowNum = region.getFirstRow(); rowNum <= region.getLastRow(); rowNum++) { Row row = sheet.getRow(rowNum); if (row == null) continue; Cell cell = row.getCell(columnIndex); if (cell == null) continue; // 应用居中样式 cell.setCellStyle(centerStyle); } } } } 帮我想一个设计模式,优化一下代码,将单元测试类和每个类都分开,另外我简单说一下逻辑: 现在我有多个类,例如IPCH5 NVRKT2 IPCH9,每个类都有单独的PicturePollingAnalysisTask VideoPollingAnalysisTask VideoTask,里面的逻辑都不一样,怎么调整
最新发布
09-04
<think> 我们面对的是一个代码优化问题,需要满足以下要求: 1. 分离单元测试类和生产代码类 2. 处理多种设备类(IPCH5, NVRKT2, IPCH9)及其对应的任务类(PicturePollingAnalysisTask, VideoPollingAnalysisTask, VideoTask) 3. 调整代码逻辑,使其更清晰、可扩展 根据引用材料,我们可以考虑以下设计模式: 引用[1]提到策略模式:定义一系列算法,封装每个算法,并使它们可以互换。策略模式让算法独立于使用它的客户而变化。这适用于我们有多类设备,每类设备有不同任务(行为)的场景。 引用[2]提到工厂方法模式:解决简单工厂模式违反开闭原则的问题,通过定义一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。这可以用于创建不同的设备对象和任务对象。 引用[4]提到状态模式:当一个对象内在状态改变时允许改变其行为。但我们的场景中,设备类型是固定的,任务类型也是固定的,状态变化不明显,所以状态模式可能不适用。 引用[3]提到,大量使用策略模式会导致类膨胀,可以用枚举类来替代接口+实现类的方式。但考虑到我们设备类型和任务类型较多,且可能有不同的行为,使用策略模式配合工厂方法可能更合适。 此外,我们还需要分离单元测试类。我们可以将测试类放在单独的包中,例如`src/test/java`,与生产代码`src/main/java`分开。同时,使用工厂模式可以帮助我们在测试时注入模拟对象。 具体设计思路如下: 1. 设备类(Device)抽象:定义一个设备接口,包含执行任务的方法。 2. 具体设备类:实现设备接口,每个设备类可以包含一组任务(使用组合关系,设备拥有任务对象)。 3. 任务类(Task)抽象:定义一个任务接口,包含任务执行的方法。 4. 具体任务类:实现任务接口,每个任务类代表一种具体的任务。 5. 工厂模式:创建设备和任务的工厂,便于扩展。这里可以使用抽象工厂模式,因为我们需要创建多个相关对象(设备和任务)。 6. 测试类:针对每个类编写独立的单元测试,放在测试目录下。 类图设计如下: ``` +-----------------+ | Device | +-----------------+ | + executeTask() | +-----------------+ ^ | +----------------------+-----------------------+ | | | +-----------------+ +-----------------+ +-----------------+ | IPCH5Device | | NVRKT2Device | | IPCH9Device | +-----------------+ +-----------------+ +-----------------+ | | | | | | +-----------------+ +-----------------+ +-----------------+ +-----------------+ | Task | +-----------------+ | + runTask() | +-----------------+ ^ | +-----------------+-----------+-----------+-----------------+ | | | | +----------------------+ +----------------------+ +----------------------+ | PicturePollingTask | | VideoPollingTask | | VideoTask | +----------------------+ +----------------------+ +----------------------+ | | | | | | +----------------------+ +----------------------+ +----------------------+ ``` 设备类通过组合的方式持有任务对象。例如,一个IPCH5设备可以执行PicturePollingTask,也可以执行VideoTask,具体由设备初始化时传入的任务对象决定。 工厂部分,我们可以定义: - 设备工厂接口:`DeviceFactory`,包含创建设备的方法。 - 任务工厂接口:`TaskFactory`,包含创建任务的方法。 - 然后为每种设备族(比如针对IPCH5的设备族)创建具体的工厂,该工厂知道如何创建对应的设备和任务。 但是,考虑到任务类型和设备类型并非完全绑定(同一设备可以执行不同任务),我们可以将任务工厂独立出来,设备工厂在创建设备时,可以传入任务对象(或者任务工厂)。 为了简化,我们可以使用简单工厂+策略模式: - 设备工厂:根据设备类型字符串创建设备对象。 - 任务工厂:根据任务类型字符串创建任务对象。 - 设备对象在创建时,可以设置其任务(通过setter或者构造器注入)。 这样,当新增设备类型或任务类型时,只需要扩展工厂和具体类,而不需要修改原有代码。 代码结构示例: 生产代码目录(src/main/java): ``` com.example.designpattern device/ Device.java IPCH5Device.java NVRKT2Device.java IPCH9Device.java task/ Task.java PicturePollingAnalysisTask.java VideoPollingAnalysisTask.java VideoTask.java factory/ DeviceFactory.java TaskFactory.java SimpleDeviceFactory.java SimpleTaskFactory.java ``` 测试代码目录(src/test/java): ``` com.example.designpattern device/ IPCH5DeviceTest.java NVRKT2DeviceTest.java IPCH9DeviceTest.java task/ PicturePollingAnalysisTaskTest.java VideoPollingAnalysisTaskTest.java VideoTaskTest.java factory/ SimpleDeviceFactoryTest.java SimpleTaskFactoryTest.java ``` 这样,单元测试类与生产代码类就分离开了。 具体代码实现: 1. 定义任务接口: ```java public interface Task { void execute(); } ``` 2. 实现具体任务类: ```java public class PicturePollingAnalysisTask implements Task { @Override public void execute() { // 具体任务逻辑 } } public class VideoPollingAnalysisTask implements Task { @Override public void execute() { // 具体任务逻辑 } } public class VideoTask implements Task { @Override public void execute() { // 具体任务逻辑 } } ``` 3. 定义设备接口: ```java public interface Device { void runTask(); // 设备运行任务的方法 void setTask(Task task); // 设置任务(策略模式,可以动态替换任务) } ``` 4. 实现具体设备类(以IPCH5为例): ```java public class IPCH5Device implements Device { private Task task; public IPCH5Device(Task task) { this.task = task; } @Override public void runTask() { task.execute(); } @Override public void setTask(Task task) { this.task = task; } } ``` 5. 工厂类:创建设备和任务 ```java public class SimpleTaskFactory { public static Task createTask(String taskType) { if ("Picture".equals(taskType)) { return new PicturePollingAnalysisTask(); } else if ("VideoPolling".equals(taskType)) { return new VideoPollingAnalysisTask(); } else if ("Video".equals(taskType)) { return new VideoTask(); } throw new IllegalArgumentException("Unknown task type: " + taskType); } } public class SimpleDeviceFactory { public static Device createDevice(String deviceType, Task task) { if ("IPCH5".equals(deviceType)) { return new IPCH5Device(task); } else if ("NVRKT2".equals(deviceType)) { return new NVRKT2Device(task); } else if ("IPCH9".equals(deviceType)) { return new IPCH9Device(task); } throw new IllegalArgumentException("Unknown device type: " + deviceType); } } ``` 6. 单元测试类示例(在test目录下): ```java public class IPCH5DeviceTest { @Test public void testRunTask() { // 使用模拟任务 Task mockTask = mock(Task.class); Device device = new IPCH5Device(mockTask); device.runTask(); // 验证mockTask的execute方法被调用 verify(mockTask).execute(); } } ``` 以上设计使用了策略模式(设备运行的任务可以动态替换)和简单工厂模式(集中创建对象)。这样,当新增设备或任务时,只需要增加相应的具体类和修改工厂方法即可,符合开闭原则。 另外,单元测试类独立于生产代码,便于维护。 优化点:如果担心工厂类修改违反开闭原则,可以改用工厂方法模式,每个设备类型和任务类型有对应的工厂子类,但这样会增加类的数量。考虑到设备类型和任务类型相对固定,简单工厂模式更简单直观。 因此,我们采用策略模式+简单工厂模式,并分离测试代码,即可满足需求。 相关问题: 1. 如何在策略模式中管理大量的策略类? 2. 简单工厂模式与工厂方法模式在应用场景上的区别是什么? 3. 如何设计单元测试来模拟策略对象的行为? </think> 基于您的需求,我将使用策略模式配合工厂方法模式进行代码优化,实现设备与任务解耦、测试分离的目标。以下是详细设计方案: ### 解决方案设计 ```plantuml @startuml !theme plain interface Device { + executeTask(Task task) } class IPCH5Device implements Device class NVRKT2Device implements Device class IPCH9Device implements Device interface Task { + run() } class PicturePollingAnalysisTask implements Task class VideoPollingAnalysisTask implements Task class VideoTask implements Task abstract class DeviceFactory { + {static} createDevice(String type) : Device + {static} createTask(String type) : Task } class TestFactory extends DeviceFactory Device o--> Task DeviceFactory ..> Device DeviceFactory ..> Task @enduml ``` ### 核心代码实现 ```java // 1. 设备接口与实现(src/main/java/device) public interface Device { void executeTask(Task task); } public class IPCH5Device implements Device { @Override public void executeTask(Task task) { System.out.println("IPCH5执行任务"); task.run(); } } // 其他设备类同理(NVRKT2Device, IPCH9Device) // 2. 任务接口与实现(src/main/java/task) public interface Task { void run(); } public class PicturePollingAnalysisTask implements Task { @Override public void run() { System.out.println("图片轮询分析任务"); } } // 其他任务类同理(VideoPollingAnalysisTask, VideoTask) // 3. 工厂模式封装(src/main/java/factory) public abstract class DeviceFactory { public static Device createDevice(String type) { switch(type) { case "IPCH5": return new IPCH5Device(); case "NVRKT2": return new NVRKT2Device(); case "IPCH9": return new IPCH9Device(); default: throw new IllegalArgumentException("未知设备类型"); } } public static Task createTask(String type) { switch(type) { case "Picture": return new PicturePollingAnalysisTask(); case "VideoPolling": return new VideoPollingAnalysisTask(); case "Video": return new VideoTask(); default: throw new IllegalArgumentException("未知任务类型"); } } } // 4. 单元测试类(src/test/java) public class DeviceTest { @Test public void testIPCH5WithPictureTask() { Device device = DeviceFactory.createDevice("IPCH5"); Task task = DeviceFactory.createTask("Picture"); device.executeTask(task); // 验证设备与任务协同 } @Test public void testNVRKT2WithVideoTask() { // 测试逻辑同上... } } ``` ### 设计优势 1. **策略模式应用** 设备与任务通过接口解耦,符合策略模式定义[^1]。新增设备类型只需实现`Device`接口,新增任务实现`Task`接口,无需修改已有代码。 2. **工厂方法优化** 解决简单工厂的闭包原则问题[^2],通过静态工厂方法统一创建对象,支持扩展新设备/
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值