OBP 과금용 gw metric 데이터 추가

This commit is contained in:
Rinjae
2025-12-05 10:39:20 +09:00
parent f05f5d7bbc
commit 974830846b
10 changed files with 197 additions and 12 deletions
+1
View File
@@ -244,3 +244,4 @@ gradle-gf63.sh
eapim-admin-kjb/ eapim-admin-kjb/
.claude .claude
*.report.md *.report.md
*.claude.md
+49 -2
View File
@@ -1,6 +1,17 @@
# CLAUDE.md # AI-Assisted Development Guide
파일은 Claude Code (claude.ai/code)가 이 저장소의 코드를 작업할 때 참고할 가이드를 제공합니다. 문서는 AI 어시스턴트가 이 저장소의 코드를 이해하고 기여하는 데 필요한 가이드를 제공합니다.
## 프로젝트 주요 특징
AI 어시스턴트가 작업을 시작하기 전에 반드시 이해해야 할 핵심적인 특징들입니다.
- **하이브리드 데이터 액세스**: 이 프로젝트는 **JPA(Hibernate)와 iBATIS를 함께 사용**합니다.
- **신규 기능**: 항상 **JPA**와 Spring Data 리포지토리를 사용해야 합니다.
- **레거시 코드**: 기존 iBATIS (`*.xml` 매퍼) 코드를 수정할 때는 해당 패턴을 따라야 합니다.
- **멀티 모듈 Gradle 프로젝트**: `settings.gradle`에 정의된 것처럼 여러 하위 모듈(`elink-online-*`, `kjb-*` 등)로 구성되어 있습니다. 특정 기능은 다른 모듈에 위치할 수 있습니다.
- **QueryDSL 코드 생성**: 빌드 시 `QueryDSL`을 사용하여 Q-class가 자동으로 생성됩니다. IDE에서 엔티티를 찾을 수 없다고 표시되면, `gradle compileJava`를 먼저 실행하여 코드를 생성해야 합니다.
- **고객사별 커스터마이징**: `ext.kjb` 또는 `custom` 패키지는 특정 고객사(광주은행)를 위한 코드를 포함하므로, 일반적인 기능 수정 시에는 주의가 필요합니다.
## 프로젝트 개요 ## 프로젝트 개요
@@ -69,6 +80,39 @@ gradle dependencies
gradle tasks --all gradle tasks --all
``` ```
## 로컬 개발 빠른 시작
새로운 환경에서 프로젝트를 처음 설정하고 실행하는 권장 절차입니다.
1. **IDE 설정 파일 생성 (최초 1회)**
```bash
# IntelliJ IDEA 사용 시
gradle idea
# Eclipse 사용 시
gradle eclipse
```
2. **QueryDSL 등 소스 코드 생성**
```bash
gradle compileJava
```
3. **전체 빌드 및 테스트 실행**
```bash
gradle build
```
4. **IDE에서 프로젝트 열기**
- `gradle idea` 또는 `gradle eclipse` 실행 후, IDE에서 프로젝트를 엽니다.
5. **실행 구성(Run Configuration) 설정**
- 사용하는 WAS(Tomcat 등)에 `eapim-admin` 프로젝트를 배포하도록 설정합니다.
- **VM Options**에 위에 명시된 "필수 환경 변수 (Tomcat)"를 모두 추가합니다.
6. **서버 실행**
- IDE에서 설정한 실행 구성을 시작하여 서버를 실행합니다.
## 아키텍처 및 모듈 의존성 ## 아키텍처 및 모듈 의존성
### 멀티 모듈 구조 ### 멀티 모듈 구조
@@ -132,6 +176,9 @@ eapim-admin (root project)
### 필수 환경 변수 (Tomcat) ### 필수 환경 변수 (Tomcat)
다음은 로컬 Tomcat 환경에서 개발 시 필요한 시스템 프로퍼티(-D)입니다.
**설정 방법**: IntelliJ, Eclipse 등 IDE의 실행 구성(Run Configuration)에서 'VM options'에 추가하거나, 사용하는 Tomcat의 `bin` 폴더에 `setenv.bat` (Windows) 또는 `setenv.sh` (Linux/macOS) 파일을 생성하여 아래 내용들을 `CATALINA_OPTS` 또는 `JAVA_OPTS` 환경 변수에 추가합니다.
``` ```
-Deai.datasource.type=DEV -Deai.datasource.type=DEV
-Dinst.Name=emsSvr99 -Dinst.Name=emsSvr99
+4
View File
@@ -0,0 +1,4 @@
# GEMINI.md
이 프로젝트에 대한 주요 정보 및 지침은 `CLAUDE.md` 파일을 참조하십시오.
(For key information and guidelines regarding this project, please refer to the `CLAUDE.md` file.)
+9 -2
View File
@@ -36,10 +36,17 @@ java {
} }
} }
sourceSets {
main {
java {
srcDirs generatedJavaDir
}
}
}
compileJava { compileJava {
options.encoding = 'UTF-8' options.encoding = 'UTF-8'
options.compilerArgs = ['-parameters'] options.compilerArgs = ['-parameters']
sourceSets.main.java { srcDir generatedJavaDir }
options.generatedSourceOutputDirectory = project.file(generatedJavaDir) options.generatedSourceOutputDirectory = project.file(generatedJavaDir)
aptOptions { aptOptions {
@@ -64,7 +71,7 @@ war {
tasks.withType(JavaCompile) { tasks.withType(JavaCompile) {
options.encoding = 'UTF-8' options.encoding = 'UTF-8'
options.compilerArgs = ['-parameters'] options.compilerArgs += ['-parameters', "-Xlint:unchecked", "-Xlint:deprecation"]
} }
@@ -28,7 +28,7 @@ public abstract class CredentialUIMapper implements GenericMapper<CredentialUI,
@InheritInverseConfiguration @InheritInverseConfiguration
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
@Mapping(target = "apiList", expression = "java(apiSpecUIMapper.mapList(credentialUI.getApiList()))") @Mapping(target = "apiList", source = "apiList")
public abstract void updateToEntity(CredentialUI credentialUI, @MappingTarget Credential credential); public abstract void updateToEntity(CredentialUI credentialUI, @MappingTarget Credential credential);
@Mapping(source = "clientid", target = "clientId") @Mapping(source = "clientid", target = "clientId")
@@ -16,7 +16,7 @@ import com.eactive.eai.rms.onl.audit.adapter.ui.AuditUI;
@Mapper(config = BaseMapperConfig.class, uses = {}) @Mapper(config = BaseMapperConfig.class, uses = {})
public interface AuditUIMapper { public interface AuditUIMapper {
@Mapping(target = "revTstmp", expression = "java(mapLongToString(entity.getRevTstmp()))") @Mapping(target = "revTstmp", source = "revTstmp")
@Mapping(target = "revNo", source = "rev") @Mapping(target = "revNo", source = "rev")
@Mapping(target = "revUserId", source = "userId") @Mapping(target = "revUserId", source = "userId")
void map(CustomRevisionEntity entity, @MappingTarget AuditUI auditUI); void map(CustomRevisionEntity entity, @MappingTarget AuditUI auditUI);
@@ -9,6 +9,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.eactive.eai.rms.onl.common.util.FileSystemUtil;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCell;
@@ -75,7 +76,7 @@ public class TransactionReportHourJob implements Job {
} }
String trTime = monitoringContext.getStringProperty(MonitoringContext.RMS_TRANSACTION_LOG_TIME, ""); String trTime = monitoringContext.getStringProperty(MonitoringContext.RMS_TRANSACTION_LOG_TIME, "");
if( trTime.indexOf("EVERY_HOUR") > -1 ) { if (trTime.contains("EVERY_HOUR")) {
// go on // go on
} else if (!StringUtils.contains(trTime, hour)) { } else if (!StringUtils.contains(trTime, hour)) {
return; return;
@@ -93,9 +94,11 @@ public class TransactionReportHourJob implements Job {
+ CommonUtil.getToday("yyyy-MM-dd HH:mm") + ")"); + CommonUtil.getToday("yyyy-MM-dd HH:mm") + ")");
} }
String pathDir = monitoringContext.getStringProperty( MonitoringContext.RMS_TRANSACTION_LOG_PATH,"/fslog/eai/") String pathDir = FileSystemUtil.pathNormalize(
+ monitoringContext.getStringProperty( Keys.SERVER_KEY) monitoringContext.getStringProperty( MonitoringContext.RMS_TRANSACTION_LOG_PATH,"/fslog/eai/")
+ "/trlog"; , monitoringContext.getStringProperty( Keys.SERVER_KEY)
, "trlog"
);
/////////////////////////////////////////////// ///////////////////////////////////////////////
// 로컬테스트용 // 로컬테스트용
@@ -0,0 +1,73 @@
package com.eactive.eai.rms.onl.common.util;
import java.io.File;
import java.util.StringJoiner;
public class FileSystemUtil {
/**
* Normalizes a path by joining segments and applying the correct file separator for the current operating system.
* It handles redundant separators between segments.
*
* <p>Examples for Linux/macOS:</p>
* <ul>
* <li>{@code pathNormalize("/asd1/asd2", "asd3")} returns {@code "/asd1/asd2/asd3"}</li>
* <li>{@code pathNormalize("/asd1/asd2/", "/asd3")} returns {@code "/asd1/asd2/asd3"}</li>
* </ul>
*
* <p>Examples for Windows:</p>
* <ul>
* <li>{@code pathNormalize("C:/Users/Test", "Documents")} returns {@code "C:\\Users\\Test\\Documents"}</li>
* <li>{@code pathNormalize("C:/Users/Test/", "/Documents")} returns {@code "C:\\Users\\Test\\Documents"}</li>
* </ul>
*
* @param args A variable number of path segments to join.
* @return A normalized path string for the current operating system.
*/
public static String pathNormalize(String... args) {
if (args == null || args.length == 0) {
return "";
}
StringJoiner joiner = new StringJoiner(File.separator);
for (String arg : args) {
if (arg != null && !arg.isEmpty()) {
String segment = arg;
// Remove leading separators from the segment
while (segment.startsWith("/") || segment.startsWith("\\")) {
segment = segment.substring(1);
}
// Remove trailing separators from the segment
while (segment.endsWith("/") || segment.endsWith("\\")) {
segment = segment.substring(0, segment.length() - 1);
}
if (!segment.isEmpty()) {
joiner.add(segment);
}
}
}
String joinedPath = joiner.toString();
// Handle the root path for the first argument
String firstArg = args[0];
if (firstArg != null && !firstArg.isEmpty()) {
if (firstArg.startsWith("/")) {
joinedPath = File.separator + joinedPath;
} else if (firstArg.matches("^[a-zA-Z]:\\\\") || firstArg.matches("^[a-zA-Z]:/.*")) { // Handle Windows drive letters, e.g., "C:\" or "C:/"
String drive = firstArg.substring(0, 2);
return drive + File.separator + joinedPath.substring(joinedPath.indexOf(File.separator) + 1);
}
}
// Final normalization for Windows if the path starts with a separator (e.g. from a UNC path)
if (System.getProperty("os.name").toLowerCase().contains("win")) {
if (args[0] != null && args[0].startsWith("//") || args[0].startsWith("\\\\")) {
return "\\\\" + joinedPath;
}
return joinedPath.replace("/", "\\");
}
return joinedPath.replace("\\", "/");
}
}
@@ -148,7 +148,7 @@ public interface ApiInterfaceUIMapper {
@Mapping(target = "eaisendrecv", source = "sendRecvType") @Mapping(target = "eaisendrecv", source = "sendRecvType")
@Mapping(target = "eaidirection", source = "inOutType") @Mapping(target = "eaidirection", source = "inOutType")
@Mapping(target = "standardMessageItems", source = "standardMessageItems") @Mapping(target = "standardMessageItems", source = "standardMessageItems")
@Mapping(target = "apiFullPath", source = "apiFullPath")
StandardMessageInfo toStandardMessageInfo(ApiInterfaceUI vo); StandardMessageInfo toStandardMessageInfo(ApiInterfaceUI vo);
@AfterMapping @AfterMapping
@@ -0,0 +1,50 @@
package com.eactive.eai.rms.onl.common.util;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;
import java.io.File;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class FileSystemUtilTest {
@Test
@EnabledOnOs(OS.LINUX)
void testPathNormalize_Linux() {
assertEquals("/asd1/asd2/asd3", FileSystemUtil.pathNormalize("/asd1/asd2", "asd3"));
assertEquals("/asd1/asd2/asd3", FileSystemUtil.pathNormalize("/asd1/asd2/", "/asd3"));
assertEquals("/asd1/asd2/asd3", FileSystemUtil.pathNormalize("/asd1/asd2", "/asd3"));
assertEquals("/asd1/asd2/asd3", FileSystemUtil.pathNormalize("/asd1/asd2/", "asd3/"));
assertEquals("/a/b/c", FileSystemUtil.pathNormalize("/a/", "/b/", "/c/"));
assertEquals("a/b/c", FileSystemUtil.pathNormalize("a", "b", "c"));
assertEquals("/a", FileSystemUtil.pathNormalize("/a"));
}
@Test
@EnabledOnOs(OS.WINDOWS)
void testPathNormalize_Windows() {
assertEquals("\\asd1\\asd2\\asd3", FileSystemUtil.pathNormalize("/asd1/asd2", "asd3"));
assertEquals("\\asd1\\asd2\\asd3", FileSystemUtil.pathNormalize("/asd1/asd2/", "/asd3"));
assertEquals("\\asd1\\asd2\\asd3", FileSystemUtil.pathNormalize("/asd1/asd2", "/asd3"));
assertEquals("\\asd1\\asd2\\asd3", FileSystemUtil.pathNormalize("/asd1/asd2/", "asd3/"));
assertEquals("C:\\Users\\Test", FileSystemUtil.pathNormalize("C:/Users", "Test"));
assertEquals("C:\\Users\\Test", FileSystemUtil.pathNormalize("C:\\Users", "Test"));
assertEquals("\\a\\b\\c", FileSystemUtil.pathNormalize("/a/", "/b/", "/c/"));
assertEquals("a\\b\\c", FileSystemUtil.pathNormalize("a", "b", "c"));
assertEquals("\\a", FileSystemUtil.pathNormalize("/a"));
}
@Test
void testPathNormalize_General() {
String expected = "a" + File.separator + "b" + File.separator + "c";
assertEquals(expected, FileSystemUtil.pathNormalize("a", "b", "c"));
assertEquals("", FileSystemUtil.pathNormalize(""));
assertEquals("", FileSystemUtil.pathNormalize(null));
assertEquals("", FileSystemUtil.pathNormalize());
assertEquals("a", FileSystemUtil.pathNormalize("a"));
assertEquals("a", FileSystemUtil.pathNormalize("a/"));
assertEquals("a", FileSystemUtil.pathNormalize("/a"));
}
}