Compare commits
28 Commits
c0de1f4edb
...
DEV-SRTEST
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b4d4da0b9 | ||
|
|
c551b15378 | ||
|
|
b448e68f45 | ||
|
|
b68fbb9726 | ||
| c6a2f82455 | |||
|
|
2f5dad05df | ||
|
|
b0bf4a9c68 | ||
|
|
752aae4dde | ||
|
|
5cb37cfda6 | ||
|
|
2a4b3e68e9 | ||
|
|
ca1082f1c2 | ||
|
|
7b1d3131e6 | ||
|
|
139ddbc6ca | ||
|
|
870ebb723f | ||
|
|
a08a7d25df | ||
|
|
60acc5df81 | ||
|
|
f5be5b2514 | ||
|
|
aae4898d18 | ||
|
|
06b724459e | ||
|
|
4133b63595 | ||
|
|
1e18d2bc47 | ||
|
|
0c89a09ccf | ||
|
|
3ce9201cd5 | ||
|
|
be81c095c9 | ||
|
|
d4554ce34f | ||
|
|
b6d4ab1bec | ||
|
|
2c8497ebee | ||
|
|
8a93d5d6dc |
@@ -1,8 +1,7 @@
|
|||||||
.git
|
.git
|
||||||
.gradle
|
.gradle
|
||||||
.idea
|
.idea
|
||||||
build/
|
/build/
|
||||||
*/build/
|
|
||||||
target/
|
target/
|
||||||
*/target/
|
*/target/
|
||||||
bin/
|
bin/
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Prepare Environment (Install Node.js & Git)
|
- name: Prepare Environment (Install Node.js & Git & Java 21)
|
||||||
run: |
|
run: |
|
||||||
if command -v apt-get &> /dev/null; then
|
if command -v apt-get &> /dev/null; then
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y nodejs git
|
apt-get install -y nodejs git openjdk-21-jdk rsync
|
||||||
elif command -v apk &> /dev/null; then
|
elif command -v apk &> /dev/null; then
|
||||||
apk add --no-cache nodejs git
|
apk add --no-cache nodejs git openjdk21 rsync
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
@@ -26,21 +26,22 @@ jobs:
|
|||||||
|
|
||||||
- name: Sync Code to Host Volume
|
- name: Sync Code to Host Volume
|
||||||
run: |
|
run: |
|
||||||
echo "Copying latest code to /app (Host Volume)..."
|
echo "Copying latest code to /app (Host Volume) and removing stale files..."
|
||||||
cp -a . /app/
|
if command -v rsync &> /dev/null; then
|
||||||
|
rsync -a --delete --exclude='.git' . /app/
|
||||||
|
else
|
||||||
|
rm -rf /app/dap-* /app/src /app/build.gradle /app/settings.gradle
|
||||||
|
cp -a . /app/
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Deploy Task on Host
|
- name: Deploy Task on Host
|
||||||
run: |
|
run: |
|
||||||
echo "Starting Standard CI/CD Deploy pipeline..."
|
echo "Starting Standard CI/CD Deploy pipeline..."
|
||||||
|
|
||||||
# 1. gradle 공식 이미지로 바로 컴파일 빌드!
|
# 1. runner에 설치된 java로 직접 빌드! (격리된 환경 문제 해결)
|
||||||
docker run --rm \
|
cd /app
|
||||||
-v /home/ubuntu/app/ax_hub_mcp_tool:/app \
|
chmod +x gradlew
|
||||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
./gradlew bootJar -x test
|
||||||
-v /home/ubuntu/.gradle:/home/gradle/.gradle \
|
|
||||||
-w /app \
|
|
||||||
gradle:8-jdk21 \
|
|
||||||
./gradlew bootJar -x test
|
|
||||||
|
|
||||||
# 2. 빌드 결과 plain jar 아카이브 정리
|
# 2. 빌드 결과 plain jar 아카이브 정리
|
||||||
find /app -name "*-plain.jar" -delete
|
find /app -name "*-plain.jar" -delete
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# DAP Backend
|
# DAP Backend
|
||||||
|
|
||||||
Spring Boot 기반 DAP 관리자 백엔드 API 서버 및 MCP(Model Context Protocol) Gateway / Tool 분산 서버 프로젝트입니다.
|
Spring Boot 기반 DAP 관리자 백엔드 API 서버 및 MCP(Model Context Protocol) Gateway / Tool 분산 서버 프로젝트 입니다.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -114,11 +114,13 @@ MSA 및 외부 시스템(MCI) 연동 환경의 안정성을 위해 완벽한 3-T
|
|||||||
새로운 도메인의 기능을 추가할 때 발생하는 반복적인 설정(보일러플레이트, 설정 파일 복사 등)을 1초 만에 자동화하기 위해 **DAP Developer Portal (Web UI)** 및 **CLI 스캐폴더 2종**을 제공합니다.
|
새로운 도메인의 기능을 추가할 때 발생하는 반복적인 설정(보일러플레이트, 설정 파일 복사 등)을 1초 만에 자동화하기 위해 **DAP Developer Portal (Web UI)** 및 **CLI 스캐폴더 2종**을 제공합니다.
|
||||||
|
|
||||||
### 1. DAP Developer Portal (Web UI) - 가장 추천하는 방식!
|
### 1. DAP Developer Portal (Web UI) - 가장 추천하는 방식!
|
||||||
이제 더 이상 터미널에서 명령어를 칠 필요가 없습니다. Gateway 모듈에 내장된 웹 화면에서 빈칸만 채우면 코드가 마법처럼 찍혀 나옵니다.
|
이제 더 이상 터미널에서 명령어를 칠 필요가 없습니다. Gateway 모듈에 내장된 웹 화면에서 빈칸만 채우면 신한라이프 패키지 개발 가이드에 맞춘 코드가 마법처럼 찍혀 나옵니다.
|
||||||
|
|
||||||
1. **접속 방법**: Gateway 서버 기동 후 브라우저에서 `http://localhost:8081/admin/scaffold.html` 접속
|
1. **접속 방법**: Gateway 서버 기동 후 브라우저에서 `http://localhost:8081/admin/scaffold.html` 접속
|
||||||
2. **Pod (모듈) 생성 탭**: 모듈명(예: hr)과 포트만 입력하면 독립적인 Spring Boot 모듈이 디렉토리부터 빌드 스크립트까지 완벽히 생성됩니다.
|
2. **Pod (모듈) 생성 탭**: 모듈명(예: hr)과 포트만 입력하면 독립적인 Spring Boot 모듈이 디렉토리부터 빌드 스크립트까지 완벽히 생성됩니다.
|
||||||
3. **Tool (기능) 생성 탭**: 생성된 모듈에 새로운 툴(서비스/DTO) 코드를 자동으로 주입합니다.
|
3. **Tool (기능) 생성 탭**: 생성된 모듈에 새로운 툴 코드를 자동으로 주입합니다.
|
||||||
|
- **MCI 연동 기반 툴 생성**: 4자리 시스템 코드(예: `nclg`)를 기반으로 알맞은 패키지에 `MciNclgClient`, `Converter`, `_I`, `_O` 파일이 정확하게 생성됩니다.
|
||||||
|
- **완벽한 보일러플레이트 자동화**: `UseCaseImpl` 내부에 컴포넌트(`Client`, `Converter`)가 자동으로 의존성 주입되며, Java 15 Text Block을 활용해 들여쓰기(Indentation)까지 완벽히 정렬된 코드를 제공합니다.
|
||||||
|
|
||||||
### 2. CLI 스캐폴더 (기존 터미널 방식)
|
### 2. CLI 스캐폴더 (기존 터미널 방식)
|
||||||
웹 화면을 사용할 수 없는 환경이거나 터미널이 익숙한 경우, 아래 명령어를 통해 CLI 마법사를 사용할 수 있습니다.
|
웹 화면을 사용할 수 없는 환경이거나 터미널이 익숙한 경우, 아래 명령어를 통해 CLI 마법사를 사용할 수 있습니다.
|
||||||
|
|||||||
40
cleanup.py
40
cleanup.py
@@ -1,40 +0,0 @@
|
|||||||
import re
|
|
||||||
|
|
||||||
# 1. Clean docker-compose.yml
|
|
||||||
with open('docker-compose.yml', 'r', encoding='utf-8') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
# Remove tool-email and tool-payment blocks
|
|
||||||
content = re.sub(r'^\s*tool-(email|payment)-(blue|green):.*?^\s*- SPRING_PROFILES_ACTIVE=\$\{ACTIVE_PROFILE:-local\}\n\n?', '', content, flags=re.MULTILINE | re.DOTALL)
|
|
||||||
# Remove MCP fallback routes
|
|
||||||
content = re.sub(r'^\s*- MCP_GATEWAY_FALLBACK_ROUTES_(EMAIL|PAYMENT)=.*?\n', '', content, flags=re.MULTILINE)
|
|
||||||
|
|
||||||
with open('docker-compose.yml', 'w', encoding='utf-8') as f:
|
|
||||||
f.write(content)
|
|
||||||
|
|
||||||
# 2. Clean deploy.yml
|
|
||||||
with open('.gitea/workflows/deploy.yml', 'r', encoding='utf-8') as f:
|
|
||||||
lines = f.readlines()
|
|
||||||
|
|
||||||
new_lines = []
|
|
||||||
for line in lines:
|
|
||||||
if 'tool-email' in line or 'tool-payment' in line:
|
|
||||||
# For lines that have multiple tools (like docker compose stop), just remove the specific ones
|
|
||||||
if 'docker compose stop' in line:
|
|
||||||
line = re.sub(r' tool-(email|payment)-\$[A-Z_]+', '', line)
|
|
||||||
new_lines.append(line)
|
|
||||||
else:
|
|
||||||
new_lines.append(line)
|
|
||||||
|
|
||||||
with open('.gitea/workflows/deploy.yml', 'w', encoding='utf-8') as f:
|
|
||||||
f.writelines(new_lines)
|
|
||||||
|
|
||||||
# 3. Clean nginx/conf.d/default.conf
|
|
||||||
with open('nginx/conf.d/default.conf', 'r', encoding='utf-8') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
content = re.sub(r'upstream tool-(email|payment) \{.*?\n\}\n\n?', '', content, flags=re.MULTILINE | re.DOTALL)
|
|
||||||
content = re.sub(r'server \{\n\s+listen 828[35];.*?\n\}\n\n?', '', content, flags=re.MULTILINE | re.DOTALL)
|
|
||||||
|
|
||||||
with open('nginx/conf.d/default.conf', 'w', encoding='utf-8') as f:
|
|
||||||
f.write(content)
|
|
||||||
@@ -1,19 +1,8 @@
|
|||||||
FROM eclipse-temurin:21-jdk-alpine AS builder
|
|
||||||
WORKDIR /app
|
|
||||||
COPY gradlew .
|
|
||||||
COPY gradle gradle
|
|
||||||
COPY build.gradle settings.gradle ./
|
|
||||||
|
|
||||||
COPY dap-tool-core dap-tool-core
|
|
||||||
COPY dap-gateway dap-gateway
|
|
||||||
RUN chmod +x gradlew
|
|
||||||
RUN ./gradlew clean :dap-gateway:build -x test
|
|
||||||
|
|
||||||
FROM eclipse-temurin:21-jre-alpine
|
FROM eclipse-temurin:21-jre-alpine
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN apk add --no-cache tzdata
|
RUN apk add --no-cache tzdata
|
||||||
ENV TZ=Asia/Seoul
|
ENV TZ=Asia/Seoul
|
||||||
COPY --from=builder /app/dap-gateway/build/libs/*-SNAPSHOT.jar app.jar
|
COPY dap-gateway/build/libs/*-SNAPSHOT.jar app.jar
|
||||||
EXPOSE 8081
|
EXPOSE 8081
|
||||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||||
|
|
||||||
|
|||||||
@@ -63,8 +63,9 @@ public class ScaffoldingController {
|
|||||||
String date = req.get("date");
|
String date = req.get("date");
|
||||||
if (date == null || date.trim().isEmpty()) date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd"));
|
if (date == null || date.trim().isEmpty()) date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd"));
|
||||||
boolean register = Boolean.parseBoolean(req.getOrDefault("register", "true"));
|
boolean register = Boolean.parseBoolean(req.getOrDefault("register", "true"));
|
||||||
|
String clientSystemCode = req.get("clientSystemCode");
|
||||||
|
|
||||||
return ToolScaffolder.scaffold(baseName, interfaceId, description, group, routingType, moduleName, author, date, register);
|
return ToolScaffolder.scaffold(baseName, interfaceId, description, group, routingType, moduleName, author, date, register, clientSystemCode);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return "오류 발생: " + e.getMessage();
|
return "오류 발생: " + e.getMessage();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -500,6 +500,14 @@
|
|||||||
<div class="input-hint">Controls dynamic routing exposure.</div>
|
<div class="input-hint">Controls dynamic routing exposure.</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label">Target System Code (MCI Only)</label>
|
||||||
|
<input type="text" class="form-control" name="clientSystemCode" pattern="^[a-zA-Z]{4}$" maxlength="4" minlength="4" placeholder="e.g. cfpa" oninput="this.value = this.value.toLowerCase()">
|
||||||
|
<div class="input-hint">Required for MCI Protocol (4 letters).</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
|
|||||||
@@ -173,6 +173,10 @@
|
|||||||
.replace(/'/g, "'");
|
.replace(/'/g, "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeMarkdownEmphasis(text) {
|
||||||
|
return text.replace(/\*\*/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
async function sendMessage() {
|
async function sendMessage() {
|
||||||
const text = chatInput.value.trim();
|
const text = chatInput.value.trim();
|
||||||
if (!text || isLoading) return;
|
if (!text || isLoading) return;
|
||||||
@@ -205,6 +209,7 @@
|
|||||||
// 5. 스트림 읽기
|
// 5. 스트림 읽기
|
||||||
const reader = response.body.getReader();
|
const reader = response.body.getReader();
|
||||||
const decoder = new TextDecoder("utf-8");
|
const decoder = new TextDecoder("utf-8");
|
||||||
|
let responseText = '';
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const { done, value } = await reader.read();
|
const { done, value } = await reader.read();
|
||||||
@@ -215,7 +220,8 @@
|
|||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
if (line.startsWith('data:')) {
|
if (line.startsWith('data:')) {
|
||||||
const data = line.substring(5);
|
const data = line.substring(5);
|
||||||
textContainer.innerHTML += escapeHtml(data);
|
responseText += data;
|
||||||
|
textContainer.textContent = removeMarkdownEmphasis(responseText);
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,14 @@ import com.fasterxml.jackson.annotation.JsonPropertyDescription;
|
|||||||
import io.shinhanlife.dap.lib.annotation.McpParameter;
|
import io.shinhanlife.dap.lib.annotation.McpParameter;
|
||||||
import io.shinhanlife.dap.lib.annotation.McpValidation;
|
import io.shinhanlife.dap.lib.annotation.McpValidation;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,17 +35,23 @@ public class JsonSchemaGenerator {
|
|||||||
* Java DTO 클래스를 분석하여 MCP 규격의 완전한 JSON Schema를 생성합니다.
|
* Java DTO 클래스를 분석하여 MCP 규격의 완전한 JSON Schema를 생성합니다.
|
||||||
*/
|
*/
|
||||||
public static Map<String, Object> generateSchema(Class<?> clazz) {
|
public static Map<String, Object> generateSchema(Class<?> clazz) {
|
||||||
|
return generateSchema(clazz, new HashSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> generateSchema(Class<?> clazz, Set<Class<?>> visiting) {
|
||||||
Map<String, Object> schema = new HashMap<>();
|
Map<String, Object> schema = new HashMap<>();
|
||||||
schema.put("type", "object");
|
schema.put("type", "object");
|
||||||
|
if (!visiting.add(clazz)) {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, Object> properties = new HashMap<>();
|
Map<String, Object> properties = new HashMap<>();
|
||||||
List<String> requiredList = new ArrayList<>();
|
List<String> requiredList = new ArrayList<>();
|
||||||
|
|
||||||
for (Field field : clazz.getDeclaredFields()) {
|
for (Field field : clazz.getDeclaredFields()) {
|
||||||
Map<String, Object> fieldSchema = new HashMap<>();
|
Map<String, Object> fieldSchema = createFieldSchema(field, visiting);
|
||||||
|
|
||||||
// 1. 타입 매핑
|
// 1. 타입 매핑
|
||||||
fieldSchema.put("type", mapJavaTypeToJsonType(field.getType()));
|
|
||||||
|
|
||||||
// 2. 어노테이션 기반 설명 추출
|
// 2. 어노테이션 기반 설명 추출
|
||||||
McpParameter paramAnnotation = field.getAnnotation(McpParameter.class);
|
McpParameter paramAnnotation = field.getAnnotation(McpParameter.class);
|
||||||
@@ -82,9 +92,47 @@ public class JsonSchemaGenerator {
|
|||||||
schema.put("required", requiredList);
|
schema.put("required", requiredList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visiting.remove(clazz);
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> createFieldSchema(Field field, Set<Class<?>> visiting) {
|
||||||
|
Class<?> fieldType = field.getType();
|
||||||
|
if (isSimpleType(fieldType)) {
|
||||||
|
return new HashMap<>(Map.of("type", mapJavaTypeToJsonType(fieldType)));
|
||||||
|
}
|
||||||
|
if (List.class.isAssignableFrom(fieldType)) {
|
||||||
|
Map<String, Object> fieldSchema = new HashMap<>();
|
||||||
|
fieldSchema.put("type", "array");
|
||||||
|
fieldSchema.put("items", generateItemsSchema(field, visiting));
|
||||||
|
return fieldSchema;
|
||||||
|
}
|
||||||
|
return generateSchema(fieldType, visiting);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> generateItemsSchema(Field field, Set<Class<?>> visiting) {
|
||||||
|
Type genericType = field.getGenericType();
|
||||||
|
if (genericType instanceof ParameterizedType parameterizedType) {
|
||||||
|
Type itemType = parameterizedType.getActualTypeArguments()[0];
|
||||||
|
if (itemType instanceof Class<?> itemClass) {
|
||||||
|
if (isSimpleType(itemClass)) {
|
||||||
|
return new HashMap<>(Map.of("type", mapJavaTypeToJsonType(itemClass)));
|
||||||
|
}
|
||||||
|
return generateSchema(itemClass, visiting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new HashMap<>(Map.of("type", "object"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isSimpleType(Class<?> clazz) {
|
||||||
|
return clazz == String.class
|
||||||
|
|| clazz == Integer.class || clazz == int.class
|
||||||
|
|| clazz == Long.class || clazz == long.class
|
||||||
|
|| clazz == Double.class || clazz == double.class
|
||||||
|
|| clazz == Float.class || clazz == float.class
|
||||||
|
|| clazz == Boolean.class || clazz == boolean.class;
|
||||||
|
}
|
||||||
|
|
||||||
private static String mapJavaTypeToJsonType(Class<?> clazz) {
|
private static String mapJavaTypeToJsonType(Class<?> clazz) {
|
||||||
if (clazz == String.class) return "string";
|
if (clazz == String.class) return "string";
|
||||||
if (clazz == Integer.class || clazz == int.class) return "integer";
|
if (clazz == Integer.class || clazz == int.class) return "integer";
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ public class ToolScaffolder {
|
|||||||
String createDate = getOrAsk(args, 7, scanner, "8. 작성일 (엔터 입력 시 '" + defaultDate + "'): ");
|
String createDate = getOrAsk(args, 7, scanner, "8. 작성일 (엔터 입력 시 '" + defaultDate + "'): ");
|
||||||
if (createDate.trim().isEmpty()) createDate = defaultDate;
|
if (createDate.trim().isEmpty()) createDate = defaultDate;
|
||||||
|
|
||||||
String result = scaffold(baseName, interfaceId, description, group, routingType, moduleName, author, createDate, true);
|
String result = scaffold(baseName, interfaceId, description, group, routingType, moduleName, author, createDate, true, null);
|
||||||
System.out.println(result);
|
System.out.println(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ public class ToolScaffolder {
|
|||||||
return scanner.nextLine().trim();
|
return scanner.nextLine().trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String scaffold(String baseName, String interfaceId, String description, String group, String routingType, String moduleName, String author, String createDate, boolean register) throws IOException {
|
public static String scaffold(String baseName, String interfaceId, String description, String group, String routingType, String moduleName, String author, String createDate, boolean register, String clientSystemCode) throws IOException {
|
||||||
baseName = toPascalCase(baseName);
|
baseName = toPascalCase(baseName);
|
||||||
String envSourceDir = System.getenv("AXHUB_SOURCE_DIR");
|
String envSourceDir = System.getenv("AXHUB_SOURCE_DIR");
|
||||||
Path rootDir = envSourceDir != null ? Paths.get(envSourceDir) : Paths.get(".");
|
Path rootDir = envSourceDir != null ? Paths.get(envSourceDir) : Paths.get(".");
|
||||||
@@ -95,6 +95,18 @@ public class ToolScaffolder {
|
|||||||
String bizPackage = BASE_PACKAGE + ".biz." + group.toLowerCase();
|
String bizPackage = BASE_PACKAGE + ".biz." + group.toLowerCase();
|
||||||
boolean isMci = "MCI".equalsIgnoreCase(routingType);
|
boolean isMci = "MCI".equalsIgnoreCase(routingType);
|
||||||
String mciGroupPath = "infra/itrf/mci/" + group.toLowerCase();
|
String mciGroupPath = "infra/itrf/mci/" + group.toLowerCase();
|
||||||
|
String clientPkgSuffix = "";
|
||||||
|
String clientPrefixCap = "";
|
||||||
|
Path mciClientDir = null;
|
||||||
|
|
||||||
|
if (isMci && clientSystemCode != null && clientSystemCode.length() == 4) {
|
||||||
|
String clientPrefix = clientSystemCode.toLowerCase();
|
||||||
|
clientPkgSuffix = clientPrefix.substring(0, 3) + "." + clientPrefix.substring(3, 4);
|
||||||
|
clientPrefixCap = toPascalCase(clientSystemCode);
|
||||||
|
mciGroupPath = "infra/itrf/mci/" + clientPrefix.substring(0, 3) + "/" + clientPrefix.substring(3, 4);
|
||||||
|
mciClientDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, mciGroupPath));
|
||||||
|
}
|
||||||
|
|
||||||
Path mciIoDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, mciGroupPath, "io"));
|
Path mciIoDir = rootDir.resolve(Paths.get(moduleName, BASE_PACKAGE_PATH, mciGroupPath, "io"));
|
||||||
|
|
||||||
Files.createDirectories(usecaseDir);
|
Files.createDirectories(usecaseDir);
|
||||||
@@ -102,6 +114,9 @@ public class ToolScaffolder {
|
|||||||
Files.createDirectories(dtoDir);
|
Files.createDirectories(dtoDir);
|
||||||
if (isMci) {
|
if (isMci) {
|
||||||
Files.createDirectories(mciIoDir);
|
Files.createDirectories(mciIoDir);
|
||||||
|
if (mciClientDir != null) {
|
||||||
|
Files.createDirectories(mciClientDir);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Files.createDirectories(legacyDtoDir);
|
Files.createDirectories(legacyDtoDir);
|
||||||
}
|
}
|
||||||
@@ -226,8 +241,9 @@ public class ToolScaffolder {
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import %s.converter.%sLegacyConverter;
|
import %s.converter.%sConverter;
|
||||||
import %s.infra.itrf.mci.%s.io.%s_I;
|
import %s.%s.io.%s_I;
|
||||||
|
%s
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package %s.usecase.impl
|
* @package %s.usecase.impl
|
||||||
@@ -248,8 +264,8 @@ public class ToolScaffolder {
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class %sUseCaseImpl implements %sUseCase {
|
public class %sUseCaseImpl implements %sUseCase {
|
||||||
|
|
||||||
private final AxhubMciComponent mci;
|
%s
|
||||||
private final %sLegacyConverter converter;
|
private final %sConverter converter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object execute(%sRequest req) {
|
public Object execute(%sRequest req) {
|
||||||
@@ -277,7 +293,8 @@ public class ToolScaffolder {
|
|||||||
bizPackage, baseName,
|
bizPackage, baseName,
|
||||||
bizPackage, baseName,
|
bizPackage, baseName,
|
||||||
bizPackage, baseName,
|
bizPackage, baseName,
|
||||||
BASE_PACKAGE, group.toLowerCase(), interfaceId,
|
BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId,
|
||||||
|
(clientPrefixCap.isEmpty() ? "" : "import " + BASE_PACKAGE + "." + mciGroupPath.replace("/", ".") + ".Mci" + clientPrefixCap + "Client;\n"),
|
||||||
bizPackage,
|
bizPackage,
|
||||||
baseName,
|
baseName,
|
||||||
author,
|
author,
|
||||||
@@ -285,6 +302,7 @@ public class ToolScaffolder {
|
|||||||
createDate, author,
|
createDate, author,
|
||||||
baseName,
|
baseName,
|
||||||
baseName,
|
baseName,
|
||||||
|
(clientPrefixCap.isEmpty() ? "private final AxhubMciComponent mci;" : "private final Mci" + clientPrefixCap + "Client mci;"),
|
||||||
baseName,
|
baseName,
|
||||||
baseName,
|
baseName,
|
||||||
toolName,
|
toolName,
|
||||||
@@ -299,7 +317,7 @@ public class ToolScaffolder {
|
|||||||
import %s.dto.%sResponse;
|
import %s.dto.%sResponse;
|
||||||
import %s.usecase.%sUseCase;
|
import %s.usecase.%sUseCase;
|
||||||
import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase;
|
import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase;
|
||||||
import %s.converter.%sLegacyConverter;
|
import %s.converter.%sConverter;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -323,7 +341,7 @@ public class ToolScaffolder {
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class %sUseCaseImpl extends AbstractMcpToolUseCase implements %sUseCase {
|
public class %sUseCaseImpl extends AbstractMcpToolUseCase implements %sUseCase {
|
||||||
|
|
||||||
private final %sLegacyConverter converter;
|
private final %sConverter converter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object execute(%sRequest req) {
|
public Object execute(%sRequest req) {
|
||||||
@@ -353,12 +371,12 @@ public class ToolScaffolder {
|
|||||||
|
|
||||||
if (isMci) {
|
if (isMci) {
|
||||||
String mciReqContent = """
|
String mciReqContent = """
|
||||||
package %s.infra.itrf.mci.%s.io;
|
package %s.%s.io;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package %s.infra.itrf.mci.%s.io
|
* @package %s.%s.io
|
||||||
* @className %s_I
|
* @className %s_I
|
||||||
* @description AX HUB 시스템 처리 클래스
|
* @description AX HUB 시스템 처리 클래스
|
||||||
* @author %s
|
* @author %s
|
||||||
@@ -383,16 +401,16 @@ public class ToolScaffolder {
|
|||||||
*/
|
*/
|
||||||
private String content;
|
private String content;
|
||||||
}
|
}
|
||||||
""".formatted(BASE_PACKAGE, group.toLowerCase(), BASE_PACKAGE, group.toLowerCase(), interfaceId, author, createDate, createDate, author, interfaceId);
|
""".formatted(BASE_PACKAGE, mciGroupPath.replace("/", "."), BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId, author, createDate, createDate, author, interfaceId);
|
||||||
Files.writeString(mciIoDir.resolve(interfaceId + "_I.java"), mciReqContent);
|
Files.writeString(mciIoDir.resolve(interfaceId + "_I.java"), mciReqContent);
|
||||||
|
|
||||||
String mciResContent = """
|
String mciResContent = """
|
||||||
package %s.infra.itrf.mci.%s.io;
|
package %s.%s.io;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package %s.infra.itrf.mci.%s.io
|
* @package %s.%s.io
|
||||||
* @className %s_O
|
* @className %s_O
|
||||||
* @description AX HUB 시스템 처리 클래스
|
* @description AX HUB 시스템 처리 클래스
|
||||||
* @author %s
|
* @author %s
|
||||||
@@ -409,7 +427,7 @@ public class ToolScaffolder {
|
|||||||
public class %s_O {
|
public class %s_O {
|
||||||
// TODO: Add response fields here
|
// TODO: Add response fields here
|
||||||
}
|
}
|
||||||
""".formatted(BASE_PACKAGE, group.toLowerCase(), BASE_PACKAGE, group.toLowerCase(), interfaceId, author, createDate, createDate, author, interfaceId);
|
""".formatted(BASE_PACKAGE, mciGroupPath.replace("/", "."), BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId, author, createDate, createDate, author, interfaceId);
|
||||||
Files.writeString(mciIoDir.resolve(interfaceId + "_O.java"), mciResContent);
|
Files.writeString(mciIoDir.resolve(interfaceId + "_O.java"), mciResContent);
|
||||||
|
|
||||||
String converterContent = """
|
String converterContent = """
|
||||||
@@ -417,15 +435,15 @@ public class ToolScaffolder {
|
|||||||
|
|
||||||
import %s.dto.%sRequest;
|
import %s.dto.%sRequest;
|
||||||
import %s.dto.%sResponse;
|
import %s.dto.%sResponse;
|
||||||
import %s.infra.itrf.mci.%s.io.%s_I;
|
import %s.%s.io.%s_I;
|
||||||
import %s.infra.itrf.mci.%s.io.%s_O;
|
import %s.%s.io.%s_O;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mapping;
|
import org.mapstruct.Mapping;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package %s.converter
|
* @package %s.converter
|
||||||
* @className %sLegacyConverter
|
* @className %sConverter
|
||||||
* @description AX HUB 시스템 처리 클래스
|
* @description AX HUB 시스템 처리 클래스
|
||||||
* @author %s
|
* @author %s
|
||||||
* @create %s
|
* @create %s
|
||||||
@@ -438,7 +456,7 @@ public class ToolScaffolder {
|
|||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
@Mapper(componentModel = "spring")
|
@Mapper(componentModel = "spring")
|
||||||
public interface %sLegacyConverter {
|
public interface %sConverter {
|
||||||
|
|
||||||
@Mapping(source = "phoneNumber", target = "phone")
|
@Mapping(source = "phoneNumber", target = "phone")
|
||||||
@Mapping(source = "message", target = "content")
|
@Mapping(source = "message", target = "content")
|
||||||
@@ -454,14 +472,14 @@ public class ToolScaffolder {
|
|||||||
bizPackage,
|
bizPackage,
|
||||||
bizPackage, baseName,
|
bizPackage, baseName,
|
||||||
bizPackage, baseName,
|
bizPackage, baseName,
|
||||||
BASE_PACKAGE, group.toLowerCase(), interfaceId,
|
BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId,
|
||||||
BASE_PACKAGE, group.toLowerCase(), interfaceId,
|
BASE_PACKAGE, mciGroupPath.replace("/", "."), interfaceId,
|
||||||
bizPackage, baseName, author, createDate, createDate, author,
|
bizPackage, baseName, author, createDate, createDate, author,
|
||||||
baseName, interfaceId, baseName,
|
baseName, interfaceId, baseName,
|
||||||
baseName, interfaceId,
|
baseName, interfaceId,
|
||||||
baseName, interfaceId
|
baseName, interfaceId
|
||||||
);
|
);
|
||||||
Files.writeString(converterDir.resolve(baseName + "LegacyConverter.java"), converterContent);
|
Files.writeString(converterDir.resolve(baseName + "Converter.java"), converterContent);
|
||||||
|
|
||||||
log.append("\n=========================================\n");
|
log.append("\n=========================================\n");
|
||||||
log.append(" Scaffolding Complete! (Routing: " + routingType + ")\n");
|
log.append(" Scaffolding Complete! (Routing: " + routingType + ")\n");
|
||||||
@@ -472,7 +490,47 @@ public class ToolScaffolder {
|
|||||||
log.append("[Response DTO] ").append(dtoDir.resolve(baseName + "Response.java")).append("\n");
|
log.append("[Response DTO] ").append(dtoDir.resolve(baseName + "Response.java")).append("\n");
|
||||||
log.append("[MCI Request IO] ").append(mciIoDir.resolve(interfaceId + "_I.java")).append("\n");
|
log.append("[MCI Request IO] ").append(mciIoDir.resolve(interfaceId + "_I.java")).append("\n");
|
||||||
log.append("[MCI Response IO] ").append(mciIoDir.resolve(interfaceId + "_O.java")).append("\n");
|
log.append("[MCI Response IO] ").append(mciIoDir.resolve(interfaceId + "_O.java")).append("\n");
|
||||||
log.append("[MCI Converter] ").append(converterDir.resolve(baseName + "LegacyConverter.java")).append("\n");
|
log.append("[MCI Converter] ").append(converterDir.resolve(baseName + "Converter.java")).append("\n");
|
||||||
|
|
||||||
|
if (!clientPrefixCap.isEmpty()) {
|
||||||
|
String mciClientContent = """
|
||||||
|
package %s.%s;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import io.shinhanlife.dap.lib.integration.mci.component.AxhubMciComponent;
|
||||||
|
import io.shinhanlife.glow.communication.dto.Transfer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package %s.%s
|
||||||
|
* @className Mci%sClient
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author %s
|
||||||
|
* @create %s
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* %s %s 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class Mci%sClient {
|
||||||
|
private final AxhubMciComponent mci;
|
||||||
|
|
||||||
|
public Transfer<Object> callTo(String interfaceId, String dummy, Object mciReq, Class<Object> resType) throws Exception {
|
||||||
|
return mci.callTo(interfaceId, dummy, mciReq, resType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".formatted(
|
||||||
|
BASE_PACKAGE, mciGroupPath.replace("/", "."),
|
||||||
|
BASE_PACKAGE, mciGroupPath.replace("/", "."), clientPrefixCap, author, createDate, createDate, author, clientPrefixCap
|
||||||
|
);
|
||||||
|
Files.writeString(mciClientDir.resolve("Mci" + clientPrefixCap + "Client.java"), mciClientContent);
|
||||||
|
log.append("[MCI Client] ").append(mciClientDir.resolve("Mci" + clientPrefixCap + "Client.java")).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
String legacyReqContent = """
|
String legacyReqContent = """
|
||||||
@@ -548,7 +606,7 @@ public class ToolScaffolder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @package %s.converter
|
* @package %s.converter
|
||||||
* @className %sLegacyConverter
|
* @className %sConverter
|
||||||
* @description AX HUB 시스템 처리 클래스
|
* @description AX HUB 시스템 처리 클래스
|
||||||
* @author %s
|
* @author %s
|
||||||
* @create %s
|
* @create %s
|
||||||
@@ -561,7 +619,7 @@ public class ToolScaffolder {
|
|||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
@Mapper(componentModel = "spring")
|
@Mapper(componentModel = "spring")
|
||||||
public interface %sLegacyConverter {
|
public interface %sConverter {
|
||||||
|
|
||||||
@Mapping(source = "phoneNumber", target = "phone")
|
@Mapping(source = "phoneNumber", target = "phone")
|
||||||
@Mapping(source = "message", target = "content")
|
@Mapping(source = "message", target = "content")
|
||||||
@@ -582,7 +640,7 @@ public class ToolScaffolder {
|
|||||||
bizPackage, baseName, author, createDate, createDate, author,
|
bizPackage, baseName, author, createDate, createDate, author,
|
||||||
baseName, baseName, baseName, baseName, baseName, baseName, baseName
|
baseName, baseName, baseName, baseName, baseName, baseName, baseName
|
||||||
);
|
);
|
||||||
Files.writeString(converterDir.resolve(baseName + "LegacyConverter.java"), converterContent);
|
Files.writeString(converterDir.resolve(baseName + "Converter.java"), converterContent);
|
||||||
|
|
||||||
log.append("\n=========================================\n");
|
log.append("\n=========================================\n");
|
||||||
log.append(" Scaffolding Complete! (Routing: " + routingType + ")\n");
|
log.append(" Scaffolding Complete! (Routing: " + routingType + ")\n");
|
||||||
@@ -593,7 +651,7 @@ public class ToolScaffolder {
|
|||||||
log.append("[Response DTO] ").append(dtoDir.resolve(baseName + "Response.java")).append("\n");
|
log.append("[Response DTO] ").append(dtoDir.resolve(baseName + "Response.java")).append("\n");
|
||||||
log.append("[Legacy Request DTO] ").append(legacyDtoDir.resolve(baseName + "LegacyRequest.java")).append("\n");
|
log.append("[Legacy Request DTO] ").append(legacyDtoDir.resolve(baseName + "LegacyRequest.java")).append("\n");
|
||||||
log.append("[Legacy Response DTO] ").append(legacyDtoDir.resolve(baseName + "LegacyResponse.java")).append("\n");
|
log.append("[Legacy Response DTO] ").append(legacyDtoDir.resolve(baseName + "LegacyResponse.java")).append("\n");
|
||||||
log.append("[Legacy Converter] ").append(converterDir.resolve(baseName + "LegacyConverter.java")).append("\n");
|
log.append("[Legacy Converter] ").append(converterDir.resolve(baseName + "Converter.java")).append("\n");
|
||||||
}
|
}
|
||||||
log.append("\n Tip: ").append(interfaceId).append(" 목업 데이터를 mock-responses.json에 추가하세요.\n");
|
log.append("\n Tip: ").append(interfaceId).append(" 목업 데이터를 mock-responses.json에 추가하세요.\n");
|
||||||
|
|
||||||
|
|||||||
@@ -190,11 +190,13 @@ public class BusinessToolController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 메서드 실행
|
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
Object methodResult = null;
|
Object methodResult = null;
|
||||||
methodResult = targetMethod.invoke(targetBean, invokeArgument);
|
if (targetMethod.getParameterCount() == 0) {
|
||||||
|
methodResult = targetMethod.invoke(targetBean);
|
||||||
|
} else {
|
||||||
|
methodResult = targetMethod.invoke(targetBean, invokeArgument);
|
||||||
|
}
|
||||||
|
|
||||||
long elapsed = System.currentTimeMillis() - startTime;
|
long elapsed = System.currentTimeMillis() - startTime;
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
package io.shinhanlife.dap.lib.util;
|
package io.shinhanlife.dap.lib.util;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.networknt.schema.JsonSchema;
|
||||||
|
import com.networknt.schema.JsonSchemaFactory;
|
||||||
|
import com.networknt.schema.SpecVersion;
|
||||||
|
import com.networknt.schema.ValidationMessage;
|
||||||
import io.shinhanlife.dap.lib.annotation.McpParameter;
|
import io.shinhanlife.dap.lib.annotation.McpParameter;
|
||||||
import io.shinhanlife.dap.lib.annotation.McpValidation;
|
import io.shinhanlife.dap.lib.annotation.McpValidation;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,11 +43,55 @@ class JsonSchemaGeneratorTest {
|
|||||||
assertEquals(List.of("APPROVE", "REJECT"), properties.get("approvalStatus").get("enum"));
|
assertEquals(List.of("APPROVE", "REJECT"), properties.get("approvalStatus").get("enum"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void includesNestedDtoConstraintsInGeneratedSchema() {
|
||||||
|
Map<String, Object> schema = JsonSchemaGenerator.generateSchema(NestedRequest.class);
|
||||||
|
Map<String, Object> childSchema = property(schema, "child");
|
||||||
|
|
||||||
|
assertEquals("object", childSchema.get("type"));
|
||||||
|
assertTrue(required(childSchema).contains("businessDate"));
|
||||||
|
assertEquals("^\\d{8}$", property(childSchema, "businessDate").get("pattern"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void includesNestedDtoSchemaForListItems() {
|
||||||
|
Map<String, Object> schema = JsonSchemaGenerator.generateSchema(ListRequest.class);
|
||||||
|
Map<String, Object> itemSchema = map(property(schema, "items").get("items"));
|
||||||
|
|
||||||
|
assertEquals("object", itemSchema.get("type"));
|
||||||
|
assertTrue(required(itemSchema).contains("businessDate"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void validatorRejectsInvalidNestedValue() throws Exception {
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
JsonSchema schema = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)
|
||||||
|
.getSchema(objectMapper.writeValueAsString(JsonSchemaGenerator.generateSchema(NestedRequest.class)));
|
||||||
|
Set<ValidationMessage> errors = schema.validate(objectMapper.valueToTree(Map.of(
|
||||||
|
"child", Map.of("businessDate", "2026-07-28"))));
|
||||||
|
|
||||||
|
assertFalse(errors.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Map<String, Map<String, Object>> properties(Map<String, Object> schema) {
|
private Map<String, Map<String, Object>> properties(Map<String, Object> schema) {
|
||||||
return (Map<String, Map<String, Object>>) schema.get("properties");
|
return (Map<String, Map<String, Object>>) schema.get("properties");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> property(Map<String, Object> schema, String name) {
|
||||||
|
return properties(schema).get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private Map<String, Object> map(Object value) {
|
||||||
|
return (Map<String, Object>) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private List<String> required(Map<String, Object> schema) {
|
||||||
|
return (List<String>) schema.get("required");
|
||||||
|
}
|
||||||
|
|
||||||
private static class ValidatedRequest {
|
private static class ValidatedRequest {
|
||||||
@McpParameter(description = "recipient phone number", required = true)
|
@McpParameter(description = "recipient phone number", required = true)
|
||||||
@McpValidation(pattern = "^01[0-9]{8,9}$")
|
@McpValidation(pattern = "^01[0-9]{8,9}$")
|
||||||
@@ -54,4 +105,17 @@ class JsonSchemaGeneratorTest {
|
|||||||
@McpValidation(required = true, allowedValues = {"APPROVE", "REJECT"})
|
@McpValidation(required = true, allowedValues = {"APPROVE", "REJECT"})
|
||||||
private String approvalStatus;
|
private String approvalStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class NestedRequest {
|
||||||
|
private NestedChild child;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ListRequest {
|
||||||
|
private List<NestedChild> items;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NestedChild {
|
||||||
|
@McpValidation(required = true, pattern = "^\\d{8}$")
|
||||||
|
private String businessDate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,8 @@
|
|||||||
FROM eclipse-temurin:21-jdk-alpine AS builder
|
|
||||||
WORKDIR /app
|
|
||||||
COPY gradlew .
|
|
||||||
COPY gradle gradle
|
|
||||||
COPY build.gradle settings.gradle ./
|
|
||||||
|
|
||||||
COPY dap-tool-core dap-tool-core
|
|
||||||
COPY dap-tool-oth dap-tool-oth
|
|
||||||
RUN chmod +x gradlew
|
|
||||||
RUN ./gradlew clean :dap-tool-oth:build -x test
|
|
||||||
|
|
||||||
FROM eclipse-temurin:21-jre-alpine
|
FROM eclipse-temurin:21-jre-alpine
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN apk add --no-cache tzdata
|
RUN apk add --no-cache tzdata
|
||||||
ENV TZ=Asia/Seoul
|
ENV TZ=Asia/Seoul
|
||||||
COPY --from=builder /app/dap-tool-oth/build/libs/*-SNAPSHOT.jar app.jar
|
COPY dap-tool-oth/build/libs/*-SNAPSHOT.jar app.jar
|
||||||
EXPOSE 8084
|
EXPOSE 8084
|
||||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.cmm.converter;
|
||||||
|
|
||||||
|
import io.shinhanlife.dap.mcc.biz.cmm.dto.MetaCommonCodeRequest;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.cmm.dto.MetaCommonCodeResponse;
|
||||||
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.cfp.a.io.CLCNNB00001_I;
|
||||||
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.cfp.a.io.CLCNNB00001_O;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.biz.cmm.converter
|
||||||
|
* @className MetaCommonCodeConverter
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author 09863409
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 09863409 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Mapper(componentModel = "spring")
|
||||||
|
public interface MetaCommonCodeConverter {
|
||||||
|
@Mapping(target = "csNo", source = "groupCode", defaultValue = "GRP_COMM_CD")
|
||||||
|
CLCNNB00001_I toLegacyRequest(MetaCommonCodeRequest req);
|
||||||
|
|
||||||
|
@Mapping(target = "codeList", ignore = true)
|
||||||
|
MetaCommonCodeResponse toResponse(CLCNNB00001_O mciRes);
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ import lombok.Data;
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class BalanceRequest {
|
public class BalanceRequest {
|
||||||
@McpParameter(description = "고객의 계좌번호 (- 제외)", required = true)
|
@McpParameter(description = "고객의 계좌번호 (- 제외) ", required = true)
|
||||||
@McpValidation(pattern = "\\S")
|
@McpValidation(pattern = "\\S")
|
||||||
private String accountNumber;
|
private String accountNumber;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.cmm.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.shinhanlife.dap.lib.annotation.McpParameter;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.biz.cmm.dto
|
||||||
|
* @className MetaCommonCodeRequest
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author 09863409
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 09863409 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class MetaCommonCodeRequest {
|
||||||
|
@McpParameter(description = "통합코드 그룹 ID (예: GRP_SYS_01, GRP_COMM_CD)", required = false)
|
||||||
|
private String groupCode;
|
||||||
|
|
||||||
|
@McpParameter(description = "코드명 검색 키워드 (예: 사용, 상태)", required = false)
|
||||||
|
private String codeName;
|
||||||
|
|
||||||
|
@McpParameter(description = "사용여부 (예: Y, N)", required = false)
|
||||||
|
private String useYn;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.cmm.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.biz.cmm.dto
|
||||||
|
* @className MetaCommonCodeResponse
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author 09863409
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 09863409 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class MetaCommonCodeResponse {
|
||||||
|
private List<MetaCommonCodeItem> codeList;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public static class MetaCommonCodeItem {
|
||||||
|
private String groupCode;
|
||||||
|
private String code;
|
||||||
|
private String codeName;
|
||||||
|
private String codeDesc;
|
||||||
|
private Integer sortSeq;
|
||||||
|
private String useYn;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.cmm.usecase;
|
||||||
|
|
||||||
|
import io.shinhanlife.dap.lib.annotation.McpFunction;
|
||||||
|
import io.shinhanlife.dap.lib.annotation.McpTool;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.cmm.dto.MetaCommonCodeRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.biz.cmm.usecase
|
||||||
|
* @className MetaCommonCodeUseCase
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author 09863409
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 09863409 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@McpTool(
|
||||||
|
routingType = "MCI",
|
||||||
|
categoryKey = "cmm"
|
||||||
|
)
|
||||||
|
public interface MetaCommonCodeUseCase {
|
||||||
|
@McpFunction(
|
||||||
|
displayName = "메타 통합코드 조회 툴",
|
||||||
|
name = "metaCommonCode",
|
||||||
|
description = "메타 통합코드 목록을 조회해줘",
|
||||||
|
prompt = "메타 통합코드 목록을 조회해줘",
|
||||||
|
mappingId = "CLCNNB00001",
|
||||||
|
register = false,
|
||||||
|
requiresApproval = false,
|
||||||
|
openWorldHint = true
|
||||||
|
)
|
||||||
|
Object execute(MetaCommonCodeRequest req);
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ import io.shinhanlife.dap.lib.annotation.McpTool;
|
|||||||
import io.shinhanlife.dap.lib.annotation.McpFunction;
|
import io.shinhanlife.dap.lib.annotation.McpFunction;
|
||||||
import io.shinhanlife.dap.mcc.biz.cmm.dto.*;
|
import io.shinhanlife.dap.mcc.biz.cmm.dto.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@McpTool(
|
@McpTool(
|
||||||
routingType = "HTTP",
|
routingType = "HTTP",
|
||||||
categoryKey = "cmm"
|
categoryKey = "cmm"
|
||||||
@@ -15,5 +17,5 @@ public interface TemplateUtilityUseCase {
|
|||||||
description = "요청한 템플릿(엑셀, 워드 등) 파일(양식)을 다운로드 받을 수 있는 시스템 URL을 반환합니다. AI는 이 URL을 사용자에게 마크다운 링크 형태로 제공해야 합니다.",
|
description = "요청한 템플릿(엑셀, 워드 등) 파일(양식)을 다운로드 받을 수 있는 시스템 URL을 반환합니다. AI는 이 URL을 사용자에게 마크다운 링크 형태로 제공해야 합니다.",
|
||||||
prompt = "요청하신 템플릿 양식 파일 다운로드 URL은 다음과 같습니다. 클릭하여 다운로드하세요:"
|
prompt = "요청하신 템플릿 양식 파일 다운로드 URL은 다음과 같습니다. 클릭하여 다운로드하세요:"
|
||||||
)
|
)
|
||||||
java.util.Map<String, Object> getTemplateFileUrl(TemplateDownloadRequest req);
|
Map<String, Object> getTemplateFileUrl(TemplateDownloadRequest req);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.cmm.usecase.impl;
|
||||||
|
|
||||||
|
import io.shinhanlife.dap.mcc.biz.cmm.converter.MetaCommonCodeConverter;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.cmm.dto.MetaCommonCodeRequest;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.cmm.dto.MetaCommonCodeResponse;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.cmm.dto.MetaCommonCodeResponse.MetaCommonCodeItem;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.cmm.usecase.MetaCommonCodeUseCase;
|
||||||
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.cfp.a.MciCfpaClient;
|
||||||
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.cfp.a.io.CLCNNB00001_I;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.biz.cmm.usecase.impl
|
||||||
|
* @className MetaCommonCodeUseCaseImpl
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author 09863409
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 09863409 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MetaCommonCodeUseCaseImpl implements MetaCommonCodeUseCase {
|
||||||
|
|
||||||
|
private final MciCfpaClient mci;
|
||||||
|
private final MetaCommonCodeConverter converter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object execute(MetaCommonCodeRequest req) {
|
||||||
|
log.info("[MCI Tool] {} 요청 수신. 파라미터: {}", "metaCommonCode", req);
|
||||||
|
try {
|
||||||
|
CLCNNB00001_I mciRequest = converter.toLegacyRequest(req);
|
||||||
|
|
||||||
|
Object mciResponse = mci.callCfpa0001(mciRequest);
|
||||||
|
log.info("[MCI Tool] CLCNNB00001 MCI call completed. Returning response status: {}",
|
||||||
|
mciResponse != null);
|
||||||
|
|
||||||
|
// 현업 테스트용으로 MCI 통신을 바이패스하고 하드코딩된 메타 통합코드 샘플 결과를 반환합니다.
|
||||||
|
MetaCommonCodeResponse res = new MetaCommonCodeResponse();
|
||||||
|
List<MetaCommonCodeItem> list = new ArrayList<>();
|
||||||
|
|
||||||
|
MetaCommonCodeItem item1 = new MetaCommonCodeItem();
|
||||||
|
item1.setGroupCode(req.getGroupCode() != null ? req.getGroupCode() : "GRP_COMM_CD");
|
||||||
|
item1.setCode("CD001");
|
||||||
|
item1.setCodeName("진행중");
|
||||||
|
item1.setCodeDesc("SR 요청 처리 진행 중 상태");
|
||||||
|
item1.setSortSeq(1);
|
||||||
|
item1.setUseYn("Y");
|
||||||
|
list.add(item1);
|
||||||
|
|
||||||
|
MetaCommonCodeItem item2 = new MetaCommonCodeItem();
|
||||||
|
item2.setGroupCode(req.getGroupCode() != null ? req.getGroupCode() : "GRP_COMM_CD");
|
||||||
|
item2.setCode("CD002");
|
||||||
|
item2.setCodeName("완료");
|
||||||
|
item2.setCodeDesc("SR 요청 처리 완료 상태");
|
||||||
|
item2.setSortSeq(2);
|
||||||
|
item2.setUseYn("Y");
|
||||||
|
list.add(item2);
|
||||||
|
|
||||||
|
MetaCommonCodeItem item3 = new MetaCommonCodeItem();
|
||||||
|
item3.setGroupCode(req.getGroupCode() != null ? req.getGroupCode() : "GRP_COMM_CD");
|
||||||
|
item3.setCode("CD003");
|
||||||
|
item3.setCodeName("보류");
|
||||||
|
item3.setCodeDesc("SR 요청 처리 일시 보류 상태");
|
||||||
|
item3.setSortSeq(3);
|
||||||
|
item3.setUseYn("N");
|
||||||
|
list.add(item3);
|
||||||
|
|
||||||
|
res.setCodeList(list);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e);
|
||||||
|
return Map.of("status", "ERROR", "message", e.getMessage() != null ? e.getMessage() : "Unknown error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,6 @@ import io.shinhanlife.dap.lib.annotation.McpFunction;
|
|||||||
import io.shinhanlife.dap.mcc.biz.oth.dto.*;
|
import io.shinhanlife.dap.mcc.biz.oth.dto.*;
|
||||||
|
|
||||||
@McpTool(routingType = "MCI", categoryKey = "oth")
|
@McpTool(routingType = "MCI", categoryKey = "oth")
|
||||||
public interface OnnbaMciToolUseCase {
|
public interface Onnba3011UseCase {
|
||||||
Object callOnnba3011(Onnba3011Request req);
|
Object callOnnba3011(Onnba3011Request req);
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ package io.shinhanlife.dap.mcc.biz.oth.usecase.impl;
|
|||||||
import io.shinhanlife.dap.mcc.biz.oth.converter.Onnba3011Converter;
|
import io.shinhanlife.dap.mcc.biz.oth.converter.Onnba3011Converter;
|
||||||
import io.shinhanlife.dap.mcc.infra.itrf.mci.cfp.a.MciCfpaClient;
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.cfp.a.MciCfpaClient;
|
||||||
import io.shinhanlife.dap.mcc.infra.itrf.mci.cfp.a.io.CLCNNB00001_I;
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.cfp.a.io.CLCNNB00001_I;
|
||||||
import io.shinhanlife.dap.mcc.biz.oth.usecase.OnnbaMciToolUseCase;
|
import io.shinhanlife.dap.mcc.biz.oth.usecase.Onnba3011UseCase;
|
||||||
import io.shinhanlife.dap.mcc.biz.oth.dto.Onnba3011Request;
|
import io.shinhanlife.dap.mcc.biz.oth.dto.Onnba3011Request;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -26,14 +26,13 @@ import org.springframework.stereotype.Service;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class OnnbaMciToolUseCaseImpl implements OnnbaMciToolUseCase {
|
public class Onnba3011UseCaseImpl implements Onnba3011UseCase {
|
||||||
|
|
||||||
private static final String INTERFACE_CODE_3011 = "CLCNNB00001";
|
private static final String INTERFACE_CODE_3011 = "CLCNNB00001";
|
||||||
|
|
||||||
// 공통 MCI Client 주입
|
// 공통 MCI Client 주입
|
||||||
private final MciCfpaClient mciCfpaClient;
|
private final MciCfpaClient mciCfpaClient;
|
||||||
private final Onnba3011Converter onnba3011Converter;
|
private final Onnba3011Converter onnba3011Converter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AI Agent가 호출하게 될 메서드입니다.
|
* AI Agent가 호출하게 될 메서드입니다.
|
||||||
* @McpFunction 어노테이션 하나로 AI 도구로 자동 노출 및 라우팅됩니다.
|
* @McpFunction 어노테이션 하나로 AI 도구로 자동 노출 및 라우팅됩니다.
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.smp.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.shinhanlife.dap.lib.annotation.McpParameter;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.biz.smp.dto
|
||||||
|
* @className TeamMemberRequest
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author jade
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 jade 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class TeamMemberRequest {
|
||||||
|
@McpParameter(description = "조회할 팀 이름 (예: AX, MCP, TOOL, 전체 등)", required = false)
|
||||||
|
private String teamName;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.smp.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.biz.smp.dto
|
||||||
|
* @className TeamMemberResponse
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author jade
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 jade 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class TeamMemberResponse {
|
||||||
|
private String result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.smp.usecase;
|
||||||
|
|
||||||
|
import io.shinhanlife.dap.lib.annotation.McpFunction;
|
||||||
|
import io.shinhanlife.dap.lib.annotation.McpTool;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.smp.dto.TeamMemberRequest;
|
||||||
|
|
||||||
|
@McpTool(
|
||||||
|
routingType = "DIRECT",
|
||||||
|
categoryKey = "smp"
|
||||||
|
)
|
||||||
|
public interface TeamMemberUseCase {
|
||||||
|
@McpFunction(
|
||||||
|
displayName = "신한라이프 MCP, TOOL 파트 구성원 조회",
|
||||||
|
name = "get_smp_members",
|
||||||
|
description = "신한라이프 MCP, TOOL 파트 구성원을 조회합니다.",
|
||||||
|
prompt = "신한라이프 MCP, TOOL 파트 구성원을 조회해 줘. (주의: 응답 시 ** 등 마크다운 기호를 절대 사용하지 말고 평문으로만 출력해 줘)",
|
||||||
|
mappingId = "DIRECT0001",
|
||||||
|
register = false,
|
||||||
|
requiresApproval = false,
|
||||||
|
openWorldHint = true
|
||||||
|
)
|
||||||
|
Object execute(TeamMemberRequest req);
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.smp.usecase.impl;
|
||||||
|
|
||||||
|
import io.shinhanlife.dap.mcc.biz.smp.dto.TeamMemberRequest;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.smp.dto.TeamMemberResponse;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.smp.usecase.TeamMemberUseCase;
|
||||||
|
import io.shinhanlife.dap.mcc.usecase.AbstractMcpToolUseCase;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.biz.smp.usecase.impl
|
||||||
|
* @className TeamMemberUseCaseImpl
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author jade
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 jade 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class TeamMemberUseCaseImpl extends AbstractMcpToolUseCase implements TeamMemberUseCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object execute(TeamMemberRequest req) {
|
||||||
|
log.info("[A01] 신한라이프 MCP, TOOL 파트 구성원 조회 요청: {}", req);
|
||||||
|
|
||||||
|
String filter = req != null && req.getTeamName() != null ? req.getTeamName().toUpperCase() : "전체";
|
||||||
|
|
||||||
|
String resultString = "";
|
||||||
|
if (filter.contains("AX")) {
|
||||||
|
resultString += "ax 추진팀 박세진 프로\n";
|
||||||
|
} else if (filter.contains("MCP") && !filter.contains("TOOL")) {
|
||||||
|
resultString += "MCP 팀은 고석민 수석 , 장효원 책임\n";
|
||||||
|
} else if (filter.contains("TOOL") && !filter.contains("MCP")) {
|
||||||
|
resultString += "TOOL 팀은 김형식 수석 ,김영진 책임 , 김도겸 대리 , 이주희 선임 , 문주현 선임 , 이보람 대리 , 박수빈 대리\n";
|
||||||
|
} else {
|
||||||
|
resultString += "ax 추진팀 박세진 프로\n" +
|
||||||
|
"MCP & TOOL 팀 담당자는 윤희준 이사\n" +
|
||||||
|
"MCP 팀은 고석민 수석 , 장효원 책임\n" +
|
||||||
|
"TOOL 팀은 김형식 수석 ,김영진 책임 , 김도겸 대리 , 이주희 선임 , 문주현 선임 , 이보람 대리 , 박수빈 대리";
|
||||||
|
}
|
||||||
|
|
||||||
|
TeamMemberResponse res = new TeamMemberResponse();
|
||||||
|
res.setResult(resultString.trim());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.sol.converter;
|
||||||
|
|
||||||
|
import io.shinhanlife.dap.mcc.biz.sol.dto.SolReqListRequest;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.sol.dto.SolReqListResponse;
|
||||||
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g.io.SOLG00000001_I;
|
||||||
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g.io.SOLG00000001_O;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.biz.sol.converter
|
||||||
|
* @className SolReqListConverter
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author jade
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 jade 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Mapper(componentModel = "spring")
|
||||||
|
public interface SolReqListConverter {
|
||||||
|
@Mapping(source = "status", target = "reqStatus", defaultValue = "진행중")
|
||||||
|
@Mapping(source = "period", target = "reqPeriod", defaultValue = "최근 3개월")
|
||||||
|
@Mapping(source = "target", target = "reqTarget", defaultValue = "나의 업무")
|
||||||
|
SOLG00000001_I toLegacyRequest(SolReqListRequest req);
|
||||||
|
|
||||||
|
SolReqListResponse toResponse(SOLG00000001_O mciRes);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.sol.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.shinhanlife.dap.lib.annotation.McpParameter;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.biz.sol.dto
|
||||||
|
* @className SolReqListRequest
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author jade
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 jade 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class SolReqListRequest {
|
||||||
|
@McpParameter(description = "진행상태 (예: 진행중, 완료 등)", required = false)
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
@McpParameter(description = "조회기간 (예: 1개월, 3개월 등)", required = false)
|
||||||
|
private String period;
|
||||||
|
|
||||||
|
@McpParameter(description = "조회대상 (예: 나의 업무, 전체 등)", required = false)
|
||||||
|
private String target;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.sol.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.biz.sol.dto
|
||||||
|
* @className SolReqListResponse
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author jade
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 jade 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class SolReqListResponse {
|
||||||
|
private List<SolReqListItem> reqList;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public static class SolReqListItem {
|
||||||
|
private String srId;
|
||||||
|
private String srName;
|
||||||
|
private String process;
|
||||||
|
private String devStage;
|
||||||
|
private String appName;
|
||||||
|
private String requester;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.sol.usecase;
|
||||||
|
|
||||||
|
import io.shinhanlife.dap.lib.annotation.McpFunction;
|
||||||
|
import io.shinhanlife.dap.lib.annotation.McpTool;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.sol.dto.SolReqListRequest;
|
||||||
|
|
||||||
|
@McpTool(
|
||||||
|
routingType = "MCI",
|
||||||
|
categoryKey = "sol"
|
||||||
|
)
|
||||||
|
public interface SolReqListUseCase {
|
||||||
|
@McpFunction(
|
||||||
|
displayName = "SolReqList 툴",
|
||||||
|
name = "solReqList",
|
||||||
|
description = "SOL 의뢰서 목록 조회해줘",
|
||||||
|
prompt = "SOL 의뢰서 목록 조회해줘",
|
||||||
|
mappingId = "SOLG00000001",
|
||||||
|
register = false,
|
||||||
|
requiresApproval = false,
|
||||||
|
openWorldHint = true
|
||||||
|
)
|
||||||
|
Object execute(SolReqListRequest req);
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.sol.usecase.impl;
|
||||||
|
|
||||||
|
import io.shinhanlife.dap.mcc.biz.sol.dto.SolReqListRequest;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.sol.dto.SolReqListResponse;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.sol.usecase.SolReqListUseCase;
|
||||||
|
import io.shinhanlife.glow.communication.dto.Transfer;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.sol.converter.SolReqListConverter;
|
||||||
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g.io.SOLG00000001_I;
|
||||||
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g.io.SOLG00000001_O;
|
||||||
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g.MciNclgClient;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.sol.dto.SolReqListResponse.SolReqListItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.biz.sol.usecase.impl
|
||||||
|
* @className SolReqListUseCaseImpl
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author jade
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 jade 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SolReqListUseCaseImpl implements SolReqListUseCase {
|
||||||
|
|
||||||
|
private final MciNclgClient mci;
|
||||||
|
private final SolReqListConverter converter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object execute(SolReqListRequest req) {
|
||||||
|
log.info("[MCI Tool] {} 요청 수신. 파라미터: {}", "solReqList", req);
|
||||||
|
try {
|
||||||
|
SOLG00000001_I mciRequest = converter.toLegacyRequest(req);
|
||||||
|
Transfer<SOLG00000001_O> mciResponse = mci.callTo(
|
||||||
|
"SOLG00000001", "SOLG00000001", mciRequest, SOLG00000001_O.class);
|
||||||
|
log.info("[MCI Tool] SOLG00000001 MCI call completed. Returning dummy response: {}",
|
||||||
|
mciResponse != null);
|
||||||
|
// 현업 테스트용으로 MCI 통신을 바이패스하고 하드코딩된 결과를 반환합니다.
|
||||||
|
SolReqListResponse res = new SolReqListResponse();
|
||||||
|
List<SolReqListItem> list = new ArrayList<>();
|
||||||
|
|
||||||
|
SolReqListItem item1 = new SolReqListItem();
|
||||||
|
item1.setSrId("SR-2026-001");
|
||||||
|
item1.setSrName("AX HUB 메인 화면 UI 개편");
|
||||||
|
item1.setProcess("진행중");
|
||||||
|
item1.setDevStage("개발(단위테스트)");
|
||||||
|
item1.setAppName("AX HUB");
|
||||||
|
item1.setRequester("윤희준");
|
||||||
|
list.add(item1);
|
||||||
|
|
||||||
|
SolReqListItem item2 = new SolReqListItem();
|
||||||
|
item2.setSrId("SR-2026-002");
|
||||||
|
item2.setSrName("툴 연동 모듈 추가 개발");
|
||||||
|
item2.setProcess("진행중");
|
||||||
|
item2.setDevStage("분석/설계");
|
||||||
|
item2.setAppName("MCP Gateway");
|
||||||
|
item2.setRequester("고석민");
|
||||||
|
list.add(item2);
|
||||||
|
|
||||||
|
res.setReqList(list);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[MCI Tool] 연동 중 오류 발생: {}", e.getMessage(), e);
|
||||||
|
return Map.of("status", "ERROR", "message", e.getMessage() != null ? e.getMessage() : "Unknown error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import io.shinhanlife.dap.lib.integration.mci.component.AxhubMciComponent;
|
||||||
|
import io.shinhanlife.glow.communication.dto.Transfer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g
|
||||||
|
* @className MciNclgClient
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author jade
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 jade 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MciNclgClient {
|
||||||
|
private final AxhubMciComponent mci;
|
||||||
|
|
||||||
|
public <T> Transfer<T> callTo(String interfaceId, String dummy, Object mciReq, Class<T> resType) throws Exception {
|
||||||
|
return mci.callTo(interfaceId, dummy, mciReq, resType);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g.io;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g.io
|
||||||
|
* @className SOLG00000001_I
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author jade
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 jade 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SOLG00000001_I {
|
||||||
|
private String reqStatus;
|
||||||
|
private String reqPeriod;
|
||||||
|
private String reqTarget;
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g.io;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g.io
|
||||||
|
* @className SOLG00000001_O
|
||||||
|
* @description AX HUB 시스템 처리 클래스
|
||||||
|
* @author jade
|
||||||
|
* @create 2026.07.29
|
||||||
|
* <pre>
|
||||||
|
* ---------- 개정이력 ----------
|
||||||
|
* 수정일 수정자 수정내용
|
||||||
|
* ---------- -------- ---------------------------
|
||||||
|
* 2026.07.29 jade 최초생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SOLG00000001_O {
|
||||||
|
private List<SOLG00000001_O_Item> reqList;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class SOLG00000001_O_Item {
|
||||||
|
private String srId;
|
||||||
|
private String srName;
|
||||||
|
private String process;
|
||||||
|
private String devStage;
|
||||||
|
private String appName;
|
||||||
|
private String requester;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,13 +24,13 @@ import org.mockito.Mockito;
|
|||||||
* 2026.07.27 0986406 initial creation
|
* 2026.07.27 0986406 initial creation
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
class OnnbaMciToolUseCaseImplTest {
|
class Onnba3011UseCaseImplTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void convertsToolRequestBeforeCallingMciClient() throws Exception {
|
void convertsToolRequestBeforeCallingMciClient() throws Exception {
|
||||||
MciCfpaClient mciCfpaClient = Mockito.mock(MciCfpaClient.class);
|
MciCfpaClient mciCfpaClient = Mockito.mock(MciCfpaClient.class);
|
||||||
Onnba3011Converter converter = Mockito.mock(Onnba3011Converter.class);
|
Onnba3011Converter converter = Mockito.mock(Onnba3011Converter.class);
|
||||||
OnnbaMciToolUseCaseImpl useCase = new OnnbaMciToolUseCaseImpl(mciCfpaClient, converter);
|
Onnba3011UseCaseImpl useCase = new Onnba3011UseCaseImpl(mciCfpaClient, converter);
|
||||||
Onnba3011Request request = new Onnba3011Request();
|
Onnba3011Request request = new Onnba3011Request();
|
||||||
CLCNNB00001_I mciRequest = new CLCNNB00001_I();
|
CLCNNB00001_I mciRequest = new CLCNNB00001_I();
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package io.shinhanlife.dap.mcc.biz.sol.usecase.impl;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import io.shinhanlife.dap.mcc.biz.sol.converter.SolReqListConverter;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.sol.dto.SolReqListRequest;
|
||||||
|
import io.shinhanlife.dap.mcc.biz.sol.dto.SolReqListResponse;
|
||||||
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g.MciNclgClient;
|
||||||
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g.io.SOLG00000001_I;
|
||||||
|
import io.shinhanlife.dap.mcc.infra.itrf.mci.ncl.g.io.SOLG00000001_O;
|
||||||
|
import io.shinhanlife.glow.communication.dto.Transfer;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
class SolReqListUseCaseImplTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void callsMciWithConvertedRequestAndReturnsDummyResponse() throws Exception {
|
||||||
|
MciNclgClient mci = Mockito.mock(MciNclgClient.class);
|
||||||
|
SolReqListConverter converter = Mockito.mock(SolReqListConverter.class);
|
||||||
|
SolReqListUseCaseImpl useCase = new SolReqListUseCaseImpl(mci, converter);
|
||||||
|
SolReqListRequest request = new SolReqListRequest();
|
||||||
|
SOLG00000001_I mciRequest = new SOLG00000001_I();
|
||||||
|
|
||||||
|
when(converter.toLegacyRequest(request)).thenReturn(mciRequest);
|
||||||
|
when(mci.callTo(eq("SOLG00000001"), eq("SOLG00000001"), eq(mciRequest), eq(SOLG00000001_O.class)))
|
||||||
|
.thenReturn(new Transfer<>());
|
||||||
|
|
||||||
|
SolReqListResponse response = (SolReqListResponse) useCase.execute(request);
|
||||||
|
|
||||||
|
verify(converter).toLegacyRequest(request);
|
||||||
|
verify(mci).callTo("SOLG00000001", "SOLG00000001", mciRequest, SOLG00000001_O.class);
|
||||||
|
assertThat(response.getReqList()).extracting(SolReqListResponse.SolReqListItem::getSrId)
|
||||||
|
.containsExactly("SR-2026-001", "SR-2026-002");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,8 @@
|
|||||||
FROM eclipse-temurin:21-jdk-alpine AS builder
|
|
||||||
WORKDIR /app
|
|
||||||
COPY gradlew .
|
|
||||||
COPY gradle gradle
|
|
||||||
COPY build.gradle settings.gradle ./
|
|
||||||
|
|
||||||
COPY dap-tool-core dap-tool-core
|
|
||||||
COPY dap-tool-sms dap-tool-sms
|
|
||||||
RUN chmod +x gradlew
|
|
||||||
RUN ./gradlew clean :dap-tool-sms:build -x test
|
|
||||||
|
|
||||||
FROM eclipse-temurin:21-jre-alpine
|
FROM eclipse-temurin:21-jre-alpine
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN apk add --no-cache tzdata
|
RUN apk add --no-cache tzdata
|
||||||
ENV TZ=Asia/Seoul
|
ENV TZ=Asia/Seoul
|
||||||
COPY --from=builder /app/dap-tool-sms/build/libs/*-SNAPSHOT.jar app.jar
|
COPY dap-tool-sms/build/libs/*-SNAPSHOT.jar app.jar
|
||||||
EXPOSE 8082
|
EXPOSE 8082
|
||||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
$ErrorActionPreference = "Stop"
|
|
||||||
|
|
||||||
$extensions = @("*.java", "*.xml", "*.yml", "*.properties", "*.gradle", "*.md")
|
|
||||||
$baseDir = "C:\eGovFrameDev-4.3.1-64bit\workspace-egov\axhub-backend-main"
|
|
||||||
|
|
||||||
Write-Host "Replacing text (Req -> Request, Res -> Response)..."
|
|
||||||
Get-ChildItem -Path $baseDir -Include $extensions -Recurse -File | ForEach-Object {
|
|
||||||
if ($_.FullName -notmatch "\\build\\" -and $_.FullName -notmatch "\\\.git\\" -and $_.FullName -notmatch "\\\.gradle\\" -and $_.FullName -notmatch "\\bin\\") {
|
|
||||||
try {
|
|
||||||
$content = Get-Content $_.FullName -Raw -Encoding UTF8
|
|
||||||
$newContent = $content -creplace "Req\b", "Request"
|
|
||||||
$newContent = $newContent -creplace "Res\b", "Response"
|
|
||||||
if ($content -cne $newContent) {
|
|
||||||
Write-Host "Updated text in: $($_.FullName)"
|
|
||||||
$utf8NoBom = New-Object System.Text.UTF8Encoding $False
|
|
||||||
[System.IO.File]::WriteAllText($_.FullName, $newContent, $utf8NoBom)
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
Write-Host "Skipped binary or locked file: $($_.FullName)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "Renaming DTO files..."
|
|
||||||
Get-ChildItem -Path $baseDir -Include *Req.java,*Res.java -Recurse -File | ForEach-Object {
|
|
||||||
if ($_.FullName -notmatch "\\build\\" -and $_.FullName -notmatch "\\\.git\\" -and $_.FullName -notmatch "\\\.gradle\\" -and $_.FullName -notmatch "\\bin\\") {
|
|
||||||
$newName = $_.Name -creplace "Req\.java$", "Request.java"
|
|
||||||
$newName = $newName -creplace "Res\.java$", "Response.java"
|
|
||||||
Write-Host "Renaming file: $($_.FullName) -> $newName"
|
|
||||||
Rename-Item -Path $_.FullName -NewName $newName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "DTO Refactoring completed!"
|
|
||||||
33
refactor.ps1
33
refactor.ps1
@@ -1,33 +0,0 @@
|
|||||||
$ErrorActionPreference = "Stop"
|
|
||||||
|
|
||||||
$extensions = @("*.java", "*.xml", "*.yml", "*.properties", "*.gradle", "*.md", "Dockerfile*")
|
|
||||||
$baseDir = "C:\eGovFrameDev-4.3.1-64bit\workspace-egov\axhub-backend-main"
|
|
||||||
|
|
||||||
Write-Host "Replacing text..."
|
|
||||||
Get-ChildItem -Path $baseDir -Include $extensions -Recurse -File | ForEach-Object {
|
|
||||||
if ($_.FullName -notmatch "\\build\\" -and $_.FullName -notmatch "\\\.git\\" -and $_.FullName -notmatch "\\\.gradle\\" -and $_.FullName -notmatch "\\bin\\") {
|
|
||||||
try {
|
|
||||||
$content = Get-Content $_.FullName -Raw -Encoding UTF8
|
|
||||||
$newContent = $content -replace "dapms", "mcg"
|
|
||||||
$newContent = $newContent -replace "dapmt", "mcc"
|
|
||||||
if ($content -cne $newContent) {
|
|
||||||
Write-Host "Updated text in: $($_.FullName)"
|
|
||||||
$utf8NoBom = New-Object System.Text.UTF8Encoding $False
|
|
||||||
[System.IO.File]::WriteAllText($_.FullName, $newContent, $utf8NoBom)
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
Write-Host "Skipped binary or locked file: $($_.FullName)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "Renaming directories..."
|
|
||||||
Get-ChildItem -Path $baseDir -Recurse -Directory | Where-Object { $_.Name -eq "dapms" -or $_.Name -eq "dapmt" } | Sort-Object -Property @{Expression={$_.FullName.Length}; Descending=$true} | ForEach-Object {
|
|
||||||
if ($_.FullName -notmatch "\\build\\" -and $_.FullName -notmatch "\\\.git\\" -and $_.FullName -notmatch "\\\.gradle\\" -and $_.FullName -notmatch "\\bin\\") {
|
|
||||||
$newName = if ($_.Name -eq "dapms") { "mcg" } else { "mcc" }
|
|
||||||
Write-Host "Renaming dir: $($_.FullName) -> $newName"
|
|
||||||
Rename-Item -Path $_.FullName -NewName $newName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "Refactoring completed!"
|
|
||||||
Reference in New Issue
Block a user