diff --git a/docs/API_ARCHITECTURE.md b/docs/API_ARCHITECTURE.md deleted file mode 100644 index 99f397b..0000000 --- a/docs/API_ARCHITECTURE.md +++ /dev/null @@ -1,958 +0,0 @@ -# VMIS API 통합 아키텍처 문서 - -## 📋 목차 -- [1. 개요](#1-개요) -- [2. 패키지 구조](#2-패키지-구조) -- [3. 아키텍처 패턴](#3-아키텍처-패턴) -- [4. Internal Mode 상세](#4-internal-mode-상세) -- [5. External Mode 상세](#5-external-mode-상세) -- [6. 공통 구성요소](#6-공통-구성요소) -- [7. 데이터 흐름](#7-데이터-흐름) -- [8. 설정 가이드](#8-설정-가이드) -- [9. 사용 예제](#9-사용-예제) - ---- - -## 1. 개요 - -### 1.1 목적 -VMIS(차량관리정보시스템) API 통합 모듈은 차량 정보 조회 기능을 제공하며, 두 가지 운영 모드를 지원합니다: -- **Internal Mode**: 내부 VMIS 모듈을 직접 호출 (성능 우선) -- **External Mode**: 외부 REST API 서버 호출 (분리된 아키텍처) - -### 1.2 설계 원칙 -- **Strategy Pattern**: 런타임에 알고리즘(구현체) 전환 -- **Dependency Inversion**: 인터페이스에 의존, 구현체는 교체 가능 -- **Single Responsibility**: 각 클래스는 단일 책임만 수행 -- **Open-Closed**: 확장에는 열려있고 수정에는 닫혀있음 - ---- - -## 2. 패키지 구조 - -``` -src/main/java/go/kr/project/api/ -├── VehicleInfoService.java # 공통 인터페이스 -│ -├── config/ # 공통 설정 -│ ├── ApiConstant.java # API 상수 -│ ├── ApiMapperConfig.java # API Mapper 스캔 설정 -│ ├── VmisIntegrationConfig.java # 통합 설정 및 모니터링 -│ └── properties/ -│ └── VmisProperties.java # 설정 바인딩 클래스 -│ -├── vo/ # 공통 응답 VO (공유) -│ ├── VehicleApiResponseVO.java # 최상위 응답 객체 -│ ├── VehicleBasicInfoVO.java # 차량 기본정보 VO -│ ├── VehicleLedgerVO.java # 차량 등록원부 VO -│ ├── VehicleBasicRequestVO.java # 기본정보 요청 VO -│ └── VehicleLedgerRequestVO.java # 등록원부 요청 VO -│ -├── internal/ # Internal Mode (내부 모듈) -│ ├── service/ -│ │ ├── InternalVehicleInfoServiceImpl.java # 내부 모드 구현체 ⭐ -│ │ ├── VmisCarBassMatterInqireService.java # 기본정보 조회 서비스 -│ │ ├── VmisCarBassMatterInqireLogService.java # 기본정보 로그 서비스 -│ │ ├── VmisCarLedgerFrmbkService.java # 등록원부 조회 서비스 -│ │ └── VmisCarLedgerFrmbkLogService.java # 등록원부 로그 서비스 -│ │ -│ ├── client/ -│ │ ├── GovernmentApi.java # 정부 API 인터페이스 -│ │ └── GovernmentApiClient.java # 정부 API 클라이언트 -│ │ -│ ├── mapper/ -│ │ ├── VmisCarBassMatterInqireMapper.java # 기본정보 Mapper -│ │ └── VmisCarLedgerFrmbkMapper.java # 등록원부 Mapper -│ │ -│ ├── model/ # Internal 전용 모델 -│ │ ├── basic/ -│ │ │ ├── BasicRequest.java # 기본정보 요청 -│ │ │ ├── BasicResponse.java # 기본정보 응답 -│ │ │ └── VmisCarBassMatterInqireVO.java -│ │ ├── ledger/ -│ │ │ ├── LedgerRequest.java # 등록원부 요청 -│ │ │ ├── LedgerResponse.java # 등록원부 응답 -│ │ │ ├── VmisCarLedgerFrmbkVO.java -│ │ │ └── VmisCarLedgerFrmbkDtlVO.java -│ │ └── common/ -│ │ └── Envelope.java # 공통 Envelope -│ │ -│ ├── config/ -│ │ ├── HttpClientConfig.java # RestTemplate 설정 -│ │ ├── OpenApiConfig.java # OpenAPI 설정 -│ │ ├── PropertiesConfig.java # Properties 빈 등록 -│ │ ├── GpkiConfig.java # GPKI 설정 -│ │ └── Globals.java # 전역 상수 -│ │ -│ ├── controller/ -│ │ └── VehicleInterfaceController.java # REST API 컨트롤러 -│ │ -│ ├── enricher/ -│ │ └── VmisRequestEnricher.java # 요청 데이터 자동 보강 -│ │ -│ ├── gpki/ -│ │ ├── GpkiService.java # GPKI 인터페이스 -│ │ ├── RealGpkiService.java # 실제 GPKI 구현 -│ │ └── NoopGpkiService.java # GPKI 비활성화 구현 -│ │ -│ └── util/ -│ └── VehicleResponseMapper.java # 내부↔외부 VO 변환 -│ -└── external/ # External Mode (외부 API) - └── service/ - ├── ExternalVehicleInfoServiceImpl.java # 외부 모드 구현체 ⭐ - └── ExternalVehicleApiService.java # 외부 API 호출 서비스 -``` - ---- - -## 3. 아키텍처 패턴 - -### 3.1 Strategy Pattern (전략 패턴) - -```java -// 공통 인터페이스 -public interface VehicleInfoService { - VehicleApiResponseVO getVehicleInfo(String vehicleNumber); - List getVehiclesInfo(List vehicleNumbers); -} - -// Internal Mode 구현체 -@Service -@ConditionalOnProperty(name = "vmis.integration.mode", havingValue = "internal") -public class InternalVehicleInfoServiceImpl implements VehicleInfoService { - // 내부 VMIS 모듈 직접 호출 -} - -// External Mode 구현체 -@Service -@ConditionalOnProperty(name = "vmis.integration.mode", havingValue = "external", matchIfMissing = true) -public class ExternalVehicleInfoServiceImpl implements VehicleInfoService { - // 외부 REST API 호출 -} -``` - -**장점:** -- 런타임에 구현체 전환 가능 -- 클라이언트 코드는 인터페이스만 의존 -- 새로운 전략 추가 시 기존 코드 수정 불필요 - -### 3.2 의존성 주입 (Dependency Injection) - -```yaml -# application.yml -vmis: - integration: - mode: internal # 또는 external -``` - -Spring의 `@ConditionalOnProperty`를 통해 설정값에 따라 자동으로 적절한 구현체가 Bean으로 등록됩니다. - -```java -@Autowired -private VehicleInfoService vehicleInfoService; -// 설정에 따라 InternalVehicleInfoServiceImpl 또는 -// ExternalVehicleInfoServiceImpl이 주입됨 -``` - -### 3.3 계층화 아키텍처 - -``` -┌─────────────────────────────────────┐ -│ Controller Layer │ ← REST API 엔드포인트 -├─────────────────────────────────────┤ -│ Service Layer (VehicleInfoService)│ ← 비즈니스 로직 -├─────────────────────────────────────┤ -│ Client/Mapper Layer │ ← 데이터 접근 -├─────────────────────────────────────┤ -│ External System (정부 API/DB) │ ← 외부 시스템 -└─────────────────────────────────────┘ -``` - ---- - -## 4. Internal Mode 상세 - -### 4.1 개요 -내부 VMIS 모듈을 직접 사용하여 정부 시스템(MOLIT)과 통신합니다. - -**장점:** -- 네트워크 오버헤드 감소 (외부 서버 호출 불필요) -- 빠른 응답 속도 -- 단일 애플리케이션으로 운영 가능 - -**단점:** -- GPKI 인증서 관리 필요 -- 정부 API 연동 복잡도 증가 - -### 4.2 주요 구성요소 - -#### 4.2.1 InternalVehicleInfoServiceImpl -```java -@Service -@ConditionalOnProperty(name = "vmis.integration.mode", havingValue = "internal") -public class InternalVehicleInfoServiceImpl implements VehicleInfoService { - - private final VmisCarBassMatterInqireService carBassMatterInqireService; - private final VmisCarLedgerFrmbkService carLedgerFrmbkService; - - @Override - public VehicleApiResponseVO getVehicleInfo(String vehicleNumber) { - // 1. 기본정보 조회 - VehicleBasicInfoVO basicInfo = getBasicInfo(vehicleNumber); - - // 2. 등록원부 조회 - VehicleLedgerVO ledgerInfo = getLedgerInfo(vehicleNumber); - - // 3. 결과 통합 - return VehicleApiResponseVO.builder() - .vhrno(vehicleNumber) - .basicInfo(basicInfo) - .ledgerInfo(ledgerInfo) - .build(); - } -} -``` - -#### 4.2.2 GovernmentApiClient -정부 API와 실제 HTTP 통신을 수행합니다. - -```java -@Component -@RequiredArgsConstructor -public class GovernmentApiClient implements GovernmentApi { - - @Qualifier("vmisRestTemplate") - private final RestTemplate restTemplate; - - @Override - public ResponseEntity basic(String requestBody) { - String url = baseUrl + basicServicePath; - return restTemplate.postForEntity(url, requestBody, String.class); - } -} -``` - -#### 4.2.3 VmisRequestEnricher -요청 데이터를 자동으로 보강합니다. - -```java -@Component -public class VmisRequestEnricher { - - public void enrichBasicRequest(BasicRequest request) { - // 시스템 정보 자동 설정 - request.setInfoSysId(vmisProperties.getSystem().getInfoSysId()); - request.setInfoSysIp(vmisProperties.getSystem().getInfoSysIp()); - request.setRegionCode(vmisProperties.getSystem().getRegionCode()); - // ... - } -} -``` - -#### 4.2.4 GPKI 암호화 -운영 환경에서 정부 API 통신 시 GPKI 암호화를 사용합니다. - -```java -public interface GpkiService { - String encrypt(String plainText); - String decrypt(String encryptedText); -} - -// 개발: NoopGpkiService (암호화 없음) -// 운영: RealGpkiService (실제 GPKI 암호화) -``` - -### 4.3 데이터 흐름 - -``` -[Client] - │ - ▼ -[InternalVehicleInfoServiceImpl] - │ - ├─► [VmisCarBassMatterInqireService] - │ │ - │ ├─► [VmisRequestEnricher] ──► Request 보강 - │ ├─► [GovernmentApiClient] ──► HTTP POST - │ │ │ - │ │ ▼ - │ │ [정부 API - 기본정보] - │ │ │ - │ │ ▼ - │ ├─► [GpkiService] ──► 암호화/복호화 - │ ├─► [VmisCarBassMatterInqireMapper] ──► DB 저장 - │ └─► BasicResponse - │ - ├─► [VmisCarLedgerFrmbkService] - │ │ - │ └─► (기본정보와 동일한 흐름) - │ - └─► [VehicleResponseMapper] ──► 내부 VO → 외부 VO 변환 - │ - ▼ - VehicleApiResponseVO -``` - -### 4.4 설정 예시 - -```yaml -vmis: - integration: - mode: internal - - system: - infoSysId: "41-345" - infoSysIp: "105.19.10.135" - regionCode: "41460" - - gov: - scheme: "http" - host: "10.188.225.94:29001" - basePath: "/piss/api/molit" - services: - basic: - path: "/SignguCarBassMatterInqireService" - apiKey: "${GOV_API_KEY_BASIC}" - ledger: - path: "/SignguCarLedgerFrmbkService" - apiKey: "${GOV_API_KEY_LEDGER}" - - gpki: - enabled: "Y" # 운영: Y, 개발: N - certServerId: "SVR5640020001" - targetServerId: "SVR1500000015" -``` - ---- - -## 5. External Mode 상세 - -### 5.1 개요 -외부 VMIS-interface 서버의 REST API를 호출하여 차량 정보를 조회합니다. - -**장점:** -- 마이크로서비스 아키텍처 지원 -- GPKI 관리를 외부 서버에 위임 -- 간단한 설정 - -**단점:** -- 네트워크 오버헤드 증가 -- 외부 서버 의존성 - -### 5.2 주요 구성요소 - -#### 5.2.1 ExternalVehicleInfoServiceImpl -```java -@Service -@ConditionalOnProperty(name = "vmis.integration.mode", havingValue = "external", matchIfMissing = true) -public class ExternalVehicleInfoServiceImpl implements VehicleInfoService { - - private final ExternalVehicleApiService externalVehicleApiService; - - @Override - public VehicleApiResponseVO getVehicleInfo(String vehicleNumber) { - // 외부 API 서비스에 위임 - return externalVehicleApiService.getVehicleInfo(vehicleNumber); - } -} -``` - -#### 5.2.2 ExternalVehicleApiService -외부 REST API를 호출합니다. - -```java -@Service -@RequiredArgsConstructor -public class ExternalVehicleApiService { - - private final RestTemplate restTemplate; - - public VehicleApiResponseVO getVehicleInfo(String vehicleNumber) { - String url = vmisProperties.getExternal().getApi().getUrl(); - - VehicleBasicRequestVO request = new VehicleBasicRequestVO(); - request.setVhrno(vehicleNumber); - - return restTemplate.postForObject(url + "/basic", request, VehicleApiResponseVO.class); - } -} -``` - -### 5.3 데이터 흐름 - -``` -[Client] - │ - ▼ -[ExternalVehicleInfoServiceImpl] - │ - ▼ -[ExternalVehicleApiService] - │ - ▼ -[RestTemplate] ──► HTTP POST - │ - ▼ -[VMIS-interface Server] (외부) - │ - ├─► 정부 API 호출 - ├─► GPKI 암호화/복호화 - ├─► DB 저장 - └─► VehicleApiResponseVO 반환 - │ - ▼ -[Client] -``` - -### 5.4 설정 예시 - -```yaml -vmis: - integration: - mode: external - - external: - api: - url: "http://localhost:8081/api/v1/vehicles" - connectTimeoutMillis: 5000 - readTimeoutMillis: 10000 -``` - ---- - -## 6. 공통 구성요소 - -### 6.1 VehicleInfoService 인터페이스 -```java -public interface VehicleInfoService { - // 단일 차량 조회 - VehicleApiResponseVO getVehicleInfo(String vehicleNumber); - - // 일괄 조회 - List getVehiclesInfo(List vehicleNumbers); -} -``` - -### 6.2 공통 VO (vo 패키지) - -#### VehicleApiResponseVO -```java -@Data -@Builder -public class VehicleApiResponseVO { - private String vhrno; // 차량번호 - private boolean success; // 성공 여부 - private String message; // 메시지 - private VehicleBasicInfoVO basicInfo; // 기본정보 - private VehicleLedgerVO ledgerInfo; // 등록원부 정보 -} -``` - -#### VehicleBasicInfoVO -차량 기본정보 (소유자, 차종, 연식 등) - -#### VehicleLedgerVO -자동차 등록원부 정보 (등록일, 변경이력 등) - -### 6.3 VmisProperties -application.yml의 설정을 바인딩하는 클래스입니다. - -```java -@Data -@Component -@ConfigurationProperties(prefix = "vmis") -public class VmisProperties { - private Integration integration; - private System system; - private Gov gov; - private Gpki gpki; - private External external; -} -``` - -### 6.4 ApiMapperConfig -API 전용 MyBatis Mapper를 스캔합니다. - -```java -@Configuration -@MapperScan(basePackages = "go.kr.project.api.internal.mapper") -public class ApiMapperConfig { -} -``` - ---- - -## 7. 데이터 흐름 - -### 7.1 Internal Mode 전체 흐름 - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ 1. Client Request │ -│ vehicleInfoService.getVehicleInfo("12가3456") │ -└────────────────────────┬────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ 2. InternalVehicleInfoServiceImpl │ -│ - BasicRequest 생성 (vhrno="12가3456") │ -│ - LedgerRequest 생성 (vhrno="12가3456") │ -└────────────────────────┬────────────────────────────────────────────┘ - │ - ┌───────────────┴───────────────┐ - │ │ - ▼ ▼ -┌──────────────────────┐ ┌──────────────────────┐ -│ 3-1. Basic Service │ │ 3-2. Ledger Service │ -│ - VmisRequestEnricher│ │ - VmisRequestEnricher│ -│ (시스템 정보 자동 설정)│ │ (시스템 정보 자동 설정)│ -└──────┬───────────────┘ └──────┬───────────────┘ - │ │ - ▼ ▼ -┌──────────────────────┐ ┌──────────────────────┐ -│ 4-1. 정부 API 호출 │ │ 4-2. 정부 API 호출 │ -│ - GovernmentApiClient│ │ - GovernmentApiClient│ -│ - GPKI 암호화 (운영) │ │ - GPKI 암호화 (운영) │ -│ - HTTP POST │ │ - HTTP POST │ -└──────┬───────────────┘ └──────┬───────────────┘ - │ │ - ▼ ▼ -┌──────────────────────┐ ┌──────────────────────┐ -│ 5-1. 응답 처리 │ │ 5-2. 응답 처리 │ -│ - GPKI 복호화 │ │ - GPKI 복호화 │ -│ - JSON 파싱 │ │ - JSON 파싱 │ -│ - DB 저장 (Mapper) │ │ - DB 저장 (Mapper) │ -└──────┬───────────────┘ └──────┬───────────────┘ - │ │ - └───────────────┬───────────────┘ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ 6. VehicleResponseMapper │ -│ - BasicResponse → VehicleBasicInfoVO 변환 │ -│ - LedgerResponse → VehicleLedgerVO 변환 │ -└────────────────────────┬────────────────────────────────────────────┘ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ 7. Response │ -│ VehicleApiResponseVO { │ -│ vhrno: "12가3456", │ -│ success: true, │ -│ basicInfo: { ... }, │ -│ ledgerInfo: { ... } │ -│ } │ -└─────────────────────────────────────────────────────────────────────┘ -``` - -### 7.2 External Mode 전체 흐름 - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ 1. Client Request │ -│ vehicleInfoService.getVehicleInfo("12가3456") │ -└────────────────────────┬────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ 2. ExternalVehicleInfoServiceImpl │ -│ - ExternalVehicleApiService에 위임 │ -└────────────────────────┬────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ 3. ExternalVehicleApiService │ -│ - VehicleBasicRequestVO 생성 │ -│ - RestTemplate으로 외부 API 호출 │ -└────────────────────────┬────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ 4. HTTP Request to External Server │ -│ POST http://localhost:8081/api/v1/vehicles/basic │ -│ Body: { vhrno: "12가3456" } │ -└────────────────────────┬────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ 5. VMIS-interface Server (외부) │ -│ - 정부 API 호출 │ -│ - GPKI 처리 │ -│ - DB 저장 │ -│ - VehicleApiResponseVO 반환 │ -└────────────────────────┬────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ 6. Response │ -│ VehicleApiResponseVO { │ -│ vhrno: "12가3456", │ -│ success: true, │ -│ basicInfo: { ... }, │ -│ ledgerInfo: { ... } │ -│ } │ -└─────────────────────────────────────────────────────────────────────┘ -``` - ---- - -## 8. 설정 가이드 - -### 8.1 Internal Mode 설정 - -```yaml -vmis: - integration: - mode: internal # ⭐ Internal Mode 활성화 - - # 시스템 정보 (요청 헤더에 자동 포함) - system: - infoSysId: "41-345" - infoSysIp: "${SERVER_IP:105.19.10.135}" - regionCode: "41460" - departmentCode: "" - chargerId: "" - chargerIp: "" - chargerNm: "" - - # 정부 API 연동 설정 - gov: - scheme: "http" - host: "10.188.225.94:29001" - basePath: "/piss/api/molit" - connectTimeoutMillis: 5000 - readTimeoutMillis: 10000 - services: - basic: - path: "/SignguCarBassMatterInqireService" - cntcInfoCode: "AC1_FD11_01" - apiKey: "${GOV_API_KEY_BASIC}" - ledger: - path: "/SignguCarLedgerFrmbkService" - cntcInfoCode: "AC1_FD11_02" - apiKey: "${GOV_API_KEY_LEDGER}" - - # GPKI 암호화 (운영 환경 필수) - gpki: - enabled: "Y" # Y: 암호화 사용, N: 암호화 미사용 - certServerId: "SVR5640020001" - targetServerId: "SVR1500000015" - envCertFilePathName: "src/GPKI/certs/SVR5640020001_env.cer" - sigCertFilePathName: "src/GPKI/certs/SVR5640020001_sig.cer" -``` - -### 8.2 External Mode 설정 - -```yaml -vmis: - integration: - mode: external # ⭐ External Mode 활성화 - - # 외부 API 서버 설정 - external: - api: - url: "http://localhost:8081/api/v1/vehicles" - connectTimeoutMillis: 5000 - readTimeoutMillis: 10000 -``` - -### 8.3 개발 환경 설정 (GPKI 비활성화) - -```yaml -vmis: - integration: - mode: internal - - gpki: - enabled: "N" # ⭐ GPKI 비활성화 -``` - ---- - -## 9. 사용 예제 - -### 9.1 기본 사용법 - -```java -@RestController -@RequestMapping("/api/vehicles") -@RequiredArgsConstructor -public class VehicleController { - - private final VehicleInfoService vehicleInfoService; - - /** - * 단일 차량 조회 - */ - @GetMapping("/{vehicleNumber}") - public ResponseEntity getVehicle( - @PathVariable String vehicleNumber) { - - VehicleApiResponseVO response = vehicleInfoService.getVehicleInfo(vehicleNumber); - - if (response.isSuccess()) { - return ResponseEntity.ok(response); - } else { - return ResponseEntity.badRequest().body(response); - } - } - - /** - * 일괄 조회 - */ - @PostMapping("/batch") - public ResponseEntity> getVehicles( - @RequestBody List vehicleNumbers) { - - List responses = - vehicleInfoService.getVehiclesInfo(vehicleNumbers); - - return ResponseEntity.ok(responses); - } -} -``` - -### 9.2 Service Layer에서 사용 - -```java -@Service -@RequiredArgsConstructor -public class InspectionService { - - private final VehicleInfoService vehicleInfoService; - - public void performInspection(String vehicleNumber) { - // 1. 차량 정보 조회 - VehicleApiResponseVO vehicleInfo = - vehicleInfoService.getVehicleInfo(vehicleNumber); - - if (!vehicleInfo.isSuccess()) { - throw new VehicleNotFoundException(vehicleNumber); - } - - // 2. 차량 정보를 사용한 비즈니스 로직 - VehicleBasicInfoVO basicInfo = vehicleInfo.getBasicInfo(); - String ownerName = basicInfo.getVhrNm(); // 소유자명 - String modelYear = basicInfo.getYridnw(); // 연식 - - // 3. 검사 수행 - // ... - } -} -``` - -### 9.3 응답 데이터 활용 - -```java -VehicleApiResponseVO response = vehicleInfoService.getVehicleInfo("12가3456"); - -if (response.isSuccess()) { - // 기본정보 활용 - VehicleBasicInfoVO basic = response.getBasicInfo(); - System.out.println("차량번호: " + basic.getVhrno()); - System.out.println("소유자: " + basic.getVhrNm()); - System.out.println("차종: " + basic.getVhctyNm()); - System.out.println("용도: " + basic.getVhclPrposNm()); - - // 등록원부 활용 - VehicleLedgerVO ledger = response.getLedgerInfo(); - System.out.println("최초등록일: " + ledger.getFrstRegistDe()); - System.out.println("등록상태: " + ledger.getRegistSttusNm()); -} else { - System.err.println("조회 실패: " + response.getMessage()); -} -``` - -### 9.4 일괄 조회 예제 - -```java -List vehicleNumbers = Arrays.asList( - "12가3456", - "34나5678", - "56다7890" -); - -List responses = - vehicleInfoService.getVehiclesInfo(vehicleNumbers); - -// 성공/실패 분류 -List successful = responses.stream() - .filter(VehicleApiResponseVO::isSuccess) - .collect(Collectors.toList()); - -List failed = responses.stream() - .filter(r -> !r.isSuccess()) - .collect(Collectors.toList()); - -System.out.println("성공: " + successful.size()); -System.out.println("실패: " + failed.size()); -``` - ---- - -## 10. 모드 전환 시나리오 - -### 10.1 개발 → 운영 전환 - -```yaml -# 개발 환경 (application-local.yml) -vmis: - integration: - mode: internal - gpki: - enabled: "N" # GPKI 비활성화 -``` - -```yaml -# 운영 환경 (application-prod.yml) -vmis: - integration: - mode: internal - gpki: - enabled: "Y" # GPKI 활성화 - system: - infoSysIp: "${SERVER_IP}" # 실제 서버 IP -``` - -### 10.2 Monolithic → MSA 전환 - -```yaml -# Phase 1: 단일 애플리케이션 (Internal Mode) -vmis: - integration: - mode: internal -``` - -```yaml -# Phase 2: 마이크로서비스 (External Mode) -vmis: - integration: - mode: external - external: - api: - url: "http://vmis-service:8080/api/v1/vehicles" -``` - -**코드 변경 없이 설정만으로 전환 가능!** - ---- - -## 11. 트러블슈팅 - -### 11.1 Bean 충돌 오류 - -**증상:** -``` -expected single matching bean but found 2: -internalVehicleInfoServiceImpl, externalVehicleInfoServiceImpl -``` - -**원인:** -`vmis.integration.mode` 설정이 잘못되었거나 누락됨 - -**해결:** -```yaml -vmis: - integration: - mode: internal # 또는 external (반드시 지정) -``` - -### 11.2 Mapper 중복 스캔 경고 - -**증상:** -``` -Skipping MapperFactoryBean with name 'vmisCarBassMatterInqireMapper' -Bean already defined with the same name! -``` - -**원인:** -여러 `@MapperScan`에서 같은 패키지를 중복 스캔 - -**해결:** -`ApiMapperConfig`에서 API 전용 Mapper만 스캔하도록 분리되어 있음 - -### 11.3 GPKI 오류 (운영 환경) - -**증상:** -``` -GPKI 초기화 실패: 인증서 파일을 찾을 수 없습니다 -``` - -**해결:** -1. GPKI 인증서 파일 경로 확인 -2. 개발 환경에서는 `gpki.enabled: "N"` 설정 - ---- - -## 12. 성능 최적화 - -### 12.1 Internal Mode 최적화 -- RestTemplate Connection Pool 설정 활용 -- GPKI 세션 재사용 -- DB 커넥션 풀 튜닝 - -### 12.2 External Mode 최적화 -- 외부 API 서버와 동일 네트워크 배치 -- Circuit Breaker 패턴 적용 (향후) -- 캐싱 전략 (향후) - ---- - -## 13. 보안 고려사항 - -### 13.1 GPKI 인증서 관리 -- 인증서 파일 접근 권한 제한 -- 패스워드는 환경변수로 관리 -- 인증서 만료 모니터링 - -### 13.2 API Key 관리 -```yaml -vmis: - gov: - services: - basic: - apiKey: "${GOV_API_KEY_BASIC}" # 환경변수 사용 -``` - -### 13.3 로깅 주의사항 -- 차량번호 등 개인정보는 마스킹 처리 -- 요청/응답 전문은 DEBUG 레벨로 출력 - ---- - -## 14. 확장 가능성 - -### 14.1 새로운 모드 추가 -Strategy Pattern을 사용하므로 새로운 구현체 추가 가능: - -```java -@Service -@ConditionalOnProperty(name = "vmis.integration.mode", havingValue = "cache") -public class CachedVehicleInfoServiceImpl implements VehicleInfoService { - // 캐시 기반 구현 -} -``` - -### 14.2 새로운 차량 정보 조회 API 추가 -1. 정부 API 인터페이스 메서드 추가 -2. Service 계층에 메서드 추가 -3. Mapper 및 Model 추가 -4. VehicleInfoService 인터페이스 확장 - ---- - -## 15. 참고 자료 - -### 15.1 관련 설정 파일 -- `src/main/resources/application.yml` -- `src/main/resources/mybatis/mapper/api-internal/` - -### 15.2 관련 문서 -- Spring Boot Conditional Beans -- Strategy Pattern -- MyBatis Integration - ---- - -**문서 버전:** 1.0 -**최종 수정일:** 2025-11-07 -**작성자:** VIPS Development Team diff --git a/docs/자동차과태료 비교로직 정리.txt b/docs/자동차과태료 비교로직 정리.txt index b0a3f48..0f9921a 100644 --- a/docs/자동차과태료 비교로직 정리.txt +++ b/docs/자동차과태료 비교로직 정리.txt @@ -1,4 +1,13 @@ + - yml flag 값에 따라, 차량기본정보를 구 or 신 api 호출할지 결정 + - 구 or 신 api 통일한 model object 값으로 처리될수 있도록 통합 model 필요 및 자동변환 처리 + +1. 자동차기본정보 api 호출 [차량번호, 부과일자:검사일] -> response.차대번호 +2. 자동차기본정보 api 호출 [1.response.차대번호, 부과일자:오늘일자] -> response.차량번호, response.성명, response.민원인주민번호, response.민원인법정동코드 +3. 자동차등록원본(갑) api 호출 [2.response.차량번호, 2.response.성명, 2.response.민원인주민번호, 2.response.민원인법정동코드] + -- 비교로직에 사용될 api response 정보 + + * 순서 중요!! * 조건에 걸리는 순간 다음 차량번호 비교 진행 * 현재는 하나의 api 를 호출해서 비교로직 진행 -> @@ -8,18 +17,24 @@ --- 상품용 [차량기본정보 필요] +-- 상품용 [자동차등록원부(갑) 필요] +----- 필요한 api 정보 +1. 자동차기본정보 api 호출 [차량번호, 부과일자:검사일] -> response.차대번호 +2. 자동차기본정보 api 호출 [1.response.차대번호, 부과일자:오늘일자] -> response.차량번호, response.성명, response.민원인주민번호, response.민원인법정동코드 +3. 자동차등록원본(갑) api 호출 [2.response.차량번호, 2.response.성명, 2.response.민원인주민번호, 2.response.민원인법정동코드] + -- 비교로직에 사용될 api response 정보 +---------------------------------- 1. TB_CAR_FFNLG_TRGT.검사일 기준 api 호출 2. api.MBER_NM like ‘%상품용%’ 3. (갑부 상세(LedgerRecord) List.CHG_YMD between TB_CAR_FFNLG_TRGT.유효기간만료일 and TB_CAR_FFNLG_TRGT.검사종료일자) and (갑부 상세 List.CHANGE_JOB_SE_CODE = '11' --명의이전 코드) 4. TB_CAR_FFNLG_TRGT 비고 : 조건에 걸린 - "[상품용] 갑부정보" --- 이첩-1 [차량등록원부(갑) 필요] +-- 이첩-1 [차동차기본정보] 1. TB_CAR_FFNLG_TRGT.검사일 기준 api 호출 2. 아래 로직 참조 /** - * 이첩 조건1: 법정동코드 불일치 + * 이첩 조건1: 1. TB_CAR_FFNLG_TRGT.DAYCNT(textFile 일수) <= 115 이내, 법정동코드 불일치 * 사용본거지법정동코드 앞 4자리 != 사용자 조직코드 앞 4자리 */ private boolean checkTransferCondition1_LegalDongMismatch(BasicResponse.Record basicInfo, String userId, String vhclno) { @@ -63,3 +78,17 @@ private boolean checkTransferCondition1_LegalDongMismatch(BasicResponse.Record b 4. 2 api<->3 api 자동차기본정보 : 사용본거지법정동코드 앞 4자리 다를경우 5. TB_CAR_FFNLG_TRGT 비고 : 조건에 걸린 - "전라남도 순천시 / 김정대, 115일 도래지, [2개의 api 법정동코드 및 법정동명]" + + +차량번호 +if(TB_CAR_FFNLG_TRGT.DAYCNT(textFile 일수) > 115) + 부과기준일 = (TB_CAR_FFNLG_TRGT.검사종료일자 + 115일) + TB_CAR_FFNLG_TRGT 비고 : 조건에 걸린 - "전라남도 순천시 / 김정대, 115일 도래지, [2개의 api 법정동코드 및 법정동명]" + 이첩-2 +else{ + 부과기준일 = (TB_CAR_FFNLG_TRGT.검사일자) + table 비고 : 조건에 걸린 - "서울시 용산구/ 이경호, 검사일사용본거지, [검사대상, 사용자 조직코드 앞 4자리 및 법정동명]" + 이첩-1 +} +call api +