refactor: 차량 정보 및 등록원부 서비스 구현 추가
- ExternalVehicleApiServiceImpl: 외부 VMIS API 호출 구현 - 차량 기본정보 및 등록원부 조회 로직 추가 - 오류 처리 및 실패 응답 객체 생성 로직 포함 - VmisCarBassMatterInqireServiceImpl/VmisCarLedgerFrmbkServiceImpl: - 내부 서비스 관계와 API 호출 보강, 응답 로그 저장 로직 추가 - 오류 시 트랜잭션 독립적 로그 작성 보장 - 관련 로그 서비스 구현체 (VmisCarBassMatterInqireLogServiceImpl, VmisCarLedgerFrmbkLogServiceImpl): 요청/응답 로그 저장 및 오류 로그 추가 - 기존 인터페이스 및 클래스 위치 이동 (VehicleInfoService 등)internalApi
parent
6b47e3f84c
commit
91f7d04f4a
@ -1,4 +1,4 @@
|
|||||||
package go.kr.project.api;
|
package go.kr.project.api.external.service;
|
||||||
|
|
||||||
import go.kr.project.api.model.VehicleApiResponseVO;
|
import go.kr.project.api.model.VehicleApiResponseVO;
|
||||||
|
|
||||||
@ -0,0 +1,195 @@
|
|||||||
|
package go.kr.project.api.external.service.impl;
|
||||||
|
|
||||||
|
import go.kr.project.api.external.service.ExternalVehicleApiService;
|
||||||
|
import go.kr.project.api.model.request.BasicRequest;
|
||||||
|
import go.kr.project.api.model.request.LedgerRequest;
|
||||||
|
import go.kr.project.api.model.*;
|
||||||
|
import go.kr.project.api.model.response.*;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 외부 VMIS-interface API 호출 서비스 구현체
|
||||||
|
* VMIS-interface 프로그램의 API를 호출하여 차량 정보를 조회하는 서비스
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class ExternalVehicleApiServiceImpl implements ExternalVehicleApiService {
|
||||||
|
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
|
||||||
|
// VMIS-interface API URL
|
||||||
|
private static final String VMIS_API_BASE_URL = "http://localhost:8081/api/v1/vehicles";
|
||||||
|
private static final String BASIC_INFO_URL = VMIS_API_BASE_URL + "/basic";
|
||||||
|
private static final String LEDGER_INFO_URL = VMIS_API_BASE_URL + "/ledger";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<VehicleApiResponseVO> getVehiclesInfo(List<String> vehicleNumbers) {
|
||||||
|
log.info("차량 정보 일괄 조회 시작 - 대상 차량 수: {}", vehicleNumbers.size());
|
||||||
|
|
||||||
|
List<VehicleApiResponseVO> responses = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String vehicleNumber : vehicleNumbers) {
|
||||||
|
try {
|
||||||
|
VehicleApiResponseVO response = getVehicleInfo(vehicleNumber);
|
||||||
|
responses.add(response);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("차량번호 {} 조회 중 오류 발생: {}", vehicleNumber, e.getMessage(), e);
|
||||||
|
|
||||||
|
// 오류 발생 시에도 응답 객체 생성하여 추가
|
||||||
|
VehicleApiResponseVO errorResponse = VehicleApiResponseVO.builder()
|
||||||
|
.vhrno(vehicleNumber)
|
||||||
|
.success(false)
|
||||||
|
.message("조회 실패: " + e.getMessage())
|
||||||
|
.build();
|
||||||
|
responses.add(errorResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("차량 정보 일괄 조회 완료 - 성공: {}, 실패: {}",
|
||||||
|
responses.stream().filter(VehicleApiResponseVO::isSuccess).count(),
|
||||||
|
responses.stream().filter(r -> !r.isSuccess()).count());
|
||||||
|
|
||||||
|
return responses;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VehicleApiResponseVO getVehicleInfo(String vehicleNumber) {
|
||||||
|
log.info("차량 정보 조회 시작 - 차량번호: {}", vehicleNumber);
|
||||||
|
|
||||||
|
VehicleApiResponseVO response = new VehicleApiResponseVO();
|
||||||
|
response.setVhrno(vehicleNumber);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. 차량 기본정보 조회
|
||||||
|
BasicResponse basicInfo = getBasicInfo(vehicleNumber);
|
||||||
|
response.setBasicInfo(basicInfo);
|
||||||
|
|
||||||
|
// 2. 자동차 등록원부 조회
|
||||||
|
LedgerResponse ledgerInfo = getLedgerInfo(vehicleNumber);
|
||||||
|
response.setLedgerInfo(ledgerInfo);
|
||||||
|
|
||||||
|
// 3. 결과 검증
|
||||||
|
if (basicInfo != null && "00".equals(basicInfo.getCntcResultCode())) {
|
||||||
|
response.setSuccess(true);
|
||||||
|
response.setMessage("조회 성공");
|
||||||
|
log.info("차량번호 {} 조회 성공", vehicleNumber);
|
||||||
|
} else {
|
||||||
|
response.setSuccess(false);
|
||||||
|
response.setMessage(basicInfo != null ? basicInfo.getCntcResultDtls() : "조회 실패");
|
||||||
|
log.warn("차량번호 {} 조회 실패 - {}", vehicleNumber, response.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
response.setSuccess(false);
|
||||||
|
response.setMessage("API 호출 오류: " + e.getMessage());
|
||||||
|
log.error("차량번호 {} API 호출 중 오류 발생", vehicleNumber, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 차량 기본정보 조회 API 호출
|
||||||
|
* VMIS-interface의 RequestEnricher가 기본 설정값을 자동으로 채워주므로 차량번호만 전송
|
||||||
|
*
|
||||||
|
* @param vehicleNumber 차량번호
|
||||||
|
* @return 차량 기본정보
|
||||||
|
*/
|
||||||
|
private BasicResponse getBasicInfo(String vehicleNumber) {
|
||||||
|
log.debug("차량 기본정보 조회 API 호출 - 차량번호: {}", vehicleNumber);
|
||||||
|
|
||||||
|
// 요청 객체 생성 - 차량번호만 설정 (나머지는 RequestEnricher가 자동 설정)
|
||||||
|
BasicRequest request = new BasicRequest();
|
||||||
|
request.setVhrno(vehicleNumber);
|
||||||
|
|
||||||
|
// Envelope로 감싸기
|
||||||
|
Envelope<BasicRequest> requestEnvelope = new Envelope<>(request);
|
||||||
|
|
||||||
|
// HTTP 헤더 설정
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
HttpEntity<Envelope<BasicRequest>> requestEntity = new HttpEntity<>(requestEnvelope, headers);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// API 호출
|
||||||
|
ResponseEntity<Envelope<BasicResponse>> responseEntity = restTemplate.exchange(
|
||||||
|
BASIC_INFO_URL,
|
||||||
|
HttpMethod.POST,
|
||||||
|
requestEntity,
|
||||||
|
new ParameterizedTypeReference<Envelope<BasicResponse>>() {}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (responseEntity.getStatusCode() == HttpStatus.OK && responseEntity.getBody() != null) {
|
||||||
|
List<BasicResponse> data = responseEntity.getBody().getData();
|
||||||
|
if (data != null && !data.isEmpty()) {
|
||||||
|
return data.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.warn("차량 기본정보 조회 응답이 비어있음 - 차량번호: {}", vehicleNumber);
|
||||||
|
return null;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("차량 기본정보 조회 API 호출 실패 - 차량번호: {}", vehicleNumber, e);
|
||||||
|
throw new RuntimeException("차량 기본정보 조회 실패: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 자동차 등록원부(갑) 조회 API 호출
|
||||||
|
* VMIS-interface의 RequestEnricher가 기본 설정값을 자동으로 채워주므로 차량번호만 전송
|
||||||
|
*
|
||||||
|
* @param vehicleNumber 차량번호
|
||||||
|
* @return 등록원부 정보
|
||||||
|
*/
|
||||||
|
private LedgerResponse getLedgerInfo(String vehicleNumber) {
|
||||||
|
log.debug("자동차 등록원부 조회 API 호출 - 차량번호: {}", vehicleNumber);
|
||||||
|
|
||||||
|
// 요청 객체 생성 - 차량번호만 설정 (나머지는 RequestEnricher가 자동 설정)
|
||||||
|
LedgerRequest request = new LedgerRequest();
|
||||||
|
request.setVhrno(vehicleNumber);
|
||||||
|
|
||||||
|
// Envelope로 감싸기
|
||||||
|
Envelope<LedgerRequest> requestEnvelope = new Envelope<>(request);
|
||||||
|
|
||||||
|
// HTTP 헤더 설정
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
HttpEntity<Envelope<LedgerRequest>> requestEntity = new HttpEntity<>(requestEnvelope, headers);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// API 호출
|
||||||
|
ResponseEntity<Envelope<LedgerResponse>> responseEntity = restTemplate.exchange(
|
||||||
|
LEDGER_INFO_URL,
|
||||||
|
HttpMethod.POST,
|
||||||
|
requestEntity,
|
||||||
|
new ParameterizedTypeReference<Envelope<LedgerResponse>>() {}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (responseEntity.getStatusCode() == HttpStatus.OK && responseEntity.getBody() != null) {
|
||||||
|
List<LedgerResponse> data = responseEntity.getBody().getData();
|
||||||
|
if (data != null && !data.isEmpty()) {
|
||||||
|
return data.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.warn("자동차 등록원부 조회 응답이 비어있음 - 차량번호: {}", vehicleNumber);
|
||||||
|
return null;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("자동차 등록원부 조회 API 호출 실패 - 차량번호: {}", vehicleNumber, e);
|
||||||
|
throw new RuntimeException("자동차 등록원부 조회 실패: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package go.kr.project.api.external.service;
|
package go.kr.project.api.external.service.impl;
|
||||||
|
|
||||||
import go.kr.project.api.VehicleInfoService;
|
import go.kr.project.api.external.service.ExternalVehicleApiService;
|
||||||
|
import go.kr.project.api.external.service.VehicleInfoService;
|
||||||
import go.kr.project.api.model.VehicleApiResponseVO;
|
import go.kr.project.api.model.VehicleApiResponseVO;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -1,56 +1,25 @@
|
|||||||
package go.kr.project.api.internal.service;
|
package go.kr.project.api.internal.service;
|
||||||
|
|
||||||
import go.kr.project.api.internal.mapper.VmisCarBassMatterInqireMapper;
|
|
||||||
import go.kr.project.api.model.response.VmisCarBassMatterInqireVO;
|
import go.kr.project.api.model.response.VmisCarBassMatterInqireVO;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 자동차 기본사항 조회 로그 전용 서비스.
|
* 자동차 기본사항 조회 로그 전용 서비스 인터페이스
|
||||||
*
|
*
|
||||||
* <p>로그 적재만 별도 트랜잭션(REQUIRES_NEW)으로 처리하여,
|
* <p>로그 적재만 별도 트랜잭션(REQUIRES_NEW)으로 처리하여,
|
||||||
* 외부 호출 실패나 상위 트랜잭션 롤백 상황에서도 로그는 영속화되도록 보장한다.</p>
|
* 외부 호출 실패나 상위 트랜잭션 롤백 상황에서도 로그는 영속화되도록 보장한다.</p>
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
public interface VmisCarBassMatterInqireLogService {
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class VmisCarBassMatterInqireLogService {
|
|
||||||
|
|
||||||
private final VmisCarBassMatterInqireMapper carBassMatterInqireMapper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 최초 API 요청 정보를 등록한다. (REQUIRES_NEW)
|
* 최초 API 요청 정보를 등록한다. (REQUIRES_NEW)
|
||||||
* @param request 요청 정보
|
* @param request 요청 정보
|
||||||
* @return 생성된 ID
|
* @return 생성된 ID
|
||||||
*/
|
*/
|
||||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
String createInitialRequestNewTx(VmisCarBassMatterInqireVO request);
|
||||||
public String createInitialRequestNewTx(VmisCarBassMatterInqireVO request) {
|
|
||||||
String generatedId = carBassMatterInqireMapper.selectNextCarBassMatterInqireId();
|
|
||||||
request.setCarBassMatterInqire(generatedId);
|
|
||||||
int result = carBassMatterInqireMapper.insertCarBassMatterInqire(request);
|
|
||||||
if (result != 1) {
|
|
||||||
throw new RuntimeException("자동차 기본 사항 조회 정보 등록 실패");
|
|
||||||
}
|
|
||||||
log.info("[BASIC-REQ-LOG] 요청 정보 저장 완료(별도TX) - ID: {}, 차량번호: {}", generatedId, request.getDmndVhrno());
|
|
||||||
return generatedId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 응답/에러 결과를 업데이트한다. (REQUIRES_NEW)
|
* 응답/에러 결과를 업데이트한다. (REQUIRES_NEW)
|
||||||
* @param response 업데이트 내용
|
* @param response 업데이트 내용
|
||||||
*/
|
*/
|
||||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
void updateResponseNewTx(VmisCarBassMatterInqireVO response);
|
||||||
public void updateResponseNewTx(VmisCarBassMatterInqireVO response) {
|
|
||||||
if (response.getCarBassMatterInqire() == null) {
|
|
||||||
throw new IllegalArgumentException("자동차 기본 사항 조회 ID는 필수입니다.");
|
|
||||||
}
|
|
||||||
int result = carBassMatterInqireMapper.updateCarBassMatterInqire(response);
|
|
||||||
if (result != 1) {
|
|
||||||
throw new RuntimeException("자동차 기본 사항 조회 정보 업데이트 실패 - ID: " + response.getCarBassMatterInqire());
|
|
||||||
}
|
|
||||||
log.info("[BASIC-RES-LOG] 응답/에러 정보 저장 완료(별도TX) - ID: {}, 결과코드: {}", response.getCarBassMatterInqire(), response.getCntcResultCode());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,87 +1,28 @@
|
|||||||
package go.kr.project.api.internal.service;
|
package go.kr.project.api.internal.service;
|
||||||
|
|
||||||
import go.kr.project.api.internal.client.GovernmentApi;
|
|
||||||
import go.kr.project.api.config.ApiConstant;
|
|
||||||
import go.kr.project.api.internal.util.ExceptionDetailUtil;
|
|
||||||
import go.kr.project.api.model.request.BasicRequest;
|
import go.kr.project.api.model.request.BasicRequest;
|
||||||
import go.kr.project.api.model.response.BasicResponse;
|
import go.kr.project.api.model.response.BasicResponse;
|
||||||
import go.kr.project.api.model.response.VmisCarBassMatterInqireVO;
|
|
||||||
import go.kr.project.api.model.Envelope;
|
import go.kr.project.api.model.Envelope;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 자동차 기본 사항 조회 서비스
|
* 자동차 기본사항 조회 서비스 인터페이스
|
||||||
*
|
*
|
||||||
* <p>API 호출 정보를 관리하는 서비스 클래스입니다.</p>
|
* <p>API 호출 정보를 관리하는 서비스입니다.</p>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>최초 요청: createInitialRequest() - 시퀀스로 ID 생성 후 INSERT</li>
|
* <li>요청 데이터 보강</li>
|
||||||
* <li>결과 업데이트: updateResponse() - 응답 데이터 UPDATE</li>
|
* <li>최초 요청 로그 저장</li>
|
||||||
|
* <li>외부 API 호출</li>
|
||||||
|
* <li>응답 로그 업데이트</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
public interface VmisCarBassMatterInqireService {
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class VmisCarBassMatterInqireService {
|
|
||||||
|
|
||||||
private final GovernmentApi governmentApi;
|
|
||||||
private final VmisRequestEnricher enricher;
|
|
||||||
private final VmisCarBassMatterInqireLogService logService;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 자동차 기본사항 조회: 보강 -> 최초요청로그 -> 외부호출 -> 응답로그.
|
* 자동차 기본사항 조회
|
||||||
|
*
|
||||||
|
* @param envelope 요청 Envelope
|
||||||
|
* @return 응답 Envelope
|
||||||
*/
|
*/
|
||||||
@Transactional
|
ResponseEntity<Envelope<BasicResponse>> basic(Envelope<BasicRequest> envelope);
|
||||||
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);
|
|
||||||
VmisCarBassMatterInqireVO logEntity = VmisCarBassMatterInqireVO.fromRequest(req);
|
|
||||||
generatedId = logService.createInitialRequestNewTx(logEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3) 외부 API 호출
|
|
||||||
ResponseEntity<Envelope<BasicResponse>> response = governmentApi.callBasic(envelope);
|
|
||||||
|
|
||||||
// 4) 응답 로그 업데이트
|
|
||||||
// 원본 소스, 정상적인 호출, 리턴(에러 리턴포함) 일 경우에만 에러 로그 남김
|
|
||||||
if (generatedId != null && response.getBody() != null) {
|
|
||||||
VmisCarBassMatterInqireVO update = VmisCarBassMatterInqireVO.fromResponse(generatedId, response.getBody());
|
|
||||||
if (update != null) {
|
|
||||||
logService.updateResponseNewTx(update);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
} catch (Exception e) {
|
|
||||||
// 5) 오류 로그 업데이트
|
|
||||||
if (generatedId != null) {
|
|
||||||
try {
|
|
||||||
String detail = ExceptionDetailUtil.buildForLog(e);
|
|
||||||
VmisCarBassMatterInqireVO errorLog = VmisCarBassMatterInqireVO.builder()
|
|
||||||
.carBassMatterInqire(generatedId) // 자동차기본사항조회 ID (PK)
|
|
||||||
.cntcResultCode(ApiConstant.CNTC_RESULT_CODE_ERROR) // 연계결과코드 (에러)
|
|
||||||
.cntcResultDtls(detail) // 연계결과상세 (에러 메시지)
|
|
||||||
.build();
|
|
||||||
logService.updateResponseNewTx(errorLog);
|
|
||||||
log.error("[BASIC-ERR-LOG] API 호출 에러 정보 저장 완료(별도TX) - ID: {}, detail: {}", generatedId, detail, e);
|
|
||||||
} catch (Exception ignore) {
|
|
||||||
log.error("[BASIC-ERR-LOG] 에러 로그 저장 실패 - ID: {}", generatedId, ignore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,61 +1,33 @@
|
|||||||
package go.kr.project.api.internal.service;
|
package go.kr.project.api.internal.service;
|
||||||
|
|
||||||
import go.kr.project.api.internal.mapper.VmisCarLedgerFrmbkMapper;
|
|
||||||
import go.kr.project.api.model.response.VmisCarLedgerFrmbkDtlVO;
|
import go.kr.project.api.model.response.VmisCarLedgerFrmbkDtlVO;
|
||||||
import go.kr.project.api.model.response.VmisCarLedgerFrmbkVO;
|
import go.kr.project.api.model.response.VmisCarLedgerFrmbkVO;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 자동차 등록 원부(갑) 로그 전용 서비스.
|
* 자동차 등록 원부(갑) 로그 전용 서비스 인터페이스
|
||||||
* - 모든 로깅(write)은 별도 트랜잭션(REQUIRES_NEW)으로 수행하여 상위 트랜잭션 롤백의 영향을 받지 않도록 한다.
|
* - 모든 로깅(write)은 별도 트랜잭션(REQUIRES_NEW)으로 수행하여 상위 트랜잭션 롤백의 영향을 받지 않도록 한다.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
public interface VmisCarLedgerFrmbkLogService {
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class VmisCarLedgerFrmbkLogService {
|
|
||||||
|
|
||||||
private final VmisCarLedgerFrmbkMapper mapper;
|
/**
|
||||||
|
* 최초 요청 정보를 등록한다. (REQUIRES_NEW)
|
||||||
|
* @param request 요청 정보
|
||||||
|
* @return 생성된 ID
|
||||||
|
*/
|
||||||
|
String createInitialRequestNewTx(VmisCarLedgerFrmbkVO request);
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
/**
|
||||||
public String createInitialRequestNewTx(VmisCarLedgerFrmbkVO request) {
|
* 응답 결과를 업데이트한다. (REQUIRES_NEW)
|
||||||
String id = mapper.selectNextCarLedgerFrmbkId();
|
* @param response 업데이트 내용
|
||||||
request.setCarLedgerFrmbkId(id);
|
*/
|
||||||
int result = mapper.insertCarLedgerFrmbk(request);
|
void updateResponseNewTx(VmisCarLedgerFrmbkVO response);
|
||||||
if (result != 1) {
|
|
||||||
throw new RuntimeException("자동차 등록 원부(갑) 최초요청 등록 실패");
|
|
||||||
}
|
|
||||||
log.info("[LEDGER-REQ-LOG] 최초 요청 저장(별도TX) - ID: {}, 차량번호: {}", id, request.getDmndVhrno());
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
/**
|
||||||
public void updateResponseNewTx(VmisCarLedgerFrmbkVO response) {
|
* 상세 정보를 저장한다. (REQUIRES_NEW)
|
||||||
if (response.getCarLedgerFrmbkId() == null) {
|
* @param masterId 마스터 ID
|
||||||
throw new IllegalArgumentException("자동차 등록 원부(갑) ID는 필수입니다.");
|
* @param details 상세 정보 리스트
|
||||||
}
|
*/
|
||||||
int updated = mapper.updateCarLedgerFrmbk(response);
|
void saveDetailsNewTx(String masterId, List<VmisCarLedgerFrmbkDtlVO> details);
|
||||||
if (updated != 1) {
|
|
||||||
throw new RuntimeException("자동차 등록 원부(갑) 정보 업데이트 실패 - ID: " + response.getCarLedgerFrmbkId());
|
|
||||||
}
|
|
||||||
log.info("[LEDGER-RES-LOG] 마스터 응답 업데이트(별도TX) - ID: {}, 결과코드: {}",
|
|
||||||
response.getCarLedgerFrmbkId(), response.getCntcResultCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
|
||||||
public void saveDetailsNewTx(String masterId, List<VmisCarLedgerFrmbkDtlVO> details) {
|
|
||||||
if (details == null || details.isEmpty()) return;
|
|
||||||
for (VmisCarLedgerFrmbkDtlVO dtl : details) {
|
|
||||||
String dtlId = mapper.selectNextCarLedgerFrmbkDtlId();
|
|
||||||
dtl.setCarLedgerFrmbkDtlId(dtlId);
|
|
||||||
dtl.setCarLedgerFrmbkId(masterId);
|
|
||||||
mapper.insertCarLedgerFrmbkDtl(dtl);
|
|
||||||
}
|
|
||||||
log.info("[LEDGER-RES-LOG] 상세 {}건 저장(별도TX) - ID: {}", details.size(), masterId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,85 +1,21 @@
|
|||||||
package go.kr.project.api.internal.service;
|
package go.kr.project.api.internal.service;
|
||||||
|
|
||||||
import go.kr.project.api.internal.client.GovernmentApi;
|
|
||||||
import go.kr.project.api.config.ApiConstant;
|
|
||||||
import go.kr.project.api.model.Envelope;
|
import go.kr.project.api.model.Envelope;
|
||||||
import go.kr.project.api.model.response.VmisCarLedgerFrmbkDtlVO;
|
|
||||||
import go.kr.project.api.model.response.VmisCarLedgerFrmbkVO;
|
|
||||||
import go.kr.project.api.model.request.LedgerRequest;
|
import go.kr.project.api.model.request.LedgerRequest;
|
||||||
import go.kr.project.api.model.response.LedgerResponse;
|
import go.kr.project.api.model.response.LedgerResponse;
|
||||||
import go.kr.project.api.internal.util.ExceptionDetailUtil;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 자동차 등록 원부(갑) 서비스 (오케스트레이션)
|
* 자동차 등록 원부(갑) 서비스 인터페이스
|
||||||
* - 요청 보강, 외부 API 호출, 로그 서비스 위임
|
* - 요청 보강, 외부 API 호출, 로그 서비스 위임
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
public interface VmisCarLedgerFrmbkService {
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class VmisCarLedgerFrmbkService {
|
|
||||||
|
|
||||||
private final GovernmentApi governmentApi;
|
|
||||||
private final VmisRequestEnricher enricher;
|
|
||||||
private final VmisCarLedgerFrmbkLogService logService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 자동차 등록원부(갑) 조회: 보강 -> 최초요청로그(별도TX) -> 외부호출 -> 응답로그(마스터/상세, 별도TX) -> 오류 시 에러로그(별도TX).
|
* 자동차 등록원부(갑) 조회
|
||||||
|
*
|
||||||
|
* @param envelope 요청 Envelope
|
||||||
|
* @return 응답 Envelope
|
||||||
*/
|
*/
|
||||||
@Transactional
|
ResponseEntity<Envelope<LedgerResponse>> ledger(Envelope<LedgerRequest> envelope);
|
||||||
public ResponseEntity<Envelope<LedgerResponse>> ledger(Envelope<LedgerRequest> envelope) {
|
|
||||||
// 1) 요청 보강
|
|
||||||
enricher.enrichLedger(envelope);
|
|
||||||
|
|
||||||
String generatedId = null;
|
|
||||||
try {
|
|
||||||
// 2) 최초 요청 로그 저장 (첫 번째 데이터 기준)
|
|
||||||
if (envelope.getData() != null && !envelope.getData().isEmpty()) {
|
|
||||||
LedgerRequest req = envelope.getData().get(0);
|
|
||||||
VmisCarLedgerFrmbkVO init = VmisCarLedgerFrmbkVO.fromRequest(req);
|
|
||||||
generatedId = logService.createInitialRequestNewTx(init);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3) 외부 API 호출
|
|
||||||
ResponseEntity<Envelope<LedgerResponse>> response = governmentApi.callLedger(envelope);
|
|
||||||
|
|
||||||
// 4) 응답 로그 업데이트 (마스터 + 상세)
|
|
||||||
if (generatedId != null && response.getBody() != null &&
|
|
||||||
response.getBody().getData() != null && !response.getBody().getData().isEmpty()) {
|
|
||||||
LedgerResponse body = response.getBody().getData().get(0);
|
|
||||||
VmisCarLedgerFrmbkVO masterUpdate = VmisCarLedgerFrmbkVO.fromResponseMaster(generatedId, body);
|
|
||||||
logService.updateResponseNewTx(masterUpdate);
|
|
||||||
|
|
||||||
List<VmisCarLedgerFrmbkDtlVO> details = VmisCarLedgerFrmbkDtlVO.listFromResponse(body, generatedId);
|
|
||||||
if (details != null && !details.isEmpty()) {
|
|
||||||
logService.saveDetailsNewTx(generatedId, details);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
} catch (Exception e) {
|
|
||||||
// 5) 오류 로그 업데이트
|
|
||||||
if (generatedId != null) {
|
|
||||||
try {
|
|
||||||
String detail = ExceptionDetailUtil.buildForLog(e);
|
|
||||||
VmisCarLedgerFrmbkVO errorLog = VmisCarLedgerFrmbkVO.builder()
|
|
||||||
.carLedgerFrmbkId(generatedId)
|
|
||||||
.cntcResultCode(ApiConstant.CNTC_RESULT_CODE_ERROR)
|
|
||||||
.cntcResultDtls(detail)
|
|
||||||
.build();
|
|
||||||
logService.updateResponseNewTx(errorLog);
|
|
||||||
log.error("[LEDGER-ERR-LOG] API 호출 에러 정보 저장 완료(별도TX) - ID: {}, detail: {}", generatedId, detail, e);
|
|
||||||
} catch (Exception ignore) {
|
|
||||||
log.error("[LEDGER-ERR-LOG] 에러 로그 저장 실패 - ID: {}", generatedId, ignore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package go.kr.project.api.internal.service;
|
package go.kr.project.api.internal.service.impl;
|
||||||
|
|
||||||
import go.kr.project.api.VehicleInfoService;
|
import go.kr.project.api.external.service.VehicleInfoService;
|
||||||
|
import go.kr.project.api.internal.service.VmisCarBassMatterInqireService;
|
||||||
|
import go.kr.project.api.internal.service.VmisCarLedgerFrmbkService;
|
||||||
import go.kr.project.api.model.VehicleApiResponseVO;
|
import go.kr.project.api.model.VehicleApiResponseVO;
|
||||||
import go.kr.project.api.model.request.BasicRequest;
|
import go.kr.project.api.model.request.BasicRequest;
|
||||||
import go.kr.project.api.model.response.BasicResponse;
|
import go.kr.project.api.model.response.BasicResponse;
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
package go.kr.project.api.internal.service.impl;
|
||||||
|
|
||||||
|
import go.kr.project.api.internal.mapper.VmisCarBassMatterInqireMapper;
|
||||||
|
import go.kr.project.api.internal.service.VmisCarBassMatterInqireLogService;
|
||||||
|
import go.kr.project.api.model.response.VmisCarBassMatterInqireVO;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 자동차 기본사항 조회 로그 전용 서비스 구현체
|
||||||
|
*
|
||||||
|
* <p>로그 적재만 별도 트랜잭션(REQUIRES_NEW)으로 처리하여,
|
||||||
|
* 외부 호출 실패나 상위 트랜잭션 롤백 상황에서도 로그는 영속화되도록 보장한다.</p>
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class VmisCarBassMatterInqireLogServiceImpl implements VmisCarBassMatterInqireLogService {
|
||||||
|
|
||||||
|
private final VmisCarBassMatterInqireMapper carBassMatterInqireMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 최초 API 요청 정보를 등록한다. (REQUIRES_NEW)
|
||||||
|
* @param request 요청 정보
|
||||||
|
* @return 생성된 ID
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
|
public String createInitialRequestNewTx(VmisCarBassMatterInqireVO request) {
|
||||||
|
String generatedId = carBassMatterInqireMapper.selectNextCarBassMatterInqireId();
|
||||||
|
request.setCarBassMatterInqire(generatedId);
|
||||||
|
int result = carBassMatterInqireMapper.insertCarBassMatterInqire(request);
|
||||||
|
if (result != 1) {
|
||||||
|
throw new RuntimeException("자동차 기본 사항 조회 정보 등록 실패");
|
||||||
|
}
|
||||||
|
log.info("[BASIC-REQ-LOG] 요청 정보 저장 완료(별도TX) - ID: {}, 차량번호: {}", generatedId, request.getDmndVhrno());
|
||||||
|
return generatedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 응답/에러 결과를 업데이트한다. (REQUIRES_NEW)
|
||||||
|
* @param response 업데이트 내용
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
|
public void updateResponseNewTx(VmisCarBassMatterInqireVO response) {
|
||||||
|
if (response.getCarBassMatterInqire() == null) {
|
||||||
|
throw new IllegalArgumentException("자동차 기본 사항 조회 ID는 필수입니다.");
|
||||||
|
}
|
||||||
|
int result = carBassMatterInqireMapper.updateCarBassMatterInqire(response);
|
||||||
|
if (result != 1) {
|
||||||
|
throw new RuntimeException("자동차 기본 사항 조회 정보 업데이트 실패 - ID: " + response.getCarBassMatterInqire());
|
||||||
|
}
|
||||||
|
log.info("[BASIC-RES-LOG] 응답/에러 정보 저장 완료(별도TX) - ID: {}, 결과코드: {}", response.getCarBassMatterInqire(), response.getCntcResultCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
package go.kr.project.api.internal.service.impl;
|
||||||
|
|
||||||
|
import go.kr.project.api.internal.client.GovernmentApi;
|
||||||
|
import go.kr.project.api.config.ApiConstant;
|
||||||
|
import go.kr.project.api.internal.service.VmisCarBassMatterInqireLogService;
|
||||||
|
import go.kr.project.api.internal.service.VmisCarBassMatterInqireService;
|
||||||
|
import go.kr.project.api.internal.service.VmisRequestEnricher;
|
||||||
|
import go.kr.project.api.internal.util.ExceptionDetailUtil;
|
||||||
|
import go.kr.project.api.model.request.BasicRequest;
|
||||||
|
import go.kr.project.api.model.response.BasicResponse;
|
||||||
|
import go.kr.project.api.model.response.VmisCarBassMatterInqireVO;
|
||||||
|
import go.kr.project.api.model.Envelope;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 자동차 기본 사항 조회 서비스 구현체
|
||||||
|
*
|
||||||
|
* <p>API 호출 정보를 관리하는 서비스 클래스입니다.</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>최초 요청: createInitialRequest() - 시퀀스로 ID 생성 후 INSERT</li>
|
||||||
|
* <li>결과 업데이트: updateResponse() - 응답 데이터 UPDATE</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class VmisCarBassMatterInqireServiceImpl implements VmisCarBassMatterInqireService {
|
||||||
|
|
||||||
|
private final GovernmentApi governmentApi;
|
||||||
|
private final VmisRequestEnricher enricher;
|
||||||
|
private final VmisCarBassMatterInqireLogService logService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 자동차 기본사항 조회: 보강 -> 최초요청로그 -> 외부호출 -> 응답로그.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@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);
|
||||||
|
VmisCarBassMatterInqireVO logEntity = VmisCarBassMatterInqireVO.fromRequest(req);
|
||||||
|
generatedId = logService.createInitialRequestNewTx(logEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) 외부 API 호출
|
||||||
|
ResponseEntity<Envelope<BasicResponse>> response = governmentApi.callBasic(envelope);
|
||||||
|
|
||||||
|
// 4) 응답 로그 업데이트
|
||||||
|
// 원본 소스, 정상적인 호출, 리턴(에러 리턴포함) 일 경우에만 에러 로그 남김
|
||||||
|
if (generatedId != null && response.getBody() != null) {
|
||||||
|
VmisCarBassMatterInqireVO update = VmisCarBassMatterInqireVO.fromResponse(generatedId, response.getBody());
|
||||||
|
if (update != null) {
|
||||||
|
logService.updateResponseNewTx(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 5) 오류 로그 업데이트
|
||||||
|
if (generatedId != null) {
|
||||||
|
try {
|
||||||
|
String detail = ExceptionDetailUtil.buildForLog(e);
|
||||||
|
VmisCarBassMatterInqireVO errorLog = VmisCarBassMatterInqireVO.builder()
|
||||||
|
.carBassMatterInqire(generatedId) // 자동차기본사항조회 ID (PK)
|
||||||
|
.cntcResultCode(ApiConstant.CNTC_RESULT_CODE_ERROR) // 연계결과코드 (에러)
|
||||||
|
.cntcResultDtls(detail) // 연계결과상세 (에러 메시지)
|
||||||
|
.build();
|
||||||
|
logService.updateResponseNewTx(errorLog);
|
||||||
|
log.error("[BASIC-ERR-LOG] API 호출 에러 정보 저장 완료(별도TX) - ID: {}, detail: {}", generatedId, detail, e);
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
log.error("[BASIC-ERR-LOG] 에러 로그 저장 실패 - ID: {}", generatedId, ignore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
package go.kr.project.api.internal.service.impl;
|
||||||
|
|
||||||
|
import go.kr.project.api.internal.mapper.VmisCarLedgerFrmbkMapper;
|
||||||
|
import go.kr.project.api.internal.service.VmisCarLedgerFrmbkLogService;
|
||||||
|
import go.kr.project.api.model.response.VmisCarLedgerFrmbkDtlVO;
|
||||||
|
import go.kr.project.api.model.response.VmisCarLedgerFrmbkVO;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 자동차 등록 원부(갑) 로그 전용 서비스 구현체
|
||||||
|
* - 모든 로깅(write)은 별도 트랜잭션(REQUIRES_NEW)으로 수행하여 상위 트랜잭션 롤백의 영향을 받지 않도록 한다.
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class VmisCarLedgerFrmbkLogServiceImpl implements VmisCarLedgerFrmbkLogService {
|
||||||
|
|
||||||
|
private final VmisCarLedgerFrmbkMapper mapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
|
public String createInitialRequestNewTx(VmisCarLedgerFrmbkVO request) {
|
||||||
|
String id = mapper.selectNextCarLedgerFrmbkId();
|
||||||
|
request.setCarLedgerFrmbkId(id);
|
||||||
|
int result = mapper.insertCarLedgerFrmbk(request);
|
||||||
|
if (result != 1) {
|
||||||
|
throw new RuntimeException("자동차 등록 원부(갑) 최초요청 등록 실패");
|
||||||
|
}
|
||||||
|
log.info("[LEDGER-REQ-LOG] 최초 요청 저장(별도TX) - ID: {}, 차량번호: {}", id, request.getDmndVhrno());
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
|
public void updateResponseNewTx(VmisCarLedgerFrmbkVO response) {
|
||||||
|
if (response.getCarLedgerFrmbkId() == null) {
|
||||||
|
throw new IllegalArgumentException("자동차 등록 원부(갑) ID는 필수입니다.");
|
||||||
|
}
|
||||||
|
int updated = mapper.updateCarLedgerFrmbk(response);
|
||||||
|
if (updated != 1) {
|
||||||
|
throw new RuntimeException("자동차 등록 원부(갑) 정보 업데이트 실패 - ID: " + response.getCarLedgerFrmbkId());
|
||||||
|
}
|
||||||
|
log.info("[LEDGER-RES-LOG] 마스터 응답 업데이트(별도TX) - ID: {}, 결과코드: {}",
|
||||||
|
response.getCarLedgerFrmbkId(), response.getCntcResultCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
|
public void saveDetailsNewTx(String masterId, List<VmisCarLedgerFrmbkDtlVO> details) {
|
||||||
|
if (details == null || details.isEmpty()) return;
|
||||||
|
for (VmisCarLedgerFrmbkDtlVO dtl : details) {
|
||||||
|
String dtlId = mapper.selectNextCarLedgerFrmbkDtlId();
|
||||||
|
dtl.setCarLedgerFrmbkDtlId(dtlId);
|
||||||
|
dtl.setCarLedgerFrmbkId(masterId);
|
||||||
|
mapper.insertCarLedgerFrmbkDtl(dtl);
|
||||||
|
}
|
||||||
|
log.info("[LEDGER-RES-LOG] 상세 {}건 저장(별도TX) - ID: {}", details.size(), masterId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
package go.kr.project.api.internal.service.impl;
|
||||||
|
|
||||||
|
import go.kr.project.api.internal.client.GovernmentApi;
|
||||||
|
import go.kr.project.api.config.ApiConstant;
|
||||||
|
import go.kr.project.api.internal.service.VmisCarLedgerFrmbkLogService;
|
||||||
|
import go.kr.project.api.internal.service.VmisCarLedgerFrmbkService;
|
||||||
|
import go.kr.project.api.internal.service.VmisRequestEnricher;
|
||||||
|
import go.kr.project.api.model.Envelope;
|
||||||
|
import go.kr.project.api.model.response.VmisCarLedgerFrmbkDtlVO;
|
||||||
|
import go.kr.project.api.model.response.VmisCarLedgerFrmbkVO;
|
||||||
|
import go.kr.project.api.model.request.LedgerRequest;
|
||||||
|
import go.kr.project.api.model.response.LedgerResponse;
|
||||||
|
import go.kr.project.api.internal.util.ExceptionDetailUtil;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 자동차 등록 원부(갑) 서비스 구현체 (오케스트레이션)
|
||||||
|
* - 요청 보강, 외부 API 호출, 로그 서비스 위임
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class VmisCarLedgerFrmbkServiceImpl implements VmisCarLedgerFrmbkService {
|
||||||
|
|
||||||
|
private final GovernmentApi governmentApi;
|
||||||
|
private final VmisRequestEnricher enricher;
|
||||||
|
private final VmisCarLedgerFrmbkLogService logService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 자동차 등록원부(갑) 조회: 보강 -> 최초요청로그(별도TX) -> 외부호출 -> 응답로그(마스터/상세, 별도TX) -> 오류 시 에러로그(별도TX).
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public ResponseEntity<Envelope<LedgerResponse>> ledger(Envelope<LedgerRequest> envelope) {
|
||||||
|
// 1) 요청 보강
|
||||||
|
enricher.enrichLedger(envelope);
|
||||||
|
|
||||||
|
String generatedId = null;
|
||||||
|
try {
|
||||||
|
// 2) 최초 요청 로그 저장 (첫 번째 데이터 기준)
|
||||||
|
if (envelope.getData() != null && !envelope.getData().isEmpty()) {
|
||||||
|
LedgerRequest req = envelope.getData().get(0);
|
||||||
|
VmisCarLedgerFrmbkVO init = VmisCarLedgerFrmbkVO.fromRequest(req);
|
||||||
|
generatedId = logService.createInitialRequestNewTx(init);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) 외부 API 호출
|
||||||
|
ResponseEntity<Envelope<LedgerResponse>> response = governmentApi.callLedger(envelope);
|
||||||
|
|
||||||
|
// 4) 응답 로그 업데이트 (마스터 + 상세)
|
||||||
|
if (generatedId != null && response.getBody() != null &&
|
||||||
|
response.getBody().getData() != null && !response.getBody().getData().isEmpty()) {
|
||||||
|
LedgerResponse body = response.getBody().getData().get(0);
|
||||||
|
VmisCarLedgerFrmbkVO masterUpdate = VmisCarLedgerFrmbkVO.fromResponseMaster(generatedId, body);
|
||||||
|
logService.updateResponseNewTx(masterUpdate);
|
||||||
|
|
||||||
|
List<VmisCarLedgerFrmbkDtlVO> details = VmisCarLedgerFrmbkDtlVO.listFromResponse(body, generatedId);
|
||||||
|
if (details != null && !details.isEmpty()) {
|
||||||
|
logService.saveDetailsNewTx(generatedId, details);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 5) 오류 로그 업데이트
|
||||||
|
if (generatedId != null) {
|
||||||
|
try {
|
||||||
|
String detail = ExceptionDetailUtil.buildForLog(e);
|
||||||
|
VmisCarLedgerFrmbkVO errorLog = VmisCarLedgerFrmbkVO.builder()
|
||||||
|
.carLedgerFrmbkId(generatedId)
|
||||||
|
.cntcResultCode(ApiConstant.CNTC_RESULT_CODE_ERROR)
|
||||||
|
.cntcResultDtls(detail)
|
||||||
|
.build();
|
||||||
|
logService.updateResponseNewTx(errorLog);
|
||||||
|
log.error("[LEDGER-ERR-LOG] API 호출 에러 정보 저장 완료(별도TX) - ID: {}, detail: {}", generatedId, detail, e);
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
log.error("[LEDGER-ERR-LOG] 에러 로그 저장 실패 - ID: {}", generatedId, ignore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue