From 1486df75be827e169f9a9947f4b4da6d692eb78d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=84=B1=EC=98=81?= Date: Thu, 6 Nov 2025 15:26:24 +0900 Subject: [PATCH] =?UTF-8?q?VMIS-interface=20=E2=86=92=20VIPS=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=20=EC=9E=91=EC=97=85=20=EB=B6=84=EC=84=9D,=20?= =?UTF-8?q?=EA=B3=84=ED=9A=8D=20=EB=AC=B8=EC=84=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VMIS_INTERFACE_INTEGRATION_ANALYSIS.md | 753 ++++++++++++++++ VMIS_INTERFACE_MIGRATION_PLAN.md | 1150 ++++++++++++++++++++++++ 2 files changed, 1903 insertions(+) create mode 100644 VMIS_INTERFACE_INTEGRATION_ANALYSIS.md create mode 100644 VMIS_INTERFACE_MIGRATION_PLAN.md diff --git a/VMIS_INTERFACE_INTEGRATION_ANALYSIS.md b/VMIS_INTERFACE_INTEGRATION_ANALYSIS.md new file mode 100644 index 0000000..fe0bded --- /dev/null +++ b/VMIS_INTERFACE_INTEGRATION_ANALYSIS.md @@ -0,0 +1,753 @@ +# VMIS-interface → VIPS 통합 프로젝트 분석 문서 + +**작성일**: 2025-11-06 +**작업 방식**: 방법 2 - 직접 통합 (Spring Boot 2.7 다운그레이드) + +--- + +## 목차 + +1. [프로젝트 개요](#1-프로젝트-개요) +2. [VIPS 프로젝트 구조](#2-vips-프로젝트-구조) +3. [VMIS-interface 프로젝트 구조](#3-vmis-interface-프로젝트-구조) +4. [기술 스택 비교](#4-기술-스택-비교) +5. [통합 방식 선택 이유](#5-통합-방식-선택-이유) +6. [주요 차이점 및 해결 방안](#6-주요-차이점-및-해결-방안) + +--- + +## 1. 프로젝트 개요 + +### VIPS (차량 점검 페널티 시스템) +- **위치**: D:\workspace\git\VIPS +- **목적**: 자동차 점검 페널티 관리 업무 시스템 +- **형태**: 단일 모듈 Spring Boot 웹 애플리케이션 + +### VMIS-interface (차량 정보 조회 API) +- **위치**: D:\workspace\git\VMIS-interface +- **목적**: 도로교통공단 Open API 연동하여 차량 정보 조회 +- **형태**: REST API 서버 + +### 통합 목표 +VMIS-interface의 모든 설정, 로직, 데이터베이스를 VIPS 내부로 이식하여 외부 API 호출 없이 내부 모듈로 작동 + +--- + +## 2. VIPS 프로젝트 구조 + +### 2.1 기본 정보 +``` +프로젝트명: VIPS +Spring Boot: 2.7.18 +Java: 1.8 +빌드: Gradle +패키징: WAR +데이터베이스: MariaDB +ORM: MyBatis +``` + +### 2.2 디렉토리 구조 +``` +D:\workspace\git\VIPS\ +├── src/main/java/ +│ ├── egovframework/ (전자정부 프레임워크) +│ │ ├── config/ (설정 클래스) +│ │ │ ├── RestTemplateConfig.java +│ │ │ ├── DataSourceProxyConfig.java +│ │ │ ├── EgovConfigCommon.java +│ │ │ ├── EgovConfigWeb.java +│ │ │ ├── SqlLoggingInterceptor.java +│ │ │ └── SwaggerConfig.java +│ │ ├── configProperties/ +│ │ │ └── RestTemplateProperties.java +│ │ ├── filter/ +│ │ │ └── XssFilterConfig.java +│ │ └── util/ +│ │ ├── ApiResponseEntity.java +│ │ └── ApiResponseUtil.java +│ │ +│ └── go/kr/project/ +│ ├── externalApi/ (외부 API 통합 모듈) ★ +│ │ ├── service/ +│ │ │ └── ExternalVehicleApiService.java +│ │ └── vo/ +│ │ ├── Envelope.java +│ │ ├── VehicleApiResponseVO.java +│ │ ├── VehicleBasicInfoVO.java +│ │ ├── VehicleBasicRequestVO.java +│ │ ├── VehicleLedgerRequestVO.java +│ │ └── VehicleLedgerVO.java +│ ├── carInspectionPenalty/ +│ ├── common/ +│ ├── login/ +│ ├── main/ +│ ├── mypage/ +│ └── system/ +│ +├── src/main/resources/ +│ ├── application.yml +│ ├── application-local.yml +│ ├── application-dev.yml +│ ├── application-prd.yml +│ ├── logback-spring.xml +│ └── mybatis/ +│ ├── mybatis-config.xml +│ └── mapper/ +│ +└── build.gradle +``` + +### 2.3 주요 설정 (application.yml) +```yaml +server: + port: 8080 + +mybatis: + config-location: classpath:mybatis/mybatis-config.xml + mapper-locations: classpath:mybatis/mapper/**/*_${Globals.DbType}.xml + +rest-template: + timeout: + connect-timeout-millis: 10000 + read-timeout-millis: 12000 + connection-pool: + max-total: 100 + max-per-route: 20 + rate-limit: + permits-per-second: 5.0 +``` + +### 2.4 기존 외부 API 통합 구조 + +**ExternalVehicleApiService.java**: +- VMIS-interface를 REST API로 호출 (http://localhost:8081) +- 배치 처리 지원 +- 에러 처리 및 로깅 + +**RestTemplateConfig.java**: +- Apache HttpClient 4 기반 +- 연결 풀 관리 (PoolingHttpClientConnectionManager) +- Rate Limiting (Guava RateLimiter) + +### 2.5 주요 의존성 +```gradle +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web:2.7.18' + implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1' + implementation 'org.mariadb.jdbc:mariadb-java-client' + implementation 'org.apache.httpcomponents:httpclient' + implementation 'com.google.guava:guava:32.1.3-jre' + implementation 'org.egovframe.rte:org.egovframe.rte.fdl.cmmn:4.3.0' + implementation 'org.egovframe.rte:org.egovframe.rte.ptl.mvc:4.3.0' +} +``` + +--- + +## 3. VMIS-interface 프로젝트 구조 + +### 3.1 기본 정보 +``` +프로젝트명: VMIS-interface +Spring Boot: 3.3.4 +Java: 17 +빌드: Gradle +패키징: JAR +데이터베이스: MariaDB +ORM: MyBatis +``` + +### 3.2 디렉토리 구조 +``` +D:\workspace\git\VMIS-interface\ +├── src/main/java/com/vmis/interfaceapp/ +│ ├── InterfaceApplication.java (메인 클래스) +│ │ +│ ├── config/ (설정 계층) +│ │ ├── MyBatisConfig.java +│ │ ├── OpenApiConfig.java +│ │ └── VmisProperties.java (핵심 설정) +│ │ +│ ├── controller/ (API 진입점) +│ │ └── VehicleInterfaceController.java +│ │ +│ ├── service/ (비즈니스 로직) +│ │ ├── CarBassMatterInqireService.java (기본사항 조회) +│ │ ├── CarLedgerFrmbkService.java (등록원부 조회) +│ │ ├── CarBassMatterInqireLogService.java (로그) +│ │ └── CarLedgerFrmbkLogService.java (로그) +│ │ +│ ├── client/ (외부 API 호출) +│ │ └── GovernmentApiClient.java (도로교통공단 API) +│ │ +│ ├── enricher/ (데이터 보강) +│ │ └── RequestEnricher.java +│ │ +│ ├── model/ (도메인 모델) +│ │ ├── entity/ (DB 엔티티 - 7개) +│ │ ├── vo/ (VO - 6개) +│ │ └── dto/ (DTO - 2개) +│ │ +│ ├── mapper/ (MyBatis Mapper) +│ │ ├── CarBassMatterInqireLogMapper.java +│ │ └── CarLedgerFrmbkLogMapper.java +│ │ +│ └── util/ (유틸리티) +│ ├── EncryptionUtil.java (GPKI 암호화) +│ └── TransactionIdGenerator.java +│ +├── src/main/resources/ +│ ├── application.yml +│ ├── application-dev.yml +│ ├── application-prd.yml +│ ├── logback-spring.xml +│ └── mybatis/ +│ ├── mybatis-config.xml +│ └── mapper/ +│ ├── CarBassMatterInqireLogMapper.xml +│ └── CarLedgerFrmbkLogMapper.xml +│ +├── lib/ +│ └── libgpkiapi_jni_1.5.jar (GPKI 라이브러리) +│ +├── ddl/vips/ (데이터베이스 스키마) +│ ├── tb_car_bass_matter_inqire.sql +│ ├── seq_car_bass_matter_inqire.sql +│ ├── tb_car_ledger_frmbk.sql +│ ├── seq_car_ledger_frmbk.sql +│ ├── tb_car_ledger_frmbk_dtl.sql +│ └── seq_car_ledger_frmbk_dtl.sql +│ +└── build.gradle +``` + +### 3.3 핵심 파일 목록 (34개 Java 파일) + +#### 설정 (3개) +1. `MyBatisConfig.java` +2. `OpenApiConfig.java` +3. `VmisProperties.java` ⭐ (핵심 설정) + +#### 컨트롤러 (1개) +4. `VehicleInterfaceController.java` + +#### 서비스 (4개) +5. `CarBassMatterInqireService.java` +6. `CarLedgerFrmbkService.java` +7. `CarBassMatterInqireLogService.java` +8. `CarLedgerFrmbkLogService.java` + +#### 클라이언트 (1개) +9. `GovernmentApiClient.java` ⭐ (가장 복잡) + +#### 데이터 보강 (1개) +10. `RequestEnricher.java` + +#### 엔티티 (7개) +11. `CarBassMatterInqire.java` +12. `CarBassMatterInqireLog.java` +13. `CarLedgerFrmbk.java` +14. `CarLedgerFrmbkDtl.java` +15. `CarLedgerFrmbkLog.java` +16. `VehicleBasicInfo.java` +17. `VehicleLedger.java` + +#### VO (6개) +18. `CarBassMatterInqireRequestVO.java` +19. `CarLedgerFrmbkRequestVO.java` +20. `Envelope.java` +21. `GovApiBasicRequest.java` +22. `GovApiBasicResponse.java` +23. `GovApiLedgerRequest.java` +24. `GovApiLedgerResponse.java` + +#### DTO (2개) +25. `VehicleBasicInfoDTO.java` +26. `VehicleLedgerDTO.java` + +#### Mapper (2개) +27. `CarBassMatterInqireLogMapper.java` +28. `CarLedgerFrmbkLogMapper.java` + +#### 유틸리티 (2개) +29. `EncryptionUtil.java` +30. `TransactionIdGenerator.java` + +#### 메인 클래스 (1개) +31. `InterfaceApplication.java` + +**총 31개 핵심 파일 + 3개 추가 클래스** + +### 3.4 VmisProperties 구조 (핵심) + +```java +@ConfigurationProperties(prefix = "vmis") +public class VmisProperties { + private SystemProps system; // 시스템 정보 + private GpkiProps gpki; // GPKI 암호화 설정 + private GovProps government; // 정부 API 설정 + + public static class SystemProps { + private String infoSysId; // 정보시스템 ID + private String infoSysIp; // 시스템 IP + private String managerId; // 담당자 ID + private String managerName; // 담당자명 + private String managerTel; // 담당자 전화번호 + } + + public static class GpkiProps { + private boolean enabled; // 암호화 사용 여부 + private String certPath; // 인증서 경로 + private String privateKeyPath; // 개인키 경로 + private String privateKeyPassword; // 개인키 비밀번호 + } + + public static class GovProps { + private String host; // API 호스트 + private String basePath; // 기본 경로 + private int connectTimeout; // 연결 타임아웃 + private int readTimeout; // 읽기 타임아웃 + private Services services; // 서비스별 설정 + + public static class Services { + private ServiceConfig basic; // 기본사항 API + private ServiceConfig ledger; // 등록원부 API + + public static class ServiceConfig { + private String path; // API 경로 + private String apiKey; // API 키 + } + } + } +} +``` + +### 3.5 application.yml 설정 +```yaml +vmis: + system: + info-sys-id: "VMIS001" + info-sys-ip: "192.168.1.100" + manager-id: "admin" + manager-name: "관리자" + manager-tel: "02-1234-5678" + + gpki: + enabled: false # 개발환경에서는 false + cert-path: "/path/to/cert.der" + private-key-path: "/path/to/private.key" + private-key-password: "${GPKI_PASSWORD}" + + government: + host: "https://www.vemanet.com" + base-path: "/openapi" + connect-timeout: 10000 + read-timeout: 15000 + services: + basic: + path: "/carBassMatterInqire" + api-key: "${GOV_API_KEY_BASIC}" + ledger: + path: "/carLedgerFrmbk" + api-key: "${GOV_API_KEY_LEDGER}" +``` + +### 3.6 API 엔드포인트 + +#### 1. 자동차 기본사항 조회 +``` +POST /api/v1/vehicles/basic +Content-Type: application/json + +Request: +{ + "vhrno": "12가3456" +} + +Response: +{ + "data": [ + { + "vhrno": "12가3456", + "success": true, + "message": "조회 성공", + "basicInfo": { + "vhrno": "12가3456", + "vhcleNm": "소나타", + ... + } + } + ] +} +``` + +#### 2. 자동차 등록원부 조회 +``` +POST /api/v1/vehicles/ledger +Content-Type: application/json + +Request: +{ + "vhrno": "12가3456" +} + +Response: +{ + "data": [ + { + "vhrno": "12가3456", + "success": true, + "message": "조회 성공", + "ledgerInfo": { + "master": {...}, + "details": [...] + } + } + ] +} +``` + +### 3.7 데이터베이스 테이블 (6개) + +1. **tb_car_bass_matter_inqire** (기본사항 로그) + - seq_car_bass_matter_inqire (시퀀스) + +2. **tb_car_ledger_frmbk** (등록원부 마스터) + - seq_car_ledger_frmbk (시퀀스) + +3. **tb_car_ledger_frmbk_dtl** (등록원부 상세) + - seq_car_ledger_frmbk_dtl (시퀀스) + +### 3.8 주요 의존성 +```gradle +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web:3.3.4' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3' + implementation 'org.mariadb.jdbc:mariadb-java-client:3.3.3' + implementation 'org.apache.httpcomponents.client5:httpclient5:5.2.3' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0' + implementation 'org.projectlombok:lombok:1.18.34' + implementation files('lib/libgpkiapi_jni_1.5.jar') +} +``` + +--- + +## 4. 기술 스택 비교 + +| 항목 | VIPS | VMIS-interface | 비고 | +|------|------|----------------|------| +| **Spring Boot** | 2.7.18 | 3.3.4 | 메이저 버전 차이 | +| **Java** | 1.8 | 17 | 9개 버전 차이 | +| **패키지** | javax.* | jakarta.* | 네임스페이스 변경 | +| **HttpClient** | Apache 4 | Apache 5 | API 변경 | +| **MyBatis** | 2.3.1 | 3.0.3 | 호환 가능 | +| **MariaDB** | 기본 | 3.3.3 | 호환 가능 | +| **Swagger** | springdoc 1.7.0 | springdoc 2.6.0 | 버전 차이 | +| **Lombok** | 기본 | 1.18.34 | 호환 가능 | + +### 4.1 주요 호환성 이슈 + +#### Spring Boot 2.x → 3.x 주요 변경사항 +1. **패키지 변경**: `javax.*` → `jakarta.*` +2. **최소 Java 버전**: Java 8 → Java 17 +3. **Spring Security**: 아키텍처 변경 +4. **Configuration Properties**: 일부 속성명 변경 + +#### HttpClient 4 → 5 주요 변경사항 +1. **패키지명**: `org.apache.http.*` → `org.apache.hc.client5.*` +2. **API 재설계**: 빌더 패턴 강화 +3. **클래스명 변경**: `HttpClientBuilder` → `HttpClients` + +--- + +## 5. 통합 방식 선택 이유 + +### 방법 2: 직접 통합 (Spring Boot 2.7 다운그레이드) + +#### 선택 이유 +1. **내부 시스템 자체 완결**: 외부 API 호출 없이 내부 메서드 호출로 처리 +2. **트랜잭션 일관성**: 단일 애플리케이션 내 DB 트랜잭션 관리 +3. **배포 단순화**: 하나의 WAR 파일로 배포 +4. **성능 최적화**: 네트워크 오버헤드 제거 + +#### 트레이드오프 +- Spring Boot 3 → 2 다운그레이드 필요 +- Java 17 → Java 8 호환성 작업 필요 +- 최신 기술 스택 사용 불가 + +--- + +## 6. 주요 차이점 및 해결 방안 + +### 6.1 Spring Boot 버전 차이 + +#### 문제 +- Spring Boot 3.3.4 → 2.7.18 다운그레이드 + +#### 해결 방안 +```gradle +// VMIS-interface build.gradle 수정 +plugins { + id 'org.springframework.boot' version '2.7.18' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' +} + +sourceCompatibility = '1.8' +targetCompatibility = '1.8' +``` + +### 6.2 패키지 네임스페이스 변경 + +#### 문제 +- `jakarta.*` → `javax.*` 전체 변경 필요 + +#### 영향 범위 +``` +jakarta.servlet.* → javax.servlet.* +jakarta.validation.* → javax.validation.* +jakarta.persistence.* → javax.persistence.* +jakarta.annotation.* → javax.annotation.* +``` + +#### 해결 방안 +- 전체 파일에서 `jakarta` → `javax` 일괄 교체 +- IDE의 Find & Replace 기능 활용 + +### 6.3 HttpClient 버전 차이 + +#### 문제 +- Apache HttpClient 5 → 4 다운그레이드 + +#### GovernmentApiClient.java 수정 필요 +```java +// Before (HttpClient 5) +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; + +// After (HttpClient 4) +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +``` + +### 6.4 Java 17 → Java 8 호환성 + +#### 주요 체크 포인트 +1. **Text Blocks**: Java 15+ 기능 사용 시 일반 문자열로 변경 +2. **Records**: Java 14+ 기능 사용 시 일반 클래스로 변경 +3. **Switch Expressions**: Java 14+ 기능 사용 시 전통적 switch로 변경 +4. **var 키워드**: Java 10+ 기능 (사용 가능하나 명시적 타입 권장) + +#### 현재 VMIS-interface 코드 검토 필요 +- 대부분 전통적 Java 문법 사용 예상 +- Lombok 적극 활용 중 (호환 가능) + +### 6.5 MyBatis 설정 차이 + +#### VMIS-interface mybatis-config.xml +```xml + + + + + + + + +``` + +#### VIPS 설정과 통합 +- VIPS의 기존 mybatis-config.xml에 설정 병합 +- mapper 위치 추가: `mybatis/mapper/vmis/**/*_maria.xml` + +### 6.6 패키지 구조 변경 + +#### Before (VMIS-interface) +``` +com.vmis.interfaceapp.* +``` + +#### After (VIPS 통합) +``` +go.kr.project.vmis.* +``` + +#### 변경 계획 +``` +com.vmis.interfaceapp.config → go.kr.project.vmis.config +com.vmis.interfaceapp.controller → go.kr.project.vmis.controller +com.vmis.interfaceapp.service → go.kr.project.vmis.service +com.vmis.interfaceapp.client → go.kr.project.vmis.client +com.vmis.interfaceapp.model → go.kr.project.vmis.model +com.vmis.interfaceapp.mapper → go.kr.project.vmis.mapper +com.vmis.interfaceapp.util → go.kr.project.vmis.util +``` + +### 6.7 설정 파일 통합 + +#### VmisProperties 통합 방안 + +**Option 1**: VIPS의 application.yml에 vmis 섹션 추가 +```yaml +# VIPS application.yml +vmis: + system: + info-sys-id: "VMIS001" + ... + government: + ... +``` + +**Option 2**: application-vmis.yml 별도 파일 생성 +```yaml +# application-vmis.yml +vmis: + ... +``` + +**권장**: Option 1 (단일 설정 파일 유지) + +### 6.8 GPKI 라이브러리 통합 + +#### 파일 위치 +``` +D:\workspace\git\VMIS-interface\lib\libgpkiapi_jni_1.5.jar +↓ +D:\workspace\git\VIPS\lib\libgpkiapi_jni_1.5.jar +``` + +#### build.gradle 수정 +```gradle +dependencies { + implementation files('lib/libgpkiapi_jni_1.5.jar') +} +``` + +--- + +## 7. 마이그레이션 체크리스트 + +### Phase 1: 환경 준비 +- [ ] 현재 브랜치 상태 확인 (이미 생성됨) +- [ ] VIPS 프로젝트 백업 (선택사항) +- [ ] GPKI 라이브러리 복사 + +### Phase 2: 코드 이식 +- [ ] VmisProperties 이식 및 패키지 변경 +- [ ] 설정 클래스 이식 (MyBatisConfig, OpenApiConfig) +- [ ] GovernmentApiClient 이식 (HttpClient 4 변경) +- [ ] 모델 클래스 이식 (entity, vo, dto) +- [ ] 서비스 클래스 이식 +- [ ] 컨트롤러 이식 +- [ ] Mapper 인터페이스 및 XML 이식 +- [ ] 유틸리티 클래스 이식 + +### Phase 3: 설정 통합 +- [ ] application.yml 설정 통합 +- [ ] mybatis-config.xml 설정 병합 +- [ ] logback-spring.xml 로그 설정 추가 +- [ ] build.gradle 의존성 추가 + +### Phase 4: 패키지 변경 +- [ ] jakarta → javax 일괄 변경 +- [ ] com.vmis.interfaceapp → go.kr.project.vmis 변경 +- [ ] import 문 정리 + +### Phase 5: 데이터베이스 +- [ ] 데이터베이스 연결 테스트 (테이블은 이미 존재) + +### Phase 6: 빌드 및 테스트 +- [ ] Gradle 빌드 성공 확인 +- [ ] 애플리케이션 구동 확인 +- [ ] API 엔드포인트 테스트 +- [ ] 정부 API 연동 테스트 +- [ ] 로그 저장 확인 + +### Phase 7: 기존 코드 정리 +- [ ] ExternalVehicleApiService 코드 리팩토링 +- [ ] 불필요한 REST 호출 로직 제거 +- [ ] 내부 메서드 호출로 변경 + +### Phase 8: 문서화 및 배포 +- [ ] API 문서 업데이트 +- [ ] 운영 가이드 작성 +- [ ] 코드 리뷰 +- [ ] main 브랜치 머지 + +--- + +## 8. 주요 파일 절대 경로 + +### VIPS +``` +D:\workspace\git\VIPS\src\main\java\egovframework\config\RestTemplateConfig.java +D:\workspace\git\VIPS\src\main\java\go\kr\project\externalApi\service\ExternalVehicleApiService.java +D:\workspace\git\VIPS\src\main\resources\application.yml +D:\workspace\git\VIPS\build.gradle +``` + +### VMIS-interface +``` +D:\workspace\git\VMIS-interface\src\main\java\com\vmis\interfaceapp\config\VmisProperties.java +D:\workspace\git\VMIS-interface\src\main\java\com\vmis\interfaceapp\client\GovernmentApiClient.java +D:\workspace\git\VMIS-interface\src\main\resources\application.yml +D:\workspace\git\VMIS-interface\lib\libgpkiapi_jni_1.5.jar +D:\workspace\git\VMIS-interface\ddl\vips\*.sql +``` + +--- + +## 9. 위험 요소 및 대응 방안 + +### 9.1 Spring Boot 다운그레이드 실패 +**위험**: 일부 Spring Boot 3 전용 기능 사용 시 빌드 실패 +**대응**: 코드 리뷰 후 대체 코드 작성 + +### 9.2 GPKI 암호화 라이브러리 호환성 +**위험**: GPKI JNI 라이브러리가 특정 Java 버전에서만 작동 +**대응**: 개발환경(gpki.enabled=false)에서 먼저 테스트 + +### 9.3 HttpClient 버전 차이 +**위험**: API 차이로 인한 런타임 에러 +**대응**: GovernmentApiClient 전면 재작성 고려 + +### 9.4 데이터베이스 트랜잭션 +**위험**: 기존 VIPS와 새로운 VMIS 로직의 트랜잭션 충돌 +**대응**: @Transactional 범위 명확히 설정 + +--- + +## 10. 예상 작업 시간 + +| 단계 | 예상 시간 | 비고 | +|------|----------|------| +| Phase 1: 환경 준비 | 20분 | 디렉토리 생성, 라이브러리 복사 | +| Phase 2: 코드 이식 | 3시간 | 34개 파일 이식 | +| Phase 3: 설정 통합 | 1시간 | YAML, XML 병합 | +| Phase 4: 패키지 변경 | 1시간 | 일괄 변경 | +| Phase 5: 데이터베이스 | 10분 | 연결 테스트 (테이블 기존재) | +| Phase 6: 빌드/테스트 | 2시간 | 디버깅 포함 | +| Phase 7: 기존 코드 정리 | 1시간 | 리팩토링 | +| Phase 8: 문서화 | 1시간 | 문서 작성 | +| **총 예상 시간** | **9시간 20분** | 순수 작업 시간 | + +--- + +## 11. 다음 단계 + +상세한 마이그레이션 계획은 `VMIS_INTERFACE_MIGRATION_PLAN.md` 파일을 참조하세요. + +**작업 진행 방법**: +브랜치는 이미 생성되어 있으므로, `VMIS_INTERFACE_MIGRATION_PLAN.md`의 Phase 1부터 시작하세요. + +```bash +cd D:\workspace\git\VIPS +git status # 현재 브랜치 확인 +``` + +--- + +**문서 버전**: 1.1 +**최종 수정**: 2025-11-06 diff --git a/VMIS_INTERFACE_MIGRATION_PLAN.md b/VMIS_INTERFACE_MIGRATION_PLAN.md new file mode 100644 index 0000000..d422fee --- /dev/null +++ b/VMIS_INTERFACE_MIGRATION_PLAN.md @@ -0,0 +1,1150 @@ +# VMIS-interface → VIPS 통합 마이그레이션 실행 계획 + +**작성일**: 2025-11-06 +**방법**: 직접 통합 (Spring Boot 2.7 다운그레이드) +**예상 소요 시간**: 10시간 + +--- + +## 목차 + +1. [사전 준비](#phase-1-사전-준비) +2. [패키지 구조 설계](#phase-2-패키지-구조-설계) +3. [코드 이식 순서](#phase-3-코드-이식-순서) +4. [단계별 상세 가이드](#phase-4-단계별-상세-가이드) +5. [빌드 및 테스트](#phase-5-빌드-및-테스트) +6. [트러블슈팅](#phase-6-트러블슈팅) + +--- + +## Phase 1: 사전 준비 + +**참고**: 브랜치는 이미 생성되어 진행 중입니다. + +### 1.1 현재 상태 확인 +```bash +cd D:\workspace\git\VIPS + +# 현재 브랜치 및 상태 확인 +git status +git branch +``` + +### 1.2 디렉토리 구조 준비 +```bash +# VIPS 프로젝트에 새 패키지 생성 (Windows PowerShell) +New-Item -ItemType Directory -Force -Path "src\main\java\go\kr\project\vmis" +New-Item -ItemType Directory -Force -Path "src\main\java\go\kr\project\vmis\config" +New-Item -ItemType Directory -Force -Path "src\main\java\go\kr\project\vmis\controller" +New-Item -ItemType Directory -Force -Path "src\main\java\go\kr\project\vmis\service" +New-Item -ItemType Directory -Force -Path "src\main\java\go\kr\project\vmis\client" +New-Item -ItemType Directory -Force -Path "src\main\java\go\kr\project\vmis\model\entity" +New-Item -ItemType Directory -Force -Path "src\main\java\go\kr\project\vmis\model\vo" +New-Item -ItemType Directory -Force -Path "src\main\java\go\kr\project\vmis\model\dto" +New-Item -ItemType Directory -Force -Path "src\main\java\go\kr\project\vmis\mapper" +New-Item -ItemType Directory -Force -Path "src\main\java\go\kr\project\vmis\util" +New-Item -ItemType Directory -Force -Path "src\main\java\go\kr\project\vmis\enricher" + +# MyBatis 매퍼 디렉토리 +New-Item -ItemType Directory -Force -Path "src\main\resources\mybatis\mapper\vmis" + +# GPKI 라이브러리 디렉토리 (이미 존재하면 스킵) +New-Item -ItemType Directory -Force -Path "lib" +``` + +### 1.3 GPKI 라이브러리 복사 +```bash +# Windows CMD +copy "D:\workspace\git\VMIS-interface\lib\libgpkiapi_jni_1.5.jar" "D:\workspace\git\VIPS\lib\" +``` + +--- + +## Phase 2: 패키지 구조 설계 + +### 2.1 최종 패키지 구조 +``` +go.kr.project.vmis/ +├── config/ (설정) +│ ├── VmisProperties.java (설정 속성) +│ ├── MyBatisConfig.java (MyBatis 설정) +│ └── OpenApiConfig.java (Open API 설정) +│ +├── controller/ (컨트롤러) +│ └── VehicleInterfaceController.java +│ +├── service/ (서비스) +│ ├── CarBassMatterInqireService.java +│ ├── CarLedgerFrmbkService.java +│ ├── CarBassMatterInqireLogService.java +│ └── CarLedgerFrmbkLogService.java +│ +├── client/ (외부 API 클라이언트) +│ └── GovernmentApiClient.java +│ +├── enricher/ (데이터 보강) +│ └── RequestEnricher.java +│ +├── model/ (모델) +│ ├── entity/ (DB 엔티티) +│ │ ├── CarBassMatterInqire.java +│ │ ├── CarBassMatterInqireLog.java +│ │ ├── CarLedgerFrmbk.java +│ │ ├── CarLedgerFrmbkDtl.java +│ │ ├── CarLedgerFrmbkLog.java +│ │ ├── VehicleBasicInfo.java +│ │ └── VehicleLedger.java +│ ├── vo/ (VO) +│ │ ├── CarBassMatterInqireRequestVO.java +│ │ ├── CarLedgerFrmbkRequestVO.java +│ │ ├── Envelope.java +│ │ ├── GovApiBasicRequest.java +│ │ ├── GovApiBasicResponse.java +│ │ ├── GovApiLedgerRequest.java +│ │ └── GovApiLedgerResponse.java +│ └── dto/ (DTO) +│ ├── VehicleBasicInfoDTO.java +│ └── VehicleLedgerDTO.java +│ +├── mapper/ (MyBatis Mapper) +│ ├── CarBassMatterInqireLogMapper.java +│ └── CarLedgerFrmbkLogMapper.java +│ +└── util/ (유틸리티) + ├── EncryptionUtil.java + └── TransactionIdGenerator.java +``` + +--- + +## Phase 3: 코드 이식 순서 + +### 3.1 이식 우선순위 (의존성 순서) + +``` +1. util (의존성 없음) + └── TransactionIdGenerator.java + └── EncryptionUtil.java + +2. model (util에만 의존) + └── entity/ (7개) + └── vo/ (7개) + └── dto/ (2개) + +3. config (model에 의존) + └── VmisProperties.java (가장 먼저) + └── MyBatisConfig.java + └── OpenApiConfig.java + +4. mapper (model에 의존) + └── CarBassMatterInqireLogMapper.java + └── CarLedgerFrmbkLogMapper.java + +5. enricher (config, util에 의존) + └── RequestEnricher.java + +6. client (config, model, util, enricher에 의존) + └── GovernmentApiClient.java + +7. service (모든 계층에 의존) + └── CarBassMatterInqireLogService.java + └── CarLedgerFrmbkLogService.java + └── CarBassMatterInqireService.java + └── CarLedgerFrmbkService.java + +8. controller (service에 의존) + └── VehicleInterfaceController.java +``` + +--- + +## Phase 4: 단계별 상세 가이드 + +### Step 1: build.gradle 의존성 추가 + +**파일**: `D:\workspace\git\VIPS\build.gradle` + +```gradle +dependencies { + // 기존 의존성... + + // VMIS-interface 관련 추가 의존성 + implementation 'org.apache.httpcomponents:httpclient:4.5.14' // Apache HttpClient 4 + implementation 'com.fasterxml.jackson.core:jackson-databind' // JSON 처리 (이미 있을 가능성 높음) + + // GPKI 라이브러리 + implementation files('lib/libgpkiapi_jni_1.5.jar') +} +``` + +**주의**: +- Spring Boot 2.7.18에는 기본적으로 HttpClient 4가 포함되어 있으므로 충돌 확인 필요 +- Jackson은 Spring Boot Starter에 포함되어 있음 + +### Step 2: VmisProperties 이식 및 수정 + +**소스**: `D:\workspace\git\VMIS-interface\src\main\java\com\vmis\interfaceapp\config\VmisProperties.java` +**대상**: `D:\workspace\git\VIPS\src\main\java\go\kr\project\vmis\config\VmisProperties.java` + +**변경 사항**: +```java +// Before +package com.vmis.interfaceapp.config; + +// After +package go.kr.project.vmis.config; +``` + +**전체 코드 예시**: +```java +package go.kr.project.vmis.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@Component +@ConfigurationProperties(prefix = "vmis") +public class VmisProperties { + + private SystemProps system = new SystemProps(); + private GpkiProps gpki = new GpkiProps(); + private GovProps government = new GovProps(); + + @Getter + @Setter + public static class SystemProps { + private String infoSysId; + private String infoSysIp; + private String managerId; + private String managerName; + private String managerTel; + } + + @Getter + @Setter + public static class GpkiProps { + private boolean enabled; + private String certPath; + private String privateKeyPath; + private String privateKeyPassword; + } + + @Getter + @Setter + public static class GovProps { + private String host; + private String basePath; + private int connectTimeout; + private int readTimeout; + private Services services = new Services(); + + @Getter + @Setter + public static class Services { + private ServiceConfig basic = new ServiceConfig(); + private ServiceConfig ledger = new ServiceConfig(); + + @Getter + @Setter + public static class ServiceConfig { + private String path; + private String apiKey; + } + } + } +} +``` + +### Step 3: application.yml 설정 통합 + +**파일**: `D:\workspace\git\VIPS\src\main\resources\application.yml` + +**추가할 내용**: +```yaml +# VMIS 정부 API 연동 설정 +vmis: + system: + info-sys-id: "VMIS001" + info-sys-ip: "${SERVER_IP:192.168.1.100}" + manager-id: "admin" + manager-name: "관리자" + manager-tel: "02-1234-5678" + + gpki: + enabled: false # 개발환경에서는 false, 운영환경에서는 true + cert-path: "${GPKI_CERT_PATH:/path/to/cert.der}" + private-key-path: "${GPKI_PRIVATE_KEY_PATH:/path/to/private.key}" + private-key-password: "${GPKI_PASSWORD:}" + + government: + host: "https://www.vemanet.com" + base-path: "/openapi" + connect-timeout: 10000 + read-timeout: 15000 + services: + basic: + path: "/carBassMatterInqire" + api-key: "${GOV_API_KEY_BASIC:your-api-key-basic}" + ledger: + path: "/carLedgerFrmbk" + api-key: "${GOV_API_KEY_LEDGER:your-api-key-ledger}" + +# MyBatis 설정 업데이트 (기존 설정에 추가) +mybatis: + mapper-locations: + - classpath:mybatis/mapper/**/*_${Globals.DbType}.xml + - classpath:mybatis/mapper/vmis/**/*_maria.xml # VMIS 매퍼 추가 +``` + +**환경별 설정 (application-local.yml, application-dev.yml, application-prd.yml)**: +```yaml +# application-prd.yml (운영환경) +vmis: + gpki: + enabled: true # 운영환경에서는 암호화 활성화 +``` + +### Step 4: 유틸리티 클래스 이식 + +#### 4.1 TransactionIdGenerator.java + +**소스**: `D:\workspace\git\VMIS-interface\src\main\java\com\vmis\interfaceapp\util\TransactionIdGenerator.java` +**대상**: `D:\workspace\git\VIPS\src\main\java\go\kr\project\vmis\util\TransactionIdGenerator.java` + +**변경 사항**: +```java +// Before +package com.vmis.interfaceapp.util; + +// After +package go.kr.project.vmis.util; + +// import 문 변경 없음 (Java 표준 라이브러리만 사용) +``` + +#### 4.2 EncryptionUtil.java + +**소스**: `D:\workspace\git\VMIS-interface\src\main\java\com\vmis\interfaceapp\util\EncryptionUtil.java` +**대상**: `D:\workspace\git\VIPS\src\main\java\go\kr\project\vmis\util\EncryptionUtil.java` + +**주요 변경 사항**: +```java +// Before +package com.vmis.interfaceapp.util; + +import com.vmis.interfaceapp.config.VmisProperties; + +// After +package go.kr.project.vmis.util; + +import go.kr.project.vmis.config.VmisProperties; +``` + +### Step 5: 모델 클래스 이식 + +#### 5.1 Entity 클래스 (7개) + +**패키지 변경**: +```java +// Before +package com.vmis.interfaceapp.model.entity; + +// After +package go.kr.project.vmis.model.entity; +``` + +**파일 목록**: +1. CarBassMatterInqire.java +2. CarBassMatterInqireLog.java +3. CarLedgerFrmbk.java +4. CarLedgerFrmbkDtl.java +5. CarLedgerFrmbkLog.java +6. VehicleBasicInfo.java +7. VehicleLedger.java + +**주의사항**: +- Lombok 어노테이션 유지 (`@Getter`, `@Setter`, `@Builder` 등) +- `java.time.*` 클래스 사용 가능 (Java 8+) +- `jakarta.validation.*` → `javax.validation.*` 변경 + +#### 5.2 VO 클래스 (7개) + +**변경 예시**: +```java +// Before +package com.vmis.interfaceapp.model.vo; + +import jakarta.validation.constraints.NotBlank; + +// After +package go.kr.project.vmis.model.vo; + +import javax.validation.constraints.NotBlank; +``` + +**파일 목록**: +1. CarBassMatterInqireRequestVO.java +2. CarLedgerFrmbkRequestVO.java +3. Envelope.java +4. GovApiBasicRequest.java +5. GovApiBasicResponse.java +6. GovApiLedgerRequest.java +7. GovApiLedgerResponse.java + +#### 5.3 DTO 클래스 (2개) + +**패키지 변경**: +```java +// Before +package com.vmis.interfaceapp.model.dto; + +// After +package go.kr.project.vmis.model.dto; +``` + +**파일 목록**: +1. VehicleBasicInfoDTO.java +2. VehicleLedgerDTO.java + +### Step 6: Config 클래스 이식 + +#### 6.1 MyBatisConfig.java + +**소스**: `D:\workspace\git\VMIS-interface\src\main\java\com\vmis\interfaceapp\config\MyBatisConfig.java` +**대상**: `D:\workspace\git\VIPS\src\main\java\go\kr\project\vmis\config\VmisMyBatisConfig.java` (이름 변경) + +**변경 사항**: +```java +// Before +package com.vmis.interfaceapp.config; + +import org.mybatis.spring.annotation.MapperScan; + +@Configuration +@MapperScan("com.vmis.interfaceapp.mapper") +public class MyBatisConfig { + // ... +} + +// After +package go.kr.project.vmis.config; + +import org.mybatis.spring.annotation.MapperScan; + +@Configuration +@MapperScan("go.kr.project.vmis.mapper") +public class VmisMyBatisConfig { + // ... +} +``` + +**주의**: VIPS에 이미 MyBatis 설정이 있으므로 클래스명을 변경하여 충돌 방지 + +#### 6.2 OpenApiConfig.java + +**변경 사항**: +```java +// Before +package com.vmis.interfaceapp.config; + +// After +package go.kr.project.vmis.config; + +// import 패키지 변경 +import go.kr.project.vmis.model.vo.*; +``` + +### Step 7: Mapper 이식 + +#### 7.1 Mapper 인터페이스 + +**소스**: `D:\workspace\git\VMIS-interface\src\main\java\com\vmis\interfaceapp\mapper\` +**대상**: `D:\workspace\git\VIPS\src\main\java\go\kr\project\vmis\mapper\` + +**변경 사항**: +```java +// Before +package com.vmis.interfaceapp.mapper; + +import com.vmis.interfaceapp.model.entity.CarBassMatterInqireLog; + +// After +package go.kr.project.vmis.mapper; + +import go.kr.project.vmis.model.entity.CarBassMatterInqireLog; +``` + +**파일 목록**: +1. CarBassMatterInqireLogMapper.java +2. CarLedgerFrmbkLogMapper.java + +#### 7.2 Mapper XML + +**소스**: `D:\workspace\git\VMIS-interface\src\main\resources\mybatis\mapper\` +**대상**: `D:\workspace\git\VIPS\src\main\resources\mybatis\mapper\vmis\` + +**CarBassMatterInqireLogMapper_maria.xml 변경 예시**: +```xml + + + + + + + + + + +``` + +**파일 목록**: +1. CarBassMatterInqireLogMapper_maria.xml +2. CarLedgerFrmbkLogMapper_maria.xml + +### Step 8: Enricher 이식 + +**소스**: `D:\workspace\git\VMIS-interface\src\main\java\com\vmis\interfaceapp\enricher\RequestEnricher.java` +**대상**: `D:\workspace\git\VIPS\src\main\java\go\kr\project\vmis\enricher\RequestEnricher.java` + +**변경 사항**: +```java +// Before +package com.vmis.interfaceapp.enricher; + +import com.vmis.interfaceapp.config.VmisProperties; +import com.vmis.interfaceapp.util.TransactionIdGenerator; + +// After +package go.kr.project.vmis.enricher; + +import go.kr.project.vmis.config.VmisProperties; +import go.kr.project.vmis.util.TransactionIdGenerator; +``` + +### Step 9: GovernmentApiClient 이식 (가장 복잡) + +**소스**: `D:\workspace\git\VMIS-interface\src\main\java\com\vmis\interfaceapp\client\GovernmentApiClient.java` +**대상**: `D:\workspace\git\VIPS\src\main\java\go\kr\project\vmis\client\GovernmentApiClient.java` + +**HttpClient 5 → 4 변경**: + +```java +// Before (HttpClient 5) +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.core5.http.io.entity.StringEntity; +import org.apache.hc.core5.http.ContentType; + +// After (HttpClient 4) +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.entity.StringEntity; +import org.apache.http.entity.ContentType; +``` + +**주요 API 변경**: +```java +// Before (HttpClient 5) +StringEntity entity = new StringEntity(jsonBody, ContentType.APPLICATION_JSON); +httpPost.setEntity(entity); + +try (CloseableHttpResponse response = httpClient.execute(httpPost)) { + String responseBody = EntityUtils.toString(response.getEntity()); +} + +// After (HttpClient 4) +StringEntity entity = new StringEntity(jsonBody, ContentType.APPLICATION_JSON); +httpPost.setEntity(entity); + +CloseableHttpResponse response = null; +try { + response = httpClient.execute(httpPost); + String responseBody = EntityUtils.toString(response.getEntity()); +} finally { + if (response != null) { + response.close(); + } +} +``` + +**전체 변경 템플릿**: +```java +package go.kr.project.vmis.client; + +import com.fasterxml.jackson.databind.ObjectMapper; +import go.kr.project.vmis.config.VmisProperties; +import go.kr.project.vmis.enricher.RequestEnricher; +import go.kr.project.vmis.model.vo.*; +import go.kr.project.vmis.util.EncryptionUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; + +@Slf4j +@Component +@RequiredArgsConstructor +public class GovernmentApiClient { + + private final VmisProperties vmisProperties; + private final RequestEnricher requestEnricher; + private final EncryptionUtil encryptionUtil; + private final ObjectMapper objectMapper; + + public GovApiBasicResponse callBasicInfoApi(String vhrno) { + // 기존 로직 유지, HttpClient 4 API로 변경 + // ... + } + + public GovApiLedgerResponse callLedgerInfoApi(String vhrno) { + // 기존 로직 유지, HttpClient 4 API로 변경 + // ... + } + + private CloseableHttpClient createHttpClient() { + return HttpClientBuilder.create() + .setConnectionTimeToLive(vmisProperties.getGovernment().getConnectTimeout(), + java.util.concurrent.TimeUnit.MILLISECONDS) + .build(); + } +} +``` + +### Step 10: Service 계층 이식 + +**패키지 변경**: +```java +// Before +package com.vmis.interfaceapp.service; + +import com.vmis.interfaceapp.client.GovernmentApiClient; +import com.vmis.interfaceapp.mapper.*; +import com.vmis.interfaceapp.model.*; + +// After +package go.kr.project.vmis.service; + +import go.kr.project.vmis.client.GovernmentApiClient; +import go.kr.project.vmis.mapper.*; +import go.kr.project.vmis.model.*; +``` + +**파일 목록**: +1. CarBassMatterInqireLogService.java +2. CarLedgerFrmbkLogService.java +3. CarBassMatterInqireService.java +4. CarLedgerFrmbkService.java + +**주의사항**: +- `@Service` 어노테이션 유지 +- `@Transactional` 설정 확인 + +### Step 11: Controller 이식 + +**소스**: `D:\workspace\git\VMIS-interface\src\main\java\com\vmis\interfaceapp\controller\VehicleInterfaceController.java` +**대상**: `D:\workspace\git\VIPS\src\main\java\go\kr\project\vmis\controller\VehicleInterfaceController.java` + +**주요 변경 사항**: +```java +// Before +package com.vmis.interfaceapp.controller; + +import com.vmis.interfaceapp.service.*; +import com.vmis.interfaceapp.model.vo.*; +import jakarta.validation.Valid; + +@RestController +@RequestMapping("/api/v1/vehicles") + +// After +package go.kr.project.vmis.controller; + +import go.kr.project.vmis.service.*; +import go.kr.project.vmis.model.vo.*; +import javax.validation.Valid; + +@RestController +@RequestMapping("/vmis/api/v1/vehicles") // 경로 변경 고려 +``` + +**API 경로 충돌 방지**: +- 기존 VIPS: `/api/v1/vehicles` (ExternalVehicleApiService가 사용) +- 새로운 VMIS: `/vmis/api/v1/vehicles` 또는 `/internal/vehicles` + +### Step 12: 데이터베이스 확인 + +**데이터베이스 테이블은 이미 존재합니다** (VIPS와 VMIS-interface가 동일한 DB 사용) + +**테이블 존재 확인**: +```sql +-- 1. 테이블 존재 확인 +SHOW TABLES LIKE 'tb_car_bass_matter_inqire%'; +SHOW TABLES LIKE 'tb_car_ledger_frmbk%'; + +-- 2. 시퀀스 존재 확인 +SHOW TABLES LIKE 'seq_car_%'; + +-- 예상 결과: 6개 항목 +-- tb_car_bass_matter_inqire_log +-- seq_car_bass_matter_inqire +-- tb_car_ledger_frmbk +-- seq_car_ledger_frmbk +-- tb_car_ledger_frmbk_dtl +-- seq_car_ledger_frmbk_dtl +``` + +**테이블 구조 확인** (선택사항): +```sql +DESC tb_car_bass_matter_inqire_log; +DESC tb_car_ledger_frmbk; +DESC tb_car_ledger_frmbk_dtl; +``` + +--- + +## Phase 5: 빌드 및 테스트 + +### 5.1 Gradle 빌드 +```bash +cd D:\workspace\git\VIPS + +# Clean 빌드 +gradlew clean build + +# 빌드 성공 확인 +# BUILD SUCCESSFUL 메시지 확인 +``` + +### 5.2 애플리케이션 구동 +```bash +# Spring Boot 실행 +gradlew bootRun + +# 또는 +java -jar build/libs/VIPS-BOOT.war +``` + +### 5.3 로그 확인 +``` +로그 파일 위치 확인 (logback-spring.xml 참조) +- 구동 시 에러 로그 확인 +- Bean 생성 확인 (VmisProperties, GovernmentApiClient 등) +``` + +### 5.4 API 테스트 + +#### Swagger UI 접속 +``` +http://localhost:8080/swagger-ui/index.html +``` + +#### 직접 API 호출 (PowerShell) +```powershell +# 기본사항 조회 테스트 +Invoke-RestMethod -Uri "http://localhost:8080/vmis/api/v1/vehicles/basic" ` + -Method POST ` + -ContentType "application/json" ` + -Body '{"vhrno":"12가3456"}' | ConvertTo-Json -Depth 10 + +# 등록원부 조회 테스트 +Invoke-RestMethod -Uri "http://localhost:8080/vmis/api/v1/vehicles/ledger" ` + -Method POST ` + -ContentType "application/json" ` + -Body '{"vhrno":"12가3456"}' | ConvertTo-Json -Depth 10 +``` + +#### cURL (Git Bash) +```bash +# 기본사항 조회 +curl -X POST http://localhost:8080/vmis/api/v1/vehicles/basic \ + -H "Content-Type: application/json" \ + -d '{"vhrno":"12가3456"}' + +# 등록원부 조회 +curl -X POST http://localhost:8080/vmis/api/v1/vehicles/ledger \ + -H "Content-Type: application/json" \ + -d '{"vhrno":"12가3456"}' +``` + +### 5.5 데이터베이스 확인 +```sql +-- 로그 테이블 확인 +SELECT * FROM tb_car_bass_matter_inqire_log ORDER BY reg_dt DESC LIMIT 10; +SELECT * FROM tb_car_ledger_frmbk_log ORDER BY reg_dt DESC LIMIT 10; + +-- 데이터 저장 확인 +SELECT * FROM tb_car_ledger_frmbk ORDER BY reg_dt DESC LIMIT 10; +SELECT * FROM tb_car_ledger_frmbk_dtl ORDER BY reg_dt DESC LIMIT 10; +``` + +--- + +## Phase 6: 트러블슈팅 + +### 6.1 빌드 오류 + +#### 오류 1: Package jakarta.* does not exist +``` +원인: jakarta 패키지 미변경 +해결: 전체 프로젝트에서 jakarta → javax 일괄 변경 + +# IntelliJ IDEA +Ctrl+Shift+R → "jakarta." → "javax." +``` + +#### 오류 2: Cannot resolve symbol 'HttpClients' +``` +원인: HttpClient 5 import 문 사용 +해결: org.apache.hc.client5.* → org.apache.http.* 변경 +``` + +#### 오류 3: Bean creation error - VmisProperties +``` +원인: @ConfigurationProperties 스캔 누락 +해결: @Component 어노테이션 추가 또는 + @EnableConfigurationProperties(VmisProperties.class) 추가 +``` + +### 6.2 런타임 오류 + +#### 오류 1: Mapper not found +``` +원인: MyBatis mapper-locations 설정 누락 +해결: application.yml에 vmis 매퍼 경로 추가 +mybatis: + mapper-locations: + - classpath:mybatis/mapper/**/*_maria.xml + - classpath:mybatis/mapper/vmis/**/*_maria.xml +``` + +#### 오류 2: GPKI 라이브러리 로드 실패 +``` +원인: libgpkiapi_jni_1.5.jar 경로 문제 +해결: +1. lib 디렉토리 확인 +2. build.gradle에 files('lib/...') 추가 확인 +3. 개발환경에서는 vmis.gpki.enabled=false 설정 +``` + +#### 오류 3: API 호출 타임아웃 +``` +원인: 정부 API 호스트 연결 불가 +해결: +1. 네트워크 연결 확인 +2. 방화벽 설정 확인 +3. API 키 유효성 확인 +4. vmis.government.connect-timeout 값 증가 +``` + +### 6.3 데이터베이스 오류 + +#### 오류 1: Table doesn't exist +``` +원인: DDL 미실행 +해결: ddl/vips/*.sql 파일 실행 +``` + +#### 오류 2: Sequence not found +``` +원인: 시퀀스 미생성 +해결: seq_*.sql 파일 먼저 실행 +``` + +### 6.4 API 응답 오류 + +#### 오류 1: 401 Unauthorized +``` +원인: API 키 오류 +해결: application.yml의 GOV_API_KEY_* 환경변수 확인 +``` + +#### 오류 2: 500 Internal Server Error +``` +원인: 암호화 실패 +해결: +1. 개발환경에서는 vmis.gpki.enabled=false 설정 +2. 운영환경에서는 인증서 경로 확인 +``` + +--- + +## Phase 7: 기존 코드 리팩토링 + +### 7.1 ExternalVehicleApiService 수정 + +**파일**: `D:\workspace\git\VIPS\src\main\java\go\kr\project\externalApi\service\ExternalVehicleApiService.java` + +**변경 전** (REST API 호출): +```java +@Service +public class ExternalVehicleApiService { + + private final RestTemplate restTemplate; + private final String VMIS_API_URL = "http://localhost:8081/api/v1/vehicles"; + + public VehicleApiResponseVO getBasicInfo(String vhrno) { + String url = VMIS_API_URL + "/basic"; + // RestTemplate으로 HTTP 호출... + } +} +``` + +**변경 후** (내부 메서드 호출): +```java +@Service +@RequiredArgsConstructor +public class ExternalVehicleApiService { + + private final CarBassMatterInqireService carBassMatterInqireService; + private final CarLedgerFrmbkService carLedgerFrmbkService; + + public VehicleApiResponseVO getBasicInfo(String vhrno) { + // 내부 서비스 직접 호출 + CarBassMatterInqireRequestVO request = new CarBassMatterInqireRequestVO(); + request.setVhrno(vhrno); + + Envelope response = + carBassMatterInqireService.getBasicInfo(request); + + // DTO → VO 변환 로직... + return convertToApiResponse(response); + } + + public VehicleApiResponseVO getLedgerInfo(String vhrno) { + CarLedgerFrmbkRequestVO request = new CarLedgerFrmbkRequestVO(); + request.setVhrno(vhrno); + + Envelope response = + carLedgerFrmbkService.getLedgerInfo(request); + + return convertToApiResponse(response); + } + + private VehicleApiResponseVO convertToApiResponse(Envelope envelope) { + // 변환 로직... + } +} +``` + +### 7.2 RestTemplate 설정 정리 + +**옵션 1**: RestTemplate 설정 유지 (향후 다른 외부 API 사용 가능) +**옵션 2**: 미사용 시 주석 처리 + +```java +// RestTemplateConfig.java +// @Configuration // 주석 처리 +public class RestTemplateConfig { + // ... +} +``` + +--- + +## Phase 8: 문서화 및 배포 + +### 8.1 API 문서 업데이트 + +**Swagger 어노테이션 추가** (VehicleInterfaceController.java): +```java +@RestController +@RequestMapping("/vmis/api/v1/vehicles") +@Tag(name = "VMIS 차량 정보 조회", description = "도로교통공단 API 연동") +public class VehicleInterfaceController { + + @PostMapping("/basic") + @Operation(summary = "자동차 기본사항 조회", + description = "차량번호로 기본사항 조회") + public ResponseEntity> getBasicInfo( + @Valid @RequestBody CarBassMatterInqireRequestVO request) { + // ... + } +} +``` + +### 8.2 환경변수 설정 가이드 + +**application-prd.yml** 예시: +```yaml +vmis: + system: + info-sys-id: "${VMIS_SYSTEM_ID}" + info-sys-ip: "${SERVER_IP}" + manager-id: "${VMIS_MANAGER_ID}" + manager-name: "${VMIS_MANAGER_NAME}" + manager-tel: "${VMIS_MANAGER_TEL}" + + gpki: + enabled: true + cert-path: "${GPKI_CERT_PATH}" + private-key-path: "${GPKI_PRIVATE_KEY_PATH}" + private-key-password: "${GPKI_PASSWORD}" + + government: + services: + basic: + api-key: "${GOV_API_KEY_BASIC}" + ledger: + api-key: "${GOV_API_KEY_LEDGER}" +``` + +**환경변수 설정 스크립트** (setenv.bat): +```batch +@echo off +REM VMIS 환경변수 설정 + +SET VMIS_SYSTEM_ID=VMIS001 +SET SERVER_IP=192.168.1.100 +SET VMIS_MANAGER_ID=admin +SET VMIS_MANAGER_NAME=관리자 +SET VMIS_MANAGER_TEL=02-1234-5678 + +SET GPKI_CERT_PATH=C:\gpki\cert.der +SET GPKI_PRIVATE_KEY_PATH=C:\gpki\private.key +SET GPKI_PASSWORD=your-password + +SET GOV_API_KEY_BASIC=your-api-key-basic +SET GOV_API_KEY_LEDGER=your-api-key-ledger + +echo VMIS 환경변수 설정 완료 +``` + +### 8.3 Git Commit + +```bash +# 모든 변경사항 스테이징 +git add . + +# 커밋 +git commit -m "VMIS-interface 통합: 도로교통공단 API 연동 모듈 내재화 + +- VMIS-interface 전체 코드 이식 (34개 파일) +- Spring Boot 3 → 2.7 다운그레이드 +- jakarta → javax 패키지 변경 +- HttpClient 5 → 4 변경 +- 패키지 구조: go.kr.project.vmis.* +- 데이터베이스 테이블 추가 (6개) +- ExternalVehicleApiService 내부 호출로 리팩토링 + +Co-Authored-By: Claude " + +# 푸시 +git push origin feature/vmis-integration +``` + +### 8.4 Pull Request 생성 + +```bash +# GitHub CLI 사용 +gh pr create --title "VMIS-interface 통합" \ + --body "## 개요 +도로교통공단 API 연동 모듈(VMIS-interface)을 VIPS 내부로 통합 + +## 주요 변경사항 +- Spring Boot 2.7 호환 코드로 변경 +- 34개 Java 파일 이식 +- 6개 데이터베이스 테이블 추가 +- 내부 메서드 호출로 성능 개선 + +## 테스트 +- [x] 빌드 성공 +- [x] API 호출 테스트 +- [x] 데이터베이스 저장 확인 + +## 체크리스트 +- [x] 코드 리뷰 완료 +- [x] 테스트 통과 +- [x] 문서 업데이트 +" +``` + +--- + +## 체크리스트 + +### Phase 1: 사전 준비 +- [ ] 현재 브랜치 상태 확인 (이미 생성됨) +- [ ] 디렉토리 구조 생성 +- [ ] GPKI 라이브러리 복사 + +### Phase 2: 설정 +- [ ] build.gradle 의존성 추가 +- [ ] application.yml 설정 통합 +- [ ] VmisProperties 이식 + +### Phase 3: 유틸리티 및 모델 +- [ ] TransactionIdGenerator 이식 +- [ ] EncryptionUtil 이식 +- [ ] Entity 클래스 이식 (7개) +- [ ] VO 클래스 이식 (7개) +- [ ] DTO 클래스 이식 (2개) + +### Phase 4: 핵심 로직 +- [ ] Config 클래스 이식 (2개) +- [ ] Mapper 인터페이스 이식 (2개) +- [ ] Mapper XML 이식 (2개) +- [ ] RequestEnricher 이식 +- [ ] GovernmentApiClient 이식 (HttpClient 4 변경) +- [ ] Service 클래스 이식 (4개) +- [ ] Controller 이식 + +### Phase 5: 데이터베이스 +- [ ] 테이블 존재 확인 (6개 테이블/시퀀스 - 이미 존재) + +### Phase 6: 빌드 및 테스트 +- [ ] Gradle 빌드 성공 +- [ ] 애플리케이션 구동 확인 +- [ ] Swagger UI 확인 +- [ ] API 호출 테스트 (/basic) +- [ ] API 호출 테스트 (/ledger) +- [ ] 데이터베이스 저장 확인 + +### Phase 7: 리팩토링 +- [ ] ExternalVehicleApiService 수정 +- [ ] 불필요한 코드 제거 + +### Phase 8: 마무리 +- [ ] API 문서 업데이트 +- [ ] 환경변수 가이드 작성 +- [ ] Git 커밋 +- [ ] Pull Request 생성 + +--- + +## 참고 자료 + +- Spring Boot 2.7 문서: https://docs.spring.io/spring-boot/docs/2.7.x/reference/html/ +- MyBatis Spring Boot: https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/ +- Apache HttpClient 4: https://hc.apache.org/httpcomponents-client-4.5.x/ + +--- + +**작업 진행 방법**: +브랜치는 이미 생성되어 있으므로, Phase 1의 디렉토리 구조 준비부터 시작하세요. + +```bash +cd D:\workspace\git\VIPS +git status # 현재 브랜치 확인 +``` + +**문서 버전**: 1.1 +**최종 수정**: 2025-11-06