From 9a8f716ec7659ba191dbd39487d6724feba39593 Mon Sep 17 00:00:00 2001 From: jade Date: Tue, 8 Sep 2026 09:49:00 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20MCI=20Request=20DTO=20example=20?= =?UTF-8?q?=EC=9E=90=EB=8F=99=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20Tool=20Sc?= =?UTF-8?q?affold=20UseCaseImpl/Client=20=EC=83=9D=EC=84=B1=20=ED=85=9C?= =?UTF-8?q?=ED=94=8C=EB=A6=BF=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dat/lib/util/MciResponseScaffolder.java | 64 +++++++- .../dat/lib/util/ToolScaffolder.java | 137 +++++++++++++----- 2 files changed, 159 insertions(+), 42 deletions(-) diff --git a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/MciResponseScaffolder.java b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/MciResponseScaffolder.java index e45f52b5..7f450304 100644 --- a/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/MciResponseScaffolder.java +++ b/dat-was-lib/src/main/java/io/shinhanlife/dat/lib/util/MciResponseScaffolder.java @@ -133,7 +133,7 @@ public final class MciResponseScaffolder { Map mappingBySource = normalizeMappings(parsed, mappings); validateTargetNames(parsed, mappingBySource); return new GeneratedRequestSources( - responseSource(parsed, requestPackage, requestClassName, mappingBySource), + responseSource(parsed, requestPackage, requestClassName, mappingBySource, true), requestConverterSource(parsed, requestPackage, requestClassName, converterPackage, converterClassName, mappingBySource)); } @@ -321,6 +321,11 @@ public final class MciResponseScaffolder { private static String responseSource(ParsedSource parsed, String responsePackage, String responseClassName, Map mappings) { + return responseSource(parsed, responsePackage, responseClassName, mappings, false); + } + + private static String responseSource(ParsedSource parsed, String responsePackage, String responseClassName, + Map mappings, boolean isRequest) { boolean usesList = parsed.types().stream().flatMap(type -> type.fields().stream()) .anyMatch(field -> field.type().contains("List<")); boolean usesBigDecimal = parsed.types().stream().flatMap(type -> type.fields().stream()) @@ -333,31 +338,78 @@ public final class MciResponseScaffolder { if (usesList) source.append("import java.util.List;\n"); source.append("\n@Data\n@JsonInclude(JsonInclude.Include.NON_NULL)\n") .append("public class ").append(responseClassName).append(" {\n\n") - .append(responseFields(parsed.types().getFirst(), mappings, " ")); + .append(responseFields(parsed.types().getFirst(), mappings, " ", isRequest)); for (ParsedType type : parsed.types().stream().skip(1).toList()) { source.append(" @Data\n") .append(" @JsonInclude(JsonInclude.Include.NON_NULL)\n") .append(" public static class ").append(type.name()).append(" {\n\n") - .append(responseFields(type, mappings, " ")) + .append(responseFields(type, mappings, " ", isRequest)) .append(" }\n\n"); } return source.append("}\n").toString(); } + + private static String responseFields(ParsedType type, Map mappings, String indent) { + return responseFields(type, mappings, indent, false); + } + + private static String responseFields(ParsedType type, Map mappings, String indent, boolean isRequest) { StringBuilder source = new StringBuilder(); for (ParsedField field : type.fields()) { FieldMapping mapping = mappings.get(key(type.name(), field.name())); if (!mapping.include()) continue; - source.append(indent).append("@Schema(description = \"") - .append(escapeJava(field.description())).append("\")\n") - .append(indent).append("private ").append(field.type()).append(' ') + if (isRequest) { + String example = exampleValue(field); + source.append(indent).append("@Schema(description = \"") + .append(escapeJava(field.description())) + .append("\", example = \"").append(example).append("\")\n"); + } else { + source.append(indent).append("@Schema(description = \"") + .append(escapeJava(field.description())).append("\")\n"); + } + source.append(indent).append("private ").append(field.type()).append(' ') .append(mapping.targetName().trim()).append(";\n\n"); } return source.toString(); } + private static String exampleValue(ParsedField field) { + String type = field.type(); + int length = field.length(); + String desc = field.description() == null ? "" : field.description(); + if (type.contains("List<") || type.contains("[]")) return ""; + if (type.equals("BigDecimal") || type.equals("Long") || type.equals("Integer") || type.equals("int") || type.equals("long")) { + return "0"; + } + // 날짜 패턴 + if (length == 8 && (desc.contains("일자") || desc.contains("날짜") || desc.contains("생년") || desc.contains("Ymd") || field.name().toLowerCase().contains("ymd"))) { + return "20240101"; + } + // 년월 패턴 + if (length == 6 && (desc.contains("년월") || desc.contains("연월") || field.name().toLowerCase().contains("ym"))) { + return "202401"; + } + // 코드 패턴 + if (desc.contains("코드") || desc.contains("구분") || field.name().toLowerCase().contains("cd") || field.name().toLowerCase().contains("sc")) { + return length <= 4 ? "01" : "0001"; + } + // 번호 패턴 + if (desc.contains("번호") || field.name().toLowerCase().contains("no")) { + return length <= 10 ? "1234567890".substring(0, Math.min(length, 10)) : "12345678901234"; + } + // 이름 패턴 + if (desc.contains("이름") || desc.contains("명") || field.name().toLowerCase().contains("nm")) { + return "홍길동"; + } + // 기본 String + return ""; + } + + + private static String converterSource(ParsedSource parsed, String responsePackage, String responseClassName, String converterPackage, String converterClassName, Map mappings) { 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 ea3a9379..55b612bc 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 @@ -228,8 +228,31 @@ public class ToolScaffolder { String sysCode = tool.clientSystemCode(); if (sysCode != null && (sysCode.length() == 4 || sysCode.length() == 9)) { String clientCap = toPascalCase(mciClientPrefix(sysCode)); + String recSvcId = sysCode.toUpperCase(); + String itrfId = tool.interfaceId(); writeUtf8(clientDir.resolve("Mci" + clientCap + "Client.java"), - "package " + ioPackage + ";\n\nimport io.shinhanlife.dat.lib.integration.mci.component.AxhubMciComponent;\nimport io.shinhanlife.glow.communication.dto.Transfer;\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.stereotype.Component;\n\n@Component\n@RequiredArgsConstructor\npublic class Mci" + clientCap + "Client {\n private final AxhubMciComponent mci;\n\n public Transfer callTo(String interfaceId, String dummy, Object mciReq, Class resType) throws Exception {\n return mci.callTo(interfaceId, dummy, mciReq, resType);\n }\n}\n"); + "package " + ioPackage + ";\n\n" + + "import io.shinhanlife.dat.lib.integration.mci.component.AxhubMciComponent;\n" + + "import io.shinhanlife.glow.communication.dto.Transfer;\n" + + "import " + ioPackage + ".io." + ioPrefix + "_I;\n" + + "import " + ioPackage + ".io." + ioPrefix + "_O;\n" + + "import lombok.RequiredArgsConstructor;\n" + + "import org.springframework.stereotype.Component;\n\n" + + "@Component\n" + + "@RequiredArgsConstructor\n" + + "public class Mci" + clientCap + "Client {\n\n" + + " private static final String INTERFACE_ID = \"" + itrfId + "\";\n" + + " private static final String RECEIVE_SERVICE_ID = \"" + recSvcId + "\";\n\n" + + " private final AxhubMciComponent mciComponent;\n\n" + + " public Transfer callTo(String interfaceId, String receiveServiceId, Object mciReq, Class resType) {\n" + + " return mciComponent.callTo(interfaceId, receiveServiceId, mciReq, resType);\n" + + " }\n\n" + + " public " + ioPrefix + "_O call" + toPascalCase(ioPrefix) + "(" + ioPrefix + "_I request) {\n" + + " Transfer<" + ioPrefix + "_O> transfer = mciComponent.callTo(\n" + + " INTERFACE_ID, RECEIVE_SERVICE_ID, request, " + ioPrefix + "_O.class);\n" + + " return transfer == null ? null : transfer.getBody();\n" + + " }\n" + + "}\n"); } else { writeUtf8(clientDir.resolve(baseName + "Client.java"), groupedMciClientContent(ioPackage, baseName, tool.interfaceId())); } @@ -321,12 +344,12 @@ public class ToolScaffolder { String ioPrefix = (tool.clientSystemCode() != null && !tool.clientSystemCode().isBlank()) ? tool.clientSystemCode().toUpperCase() : tool.interfaceId(); if (mci) { clientClassName = mciClientClassName(tool.clientSystemCode()); - clientVariable = mciClientVariable(tool.clientSystemCode()); + clientVariable = "mci"; } else { clientClassName = baseName + "Client"; clientVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Client"; } - String converterVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Converter"; + String converterVariable = "converter"; String integrationPackage = BASE_PACKAGE + (mci ? ".infra.itrf.mci." + formatClientSystemCode(tool.clientSystemCode(), ".") : ".infra.itrf.http." + toPackageSegment(tool.httpApiName())); imports.append("import ").append(bizPackage).append(".dto.").append(baseName).append("Request;\n") @@ -335,17 +358,23 @@ public class ToolScaffolder { .append("import ").append(integrationPackage).append(".").append(clientClassName).append(";\n") .append("import ").append(integrationPackage).append(".io.").append(mci ? ioPrefix + "_I;\n" : baseName + "HttpRequest;\n") .append("import ").append(integrationPackage).append(".io.").append(mci ? ioPrefix + "_O;\n" : baseName + "HttpResponse;\n"); - if (mci) imports.append("import io.shinhanlife.glow.communication.dto.Transfer;\n"); + if (mci) { + imports.append("import io.shinhanlife.glow.communication.dto.Transfer;\n"); + imports.append("import lombok.extern.slf4j.Slf4j;\n"); + } if (!fields.toString().contains(" " + clientVariable + ";")) { fields.append(" private final ").append(clientClassName).append(" ").append(clientVariable).append(";\n"); } - fields.append(" private final ").append(baseName).append("Converter ").append(converterVariable).append(";\n"); + if (!fields.toString().contains(" " + converterVariable + ";")) { + fields.append(" private final ").append(baseName).append("Converter ").append(converterVariable).append(";\n"); + } methods.append(groupedToolMethodContent(tool, baseName, converterVariable, clientVariable, ioPrefix, mci)); } + String slf4jAnno = tools.stream().anyMatch(t -> "MCI".equalsIgnoreCase(t.routingType())) ? "@Slf4j\n" : ""; return "package " + bizPackage + ".usecase.impl;\n\n" + "import " + bizPackage + ".usecase." + useCaseBaseName + "UseCase;\n" + "import lombok.RequiredArgsConstructor;\nimport org.springframework.stereotype.Service;\n" + imports - + "\n@Service\n@RequiredArgsConstructor\npublic class " + useCaseBaseName + "UseCaseImpl implements " + useCaseBaseName + "UseCase {\n\n" + + "\n" + slf4jAnno + "@Service\n@RequiredArgsConstructor\npublic class " + useCaseBaseName + "UseCaseImpl implements " + useCaseBaseName + "UseCase {\n\n" + fields + "\n" + methods + "}\n"; } @@ -353,35 +382,43 @@ public class ToolScaffolder { String converterVariable, String clientVariable, String ioPrefix, boolean mci) { if (mci) { + String snakeToolName = (tool.group() != null && !tool.group().isBlank() ? tool.group().toLowerCase(Locale.ROOT) + "_" : "") + + toKebabCase(baseName).toLowerCase(Locale.ROOT).replace("-", "_"); + String receiveServiceId = tool.clientSystemCode() != null ? tool.clientSystemCode().toUpperCase() : ""; return """ @Override public %sResponse %s(%sRequest req) { - %s_I request = %s.toRequest(req); + log.info("[MCI Tool] {} 요청 수신.", "%s"); try { - Transfer<%s_O> transfer = %s.callTo("%s", null, request, %s_O.class); - if (transfer == null || transfer.getBody() == null) { - %sResponse errorResponse = new %sResponse(); - errorResponse.setResultCode("ERROR"); - return errorResponse; + // MapStruct를 이용한 자동 매핑 (AI DTO -> MCI DTO) + %s_I mciReq = %s.toRequest(req); + + Transfer<%s_O> resTransfer = %s.callTo( + "%s", + "%s", + mciReq, + %s_O.class + ); + %sResponse response = new %sResponse(); + if (resTransfer != null && resTransfer.getBody() != null) { + response = %s.toResponse(resTransfer.getBody()); } - %sResponse toolResponse = %s.toResponse(transfer.getBody()); - if (toolResponse == null) { - toolResponse = new %sResponse(); - toolResponse.setResultCode("ERROR"); - return toolResponse; - } - toolResponse.setResultCode("SUCCESS"); - return toolResponse; + response.setResultCode("SUCCESS"); + return response; } catch (Exception e) { + log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e); %sResponse errorResponse = new %sResponse(); errorResponse.setResultCode("ERROR"); - errorResponse.setResultMessage("MCI call failed."); + errorResponse.setResultMessage("MCI call failed: " + e.getMessage()); return errorResponse; } } - """.formatted(baseName, tool.methodName(), baseName, ioPrefix, converterVariable, ioPrefix, - clientVariable, tool.interfaceId(), ioPrefix, baseName, baseName, baseName, converterVariable, baseName, + """.formatted(baseName, tool.methodName(), baseName, snakeToolName, + ioPrefix, converterVariable, + ioPrefix, clientVariable, tool.interfaceId(), receiveServiceId, ioPrefix, + baseName, baseName, + converterVariable, baseName, baseName); } return """ @@ -507,12 +544,12 @@ public class ToolScaffolder { String clientVariable; if (mci) { clientClassName = mciClientClassName(tool.clientSystemCode()); - clientVariable = mciClientVariable(tool.clientSystemCode()); + clientVariable = "mci"; } else { clientClassName = baseName + "Client"; clientVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Client"; } - String converterVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Converter"; + String converterVariable = "converter"; implementation = addImport(implementation, "import " + bizPackage + ".dto." + requestType + ";"); implementation = addImport(implementation, "import " + bizPackage + ".dto." + responseType + ";"); @@ -520,7 +557,13 @@ public class ToolScaffolder { implementation = addImport(implementation, "import " + integrationPackage + "." + clientClassName + ";"); implementation = addImport(implementation, "import " + integrationPackage + ".io." + requestIo + ";"); implementation = addImport(implementation, "import " + integrationPackage + ".io." + responseIo + ";"); - if (mci) implementation = addImport(implementation, "import io.shinhanlife.glow.communication.dto.Transfer;"); + if (mci) { + implementation = addImport(implementation, "import io.shinhanlife.glow.communication.dto.Transfer;"); + implementation = addImport(implementation, "import lombok.extern.slf4j.Slf4j;"); + if (!implementation.contains("@Slf4j")) { + implementation = implementation.replaceFirst("public class ", "@Slf4j\npublic class "); + } + } implementation = addImport(implementation, "import lombok.RequiredArgsConstructor;"); if (!implementation.contains("@RequiredArgsConstructor")) { implementation = implementation.replaceFirst("public class ", "@RequiredArgsConstructor\npublic class "); @@ -528,7 +571,9 @@ public class ToolScaffolder { if (!implementation.contains(" " + clientVariable + ";")) { implementation = insertConstructorField(implementation, " private final " + clientClassName + " " + clientVariable + ";"); } - implementation = insertConstructorField(implementation, " private final " + baseName + "Converter " + converterVariable + ";"); + if (!implementation.contains(" " + converterVariable + ";")) { + implementation = insertConstructorField(implementation, " private final " + baseName + "Converter " + converterVariable + ";"); + } String method = groupedToolMethodContent(tool, baseName, converterVariable, clientVariable, ioPrefix, mci); implementation = insertBeforeLastBrace(implementation, method); } @@ -979,7 +1024,7 @@ public class ToolScaffolder { if (mciReq != null) { resTransfer = mci.callTo( "%s", - null, + "%s", mciReq, %s_O.class ); @@ -1034,6 +1079,7 @@ public class ToolScaffolder { ioPrefix, ioPrefix, interfaceId, + ((clientSystemCode != null && !clientSystemCode.isBlank()) ? clientSystemCode.toUpperCase() : ""), ioPrefix, baseName, baseName, @@ -1246,14 +1292,17 @@ public class ToolScaffolder { log.append("[MCI Converter] ").append(converterDir.resolve(baseName + "Converter.java")).append("\n"); if (!clientPrefixCap.isEmpty()) { + String receiveServiceId = (clientSystemCode != null && !clientSystemCode.isBlank()) ? clientSystemCode.toUpperCase() : ""; String mciClientContent = """ package %s.%s; - + import org.springframework.stereotype.Component; import lombok.RequiredArgsConstructor; import io.shinhanlife.dat.lib.integration.mci.component.AxhubMciComponent; import io.shinhanlife.glow.communication.dto.Transfer; - + import %s.%s.io.%s_I; + import %s.%s.io.%s_O; + /** * @package %s.%s * @className Mci%sClient @@ -1265,21 +1314,37 @@ public class ToolScaffolder { * 수정일 수정자 수정내용 * ---------- -------- --------------------------- * %s %s 최초생성 - * + * * */ @Component @RequiredArgsConstructor public class Mci%sClient { - private final AxhubMciComponent mci; - - public Transfer callTo(String interfaceId, String dummy, Object mciReq, Class resType) throws Exception { - return mci.callTo(interfaceId, dummy, mciReq, resType); + + private static final String INTERFACE_ID = "%s"; + private static final String RECEIVE_SERVICE_ID = "%s"; + + private final AxhubMciComponent mciComponent; + + public Transfer callTo(String interfaceId, String receiveServiceId, Object mciReq, Class resType) { + return mciComponent.callTo(interfaceId, receiveServiceId, mciReq, resType); + } + + public %s_O call%s(%s_I request) { + Transfer<%s_O> transfer = mciComponent.callTo( + INTERFACE_ID, RECEIVE_SERVICE_ID, request, %s_O.class); + return transfer == null ? null : transfer.getBody(); } } """.formatted( BASE_PACKAGE, mciGroupPath.replace("/", "."), - BASE_PACKAGE, mciGroupPath.replace("/", "."), clientPrefixCap, author, createDate, createDate, author, clientPrefixCap + BASE_PACKAGE, mciGroupPath.replace("/", "."), ioPrefix, + BASE_PACKAGE, mciGroupPath.replace("/", "."), ioPrefix, + BASE_PACKAGE, mciGroupPath.replace("/", "."), clientPrefixCap, author, createDate, createDate, author, + clientPrefixCap, + interfaceId, receiveServiceId, + ioPrefix, toPascalCase(ioPrefix), ioPrefix, + ioPrefix, ioPrefix ); writeUtf8(mciClientDir.resolve("Mci" + clientPrefixCap + "Client.java"), mciClientContent); log.append("[MCI Client] ").append(mciClientDir.resolve("Mci" + clientPrefixCap + "Client.java")).append("\n");