diff --git a/src/main/java/com/vmis/interfaceapp/client/GovernmentApi.java b/src/main/java/com/vmis/interfaceapp/client/GovernmentApi.java
new file mode 100644
index 0000000..f4e06b2
--- /dev/null
+++ b/src/main/java/com/vmis/interfaceapp/client/GovernmentApi.java
@@ -0,0 +1,21 @@
+package com.vmis.interfaceapp.client;
+
+import com.vmis.interfaceapp.model.basic.BasicRequest;
+import com.vmis.interfaceapp.model.basic.BasicResponse;
+import com.vmis.interfaceapp.model.common.Envelope;
+import com.vmis.interfaceapp.model.ledger.LedgerRequest;
+import com.vmis.interfaceapp.model.ledger.LedgerResponse;
+import org.springframework.http.ResponseEntity;
+
+/**
+ * 정부 시스템 연계 API 추상화 인터페이스.
+ *
+ *
외부 정부 시스템과의 통신 계약을 명확히 하여 테스트 용이성과
+ * 추후 교체 가능성을 높입니다.
+ */
+public interface GovernmentApi {
+
+ ResponseEntity> callBasic(Envelope envelope);
+
+ ResponseEntity> callLedger(Envelope envelope);
+}
diff --git a/src/main/java/com/vmis/interfaceapp/client/GovernmentApiClient.java b/src/main/java/com/vmis/interfaceapp/client/GovernmentApiClient.java
index eed35c3..e8822dd 100644
--- a/src/main/java/com/vmis/interfaceapp/client/GovernmentApiClient.java
+++ b/src/main/java/com/vmis/interfaceapp/client/GovernmentApiClient.java
@@ -6,7 +6,6 @@ import com.vmis.interfaceapp.config.properties.VmisProperties;
import com.vmis.interfaceapp.gpki.GpkiService;
import com.vmis.interfaceapp.model.basic.BasicRequest;
import com.vmis.interfaceapp.model.basic.BasicResponse;
-import com.vmis.interfaceapp.model.basic.CarBassMatterInqireVO;
import com.vmis.interfaceapp.model.common.Envelope;
import com.vmis.interfaceapp.model.ledger.LedgerRequest;
import com.vmis.interfaceapp.model.ledger.LedgerResponse;
@@ -60,7 +59,7 @@ import java.nio.charset.StandardCharsets;
@Slf4j
@RequiredArgsConstructor
@Component
-public class GovernmentApiClient {
+public class GovernmentApiClient implements GovernmentApi {
/**
* Spring RestTemplate
@@ -125,12 +124,6 @@ public class GovernmentApiClient {
*/
private final ObjectMapper objectMapper;
- /**
- * 자동차 기본 사항 조회 로그 서비스
- *
- * API 호출 정보를 DB에 로그성으로 저장합니다.
- */
- private final com.vmis.interfaceapp.service.CarBassMatterInqireService carBassMatterInqireService;
/**
* 서비스 타입 열거형
@@ -322,34 +315,8 @@ public class GovernmentApiClient {
* @return ResponseEntity<Envelope<BasicResponse>> 조회 결과를 담은 응답
*/
public ResponseEntity> callBasic(Envelope envelope) {
- String generatedId = null;
-
- try {
- // 1. 요청 정보 DB 저장 (첫 번째 요청만 저장)
- if (envelope.getData() != null && !envelope.getData().isEmpty()) {
- com.vmis.interfaceapp.model.basic.BasicRequest request = envelope.getData().get(0);
- generatedId = saveRequestLog(request);
- log.info("[BASIC-REQ-LOG] 요청 정보 저장 완료 - ID: {}, 차량번호: {}", generatedId, request.getVhrno());
- }
-
- // 2. 정부 API 호출
- ResponseEntity> response = callModel(ServiceType.BASIC, envelope, new TypeReference>(){});
-
- // 3. 응답 정보 DB 업데이트
- if (generatedId != null && response.getBody() != null) {
- updateResponseLog(generatedId, response.getBody());
- log.info("[BASIC-RES-LOG] 응답 정보 저장 완료 - ID: {}", generatedId);
- }
-
- return response;
-
- } catch (Exception e) {
- // 4. 에러 발생 시 에러 정보 DB 업데이트
- if (generatedId != null) {
- updateErrorLog(generatedId, e);
- }
- throw e;
- }
+ // 순수한 전송 책임만 수행: DB 로깅은 서비스 레이어에서 처리
+ return callModel(ServiceType.BASIC, envelope, new TypeReference>(){});
}
/**
@@ -657,174 +624,4 @@ public class GovernmentApiClient {
}
}
- /**
- * 요청 정보를 DB에 저장
- *
- * @param request 요청 정보
- * @return 생성된 ID
- */
- private String saveRequestLog(com.vmis.interfaceapp.model.basic.BasicRequest request) {
- CarBassMatterInqireVO logEntity = CarBassMatterInqireVO.builder()
- .infoSysId(request.getInfoSysId())
- .infoSysIp(request.getInfoSysIp())
- .sigunguCode(request.getSigunguCode())
- .cntcInfoCode(request.getCntcInfoCode())
- .chargerId(request.getChargerId())
- .chargerIp(request.getChargerIp())
- .chargerNm(request.getChargerNm())
- .dmndLevyStdde(request.getLevyStdde())
- .dmndInqireSeCode(request.getInqireSeCode())
- .dmndVhrno(request.getVhrno())
- .dmndVin(request.getVin())
- .rgtr("SYSTEM")
- .build();
-
- return carBassMatterInqireService.createInitialRequest(logEntity);
- }
-
- /**
- * 응답 정보를 DB에 업데이트
- *
- * @param id 저장된 ID
- * @param envelope 응답 정보
- */
- private void updateResponseLog(String id, Envelope envelope) {
- com.vmis.interfaceapp.model.basic.BasicResponse response = envelope.getData() != null && !envelope.getData().isEmpty()
- ? envelope.getData().get(0)
- : null;
-
- if (response == null) {
- log.warn("[BASIC-RES-LOG] 응답 데이터가 없습니다 - ID: {}", id);
- return;
- }
-
- // Builder 패턴으로 응답 정보 매핑
- CarBassMatterInqireVO.CarBassMatterInqireVOBuilder builder = CarBassMatterInqireVO.builder()
- .carBassMatterInqire(id)
- .cntcResultCode(response.getCntcResultCode())
- .cntcResultDtls(response.getCntcResultDtls());
-
- // record가 있으면 첫 번째 record의 정보를 매핑
- if (response.getRecord() != null && !response.getRecord().isEmpty()) {
- com.vmis.interfaceapp.model.basic.BasicResponse.Record record = response.getRecord().get(0);
- mapRecordToEntity(builder, record);
- }
-
- carBassMatterInqireService.updateResponse(builder.build());
- }
-
- /**
- * Record 정보를 Entity에 매핑
- *
- * @param builder Entity Builder
- * @param record Record 정보
- */
- private void mapRecordToEntity(CarBassMatterInqireVO.CarBassMatterInqireVOBuilder builder, com.vmis.interfaceapp.model.basic.BasicResponse.Record record) {
- builder
- .prye(record.getPrye())
- .registDe(record.getRegistDe())
- .ersrRegistSeCode(record.getErsrRegistSeCode())
- .ersrRegistSeNm(record.getErsrRegistSeNm())
- .ersrRegistDe(record.getErsrRegistDe())
- .registDetailCode(record.getRegistDetailCode())
- .dsplvl(record.getDsplvl())
- .useStrnghldLegaldongCode(record.getUseStrnghldLegaldongCode())
- .useStrnghldAdstrdCode(record.getUseStrnghldAdstrdCode())
- .useStrnghldMntn(record.getUseStrnghldMntn())
- .useStrnghldLnbr(record.getUseStrnghldLnbr())
- .useStrnghldHo(record.getUseStrnghldHo())
- .useStrnghldAdresNm(record.getUseStrnghldAdresNm())
- .useStrnghldRoadNmCode(record.getUseStrnghldRoadNmCode())
- .usgsrhldUndgrndBuldSeCode(record.getUsgsrhldUndgrndBuldSeCode())
- .useStrnghldBuldMainNo(record.getUseStrnghldBuldMainNo())
- .useStrnghldBuldSubNo(record.getUseStrnghldBuldSubNo())
- .usgsrhldAdresFull(record.getUsgsrhldAdresFull())
- .mberSeCode(record.getMberSeCode())
- .mberSeNo(record.getMberSeNo())
- .mberNm(record.getMberNm())
- .telno(record.getTelno())
- .ownerLegaldongCode(record.getOwnerLegaldongCode())
- .ownerAdstrdCode(record.getOwnerAdstrdCode())
- .ownerMntn(record.getOwnerMntn())
- .ownerLnbr(record.getOwnerLnbr())
- .ownerHo(record.getOwnerHo())
- .ownerAdresNm(record.getOwnerAdresNm())
- .ownerRoadNmCode(record.getOwnerRoadNmCode())
- .ownerUndgrndBuldSeCode(record.getOwnerUndgrndBuldSeCode())
- .ownerBuldMainNo(record.getOwnerBuldMainNo())
- .ownerBuldSubNo(record.getOwnerBuldSubNo())
- .ownrWholaddr(record.getOwnerAdresFull())
- .aftrVhrno(record.getAftrVhrno())
- .useFuelCode(record.getUseFuelCode())
- .prposSeCode(record.getPrposSeCode())
- .mtrsFomNm(record.getMtrsFomNm())
- .frntVhrno(record.getFrntVhrno())
- .vhclno(record.getVhrno())
- .vin(record.getVin())
- .cnm(record.getCnm())
- .vhcleTotWt(record.getVhcleTotWt())
- .caagEndde(record.getCaagEndde())
- .changeDe(record.getChangeDe())
- .vhctyAsortCode(record.getVhctyAsortCode())
- .vhctyTyCode(record.getVhctyTyCode())
- .vhctySeCode(record.getVhctySeCode())
- .mxmmLdg(record.getMxmmLdg())
- .vhctyAsortNm(record.getVhctyAsortNm())
- .vhctyTyNm(record.getVhctyTyNm())
- .vhctySeNm(record.getVhctySeNm())
- .frstRegistDe(record.getFrstRegistDe())
- .fomNm(record.getFomNm())
- .acqsDe(record.getAcqsDe())
- .acqsEndDe(record.getAcqsEndDe())
- .yblMd(record.getYblMd())
- .transrRegistDe(record.getTransrRegistDe())
- .spcfRegistSttusCode(record.getSpcfRegistSttusCode())
- .colorNm(record.getColorNm())
- .mrtgCo(record.getMrtgCo())
- .seizrCo(record.getSeizrCo())
- .stmdCo(record.getStmdCo())
- .nmplCsdyAt(record.getNmplCsdyAt())
- .nmplCsdyRemnrDe(record.getNmplCsdyRemnrDe())
- .originSeCode(record.getOriginSeCode())
- .nmplStndrdCode(record.getNmplStndrdCode())
- .acqsAmount(record.getAcqsAmount())
- .insptValidPdBgnde(record.getInsptValidPdBgnde())
- .insptValidPdEndde(record.getInsptValidPdEndde())
- .useStrnghldGrcCode(record.getUseStrnghldGrcCode())
- .tkcarPscapCo(record.getTkcarPscapCo())
- .spmnno(record.getSpmnno())
- .trvlDstnc(record.getTrvlDstnc())
- .frstRegistRqrcno(record.getFrstRegistRqrcno())
- .vlntErsrPrvntcNticeDe(record.getVlntErsrPrvntcNticeDe())
- .registInsttNm(record.getRegistInsttNm())
- .processImprtyResnCode(record.getProcessImprtyResnCode())
- .processImprtyResnDtls(record.getProcessImprtyResnDtls())
- .cbdLt(record.getCbdLt())
- .cbdBt(record.getCbdBt())
- .cbdHg(record.getCbdHg())
- .frstMxmmLdg(record.getFrstMxmmLdg())
- .fuelCnsmpRt(record.getFuelCnsmpRt())
- .elctyCmpndFuelCnsmpRt(record.getElctyCmpndFuelCnsmpRt());
- }
-
- /**
- * 에러 정보를 DB에 업데이트
- *
- * @param id 저장된 ID
- * @param exception 발생한 예외
- */
- private void updateErrorLog(String id, Exception exception) {
- try {
- CarBassMatterInqireVO errorLog = CarBassMatterInqireVO.builder()
- .carBassMatterInqire(id)
- .cntcResultCode("99")
- .cntcResultDtls("오류: " + exception.getMessage())
- .build();
-
- carBassMatterInqireService.updateResponse(errorLog);
- log.error("[BASIC-ERR-LOG] API 호출 에러 정보 저장 완료 - ID: {}", id, exception);
- } catch (Exception e) {
- log.error("[BASIC-ERR-LOG] 에러 로그 저장 실패 - ID: {}", id, e);
- }
- }
}
diff --git a/src/main/java/com/vmis/interfaceapp/controller/VehicleInterfaceController.java b/src/main/java/com/vmis/interfaceapp/controller/VehicleInterfaceController.java
index 900aab8..f86d4e5 100644
--- a/src/main/java/com/vmis/interfaceapp/controller/VehicleInterfaceController.java
+++ b/src/main/java/com/vmis/interfaceapp/controller/VehicleInterfaceController.java
@@ -1,12 +1,11 @@
package com.vmis.interfaceapp.controller;
-import com.vmis.interfaceapp.client.GovernmentApiClient;
import com.vmis.interfaceapp.model.basic.BasicRequest;
import com.vmis.interfaceapp.model.basic.BasicResponse;
import com.vmis.interfaceapp.model.common.Envelope;
import com.vmis.interfaceapp.model.ledger.LedgerRequest;
import com.vmis.interfaceapp.model.ledger.LedgerResponse;
-import com.vmis.interfaceapp.service.RequestEnricher;
+import com.vmis.interfaceapp.service.VehicleInterfaceService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
@@ -42,11 +41,10 @@ import org.springframework.web.bind.annotation.*;
* 아키텍처 설계:
*
* - 컨트롤러는 얇은(Thin) 레이어로 설계되어 비즈니스 로직을 포함하지 않음
- * - 모든 실제 처리는 {@link GovernmentApiClient}에 위임
+ * - 모든 실제 처리는 {@link com.vmis.interfaceapp.service.VehicleInterfaceService}에 위임
* - Swagger/OpenAPI 문서 자동 생성을 위한 어노테이션 포함
*
*
- * @see GovernmentApiClient
* @see Envelope
*/
@RestController
@@ -56,24 +54,8 @@ import org.springframework.web.bind.annotation.*;
@Tag(name = "Vehicle Interfaces", description = "시군구연계 자동차 정보 연계 API")
public class VehicleInterfaceController {
- private final RequestEnricher enricher;
+ private final VehicleInterfaceService vehicleService;
- /**
- * 정부 API 클라이언트
- *
- * 정부 시스템과의 실제 통신을 담당하는 클라이언트 객체입니다.
- * 이 클라이언트는 다음 기능들을 포함합니다:
- *
- * - HTTP 요청/응답 처리
- * - GPKI 암호화/복호화
- * - 헤더 구성 및 관리
- * - 에러 처리 및 로깅
- *
- *
- * 생성자 주입(Constructor Injection)을 통해 의존성이 주입되며,
- * final 키워드로 선언되어 불변성을 보장합니다.
- */
- private final GovernmentApiClient govClient;
/**
* 자동차 기본사항 조회 API
@@ -149,10 +131,8 @@ public class VehicleInterfaceController {
public ResponseEntity> basic(
@org.springframework.web.bind.annotation.RequestBody Envelope envelope
) {
- // YAML 설정값으로 공통 필드 자동 채움
- enricher.enrichBasic(envelope);
- // 실제 처리는 GovernmentApiClient에 위임
- return govClient.callBasic(envelope);
+ // 서비스에서 요청 보강/로깅/호출을 모두 오케스트레이션
+ return vehicleService.basic(envelope);
}
/**
@@ -247,9 +227,7 @@ public class VehicleInterfaceController {
public ResponseEntity> ledger(
@org.springframework.web.bind.annotation.RequestBody Envelope envelope
) {
- // YAML 설정값으로 공통 필드 자동 채움
- enricher.enrichLedger(envelope);
- // 실제 처리는 GovernmentApiClient에 위임
- return govClient.callLedger(envelope);
+ // 서비스에서 요청 보강/호출을 오케스트레이션
+ return vehicleService.ledger(envelope);
}
}
diff --git a/src/main/java/com/vmis/interfaceapp/mapper/SampleMapper.java b/src/main/java/com/vmis/interfaceapp/mapper/SampleMapper.java
deleted file mode 100644
index 528aa2c..0000000
--- a/src/main/java/com/vmis/interfaceapp/mapper/SampleMapper.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.vmis.interfaceapp.mapper;
-
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * 샘플 MyBatis Mapper 인터페이스
- *
- * 이 인터페이스는 MyBatis 설정 테스트 및 예제 용도입니다.
- * 실제 프로젝트에서는 비즈니스 요구사항에 맞는 Mapper를 작성하세요.
- *
- * @Mapper 어노테이션을 사용하면 Spring이 자동으로 구현체를 생성합니다.
- * XML 파일의 namespace와 이 인터페이스의 경로가 일치해야 합니다.
- */
-@Mapper
-public interface SampleMapper {
-
- /**
- * 데이터베이스 연결 테스트용 쿼리
- *
- * 현재 시간을 조회하여 데이터베이스 연결이 정상적으로
- * 작동하는지 확인할 수 있습니다.
- *
- * @return 현재 시간 문자열
- */
- String selectCurrentTime();
-}
diff --git a/src/main/java/com/vmis/interfaceapp/service/VehicleInterfaceService.java b/src/main/java/com/vmis/interfaceapp/service/VehicleInterfaceService.java
new file mode 100644
index 0000000..1987d75
--- /dev/null
+++ b/src/main/java/com/vmis/interfaceapp/service/VehicleInterfaceService.java
@@ -0,0 +1,228 @@
+package com.vmis.interfaceapp.service;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.vmis.interfaceapp.client.GovernmentApi;
+import com.vmis.interfaceapp.model.basic.BasicRequest;
+import com.vmis.interfaceapp.model.basic.BasicResponse;
+import com.vmis.interfaceapp.model.basic.CarBassMatterInqireVO;
+import com.vmis.interfaceapp.model.common.Envelope;
+import com.vmis.interfaceapp.model.ledger.LedgerRequest;
+import com.vmis.interfaceapp.model.ledger.LedgerResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * 차량 연계 서비스: 컨트롤러-클라이언트 사이의 오케스트레이션 계층.
+ * - 요청 보강(RequestEnricher)
+ * - 요청/응답 DB 로깅(CarBassMatterInqire)
+ * - 정부 API 클라이언트 위임(GovernmentApi)
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class VehicleInterfaceService {
+
+ private final GovernmentApi governmentApi;
+ private final RequestEnricher enricher;
+ private final CarBassMatterInqireService carBassMatterInqireService;
+
+ /**
+ * 자동차 기본사항 조회: 보강 -> 최초요청로그 -> 외부호출 -> 응답로그.
+ */
+ @Transactional
+ public ResponseEntity> basic(Envelope envelope) {
+ // 1) 요청 보강
+ enricher.enrichBasic(envelope);
+
+ String generatedId = null;
+ try {
+ // 2) 최초 요청 로그 저장 (첫 번째 데이터 기준)
+ if (envelope.getData() != null && !envelope.getData().isEmpty()) {
+ BasicRequest req = envelope.getData().get(0);
+ CarBassMatterInqireVO logEntity = mapInitialLog(req);
+ generatedId = carBassMatterInqireService.createInitialRequest(logEntity);
+ log.info("[BASIC-REQ-LOG] 요청 정보 저장 완료 - ID: {}, 차량번호: {}", generatedId, req.getVhrno());
+ }
+
+ // 3) 외부 API 호출
+ ResponseEntity> response = governmentApi.callBasic(envelope);
+
+ // 4) 응답 로그 업데이트
+ // 원본 소스, 정상적인 호출, 리턴(에러 리턴포함) 일 경우에만 에러 로그 남김
+ if (generatedId != null && response.getBody() != null) {
+ CarBassMatterInqireVO update = mapResponseLog(generatedId, response.getBody());
+ if (update != null) {
+ carBassMatterInqireService.updateResponse(update);
+ log.info("[BASIC-RES-LOG] 응답 정보 저장 완료 - ID: {}", generatedId);
+ }
+ }
+
+ return response;
+ } catch (Exception e) {
+ // 5) 오류 로그 업데이트
+ if (generatedId != null) {
+ try {
+ String detail = buildExceptionDetail(e);
+ CarBassMatterInqireVO errorLog = CarBassMatterInqireVO.builder()
+ .carBassMatterInqire(generatedId)
+ .cntcResultCode("99")
+ .cntcResultDtls(detail)
+ .build();
+ carBassMatterInqireService.updateResponse(errorLog);
+ log.error("[BASIC-ERR-LOG] API 호출 에러 정보 저장 완료 - ID: {}, detail: {}", generatedId, detail, e);
+ } catch (Exception ignore) {
+ log.error("[BASIC-ERR-LOG] 에러 로그 저장 실패 - ID: {}", generatedId, ignore);
+ }
+ }
+ throw e;
+ }
+ }
+
+ /**
+ * 자동차 등록원부(갑) 조회: 보강 -> 외부호출. (별도 로그 테이블 미정)
+ */
+ public ResponseEntity> ledger(Envelope envelope) {
+ enricher.enrichLedger(envelope);
+ return governmentApi.callLedger(envelope);
+ }
+
+ private CarBassMatterInqireVO mapInitialLog(BasicRequest request) {
+ return CarBassMatterInqireVO.builder()
+ .infoSysId(request.getInfoSysId())
+ .infoSysIp(request.getInfoSysIp())
+ .sigunguCode(request.getSigunguCode())
+ .cntcInfoCode(request.getCntcInfoCode())
+ .chargerId(request.getChargerId())
+ .chargerIp(request.getChargerIp())
+ .chargerNm(request.getChargerNm())
+ .dmndLevyStdde(request.getLevyStdde())
+ .dmndInqireSeCode(request.getInqireSeCode())
+ .dmndVhrno(request.getVhrno())
+ .dmndVin(request.getVin())
+ .rgtr("SYSTEM")
+ .build();
+ }
+
+ private CarBassMatterInqireVO mapResponseLog(String id, Envelope envelope) {
+ if (envelope.getData() == null || envelope.getData().isEmpty()) return null;
+ BasicResponse response = envelope.getData().get(0);
+ CarBassMatterInqireVO.CarBassMatterInqireVOBuilder builder = CarBassMatterInqireVO.builder()
+ .carBassMatterInqire(id)
+ .cntcResultCode(response.getCntcResultCode())
+ .cntcResultDtls(response.getCntcResultDtls());
+
+ if (response.getRecord() != null && !response.getRecord().isEmpty()) {
+ BasicResponse.Record record = response.getRecord().get(0);
+ mapRecordToEntity(builder, record);
+ }
+ return builder.build();
+ }
+
+ private void mapRecordToEntity(CarBassMatterInqireVO.CarBassMatterInqireVOBuilder builder, BasicResponse.Record record) {
+ builder
+ .prye(record.getPrye())
+ .registDe(record.getRegistDe())
+ .ersrRegistSeCode(record.getErsrRegistSeCode())
+ .ersrRegistSeNm(record.getErsrRegistSeNm())
+ .ersrRegistDe(record.getErsrRegistDe())
+ .registDetailCode(record.getRegistDetailCode())
+ .dsplvl(record.getDsplvl())
+ .useStrnghldLegaldongCode(record.getUseStrnghldLegaldongCode())
+ .useStrnghldAdstrdCode(record.getUseStrnghldAdstrdCode())
+ .useStrnghldMntn(record.getUseStrnghldMntn())
+ .useStrnghldLnbr(record.getUseStrnghldLnbr())
+ .useStrnghldHo(record.getUseStrnghldHo())
+ .useStrnghldAdresNm(record.getUseStrnghldAdresNm())
+ .useStrnghldRoadNmCode(record.getUseStrnghldRoadNmCode())
+ .usgsrhldUndgrndBuldSeCode(record.getUsgsrhldUndgrndBuldSeCode())
+ .useStrnghldBuldMainNo(record.getUseStrnghldBuldMainNo())
+ .useStrnghldBuldSubNo(record.getUseStrnghldBuldSubNo())
+ .usgsrhldAdresFull(record.getUsgsrhldAdresFull())
+ .mberSeCode(record.getMberSeCode())
+ .mberSeNo(record.getMberSeNo())
+ .mberNm(record.getMberNm())
+ .telno(record.getTelno())
+ .ownerLegaldongCode(record.getOwnerLegaldongCode())
+ .ownerAdstrdCode(record.getOwnerAdstrdCode())
+ .ownerMntn(record.getOwnerMntn())
+ .ownerLnbr(record.getOwnerLnbr())
+ .ownerHo(record.getOwnerHo())
+ .ownerAdresNm(record.getOwnerAdresNm())
+ .ownerRoadNmCode(record.getOwnerRoadNmCode())
+ .ownerUndgrndBuldSeCode(record.getOwnerUndgrndBuldSeCode())
+ .ownerBuldMainNo(record.getOwnerBuldMainNo())
+ .ownerBuldSubNo(record.getOwnerBuldSubNo())
+ .ownrWholaddr(record.getOwnerAdresFull())
+ .aftrVhrno(record.getAftrVhrno())
+ .useFuelCode(record.getUseFuelCode())
+ .prposSeCode(record.getPrposSeCode())
+ .mtrsFomNm(record.getMtrsFomNm())
+ .frntVhrno(record.getFrntVhrno())
+ .vhclno(record.getVhrno())
+ .vin(record.getVin())
+ .cnm(record.getCnm())
+ .vhcleTotWt(record.getVhcleTotWt())
+ .caagEndde(record.getCaagEndde())
+ .changeDe(record.getChangeDe())
+ .vhctyAsortCode(record.getVhctyAsortCode())
+ .vhctyTyCode(record.getVhctyTyCode())
+ .vhctySeCode(record.getVhctySeCode())
+ .mxmmLdg(record.getMxmmLdg())
+ .vhctyAsortNm(record.getVhctyAsortNm())
+ .vhctyTyNm(record.getVhctyTyNm())
+ .vhctySeNm(record.getVhctySeNm())
+ .frstRegistDe(record.getFrstRegistDe())
+ .fomNm(record.getFomNm())
+ .acqsDe(record.getAcqsDe())
+ .acqsEndDe(record.getAcqsEndDe())
+ .yblMd(record.getYblMd())
+ .transrRegistDe(record.getTransrRegistDe())
+ .spcfRegistSttusCode(record.getSpcfRegistSttusCode())
+ .colorNm(record.getColorNm())
+ .mrtgCo(record.getMrtgCo())
+ .seizrCo(record.getSeizrCo())
+ .stmdCo(record.getStmdCo())
+ .nmplCsdyAt(record.getNmplCsdyAt())
+ .nmplCsdyRemnrDe(record.getNmplCsdyRemnrDe())
+ .originSeCode(record.getOriginSeCode())
+ .nmplStndrdCode(record.getNmplStndrdCode())
+ .acqsAmount(record.getAcqsAmount())
+ .insptValidPdBgnde(record.getInsptValidPdBgnde())
+ .insptValidPdEndde(record.getInsptValidPdEndde())
+ .useStrnghldGrcCode(record.getUseStrnghldGrcCode())
+ .tkcarPscapCo(record.getTkcarPscapCo())
+ .spmnno(record.getSpmnno())
+ .trvlDstnc(record.getTrvlDstnc())
+ .frstRegistRqrcno(record.getFrstRegistRqrcno())
+ .vlntErsrPrvntcNticeDe(record.getVlntErsrPrvntcNticeDe())
+ .registInsttNm(record.getRegistInsttNm())
+ .processImprtyResnCode(record.getProcessImprtyResnCode())
+ .processImprtyResnDtls(record.getProcessImprtyResnDtls())
+ .cbdLt(record.getCbdLt())
+ .cbdBt(record.getCbdBt())
+ .cbdHg(record.getCbdHg())
+ .frstMxmmLdg(record.getFrstMxmmLdg())
+ .fuelCnsmpRt(record.getFuelCnsmpRt())
+ .elctyCmpndFuelCnsmpRt(record.getElctyCmpndFuelCnsmpRt());
+ }
+
+ private String buildExceptionDetail(Throwable t) {
+ if (t == null) return "오류: unknown";
+ Throwable root = t;
+ int guard = 0;
+ while (root.getCause() != null && root.getCause() != root && guard++ < 20) {
+ root = root.getCause();
+ }
+ String className = root.getClass().getName();
+ String message = root.getMessage();
+ String detail = (message != null && !message.isEmpty()) ? (className + ": " + message) : root.toString();
+ // DB 컬럼(CNTC_RESULT_DTLS) 길이: 200
+ if (detail.length() > 200) {
+ detail = detail.substring(0, 200);
+ }
+ return detail;
+ }
+}
diff --git a/src/main/resources/mybatis/mapper/sample_maria.xml b/src/main/resources/mybatis/mapper/sample_maria.xml
deleted file mode 100644
index b1a4c7f..0000000
--- a/src/main/resources/mybatis/mapper/sample_maria.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-