전체 구성 수정중...
parent
2459e07a3f
commit
8eeee86a46
@ -1,36 +0,0 @@
|
||||
package go.kr.project.carInspectionPenalty.registration.comparison;
|
||||
|
||||
import go.kr.project.api.model.VehicleApiResponseVO;
|
||||
import go.kr.project.carInspectionPenalty.registration.model.CarFfnlgTrgtVO;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 비교 로직 실행에 필요한 컨텍스트 정보
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
public class ComparisonContext {
|
||||
|
||||
/**
|
||||
* 기존 과태료 대상 데이터
|
||||
*/
|
||||
private final CarFfnlgTrgtVO existingData;
|
||||
|
||||
/**
|
||||
* API 응답 데이터
|
||||
*/
|
||||
private final VehicleApiResponseVO apiResponse;
|
||||
|
||||
/**
|
||||
* 등록자 (사용자 ID)
|
||||
*/
|
||||
private final String userId;
|
||||
|
||||
/**
|
||||
* 차량번호 (편의성을 위해 추가)
|
||||
*/
|
||||
public String getVhclno() {
|
||||
return existingData != null ? existingData.getVhclno() : null;
|
||||
}
|
||||
}
|
||||
@ -1,50 +0,0 @@
|
||||
package go.kr.project.carInspectionPenalty.registration.comparison;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 비교 로직 실행 결과
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
public class ComparisonResult {
|
||||
|
||||
/**
|
||||
* 비교 로직이 적용되었는지 여부
|
||||
* true: 이 규칙이 적용되어 처리됨 (다음 규칙 실행 중단)
|
||||
* false: 이 규칙에 해당하지 않음 (다음 규칙 계속 실행)
|
||||
*/
|
||||
private final boolean applied;
|
||||
|
||||
/**
|
||||
* 처리 상태 코드
|
||||
* 02=상품용, 03=이첩, 04=내사종결 등
|
||||
*/
|
||||
private final String statusCode;
|
||||
|
||||
/**
|
||||
* 처리 결과 메시지
|
||||
*/
|
||||
private final String message;
|
||||
|
||||
/**
|
||||
* 비교 로직에 해당하지 않는 경우의 결과 생성
|
||||
*/
|
||||
public static ComparisonResult notApplied() {
|
||||
return ComparisonResult.builder()
|
||||
.applied(false)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 비교 로직이 적용된 경우의 결과 생성
|
||||
*/
|
||||
public static ComparisonResult applied(String statusCode, String message) {
|
||||
return ComparisonResult.builder()
|
||||
.applied(true)
|
||||
.statusCode(statusCode)
|
||||
.message(message)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
package go.kr.project.carInspectionPenalty.registration.comparison;
|
||||
|
||||
/**
|
||||
* 과태료 대상 비교 규칙 인터페이스
|
||||
*
|
||||
* <p>Chain of Responsibility 패턴을 사용하여 여러 비교 규칙을 순차적으로 실행합니다.</p>
|
||||
*
|
||||
* <p>각 규칙은 다음 순서로 동작합니다:</p>
|
||||
* <ol>
|
||||
* <li>비교 로직 실행</li>
|
||||
* <li>해당 규칙에 적용되면 DB 업데이트 후 ComparisonResult.applied() 반환</li>
|
||||
* <li>해당 규칙에 적용되지 않으면 ComparisonResult.notApplied() 반환</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>규칙이 applied=true를 반환하면 체인 실행이 중단되고, false를 반환하면 다음 규칙이 실행됩니다.</p>
|
||||
*/
|
||||
public interface ComparisonRule {
|
||||
|
||||
/**
|
||||
* 비교 규칙을 실행합니다.
|
||||
*
|
||||
* @param context 비교에 필요한 컨텍스트 정보
|
||||
* @return 비교 결과 (applied=true면 체인 중단, false면 다음 규칙 실행)
|
||||
*/
|
||||
ComparisonResult execute(ComparisonContext context);
|
||||
|
||||
/**
|
||||
* 규칙의 이름을 반환합니다. (로깅 및 디버깅용)
|
||||
*
|
||||
* @return 규칙 이름
|
||||
*/
|
||||
String getRuleName();
|
||||
|
||||
/**
|
||||
* 규칙의 실행 순서를 반환합니다. (낮을수록 먼저 실행)
|
||||
*
|
||||
* @return 실행 순서 (기본값: 100)
|
||||
*/
|
||||
default int getOrder() {
|
||||
return 100;
|
||||
}
|
||||
}
|
||||
@ -1,90 +0,0 @@
|
||||
package go.kr.project.carInspectionPenalty.registration.comparison;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 비교 규칙 프로세서
|
||||
*
|
||||
* <p>여러 비교 규칙을 순차적으로 실행하고 결과를 반환합니다.</p>
|
||||
*
|
||||
* <p>실행 방식:</p>
|
||||
* <ol>
|
||||
* <li>모든 규칙을 getOrder() 순서대로 정렬</li>
|
||||
* <li>순서대로 각 규칙 실행</li>
|
||||
* <li>규칙이 applied=true를 반환하면 즉시 중단</li>
|
||||
* <li>모든 규칙이 applied=false를 반환하면 null 반환</li>
|
||||
* </ol>
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ComparisonRuleProcessor {
|
||||
|
||||
private final List<ComparisonRule> rules;
|
||||
|
||||
/**
|
||||
* 생성자 주입으로 모든 ComparisonRule 빈을 자동으로 주입받습니다.
|
||||
* Spring이 자동으로 모든 ComparisonRule 구현체를 찾아서 리스트로 주입합니다.
|
||||
*/
|
||||
public ComparisonRuleProcessor(List<ComparisonRule> rules) {
|
||||
// getOrder() 순서대로 정렬
|
||||
this.rules = rules.stream()
|
||||
.sorted(Comparator.comparingInt(ComparisonRule::getOrder))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.info("========== 비교 규칙 프로세서 초기화 ==========");
|
||||
log.info("등록된 규칙 개수: {}", this.rules.size());
|
||||
this.rules.forEach(rule ->
|
||||
log.info(" - [순서: {}] {}", rule.getOrder(), rule.getRuleName())
|
||||
);
|
||||
log.info("============================================");
|
||||
}
|
||||
|
||||
/**
|
||||
* 모든 비교 규칙을 순차적으로 실행합니다.
|
||||
*
|
||||
* @param context 비교 컨텍스트
|
||||
* @return 처리 결과 (적용된 규칙이 없으면 null)
|
||||
*/
|
||||
public ComparisonResult process(ComparisonContext context) {
|
||||
String vhclno = context.getVhclno();
|
||||
log.debug("========== 비교 규칙 체인 시작: {} ==========", vhclno);
|
||||
|
||||
for (ComparisonRule rule : rules) {
|
||||
log.debug("[{}] 규칙 실행 중... 차량번호: {}", rule.getRuleName(), vhclno);
|
||||
|
||||
try {
|
||||
ComparisonResult result = rule.execute(context);
|
||||
|
||||
if (result.isApplied()) {
|
||||
log.info("[{}] 규칙 적용됨! 차량번호: {}, 상태코드: {}, 메시지: {}",
|
||||
rule.getRuleName(), vhclno, result.getStatusCode(), result.getMessage());
|
||||
log.debug("========== 비교 규칙 체인 종료 (규칙 적용): {} ==========", vhclno);
|
||||
return result;
|
||||
}
|
||||
|
||||
log.debug("[{}] 규칙 적용되지 않음. 다음 규칙으로 이동...", rule.getRuleName());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("[{}] 규칙 실행 중 오류 발생! 차량번호: {}", rule.getRuleName(), vhclno, e);
|
||||
throw new RuntimeException(
|
||||
String.format("[%s] 규칙 실행 중 오류 발생: %s - %s",
|
||||
rule.getRuleName(), vhclno, e.getMessage()), e);
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("========== 비교 규칙 체인 종료 (적용된 규칙 없음): {} ==========", vhclno);
|
||||
return null; // 적용된 규칙이 없음
|
||||
}
|
||||
|
||||
/**
|
||||
* 등록된 규칙 목록을 반환합니다. (디버깅용)
|
||||
*/
|
||||
public List<ComparisonRule> getRules() {
|
||||
return rules;
|
||||
}
|
||||
}
|
||||
@ -1,97 +0,0 @@
|
||||
package go.kr.project.carInspectionPenalty.registration.comparison.rules;
|
||||
|
||||
import go.kr.project.carInspectionPenalty.registration.comparison.ComparisonContext;
|
||||
import go.kr.project.carInspectionPenalty.registration.comparison.ComparisonResult;
|
||||
import go.kr.project.carInspectionPenalty.registration.comparison.ComparisonRule;
|
||||
import go.kr.project.carInspectionPenalty.registration.mapper.CarFfnlgTrgtMapper;
|
||||
import go.kr.project.carInspectionPenalty.registration.model.CarFfnlgTrgtVO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* 상품용 비교 규칙
|
||||
*
|
||||
* <p>대표소유자성명(MBER_NM)에서 "상품용" 문자열을 찾아 처리합니다.</p>
|
||||
*
|
||||
* <p>적용 조건:</p>
|
||||
* <ul>
|
||||
* <li>자동차 기본 사항 조회 대표소유자성명에 "상품용" 문자열 포함</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>처리 내용:</p>
|
||||
* <ul>
|
||||
* <li>TASK_PRCS_STTS_CD = 02 (상품용)</li>
|
||||
* <li>TASK_PRCS_YMD = 현재 날짜</li>
|
||||
* <li>CAR_BSC_MTTR_INQ_FLNM = 대표소유자성명</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ProductUseComparisonRule implements ComparisonRule {
|
||||
|
||||
private static final String STATUS_CODE = "02"; // 상품용
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
private final CarFfnlgTrgtMapper mapper;
|
||||
|
||||
@Override
|
||||
public ComparisonResult execute(ComparisonContext context) {
|
||||
String vhclno = context.getVhclno();
|
||||
|
||||
// API 응답 데이터 유효성 검사
|
||||
if (context.getApiResponse().getBasicInfo() == null ||
|
||||
context.getApiResponse().getBasicInfo().getRecord() == null ||
|
||||
context.getApiResponse().getBasicInfo().getRecord().isEmpty()) {
|
||||
log.debug("[{}] API 응답 데이터가 없어 규칙을 적용할 수 없습니다. 차량번호: {}", getRuleName(), vhclno);
|
||||
return ComparisonResult.notApplied();
|
||||
}
|
||||
|
||||
// 대표소유자성명 추출
|
||||
String mberNm = context.getApiResponse()
|
||||
.getBasicInfo()
|
||||
.getRecord()
|
||||
.get(0)
|
||||
.getMberNm();
|
||||
|
||||
// 상품용 체크
|
||||
if (mberNm == null || !mberNm.contains("상품용")) {
|
||||
log.debug("[{}] 상품용에 해당하지 않습니다. 차량번호: {}, 소유자명: {}", getRuleName(), vhclno, mberNm);
|
||||
return ComparisonResult.notApplied();
|
||||
}
|
||||
|
||||
log.info("[{}] 상품용 감지! 차량번호: {}, 소유자명: {}", getRuleName(), vhclno, mberNm);
|
||||
|
||||
// 업무 처리 상태 업데이트
|
||||
CarFfnlgTrgtVO updateData = context.getExistingData();
|
||||
updateData.setTaskPrcsSttsCd(STATUS_CODE);
|
||||
updateData.setTaskPrcsYmd(LocalDate.now().format(DATE_FORMATTER));
|
||||
updateData.setCarBscMttrInqFlnm(mberNm); // 소유자명 저장
|
||||
updateData.setCarBscMttrInqSggCd(null); // 이첩 필드는 null
|
||||
updateData.setCarBscMttrInqSggNm(null);
|
||||
|
||||
int updateResult = mapper.update(updateData);
|
||||
|
||||
if (updateResult > 0) {
|
||||
log.info("[{}] 처리 완료! 차량번호: {}", getRuleName(), vhclno);
|
||||
return ComparisonResult.applied(STATUS_CODE, "상품용으로 처리되었습니다.");
|
||||
} else {
|
||||
log.error("[{}] 업데이트 실패! 차량번호: {}", getRuleName(), vhclno);
|
||||
throw new RuntimeException(String.format("상품용 업데이트 실패: %s", vhclno));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRuleName() {
|
||||
return "상품용";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 10; // 상품용은 가장 먼저 체크 (낮은 순서)
|
||||
}
|
||||
}
|
||||
@ -1,169 +0,0 @@
|
||||
package go.kr.project.carInspectionPenalty.registration.comparison.rules;
|
||||
|
||||
import go.kr.project.carInspectionPenalty.registration.comparison.ComparisonContext;
|
||||
import go.kr.project.carInspectionPenalty.registration.comparison.ComparisonResult;
|
||||
import go.kr.project.carInspectionPenalty.registration.comparison.ComparisonRule;
|
||||
import go.kr.project.carInspectionPenalty.registration.mapper.CarFfnlgTrgtMapper;
|
||||
import go.kr.project.carInspectionPenalty.registration.model.CarFfnlgTrgtVO;
|
||||
import go.kr.project.system.user.mapper.UserMapper;
|
||||
import go.kr.project.system.user.model.SystemUserVO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* 이첩 비교 규칙
|
||||
*
|
||||
* <p>사용본거지법정동코드 앞 4자리와 사용자 조직코드 앞 4자리를 비교하여 처리합니다.</p>
|
||||
*
|
||||
* <p>적용 조건:</p>
|
||||
* <ul>
|
||||
* <li>자동차 기본 사항 조회 사용본거지법정동코드(USE_STRNGHLD_LEGALDONG_CODE) 앞 4자리</li>
|
||||
* <li>사용자(tb_user) ORG_CD 앞 4자리</li>
|
||||
* <li>위 두 값이 다를 경우</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>처리 내용:</p>
|
||||
* <ul>
|
||||
* <li>TASK_PRCS_STTS_CD = 03 (이첩)</li>
|
||||
* <li>TASK_PRCS_YMD = 현재 날짜</li>
|
||||
* <li>CAR_BSC_MTTR_INQ_SGG_CD = 사용본거지법정동코드 앞 5자리</li>
|
||||
* <li>CAR_BSC_MTTR_INQ_SGG_NM = tb_sgg_cd 테이블에서 조회한 시군구명</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TransferComparisonRule implements ComparisonRule {
|
||||
|
||||
private static final String STATUS_CODE = "03"; // 이첩
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
private final CarFfnlgTrgtMapper mapper;
|
||||
private final UserMapper userMapper;
|
||||
|
||||
@Override
|
||||
public ComparisonResult execute(ComparisonContext context) {
|
||||
String vhclno = context.getVhclno();
|
||||
|
||||
// API 응답 데이터 유효성 검사
|
||||
if (context.getApiResponse().getBasicInfo() == null ||
|
||||
context.getApiResponse().getBasicInfo().getRecord() == null ||
|
||||
context.getApiResponse().getBasicInfo().getRecord().isEmpty()) {
|
||||
log.debug("[{}] API 응답 데이터가 없어 규칙을 적용할 수 없습니다. 차량번호: {}", getRuleName(), vhclno);
|
||||
return ComparisonResult.notApplied();
|
||||
}
|
||||
|
||||
go.kr.project.api.model.response.BasicResponse.Record basicInfo = context.getApiResponse().getBasicInfo().getRecord().get(0);
|
||||
|
||||
// ========== 이첩 조건들 (OR 로직: 하나라도 만족하면 이첩) ==========
|
||||
|
||||
// 조건1: 법정동코드 불일치
|
||||
if (checkLegalDongCodeMismatch(context, basicInfo, vhclno)) {
|
||||
return processTransfer(context, basicInfo, vhclno, "법정동코드 불일치");
|
||||
}
|
||||
|
||||
// 조건2: 향후 추가될 이첩 조건들 (예시)
|
||||
// if (checkOtherTransferCondition(context, basicInfo, vhclno)) {
|
||||
// return processTransfer(context, basicInfo, vhclno, "다른 조건");
|
||||
// }
|
||||
|
||||
// 모든 이첩 조건에 해당하지 않음
|
||||
log.debug("[{}] 모든 이첩 조건에 해당하지 않습니다. 차량번호: {}", getRuleName(), vhclno);
|
||||
return ComparisonResult.notApplied();
|
||||
}
|
||||
|
||||
/**
|
||||
* 조건1: 법정동코드 불일치 체크
|
||||
* 사용본거지법정동코드 앞 4자리 != 사용자 조직코드 앞 4자리
|
||||
*/
|
||||
private boolean checkLegalDongCodeMismatch(ComparisonContext context,
|
||||
go.kr.project.api.model.response.BasicResponse.Record basicInfo,
|
||||
String vhclno) {
|
||||
// 사용본거지법정동코드 추출
|
||||
String useStrnghldLegaldongCode = basicInfo.getUseStrnghldLegaldongCode();
|
||||
|
||||
if (useStrnghldLegaldongCode == null || useStrnghldLegaldongCode.length() < 4) {
|
||||
log.debug("[{}][조건1] 법정동코드가 없거나 길이 부족. 차량번호: {}", getRuleName(), vhclno);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 사용자 정보 조회
|
||||
SystemUserVO userInfo = userMapper.selectUser(context.getUserId());
|
||||
if (userInfo == null || userInfo.getOrgCd() == null) {
|
||||
log.debug("[{}][조건1] 사용자 정보 없음. 차량번호: {}", getRuleName(), vhclno);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 법정동코드 앞 4자리와 사용자 조직코드 앞 4자리 비교
|
||||
String legalDong4 = useStrnghldLegaldongCode.substring(0, 4);
|
||||
String userOrgCd = userInfo.getOrgCd();
|
||||
String userOrg4 = userOrgCd.length() >= 4 ? userOrgCd.substring(0, 4) : userOrgCd;
|
||||
|
||||
if (legalDong4.equals(userOrg4)) {
|
||||
log.debug("[{}][조건1] 법정동코드 일치. 차량번호: {}, 법정동: {}, 조직: {}",
|
||||
getRuleName(), vhclno, legalDong4, userOrg4);
|
||||
return false;
|
||||
}
|
||||
|
||||
log.info("[{}][조건1] 법정동코드 불일치! 차량번호: {}, 법정동: {}, 조직: {}",
|
||||
getRuleName(), vhclno, legalDong4, userOrg4);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 이첩 처리 (공통 로직)
|
||||
*/
|
||||
private ComparisonResult processTransfer(ComparisonContext context,
|
||||
go.kr.project.api.model.response.BasicResponse.Record basicInfo,
|
||||
String vhclno,
|
||||
String reason) {
|
||||
log.info("[{}] 이첩 감지! 차량번호: {}, 사유: {}", getRuleName(), vhclno, reason);
|
||||
|
||||
// 사용본거지법정동코드 추출
|
||||
String useStrnghldLegaldongCode = basicInfo.getUseStrnghldLegaldongCode();
|
||||
|
||||
// 시군구 코드 (법정동코드 앞 5자리)
|
||||
String sggCd = (useStrnghldLegaldongCode != null && useStrnghldLegaldongCode.length() >= 5)
|
||||
? useStrnghldLegaldongCode.substring(0, 5)
|
||||
: (useStrnghldLegaldongCode != null ? useStrnghldLegaldongCode : "");
|
||||
|
||||
// 시군구명 조회
|
||||
String sggNm = mapper.selectSggNmBySggCd(sggCd);
|
||||
if (sggNm == null || sggNm.isEmpty()) {
|
||||
log.warn("[{}] 시군구명 조회 실패. 시군구코드: {} (빈 문자열로 처리)", getRuleName(), sggCd);
|
||||
sggNm = ""; // 시군구명이 없어도 이첩 처리는 진행
|
||||
}
|
||||
|
||||
// 업무 처리 상태 업데이트
|
||||
CarFfnlgTrgtVO updateData = context.getExistingData();
|
||||
updateData.setTaskPrcsSttsCd(STATUS_CODE);
|
||||
updateData.setTaskPrcsYmd(LocalDate.now().format(DATE_FORMATTER));
|
||||
updateData.setCarBscMttrInqFlnm(null); // 상품용 필드는 null
|
||||
updateData.setCarBscMttrInqSggCd(sggCd); // 시군구 코드 저장
|
||||
updateData.setCarBscMttrInqSggNm(sggNm); // 시군구명 저장
|
||||
|
||||
int updateResult = mapper.update(updateData);
|
||||
|
||||
if (updateResult > 0) {
|
||||
log.info("[{}] 처리 완료! 차량번호: {}, 시군구: {}({})", getRuleName(), vhclno, sggNm, sggCd);
|
||||
return ComparisonResult.applied(STATUS_CODE, String.format("이첩으로 처리되었습니다. (시군구: %s)", sggNm));
|
||||
} else {
|
||||
log.error("[{}] 업데이트 실패! 차량번호: {}", getRuleName(), vhclno);
|
||||
throw new RuntimeException(String.format("이첩 업데이트 실패: %s", vhclno));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRuleName() {
|
||||
return "이첩";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 20; // 상품용 다음으로 체크
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue