diff --git a/src/main/java/ru/nbch/indicsearchservice/filter/firstlevel/DefaultFirstLevelTableFilter.java b/src/main/java/ru/nbch/indicsearchservice/filter/firstlevel/DefaultFirstLevelTableFilter.java index 499af54..7e96838 100644 --- a/src/main/java/ru/nbch/indicsearchservice/filter/firstlevel/DefaultFirstLevelTableFilter.java +++ b/src/main/java/ru/nbch/indicsearchservice/filter/firstlevel/DefaultFirstLevelTableFilter.java @@ -26,7 +26,7 @@ public class DefaultFirstLevelTableFilter implements FirstLevelTableFilter { ); @Override - public List applyFilter(Map> tableDataMapByFid) { + public List applyFilter(Map> tableDataMapByFid, String memberCode) { List result = new ArrayList<>(); for (Map.Entry> entry : tableDataMapByFid.entrySet()) { @@ -34,7 +34,14 @@ public class DefaultFirstLevelTableFilter implements FirstLevelTableFilter { List tableRows = entry.getValue(); if (SUPPORTED_TABLE_NAMES.contains(tableName)) { - result.addAll(tableRows); + List tableRowsWithMatchingMemberCode = tableRows.stream() + .filter(row -> row.getFieldData().stream() + .anyMatch(field -> "MEMBER_CODE".equals(field.columnName()) && + field.columnValue() != null && + field.columnValue().toString().startsWith(memberCode))) + .toList(); + + result.addAll(tableRowsWithMatchingMemberCode); } } diff --git a/src/main/java/ru/nbch/indicsearchservice/filter/firstlevel/FirstLevelTableFilter.java b/src/main/java/ru/nbch/indicsearchservice/filter/firstlevel/FirstLevelTableFilter.java index 93556fb..663a7a9 100644 --- a/src/main/java/ru/nbch/indicsearchservice/filter/firstlevel/FirstLevelTableFilter.java +++ b/src/main/java/ru/nbch/indicsearchservice/filter/firstlevel/FirstLevelTableFilter.java @@ -6,5 +6,5 @@ import ru.nbch.indicsearchservice.filter.TableFilter; import ru.nbch.indicsearchservice.model.TableData; public interface FirstLevelTableFilter extends TableFilter { - List applyFilter(Map> tableDataMapByFid); + List applyFilter(Map> tableDataMapByFid, String memberCode); } diff --git a/src/main/java/ru/nbch/indicsearchservice/filter/secondlevel/AccountSecondLevelTableFilter.java b/src/main/java/ru/nbch/indicsearchservice/filter/secondlevel/AccountSecondLevelTableFilter.java new file mode 100644 index 0000000..b2a4f0f --- /dev/null +++ b/src/main/java/ru/nbch/indicsearchservice/filter/secondlevel/AccountSecondLevelTableFilter.java @@ -0,0 +1,69 @@ +package ru.nbch.indicsearchservice.filter.secondlevel; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.springframework.stereotype.Component; +import ru.nbch.indicsearchservice.model.TableData; + +@Component +public class AccountSecondLevelTableFilter implements SecondLevelTableFilter { + private static final Set SUPPORTED_TABLE_NAMES = Set.of( + "ACCOUNT_AMEND", + "PAYMENT", + "COLLATERAL", + "GUARANTOR", + "BANK_GUARANTEE" + ); + + @Override + public void applyFilter(List firstLevelTableDataList, Map> tableDataMapByFid) { + if (firstLevelTableDataList == null || firstLevelTableDataList.isEmpty() || tableDataMapByFid == null) { + return; + } + + Map> relatedTablesByAccSerialNum = new HashMap<>(); + + for (String supportedTableName : SUPPORTED_TABLE_NAMES) { + List childTables = tableDataMapByFid.get(supportedTableName); + + if (childTables != null) { + for (TableData childTable : childTables) { + Object accSerialNum = getFieldValue(childTable, "ACC_SERIAL_NUM"); + if (accSerialNum != null) { + relatedTablesByAccSerialNum + .computeIfAbsent(accSerialNum, k -> new ArrayList<>()) + .add(childTable); + } + } + } + } + + for (TableData parentTable : firstLevelTableDataList) { + Object serialNum = getFieldValue(parentTable, "SERIAL_NUM"); + + if (serialNum != null) { + List matchedParentTables = relatedTablesByAccSerialNum.get(serialNum); + if (matchedParentTables != null) { + parentTable.getRelatedTableData().addAll(matchedParentTables); + } + } + } + } + + private Object getFieldValue(TableData tableData, String targetColumnName) { + if (tableData.getFieldData() == null) { + return null; + } + + for (TableData.FieldData field : tableData.getFieldData()) { + if (targetColumnName.equals(field.columnName())) { + return field.columnValue(); + } + } + + return null; + } +} diff --git a/src/main/java/ru/nbch/indicsearchservice/service/IndicSearchService.java b/src/main/java/ru/nbch/indicsearchservice/service/IndicSearchService.java index 75ca97f..3755d40 100644 --- a/src/main/java/ru/nbch/indicsearchservice/service/IndicSearchService.java +++ b/src/main/java/ru/nbch/indicsearchservice/service/IndicSearchService.java @@ -1,12 +1,18 @@ package ru.nbch.indicsearchservice.service; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.util.StopWatch; import ru.nbch.indicsearchservice.dto.request.AddSearchJobRequestDto; import ru.nbch.indicsearchservice.dto.response.AddSearchJobResponseDto; import ru.nbch.indicsearchservice.dto.response.JobStatusResponseDto; @@ -15,29 +21,45 @@ import ru.nbch.indicsearchservice.filter.secondlevel.SecondLevelTableFilter; import ru.nbch.indicsearchservice.filter.thirdlevel.ThirdLevelTableFilter; import ru.nbch.indicsearchservice.loader.TableLoader; import ru.nbch.indicsearchservice.model.TableData; +import ru.nbch.indicsearchservice.util.ExcelWriter; import ru.nbch.indicsearchservice.util.IndicSearchUtils; +import tools.jackson.databind.json.JsonMapper; @Service public class IndicSearchService { + private static final Logger log = LoggerFactory.getLogger(IndicSearchService.class); + + private static final boolean IS_EXPORT_AS_EXCEL = true; + private final List tableLoaders; private final DefaultFirstLevelTableFilter firstLevelTableFilter; private final List secondLevelTableFilters; private final List thirdLevelTableFilters; private final IndicSearchUtils indicSearchUtils; + private final ExcelWriter excelWriter; + + private final JsonMapper jsonMapper; public IndicSearchService(List tableLoaders, DefaultFirstLevelTableFilter firstLevelTableFilter, List secondLevelTableFilters, List thirdLevelTableFilters, - IndicSearchUtils indicSearchUtils) { + IndicSearchUtils indicSearchUtils, + ExcelWriter excelWriter, + JsonMapper jsonMapper) { this.tableLoaders = tableLoaders; this.firstLevelTableFilter = firstLevelTableFilter; this.secondLevelTableFilters = secondLevelTableFilters; this.thirdLevelTableFilters = thirdLevelTableFilters; this.indicSearchUtils = indicSearchUtils; + this.excelWriter = excelWriter; + this.jsonMapper = jsonMapper; } public AddSearchJobResponseDto addSearchJob(AddSearchJobRequestDto request) { + StopWatch sw = new StopWatch(); + sw.start(); + List suitableTableLoaders = new ArrayList<>(); for (TableLoader tableLoader : tableLoaders) { if (tableLoader.isSuitableForDataTypeAndSearchParameter(request.getDataType(), request.getSearchParameter())) { @@ -51,15 +73,29 @@ public class IndicSearchService { request.getSearchValue() ); - Map> tableDataMapByFid = new HashMap<>(); - for (TableLoader tableLoader : suitableTableLoaders) { - tableDataMapByFid.put(tableLoader.getTableName(), tableLoader.searchByFid(foundFids)); - } + Map> tableDataMapByFid = new ConcurrentHashMap<>(); + suitableTableLoaders.parallelStream().forEach(tl -> tableDataMapByFid.put(tl.getTableName(), tl.searchByFid(foundFids))); +// for (TableLoader tableLoader : suitableTableLoaders) { +// tableDataMapByFid.put(tableLoader.getTableName(), tableLoader.searchByFid(foundFids)); +// } - List result = firstLevelTableFilter.applyFilter(tableDataMapByFid); + List result = firstLevelTableFilter.applyFilter(tableDataMapByFid, request.getMemberCode()); secondLevelTableFilters.forEach(f -> f.applyFilter(result, tableDataMapByFid)); thirdLevelTableFilters.forEach(f -> f.applyFilter(result, tableDataMapByFid)); + sw.stop(); + log.info(sw.prettyPrint()); + + if (!IS_EXPORT_AS_EXCEL) { + try { + Files.write(Path.of("1.json"), jsonMapper.writeValueAsBytes(result)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } else { + excelWriter.writeExcelFile(result); + } + return null; } diff --git a/src/main/java/ru/nbch/indicsearchservice/util/ExcelWriter.java b/src/main/java/ru/nbch/indicsearchservice/util/ExcelWriter.java new file mode 100644 index 0000000..08cb75b --- /dev/null +++ b/src/main/java/ru/nbch/indicsearchservice/util/ExcelWriter.java @@ -0,0 +1,181 @@ +package ru.nbch.indicsearchservice.util; + +import jakarta.annotation.Nullable; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.VerticalAlignment; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFFont; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import ru.nbch.indicsearchservice.model.TableData; + +@Component +public class ExcelWriter { + private static final Logger log = LoggerFactory.getLogger(ExcelWriter.class); + + public void writeExcelFile(List tableDataList) { + Map> tableDataGroupedByTables = tableDataList.stream() + .collect(Collectors.groupingBy(TableData::getTableName)); + + Path excelFile = Path.of("2.xlsx"); + + try (SXSSFWorkbook workbook = new SXSSFWorkbook(); + OutputStream os = Files.newOutputStream(excelFile)) { + CellStyle headerCellStyle = createHeaderCellStyle(workbook); + CellStyle cellStyle = createCellStyle(workbook); + + for (Map.Entry> entry : tableDataGroupedByTables.entrySet()) { + String tableName = entry.getKey(); + List tableRows = entry.getValue(); + + Sheet tableSheet = createSheet(workbook, tableName.toUpperCase()); + MutableInt currentRow = new MutableInt(0); + + for (TableData tableRow : tableRows) { + writeDataSheetIntoSheetRow( + tableRow, + tableSheet, + currentRow, + headerCellStyle, + cellStyle + ); + } + } + + workbook.write(os); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + + private CellStyle createHeaderCellStyle(Workbook workbook) { + CellStyle headerCellStyle = workbook.createCellStyle(); + headerCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + + XSSFFont font = (XSSFFont) workbook.createFont(); + font.setFontName("SansSerif"); + font.setFontHeightInPoints((short) 11); + font.setBold(true); + headerCellStyle.setFont(font); + + return headerCellStyle; + } + + private CellStyle createCellStyle(Workbook workbook) { + CellStyle cellStyle = workbook.createCellStyle(); + cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + cellStyle.setBorderBottom(BorderStyle.THIN); + cellStyle.setBorderLeft(BorderStyle.THIN); + cellStyle.setBorderTop(BorderStyle.THIN); + cellStyle.setBorderRight(BorderStyle.THIN); + + XSSFFont font = (XSSFFont) workbook.createFont(); + font.setFontName("Calibri"); + font.setFontHeightInPoints((short) 11); + cellStyle.setFont(font); + + return cellStyle; + } + + private Sheet createSheet(Workbook workbook, String sheetName) { + Sheet sheet = workbook.createSheet(sheetName); + sheet.setColumnWidth(0, 25 * 256); + sheet.setColumnWidth(1, 115 * 256); + sheet.setColumnWidth(2, 38 * 256); + + return sheet; + } + + private void createHeaderRow(String localizedTableName, + Sheet sheet, + MutableInt currentRow, + CellStyle headerCellStyle) { + Row headerRow = sheet.createRow(currentRow.intValue()); + headerRow.setHeightInPoints(15); + + Cell headerCell = headerRow.createCell(0); + headerCell.setCellValue(localizedTableName); + headerCell.setCellStyle(headerCellStyle); + sheet.addMergedRegion(new CellRangeAddress(currentRow.intValue(), currentRow.intValue(), 0, 2)); + + currentRow.increment(); + } + + public void writeDataSheetIntoSheetRow(TableData tableData, + Sheet sheet, + MutableInt currentRow, + CellStyle headerCellStyle, + CellStyle cellStyle) { + createHeaderRow( + tableData.getTableName(), + sheet, + currentRow, + headerCellStyle + ); + + for (TableData.FieldData fieldData : tableData.getFieldData()) { + writeFieldDataIntoSheetRow( + fieldData.columnName(), + fieldData.columnName(), + fieldData.columnValue(), + sheet, + currentRow, + cellStyle + ); + } + + currentRow.increment(); + + if (!tableData.getRelatedTableData().isEmpty()) { + for (TableData relatedTableData : tableData.getRelatedTableData()) { + writeDataSheetIntoSheetRow( + relatedTableData, + sheet, + currentRow, + headerCellStyle, + cellStyle + ); + } + } + } + + private void writeFieldDataIntoSheetRow(String fieldKey, + String localizedFieldKey, + @Nullable Object fieldValue, + Sheet sheet, + MutableInt currentRow, + CellStyle cellStyle) { + Row dataRow = sheet.createRow(currentRow.intValue()); + dataRow.setHeightInPoints(15); + + Cell dataFieldCell = dataRow.createCell(0); + dataFieldCell.setCellValue(fieldKey.toUpperCase()); + dataFieldCell.setCellStyle(cellStyle); + + Cell descriptionCell = dataRow.createCell(1); + descriptionCell.setCellValue(localizedFieldKey); + descriptionCell.setCellStyle(cellStyle); + + Cell dataValueCell = dataRow.createCell(2); + dataValueCell.setCellValue(Optional.ofNullable(fieldValue).orElse("").toString()); + dataValueCell.setCellStyle(cellStyle); + + currentRow.increment(); + } +}