parent
7a95540634
commit
425dd2c44d
@ -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 추상화 인터페이스.
|
||||||
|
*
|
||||||
|
* <p>외부 정부 시스템과의 통신 계약을 명확히 하여 테스트 용이성과
|
||||||
|
* 추후 교체 가능성을 높입니다.</p>
|
||||||
|
*/
|
||||||
|
public interface GovernmentApi {
|
||||||
|
|
||||||
|
ResponseEntity<Envelope<BasicResponse>> callBasic(Envelope<BasicRequest> envelope);
|
||||||
|
|
||||||
|
ResponseEntity<Envelope<LedgerResponse>> callLedger(Envelope<LedgerRequest> envelope);
|
||||||
|
}
|
||||||
@ -1,26 +0,0 @@
|
|||||||
package com.vmis.interfaceapp.mapper;
|
|
||||||
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 샘플 MyBatis Mapper 인터페이스
|
|
||||||
*
|
|
||||||
* <p>이 인터페이스는 MyBatis 설정 테스트 및 예제 용도입니다.
|
|
||||||
* 실제 프로젝트에서는 비즈니스 요구사항에 맞는 Mapper를 작성하세요.</p>
|
|
||||||
*
|
|
||||||
* <p>@Mapper 어노테이션을 사용하면 Spring이 자동으로 구현체를 생성합니다.
|
|
||||||
* XML 파일의 namespace와 이 인터페이스의 경로가 일치해야 합니다.</p>
|
|
||||||
*/
|
|
||||||
@Mapper
|
|
||||||
public interface SampleMapper {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 데이터베이스 연결 테스트용 쿼리
|
|
||||||
*
|
|
||||||
* <p>현재 시간을 조회하여 데이터베이스 연결이 정상적으로
|
|
||||||
* 작동하는지 확인할 수 있습니다.</p>
|
|
||||||
*
|
|
||||||
* @return 현재 시간 문자열
|
|
||||||
*/
|
|
||||||
String selectCurrentTime();
|
|
||||||
}
|
|
||||||
@ -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<Envelope<BasicResponse>> basic(Envelope<BasicRequest> 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<Envelope<BasicResponse>> 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<Envelope<LedgerResponse>> ledger(Envelope<LedgerRequest> 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<BasicResponse> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,44 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|
||||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
|
||||||
|
|
||||||
<!--
|
|
||||||
샘플 MyBatis Mapper XML 파일
|
|
||||||
|
|
||||||
실제 사용 시에는 테이블명과 컬럼명을 프로젝트에 맞게 수정하세요.
|
|
||||||
이 파일은 설정 테스트 및 예제 용도입니다.
|
|
||||||
-->
|
|
||||||
<mapper namespace="com.vmis.interfaceapp.mapper.SampleMapper">
|
|
||||||
|
|
||||||
<!-- 샘플 쿼리: 데이터베이스 연결 테스트 -->
|
|
||||||
<select id="selectCurrentTime" resultType="String">
|
|
||||||
SELECT NOW() AS current_time
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
추가 쿼리 예제:
|
|
||||||
|
|
||||||
<select id="selectById" parameterType="Long" resultType="com.vmis.interfaceapp.model.SampleEntity">
|
|
||||||
SELECT id, name, created_at
|
|
||||||
FROM sample_table
|
|
||||||
WHERE id = #{id}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<insert id="insert" parameterType="com.vmis.interfaceapp.model.SampleEntity">
|
|
||||||
INSERT INTO sample_table (name, created_at)
|
|
||||||
VALUES (#{name}, NOW())
|
|
||||||
</insert>
|
|
||||||
|
|
||||||
<update id="update" parameterType="com.vmis.interfaceapp.model.SampleEntity">
|
|
||||||
UPDATE sample_table
|
|
||||||
SET name = #{name}
|
|
||||||
WHERE id = #{id}
|
|
||||||
</update>
|
|
||||||
|
|
||||||
<delete id="delete" parameterType="Long">
|
|
||||||
DELETE FROM sample_table
|
|
||||||
WHERE id = #{id}
|
|
||||||
</delete>
|
|
||||||
-->
|
|
||||||
|
|
||||||
</mapper>
|
|
||||||
Loading…
Reference in New Issue