You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
32 KiB
32 KiB
VMIS API 통합 아키텍처 문서
📋 목차
- 1. 개요
- 2. 패키지 구조
- 3. 아키텍처 패턴
- 4. Internal Mode 상세
- 5. External Mode 상세
- 6. 공통 구성요소
- 7. 데이터 흐름
- 8. 설정 가이드
- 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 (전략 패턴)
// 공통 인터페이스
public interface VehicleInfoService {
VehicleApiResponseVO getVehicleInfo(String vehicleNumber);
List<VehicleApiResponseVO> getVehiclesInfo(List<String> 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)
# application.yml
vmis:
integration:
mode: internal # 또는 external
Spring의 @ConditionalOnProperty를 통해 설정값에 따라 자동으로 적절한 구현체가 Bean으로 등록됩니다.
@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
@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 통신을 수행합니다.
@Component
@RequiredArgsConstructor
public class GovernmentApiClient implements GovernmentApi {
@Qualifier("vmisRestTemplate")
private final RestTemplate restTemplate;
@Override
public ResponseEntity<String> basic(String requestBody) {
String url = baseUrl + basicServicePath;
return restTemplate.postForEntity(url, requestBody, String.class);
}
}
4.2.3 VmisRequestEnricher
요청 데이터를 자동으로 보강합니다.
@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 암호화를 사용합니다.
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 설정 예시
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
@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를 호출합니다.
@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 설정 예시
vmis:
integration:
mode: external
external:
api:
url: "http://localhost:8081/api/v1/vehicles"
connectTimeoutMillis: 5000
readTimeoutMillis: 10000
6. 공통 구성요소
6.1 VehicleInfoService 인터페이스
public interface VehicleInfoService {
// 단일 차량 조회
VehicleApiResponseVO getVehicleInfo(String vehicleNumber);
// 일괄 조회
List<VehicleApiResponseVO> getVehiclesInfo(List<String> vehicleNumbers);
}
6.2 공통 VO (vo 패키지)
VehicleApiResponseVO
@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의 설정을 바인딩하는 클래스입니다.
@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를 스캔합니다.
@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 설정
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 설정
vmis:
integration:
mode: external # ⭐ External Mode 활성화
# 외부 API 서버 설정
external:
api:
url: "http://localhost:8081/api/v1/vehicles"
connectTimeoutMillis: 5000
readTimeoutMillis: 10000
8.3 개발 환경 설정 (GPKI 비활성화)
vmis:
integration:
mode: internal
gpki:
enabled: "N" # ⭐ GPKI 비활성화
9. 사용 예제
9.1 기본 사용법
@RestController
@RequestMapping("/api/vehicles")
@RequiredArgsConstructor
public class VehicleController {
private final VehicleInfoService vehicleInfoService;
/**
* 단일 차량 조회
*/
@GetMapping("/{vehicleNumber}")
public ResponseEntity<VehicleApiResponseVO> 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<List<VehicleApiResponseVO>> getVehicles(
@RequestBody List<String> vehicleNumbers) {
List<VehicleApiResponseVO> responses =
vehicleInfoService.getVehiclesInfo(vehicleNumbers);
return ResponseEntity.ok(responses);
}
}
9.2 Service Layer에서 사용
@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 응답 데이터 활용
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 일괄 조회 예제
List<String> vehicleNumbers = Arrays.asList(
"12가3456",
"34나5678",
"56다7890"
);
List<VehicleApiResponseVO> responses =
vehicleInfoService.getVehiclesInfo(vehicleNumbers);
// 성공/실패 분류
List<VehicleApiResponseVO> successful = responses.stream()
.filter(VehicleApiResponseVO::isSuccess)
.collect(Collectors.toList());
List<VehicleApiResponseVO> failed = responses.stream()
.filter(r -> !r.isSuccess())
.collect(Collectors.toList());
System.out.println("성공: " + successful.size());
System.out.println("실패: " + failed.size());
10. 모드 전환 시나리오
10.1 개발 → 운영 전환
# 개발 환경 (application-local.yml)
vmis:
integration:
mode: internal
gpki:
enabled: "N" # GPKI 비활성화
# 운영 환경 (application-prod.yml)
vmis:
integration:
mode: internal
gpki:
enabled: "Y" # GPKI 활성화
system:
infoSysIp: "${SERVER_IP}" # 실제 서버 IP
10.2 Monolithic → MSA 전환
# Phase 1: 단일 애플리케이션 (Internal Mode)
vmis:
integration:
mode: internal
# 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 설정이 잘못되었거나 누락됨
해결:
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 초기화 실패: 인증서 파일을 찾을 수 없습니다
해결:
- GPKI 인증서 파일 경로 확인
- 개발 환경에서는
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 관리
vmis:
gov:
services:
basic:
apiKey: "${GOV_API_KEY_BASIC}" # 환경변수 사용
13.3 로깅 주의사항
- 차량번호 등 개인정보는 마스킹 처리
- 요청/응답 전문은 DEBUG 레벨로 출력
14. 확장 가능성
14.1 새로운 모드 추가
Strategy Pattern을 사용하므로 새로운 구현체 추가 가능:
@Service
@ConditionalOnProperty(name = "vmis.integration.mode", havingValue = "cache")
public class CachedVehicleInfoServiceImpl implements VehicleInfoService {
// 캐시 기반 구현
}
14.2 새로운 차량 정보 조회 API 추가
- 정부 API 인터페이스 메서드 추가
- Service 계층에 메서드 추가
- Mapper 및 Model 추가
- VehicleInfoService 인터페이스 확장
15. 참고 자료
15.1 관련 설정 파일
src/main/resources/application.ymlsrc/main/resources/mybatis/mapper/api-internal/
15.2 관련 문서
- Spring Boot Conditional Beans
- Strategy Pattern
- MyBatis Integration
문서 버전: 1.0 최종 수정일: 2025-11-07 작성자: VIPS Development Team