diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/paging/MciPagingUtils.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/paging/MciPagingUtils.java new file mode 100644 index 000000000..fe8cdf0d9 --- /dev/null +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/paging/MciPagingUtils.java @@ -0,0 +1,69 @@ +package io.shinhanlife.dat.lib.paging; + +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/** + * @package io.shinhanlife.dat.lib.paging + * @className MciPagingUtils + * @description AX HUB 시스템 처리 클래스 + * @author 0986406 + * @create 2026.09.01 + *
+ * ---------- 개정이력 ----------
+ * 수정일      수정자    수정내용
+ * ---------- -------- ---------------------------
+ * 2026.09.01  0986406    최초생성
+ * 
+ * 
+ */ +@Slf4j +public final class MciPagingUtils { + + private MciPagingUtils() { + } + + /** + * 페이징 응답 데이터(List 필드)를 대상(target) 객체에 순차적으로 병합(append)합니다. + * 클래스 상속 계층 구조를 탐색하여 모든 List 타입 필드를 병합합니다. + * + * @param target 누적할 최종 응답 DTO + * @param src 각 페이지별 응답 DTO + */ + public static void mergeResponseData(Object target, Object src) { + if (target == null || src == null) { + return; + } + Class current = target.getClass(); + while (current != null && current != Object.class) { + for (Field field : current.getDeclaredFields()) { + if (List.class.isAssignableFrom(field.getType())) { + field.setAccessible(true); + try { + List srcList = (List) field.get(src); + if (srcList != null && !srcList.isEmpty()) { + @SuppressWarnings("unchecked") + List targetList = (List) field.get(target); + if (targetList == null) { + targetList = new ArrayList<>(srcList); + field.set(target, targetList); + } else { + if (!(targetList instanceof ArrayList)) { + targetList = new ArrayList<>(targetList); + field.set(target, targetList); + } + targetList.addAll(srcList); + } + } + } catch (Exception e) { + log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); + } + } + } + current = current.getSuperclass(); + } + } +} diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java index 680acaafc..a772c9ec6 100644 --- a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/ToolScaffolder.java @@ -119,17 +119,6 @@ public class ToolScaffolder { } } - public static String businessProposalGuide() { - return """ - [업무 제안서 작성 가이드] - 통합계약원부 조회 - 1. 조회 대상·식별 기준: 무엇을 어떤 값으로 찾는지 - 계약번호가 있으면 상세 원부를 조회 - 2. 조회 목적·사용처: 어떤 업무 상황에서 쓰는지 - 해지·대출·보험금 상세는 별도 Tool - """; - } - public static String scaffoldUseCase(String useCaseName, String moduleName, String author, String createDate, List tools) throws IOException { if (tools == null || tools.isEmpty()) { @@ -340,7 +329,7 @@ public class ToolScaffolder { ? tool.clientSystemCode().toUpperCase(Locale.ROOT) + "Converter" : baseName + "Converter"; writeUtf8(targetConverterDir.resolve(converterName + ".java"), - groupedMciConverterContent(converterPkg, bizPackage, baseName, ioPackage, ioPrefix, converterName)); + groupedMciConverterContent(converterPkg, bizPackage, baseName, ioPackage, ioPrefix, converterName, pagingMode)); } else { writeUtf8(ioDir.resolve(baseName + "HttpRequest.java"), dtoContent(ioPackage + ".io", baseName + "HttpRequest", tool.inputFields(), "", "", true)); @@ -440,7 +429,8 @@ public class ToolScaffolder { .append("import ").append(bizPackage).append(".dto.").append(baseName).append("Response;\n") .append("import ").append(bizPackage).append(".paging.").append(pagingInterface).append(";\n") .append("import io.shinhanlife.dat.lib.paging.MciPage;\n") - .append("import io.shinhanlife.dat.lib.paging.").append(pagingInfoType).append(";\n"); + .append("import io.shinhanlife.dat.lib.paging.").append(pagingInfoType).append(";\n") + .append("import io.shinhanlife.dat.lib.paging.MciPagingUtils;\n"); if (!fields.toString().contains(" " + pagingVar + ";")) { fields.append(" private final ").append(pagingInterface).append(" ").append(pagingVar).append(";\n"); @@ -488,39 +478,7 @@ public class ToolScaffolder { if (hasMciOrPaging) { imports.append("import lombok.extern.slf4j.Slf4j;\n"); } - boolean hasPaging = tools.stream().anyMatch(t -> t.definitionOptions() != null && t.definitionOptions().pagingModeOrNone() != PagingMode.NONE); - if (hasPaging) { - methods.append(""" - private void mergeResponseData(Object target, Object src) { - if (target == null || src == null) return; - for (java.lang.reflect.Field field : target.getClass().getDeclaredFields()) { - if (java.util.List.class.isAssignableFrom(field.getType())) { - field.setAccessible(true); - try { - java.util.List srcList = (java.util.List) field.get(src); - if (srcList != null && !srcList.isEmpty()) { - @SuppressWarnings("unchecked") - java.util.List targetList = (java.util.List) field.get(target); - if (targetList == null) { - targetList = new java.util.ArrayList<>(srcList); - field.set(target, targetList); - } else { - if (!(targetList instanceof java.util.ArrayList)) { - targetList = new java.util.ArrayList<>(targetList); - field.set(target, targetList); - } - targetList.addAll(srcList); - } - } - } catch (Exception e) { - log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); - } - } - } - } - """); - } return "package " + bizPackage + ".usecase.impl;\n\n" + "import " + bizPackage + ".usecase." + useCaseBaseName + "UseCase;\n" + "import lombok.RequiredArgsConstructor;\nimport org.springframework.stereotype.Service;\n" + imports @@ -538,7 +496,7 @@ public class ToolScaffolder { @Override public %sResponse %s(%sRequest req) { - log.info("[MCI Tool] {} 요청 수신 (페이징 모드: %s).", "%s", "%s"); + log.info("[MCI Tool] {} 요청 수신 (페이징 모드: {}).", "%s", "%s"); try { %s pagingInfo = null; %s pagingInfoLast = null; @@ -554,7 +512,7 @@ public class ToolScaffolder { if (finalResponse == null) { finalResponse = page.data(); } else if (page.data() != null) { - mergeResponseData(finalResponse, page.data()); + MciPagingUtils.mergeResponseData(finalResponse, page.data()); } if (!page.hasNext()) { hasMore = false; @@ -566,8 +524,18 @@ public class ToolScaffolder { if (finalResponse == null) { finalResponse = new %sResponse(); + finalResponse.setResultCode("FAIL"); + finalResponse.setResultMessage("MCI 응답 데이터가 존재하지 않습니다."); + finalResponse.setHasMore(false); + finalResponse.setPageNo(1); + finalResponse.setTotalPageCount(0); + finalResponse.setTotalCount(0); + return finalResponse; + } + + if (finalResponse.getResultCode() == null || finalResponse.getResultCode().isBlank()) { + finalResponse.setResultCode("SUCCESS"); } - finalResponse.setResultCode("SUCCESS"); finalResponse.setHasMore(hasMore); if (pagingInfoLast != null) { int lastPageNo = Math.max(1, pagingInfoLast.getPageNo() - 1); @@ -598,7 +566,7 @@ public class ToolScaffolder { } """.formatted( baseName, tool.methodName(), baseName, - pagingMode, snakeToolName, pagingMode, + snakeToolName, pagingMode, pagingInfoType, pagingInfoType, baseName, @@ -610,7 +578,7 @@ public class ToolScaffolder { @Override public %sResponse %s(%sRequest req) { - log.info("[MCI Tool] {} 요청 수신 (페이징 모드: %s).", "%s", "%s"); + log.info("[MCI Tool] {} 요청 수신 (페이징 모드: {}).", "%s", "%s"); try { %s pagingInfo = null; %sResponse finalResponse = null; @@ -624,7 +592,7 @@ public class ToolScaffolder { if (finalResponse == null) { finalResponse = page.data(); } else if (page.data() != null) { - mergeResponseData(finalResponse, page.data()); + MciPagingUtils.mergeResponseData(finalResponse, page.data()); } if (!page.hasNext()) { hasMore = false; @@ -636,8 +604,15 @@ public class ToolScaffolder { if (finalResponse == null) { finalResponse = new %sResponse(); + finalResponse.setResultCode("FAIL"); + finalResponse.setResultMessage("MCI 응답 데이터가 존재하지 않습니다."); + finalResponse.setHasMore(false); + return finalResponse; + } + + if (finalResponse.getResultCode() == null || finalResponse.getResultCode().isBlank()) { + finalResponse.setResultCode("SUCCESS"); } - finalResponse.setResultCode("SUCCESS"); finalResponse.setHasMore(hasMore); if (hasMore) { finalResponse.setResultMessage("MCI 기본 최대 조회 건수(10회)까지 조회되었습니다. 추가 데이터가 더 존재합니다 (총 " + loopCount + "회 호출, hasMore=true)."); @@ -656,7 +631,7 @@ public class ToolScaffolder { } """.formatted( baseName, tool.methodName(), baseName, - pagingMode, snakeToolName, pagingMode, + snakeToolName, pagingMode, pagingInfoType, baseName, baseName, pagingInfoType, pagingVariable, @@ -729,16 +704,26 @@ public class ToolScaffolder { + "public interface " + useCaseBaseName + "Converter {\n}\n"; } - private static String groupedMciConverterContent(String converterPackage, String bizPackage, String baseName, String ioPackage, String interfaceId, String converterName) { + private static String groupedMciConverterContent(String converterPackage, String bizPackage, String baseName, String ioPackage, String interfaceId, String converterName, PagingMode pagingMode) { + String pageIgnore = ""; + if (pagingMode == PagingMode.PAGE_NUMBER) { + pageIgnore = " @Mapping(target = \"pageInfo\", ignore = true)\n"; + } else if (pagingMode == PagingMode.SCROLL) { + pageIgnore = " @Mapping(target = \"scrPageInfo\", ignore = true)\n"; + } return "package " + converterPackage + ";\n\n" + "import " + bizPackage + ".dto." + baseName + "Request;\n" + "import " + bizPackage + ".dto." + baseName + "Response;\n" + "import " + ioPackage + ".io." + interfaceId + "_I;\n" + "import " + ioPackage + ".io." + interfaceId + "_O;\n" - + "import org.mapstruct.Mapper;\nimport org.mapstruct.ReportingPolicy;\n\n" + + "import org.mapstruct.Mapper;\nimport org.mapstruct.Mapping;\nimport org.mapstruct.ReportingPolicy;\n\n" + "@Mapper(componentModel = \"spring\", unmappedTargetPolicy = ReportingPolicy.IGNORE)\n" + "public interface " + converterName + " {\n" - + " " + interfaceId + "_I toRequest(" + baseName + "Request request);\n" + + pageIgnore + + " " + interfaceId + "_I toRequest(" + baseName + "Request request);\n\n" + + " default " + interfaceId + "_I toLegacyRequest(" + baseName + "Request request) {\n" + + " return toRequest(request);\n" + + " }\n\n" + " " + baseName + "Response toResponse(" + interfaceId + "_O response);\n}\n"; } @@ -844,6 +829,7 @@ public class ToolScaffolder { implementation = addImport(implementation, "import " + bizPackage + ".paging." + pagingInterface + ";"); implementation = addImport(implementation, "import io.shinhanlife.dat.lib.paging.MciPage;"); implementation = addImport(implementation, "import io.shinhanlife.dat.lib.paging." + pagingInfoType + ";"); + implementation = addImport(implementation, "import io.shinhanlife.dat.lib.paging.MciPagingUtils;"); implementation = addImport(implementation, "import lombok.extern.slf4j.Slf4j;"); if (!implementation.contains("@Slf4j")) { implementation = implementation.replaceFirst("public class ", "@Slf4j\npublic class "); @@ -857,38 +843,6 @@ public class ToolScaffolder { } String method = groupedToolPagingMethodContent(tool, baseName, pagingVar, pagingMode, pagingInfoType); implementation = insertBeforeLastBrace(implementation, method); - if (!implementation.contains("mergeResponseData(")) { - implementation = insertBeforeLastBrace(implementation, """ - - private void mergeResponseData(Object target, Object src) { - if (target == null || src == null) return; - for (java.lang.reflect.Field field : target.getClass().getDeclaredFields()) { - if (java.util.List.class.isAssignableFrom(field.getType())) { - field.setAccessible(true); - try { - java.util.List srcList = (java.util.List) field.get(src); - if (srcList != null && !srcList.isEmpty()) { - @SuppressWarnings("unchecked") - java.util.List targetList = (java.util.List) field.get(target); - if (targetList == null) { - targetList = new java.util.ArrayList<>(srcList); - field.set(target, targetList); - } else { - if (!(targetList instanceof java.util.ArrayList)) { - targetList = new java.util.ArrayList<>(targetList); - field.set(target, targetList); - } - targetList.addAll(srcList); - } - } - } catch (Exception e) { - log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); - } - } - } - } - """); - } } else { String clientClassName; String clientVariable; @@ -1381,6 +1335,7 @@ public class ToolScaffolder { import %s.paging.%s; import io.shinhanlife.dat.lib.paging.MciPage; import io.shinhanlife.dat.lib.paging.PgNumPagingInfo; + import io.shinhanlife.dat.lib.paging.MciPagingUtils; import io.shinhanlife.glow.BizException; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @@ -1425,7 +1380,7 @@ public class ToolScaffolder { if (finalResponse == null) { finalResponse = page.data(); } else if (page.data() != null) { - mergeResponseData(finalResponse, page.data()); + MciPagingUtils.mergeResponseData(finalResponse, page.data()); } if (!page.hasNext()) { hasMore = false; @@ -1477,34 +1432,6 @@ public class ToolScaffolder { return response; } } - - private void mergeResponseData(%sResponse target, %sResponse src) { - if (target == null || src == null) return; - for (java.lang.reflect.Field field : target.getClass().getDeclaredFields()) { - if (java.util.List.class.isAssignableFrom(field.getType())) { - field.setAccessible(true); - try { - java.util.List srcList = (java.util.List) field.get(src); - if (srcList != null && !srcList.isEmpty()) { - @SuppressWarnings("unchecked") - java.util.List targetList = (java.util.List) field.get(target); - if (targetList == null) { - targetList = new java.util.ArrayList<>(srcList); - field.set(target, targetList); - } else { - if (!(targetList instanceof java.util.ArrayList)) { - targetList = new java.util.ArrayList<>(targetList); - field.set(target, targetList); - } - targetList.addAll(srcList); - } - } - } catch (Exception e) { - log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); - } - } - } - } } """.formatted( bizPackage, @@ -1525,7 +1452,6 @@ public class ToolScaffolder { baseName, baseName, baseName, baseName, - baseName, baseName, baseName, baseName ); } else { @@ -1538,6 +1464,7 @@ public class ToolScaffolder { import %s.paging.%s; import io.shinhanlife.dat.lib.paging.MciPage; import io.shinhanlife.dat.lib.paging.ScrollPagingInfo; + import io.shinhanlife.dat.lib.paging.MciPagingUtils; import io.shinhanlife.glow.BizException; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @@ -1580,7 +1507,7 @@ public class ToolScaffolder { if (finalResponse == null) { finalResponse = page.data(); } else if (page.data() != null) { - mergeResponseData(finalResponse, page.data()); + MciPagingUtils.mergeResponseData(finalResponse, page.data()); } if (!page.hasNext()) { hasMore = false; @@ -1617,34 +1544,6 @@ public class ToolScaffolder { return response; } } - - private void mergeResponseData(%sResponse target, %sResponse src) { - if (target == null || src == null) return; - for (java.lang.reflect.Field field : target.getClass().getDeclaredFields()) { - if (java.util.List.class.isAssignableFrom(field.getType())) { - field.setAccessible(true); - try { - java.util.List srcList = (java.util.List) field.get(src); - if (srcList != null && !srcList.isEmpty()) { - @SuppressWarnings("unchecked") - java.util.List targetList = (java.util.List) field.get(target); - if (targetList == null) { - targetList = new java.util.ArrayList<>(srcList); - field.set(target, targetList); - } else { - if (!(targetList instanceof java.util.ArrayList)) { - targetList = new java.util.ArrayList<>(targetList); - field.set(target, targetList); - } - targetList.addAll(srcList); - } - } - } catch (Exception e) { - log.warn("[MCI Tool] 리스트 병합 중 예외 발생 (field: {}): {}", field.getName(), e.getMessage()); - } - } - } - } } """.formatted( bizPackage, @@ -1665,7 +1564,6 @@ public class ToolScaffolder { baseName, baseName, baseName, baseName, - baseName, baseName, baseName, baseName ); } @@ -2644,6 +2542,8 @@ public class ToolScaffolder { import io.shinhanlife.dat.lib.paging.ScrollPagingInfo; import io.shinhanlife.glow.db.dto.ScrPageInfo; import io.shinhanlife.glow.communication.dto.Transfer; + import java.lang.reflect.Method; + import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -2675,6 +2575,9 @@ public class ToolScaffolder { if (request.getScrPageInfo() == null) { request.setScrPageInfo(new ScrPageInfo()); } + if (request.getScrPageInfo().getPageDataCc() <= 0) { + request.getScrPageInfo().setPageDataCc(20); + } if (pagingInfo != null) { if (pagingInfo.getScrlmhdNm() != null) request.getScrPageInfo().setScrlmhdNm(pagingInfo.getScrlmhdNm()); if (pagingInfo.getScrlItva() != null) request.getScrPageInfo().setScrlItva(pagingInfo.getScrlItva()); @@ -2682,14 +2585,14 @@ public class ToolScaffolder { if (pagingInfo.getPageDataCc() > 0) request.getScrPageInfo().setPageDataCc(pagingInfo.getPageDataCc()); } - %s_I mciReq = converter.toLegacyRequest(request); + %s_I mciReq = converter.toRequest(request); if (mciReq != null && request.getScrPageInfo() != null) { try { - java.lang.reflect.Method setMethod = mciReq.getClass().getMethod("setScrPageInfo", java.util.List.class); - setMethod.invoke(mciReq, java.util.List.of(request.getScrPageInfo())); + Method setMethod = mciReq.getClass().getMethod("setScrPageInfo", List.class); + setMethod.invoke(mciReq, List.of(request.getScrPageInfo())); } catch (NoSuchMethodException e) { try { - java.lang.reflect.Method setMethod = mciReq.getClass().getMethod("setScrPageInfo", ScrPageInfo.class); + Method setMethod = mciReq.getClass().getMethod("setScrPageInfo", ScrPageInfo.class); setMethod.invoke(mciReq, request.getScrPageInfo()); } catch (Exception ignored) {} } catch (Exception ignored) {} @@ -2703,9 +2606,9 @@ public class ToolScaffolder { ScrPageInfo resPageInfo = null; if (mciRes != null) { try { - java.lang.reflect.Method getMethod = mciRes.getClass().getMethod("getScrPageInfo"); + Method getMethod = mciRes.getClass().getMethod("getScrPageInfo"); Object val = getMethod.invoke(mciRes); - if (val instanceof java.util.List list && !list.isEmpty()) { + if (val instanceof List list && !list.isEmpty()) { if (list.get(0) instanceof ScrPageInfo pi) resPageInfo = pi; } else if (val instanceof ScrPageInfo pi) { resPageInfo = pi; @@ -2765,6 +2668,8 @@ public class ToolScaffolder { import io.shinhanlife.dat.lib.paging.PgNumPagingInfo; import io.shinhanlife.glow.db.dto.PageInfo; import io.shinhanlife.glow.communication.dto.Transfer; + import java.lang.reflect.Method; + import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -2796,19 +2701,25 @@ public class ToolScaffolder { if (request.getPageInfo() == null) { request.setPageInfo(new PageInfo()); } + if (request.getPageInfo().getPageNo() <= 0) { + request.getPageInfo().setPageNo(1); + } + if (request.getPageInfo().getPageDataCc() <= 0) { + request.getPageInfo().setPageDataCc(20); + } if (pagingInfo != null) { if (pagingInfo.getPageNo() > 0) request.getPageInfo().setPageNo(pagingInfo.getPageNo()); if (pagingInfo.getPageDataCc() > 0) request.getPageInfo().setPageDataCc(pagingInfo.getPageDataCc()); } - %s_I mciReq = converter.toLegacyRequest(request); + %s_I mciReq = converter.toRequest(request); if (mciReq != null) { try { - java.lang.reflect.Method setMethod = mciReq.getClass().getMethod("setPageInfo", java.util.List.class); - setMethod.invoke(mciReq, java.util.List.of(request.getPageInfo())); + Method setMethod = mciReq.getClass().getMethod("setPageInfo", List.class); + setMethod.invoke(mciReq, List.of(request.getPageInfo())); } catch (NoSuchMethodException e) { try { - java.lang.reflect.Method setMethod = mciReq.getClass().getMethod("setPageInfo", PageInfo.class); + Method setMethod = mciReq.getClass().getMethod("setPageInfo", PageInfo.class); setMethod.invoke(mciReq, request.getPageInfo()); } catch (Exception ignored) {} } catch (Exception ignored) {} @@ -2822,9 +2733,9 @@ public class ToolScaffolder { PageInfo resPageInfo = null; if (mciRes != null) { try { - java.lang.reflect.Method getMethod = mciRes.getClass().getMethod("getPageInfo"); + Method getMethod = mciRes.getClass().getMethod("getPageInfo"); Object val = getMethod.invoke(mciRes); - if (val instanceof java.util.List list && !list.isEmpty()) { + if (val instanceof List list && !list.isEmpty()) { if (list.get(0) instanceof PageInfo pi) resPageInfo = pi; } else if (val instanceof PageInfo pi) { resPageInfo = pi; @@ -3238,6 +3149,8 @@ public class ToolScaffolder { public interface %s { // Field names differ? Add mappings like this before the method. // @Mapping(source = "sourceField", target = "targetField") + @Mapping(target = "pageInfo", ignore = true) + @Mapping(target = "scrPageInfo", ignore = true) %s_I toLegacyRequest(%sRequest request); default %s_I toRequest(%sRequest request) { return toLegacyRequest(request);