From c06bbb3168a8b97c1bbb308a2db675d817f0b9d5 Mon Sep 17 00:00:00 2001 From: Rinjae Date: Fri, 14 Nov 2025 15:01:12 +0900 Subject: [PATCH] =?UTF-8?q?EMSADM=20DDL=20identity=20to=20sequence=20?= =?UTF-8?q?=EB=8C=80=EC=9D=91=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 180 +++++++++++++++ .../eai/custom/CustomizingAppInitializer.java | 5 + .../CustomBeanFactoryPostProcessor.java | 10 +- .../rms/common/startup/AppInitializer.java | 209 +++++++++--------- .../man/user/UserAthrRoleChgHistory.java | 16 +- .../entity/man/user/UserLoginHistory.java | 16 +- .../onl/audit/CustomRevisionEntity.java | 1 - 7 files changed, 328 insertions(+), 109 deletions(-) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..3fd2381 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,180 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +eLink EMS (eLink Management System) is a web-based management service for eLink that provides configuration, monitoring, and statistics features. This is a Spring-based Java web application deployed on Tomcat or WebLogic. + +### Key Features +- User and permission management +- Transaction log viewing (online/batch/bulk) +- Statistics and dashboard monitoring +- Interface, layout, adapter, and routing management +- Integration with external systems (UMS, EAI batch) + +## Build and Development Commands + +### Build Commands +```bash +# Standard build +gradle build + +# Build for Weblogic deployment (excludes tests) +gradle build -x test -Pprofile=weblogic + +# Build WAR file +gradle war + +# Clean build +gradle clean build +``` + +### Running Tests +```bash +# Run all tests +gradle test + +# Run specific test (use JUnit platform) +gradle test --tests "com.eactive.eai.rms.*" +``` + +### Development Setup +The application is configured via environment-specific properties files in `WebContent/WEB-INF/properties/`: +- `env.D.properties` - Development +- `env.T.properties` - Test/Staging +- `env.P.properties` - Production + +**Local Development (Tomcat)** +Set the following JVM options: +``` +-Deai.datasource.type=DEV +-Dinst.Name=emsSvr99 +-Deai.tableowner=EMSADM +-Deai.systemmode=D +-Dfile.encoding=utf-8 +-Dlogin.mode=db +-DLOGBACK_LOG_LEVEL=DEBUG +-Dlogback.configurationFile=classpath:logback-dev.xml +-Dhibernate.dialect=org.hibernate.dialect.Oracle12cDialect +-Dkjb_safedb.mode=fake +``` + +**Profile Configuration** +- `-Pprofile=weblogic`: Uses `weblogic-web.xml` instead of `web.xml` (resolves DefaultServlet issues) + +## Architecture and Code Structure + +### Multi-Module Project +This project references several external eLink modules defined in `settings.gradle`: +- `elink-online-core` - Core interfaces and classes +- `elink-online-transformer` - Message transformation logic +- `elink-online-adapter` - Communication adapters +- `elink-online-common` - Common utilities +- `elink-online-emsclient` - EMS communication client +- `elink-portal-common` - Portal shared components +- `kjb-safedb` - KJB bank-specific database encryption +- `eapim-admin-kjb` - KJB bank-specific customizations + +These modules are located in sibling directories (`../eapim-online/`, `../elink-portal-common/`, etc.) + +### Package Structure +``` +com.eactive.eai +├── agent/command - Command pattern implementations +├── common - Common utilities, iBatis, JSON serialization +├── custom - Customer-specific customizations +├── rms - Main application code +│ ├── bap - Batch processing (BAP) +│ │ ├── adaptor - Batch adapters +│ │ ├── manage - Batch management (messages, servers, properties) +│ │ └── tansaction - Batch transaction tracking +│ ├── bat - Additional batch functionality +│ ├── common - RMS common (filters, startup, services) +│ ├── data - Data entities, repositories +│ ├── env - Environment configuration +│ ├── kakao - Kakao integration +│ ├── onl - Online transaction management +│ │ ├── apim - API management (portal org, users, approvals) +│ │ ├── manage - Resource management +│ │ └── transaction - Transaction handling +│ └── service - Business services +└── ext.kjb - Kwangju Bank (KJB) extensions +``` + +### Technology Stack +- **Framework**: Spring 5.3.27 (MVC, Data JPA) +- **Persistence**: + - Hibernate 5.6.15 (JPA/ORM) + - iBatis 2.3.4 (legacy SQL mapping) + - QueryDSL 5.0.0 (type-safe queries) +- **Database**: Oracle 12c (primary), with support for MariaDB/PostgreSQL +- **Logging**: Logback 1.2.10 (with SLF4J) +- **Build**: Gradle 8.x with Java 8 +- **View**: JSP with JSTL +- **Other**: Quartz scheduler, EhCache, Jackson, Lombok, MapStruct + +### Spring Configuration +- Root context: `WebContent/WEB-INF/applicationContext.xml` +- Servlet context: `WebContent/WEB-INF/springapp-servlet.xml` +- Environment-specific configs loaded based on `${eai.systemmode}` system property +- Component scanning enabled with annotation-based configuration + +### Data Access Patterns +The application uses **dual persistence**: +1. **JPA/Hibernate** - For newer entity-based code in `com.eactive.eai.rms.data.entity` +2. **iBatis** - For legacy SQL mappings in `src/main/resources/com/eactive/eai/**/*.xml` + +Repositories use Spring Data JPA conventions, Services use `@Service`, Controllers use `@RestController`/`@Controller`. + +### Key Initialization +- `AppInitializer` - Main application startup bean that sets system properties +- `CustomizingAppInitializer` - Customer-specific initialization +- System properties: `inst.Name`, `eai.tableowner`, `eai.systemmode`, `theme.color` + +## KJB (Kwangju Bank) Specific Configuration + +### Property Management +KJB-specific properties are stored in database table `TSEAIRM24` with group name `'Monitoring'`. Key properties handled by `com.eactive.ext.kjb.common.KjbProperty`: + +**Email Notification (via EAI Batch)** +- `kjb.eai_batch.url` - EAI batch server URL for email sending + - Dev: http://172.31.32.111:10230/BATAppWeb/EaiBatCall + - QA: http://172.31.33.111:10430/BATAppWeb/EaiBatCall + - Prod: http://172.21.1.40:10860/BATAppWeb/EaiBatCall +- `kjb.ums.eai_batch.send_dir` - Email file send directory (default: `/Data/eapim/portal/sendmail/snd`) +- `kjb.ums.eai_batch.backup_dir` - Email backup directory (default: `/Data/eapim/portal/sendmail/bak`) +- `kjb.ums.eai_batch.interface_id` - Interface ID for customer email (e.g., `UAGFF00001UIE`) + +**UMS (SMS/LMS/KakaoTalk) Integration** +- `kjb.ums.host_url` - UMS API endpoint +- `kjb.ums.api_key` - UMS API authentication key +- `kjb.ums.connection_timeout` - Connection timeout in seconds +- `kjb.ums.response_timeout` - Response timeout in seconds + +### Security +- Custom password encoder: `KjbSafedbPasswordEncoder` for SafeDB integration +- Set `-Dkjb_safedb.mode=fake` for local development without SafeDB + +## Database Vendor Support + +The application supports multiple databases via vendor-specific SQL mapping files: +- Oracle: `*-oracle.xml` +- MariaDB: `*-mariadb.xml` +- PostgreSQL: `*-postgresql.xml` + +Database vendor is configured in properties files via `db.vendor` and `hibernate.dialect`. + +## WAR Deployment + +The WAR file is built as `eapim-admin.war` with context path `/monitoring`. + +**Weblogic Deployment**: Use `-Pprofile=weblogic` to include `weblogic-web.xml` configuration. + +## Important Notes + +- **Encoding**: System uses UTF-8. CharacterEncodingFilter applies UTF-8 to all requests except `*.excel` patterns. +- **XSS Protection**: CrossScriptingFilter applied to all requests via `com.eactive.eai.rms.common.filter.CrossScriptingFilter` +- **Real-time Updates**: All management changes are reflected immediately in both DB and memory +- **Instance Name**: Each deployment must have unique `inst.Name` for clustering +- **Table Owner**: Oracle schema owner specified via `eai.tableowner` property diff --git a/src/main/java/com/eactive/eai/custom/CustomizingAppInitializer.java b/src/main/java/com/eactive/eai/custom/CustomizingAppInitializer.java index 8f60bb0..88d14d5 100644 --- a/src/main/java/com/eactive/eai/custom/CustomizingAppInitializer.java +++ b/src/main/java/com/eactive/eai/custom/CustomizingAppInitializer.java @@ -3,6 +3,8 @@ package com.eactive.eai.custom; import org.apache.log4j.Logger; import org.springframework.beans.factory.InitializingBean; +import com.eactive.eai.rms.data.PortalSchemaProviderHolder; +import com.eactive.eai.rms.env.EmsConfig; import com.eactive.eai.transformer.message.ISO8583MessageFactory; /** @@ -36,5 +38,8 @@ public class CustomizingAppInitializer implements InitializingBean { logger.info(String.format("ISO8583MessageFactory registered - %s = %s", MESSAGE_TYPE_SVL, ISO8583_SVL_CLASS_NAME)); logger.info(String.format("ISO8583MessageFactory registered - %s = %s", LAYOUT_TYPE_H2H, ISO8583_H2H_CLASS_NAME)); logger.info(String.format("ISO8583MessageFactory registered - %s = %s", LAYOUT_TYPE_SVL, ISO8583_SVL_CLASS_NAME)); + + // PortalSchemaProviderHolder 초기화 (eai.tableowner 주입) + PortalSchemaProviderHolder.setProvider(() -> System.getProperty(EmsConfig.TABLE_OWNER)); } } diff --git a/src/main/java/com/eactive/eai/rms/common/spring/CustomBeanFactoryPostProcessor.java b/src/main/java/com/eactive/eai/rms/common/spring/CustomBeanFactoryPostProcessor.java index ca4a988..738b73d 100644 --- a/src/main/java/com/eactive/eai/rms/common/spring/CustomBeanFactoryPostProcessor.java +++ b/src/main/java/com/eactive/eai/rms/common/spring/CustomBeanFactoryPostProcessor.java @@ -12,6 +12,8 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import com.eactive.eai.rms.common.datasource.DataSourceType; import com.eactive.eai.rms.common.datasource.DataSourceTypeManager; +import com.eactive.eai.rms.data.PortalSchemaProviderHolder; +import com.eactive.eai.rms.env.EmsConfig; public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @@ -22,7 +24,13 @@ public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException { - + + // PortalSchemaProviderHolder 초기화 (Hibernate EntityManagerFactory 생성 전에 필요) + PortalSchemaProviderHolder.setProvider(() -> System.getProperty(EmsConfig.TABLE_OWNER)); + if (logger.isDebugEnabled()) { + logger.debug("PortalSchemaProviderHolder initialized with tableOwner: " + System.getProperty(EmsConfig.TABLE_OWNER)); + } + List dataSourceTypes = new ArrayList(); Map maps = factory.getBeansOfType(DataSourceType.class); diff --git a/src/main/java/com/eactive/eai/rms/common/startup/AppInitializer.java b/src/main/java/com/eactive/eai/rms/common/startup/AppInitializer.java index 6c02401..d410e5b 100644 --- a/src/main/java/com/eactive/eai/rms/common/startup/AppInitializer.java +++ b/src/main/java/com/eactive/eai/rms/common/startup/AppInitializer.java @@ -1,8 +1,5 @@ package com.eactive.eai.rms.common.startup; -import java.lang.reflect.Field; -import java.nio.charset.Charset; - import org.apache.log4j.Logger; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; @@ -11,115 +8,117 @@ import com.eactive.eai.rms.common.util.CommonConstants; import com.eactive.eai.rms.env.EmsConfig; import com.eactive.eai.rms.onl.common.service.AdapterStatusSendThreadPool; -public class AppInitializer implements InitializingBean, DisposableBean { - +public class AppInitializer implements InitializingBean, DisposableBean { + final Logger logger = Logger.getLogger(AppInitializer.class); - + boolean debug = true; - + private String instName; - + private String tableOwner; - private String systemMode = "D"; //EAI System Mode : [P/T/D/S] - - private String themeColor = "black"; - - private String drMode = ""; - - private String eaiDatasourceType = "DEV"; // 데이터 소스 타입 :[DEV:개발/STG:스테이징/PRD:운영] ...NSG:내부서버 - - public void setInstName(String instName) { - this.instName = instName; - } - - public void setTableOwner(String tableOwner) { - this.tableOwner = tableOwner; - } - - public void setSystemMode(String systemMode) { - this.systemMode = systemMode; - } - - public void setThemeColor(String themeColor) { - this.themeColor = themeColor; - } - - public void setDrMode(String drMode) { - this.drMode = drMode; - } - public void setEaiDatasourceType(String eaiDatasourceType) { - this.eaiDatasourceType = eaiDatasourceType; - } - - private void init() - { - if (debug) { - logger.debug("applicationInitialized"); - } - //MS949로 default encoding 고정 -// System.setProperty("file.encoding","MS949"); -// Field charset = null; -// try { -// charset = Charset.class.getDeclaredField("defaultCharset"); -// charset.setAccessible(true); -// charset.set(null, null); -// } catch (Exception e) { -// e.printStackTrace(); -// } - - // set default value - String serverName = System.getProperty(EmsConfig.INST_NAME); - if(serverName == null) { - System.setProperty(EmsConfig.INST_NAME, instName); - } - - String tOwner = System.getProperty(EmsConfig.TABLE_OWNER); - if(tOwner == null) { - System.setProperty(EmsConfig.TABLE_OWNER, tableOwner); - } - - // 서버 구분 설정(개발:D, 테스트:T, 온라인:P) - CommonConstants.SERVER_TYPE = systemMode; - - //모니터링 테마 적용 - String tColor = System.getProperty(EmsConfig.THEME_COLOR); - if(tColor == null || "".equals(tColor)) { - System.setProperty(EmsConfig.THEME_COLOR, themeColor); - } - - if (debug) { - logger.debug(EmsConfig.DR_MODE + " = " + drMode); - } - //env 프라퍼티 파일만 있음 dr 여부 셋팅 - System.setProperty(EmsConfig.DR_MODE, drMode); + private String systemMode = "D"; // EAI System Mode : [P/T/D/S] - //데이터 소스타입(DEV:개발 / STG:스테이징 / PRD:운영 ... ) - String eDatasourceType = System.getProperty(EmsConfig.DATASOURCE_TYPE); - if(eDatasourceType == null || "".equals(eDatasourceType)) { - System.setProperty(EmsConfig.DATASOURCE_TYPE, eaiDatasourceType); - } - - if (debug) { - logger.debug(EmsConfig.DATASOURCE_TYPE + " =" + eaiDatasourceType); //env 프라퍼티 - } - - if(debug) { - logger.debug("SERVER_TYPE ="+CommonConstants.SERVER_TYPE); - } - } - - public void destroy() - { - AdapterStatusSendThreadPool.destroy(); - if(debug) { - logger.debug("############ e-link WebApplication stopping... preStop ############"); - } - } + private String themeColor = "black"; + + private String drMode = ""; + + private String eaiDatasourceType = "DEV"; // 데이터 소스 타입 :[DEV:개발/STG:스테이징/PRD:운영] ...NSG:내부서버 + + public void setInstName(String instName) { + this.instName = instName; + } + + public void setTableOwner(String tableOwner) { + this.tableOwner = tableOwner; + } + + public void setSystemMode(String systemMode) { + this.systemMode = systemMode; + } + + public void setThemeColor(String themeColor) { + this.themeColor = themeColor; + } + + public void setDrMode(String drMode) { + this.drMode = drMode; + } + + public void setEaiDatasourceType(String eaiDatasourceType) { + this.eaiDatasourceType = eaiDatasourceType; + } + + private void init() { + if (debug) { + logger.debug("applicationInitialized"); + } + // MS949로 default encoding 고정 + // System.setProperty("file.encoding","MS949"); + // Field charset = null; + // try { + // charset = Charset.class.getDeclaredField("defaultCharset"); + // charset.setAccessible(true); + // charset.set(null, null); + // } catch (Exception e) { + // e.printStackTrace(); + // } + + // set default value + String serverName = System.getProperty(EmsConfig.INST_NAME); + if (serverName == null) { + System.setProperty(EmsConfig.INST_NAME, instName); + } + + String tOwner = System.getProperty(EmsConfig.TABLE_OWNER); + if (tOwner == null) { + System.setProperty(EmsConfig.TABLE_OWNER, tableOwner); + } + + // 서버 구분 설정(개발:D, 테스트:T, 온라인:P) + CommonConstants.SERVER_TYPE = systemMode; + + // 모니터링 테마 적용 + String tColor = System.getProperty(EmsConfig.THEME_COLOR); + if (tColor == null || "".equals(tColor)) { + System.setProperty(EmsConfig.THEME_COLOR, themeColor); + } + + if (debug) { + logger.debug(EmsConfig.DR_MODE + " = " + drMode); + } + // env 프라퍼티 파일만 있음 dr 여부 셋팅 + System.setProperty(EmsConfig.DR_MODE, drMode); + + // 데이터 소스타입(DEV:개발 / STG:스테이징 / PRD:운영 ... ) + String eDatasourceType = System.getProperty(EmsConfig.DATASOURCE_TYPE); + if (eDatasourceType == null || "".equals(eDatasourceType)) { + System.setProperty(EmsConfig.DATASOURCE_TYPE, eaiDatasourceType); + } + + if (debug) { + logger.debug(EmsConfig.DATASOURCE_TYPE + " =" + eaiDatasourceType); // env 프라퍼티 + } + + if (debug) { + logger.debug("SERVER_TYPE =" + CommonConstants.SERVER_TYPE); + } + + if (debug) { + logger.debug("PortalSchemaProviderHolder initialized with tableOwner: " + tableOwner); + } + } + + public void destroy() { + AdapterStatusSendThreadPool.destroy(); + if (debug) { + logger.debug("############ e-link WebApplication stopping... preStop ############"); + } + } @Override public void afterPropertiesSet() throws Exception { - init(); + init(); } -} - +} diff --git a/src/main/java/com/eactive/eai/rms/data/entity/man/user/UserAthrRoleChgHistory.java b/src/main/java/com/eactive/eai/rms/data/entity/man/user/UserAthrRoleChgHistory.java index e1e7590..910801e 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/man/user/UserAthrRoleChgHistory.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/man/user/UserAthrRoleChgHistory.java @@ -11,6 +11,7 @@ import javax.persistence.Id; import javax.persistence.Table; import org.hibernate.annotations.Comment; +import org.hibernate.annotations.GenericGenerator; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; @@ -30,7 +31,20 @@ public class UserAthrRoleChgHistory extends AbstractEntity implements Se private static final long serialVersionUID = 1L; @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) +// @GeneratedValue(strategy = GenerationType.IDENTITY) + @GenericGenerator( + name = "TB_APIMS_USER_ATHR_ROLE_CHG_H_GEN", + strategy = "com.eactive.eai.rms.data.jpa.SchemaPrefixedSequenceGenerator", + parameters = { + @org.hibernate.annotations.Parameter(name = "sequence_name", value = "TB_APIMS_USER_ATHR_ROLE_CHG_H_SEQ"), + @org.hibernate.annotations.Parameter(name = "initial_value", value = "1"), + @org.hibernate.annotations.Parameter(name = "increment_size", value = "1") + } + ) + @GeneratedValue( + strategy = GenerationType.SEQUENCE, + generator = "TB_APIMS_USER_ATHR_ROLE_CHG_H_GEN" + ) @Column(name = "CHG_LOG_ID", unique = true, nullable = false) @Comment("사용자 정보 변경 로그 식별 ID") private int chgLogId; diff --git a/src/main/java/com/eactive/eai/rms/data/entity/man/user/UserLoginHistory.java b/src/main/java/com/eactive/eai/rms/data/entity/man/user/UserLoginHistory.java index dff77ca..44db541 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/man/user/UserLoginHistory.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/man/user/UserLoginHistory.java @@ -11,6 +11,7 @@ import javax.persistence.Id; import javax.persistence.Table; import org.hibernate.annotations.Comment; +import org.hibernate.annotations.GenericGenerator; import org.springframework.data.annotation.CreatedDate; import com.eactive.eai.data.entity.AbstractEntity; @@ -30,7 +31,20 @@ public class UserLoginHistory extends AbstractEntity implements Serializ private static final long serialVersionUID = 1L; @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) +// @GeneratedValue(strategy = GenerationType.IDENTITY) + @GenericGenerator( + name = "TB_APIMS_LOIN_L_GEN", + strategy = "com.eactive.eai.rms.data.jpa.SchemaPrefixedSequenceGenerator", + parameters = { + @org.hibernate.annotations.Parameter(name = "sequence_name", value = "TB_APIMS_LOIN_L_GEN_SEQ"), + @org.hibernate.annotations.Parameter(name = "initial_value", value = "1"), + @org.hibernate.annotations.Parameter(name = "increment_size", value = "1") + } + ) + @GeneratedValue( + strategy = GenerationType.SEQUENCE, + generator = "TB_APIMS_LOIN_L_GEN" + ) @Column(name="LOIN_LOG_ID", unique = true, nullable = false) @Comment("로그인 로그 식별자") private int loginLogId; diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/audit/CustomRevisionEntity.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/audit/CustomRevisionEntity.java index dd2bc9c..85fb19f 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/onl/audit/CustomRevisionEntity.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/audit/CustomRevisionEntity.java @@ -37,5 +37,4 @@ public class CustomRevisionEntity { @Column(name = "USERID") @Comment("변경자ID") private String userId; - } \ No newline at end of file