Compare commits

...

2 Commits

Author SHA1 Message Date
박성영 bc0d2e4128 ### feat: MariaDB 데이터베이스 백업 문서 추가
- **백업 가이드 추가**
  - `docs/용인 장애인 서버에서 관리 방법.md`에 **MariaDB 데이터베이스 백업** 섹션(`6.`) 추가:
    - 백업 디렉토리 생성 방법 명시.
    - 백업 스크립트 작성 및 권한 부여 절차 설명.
    - Crontab 설정을 통한 자동화 백업 방법(매일 밤 12시) 추가.

- **백업 스크립트 상세**
  - 데이터베이스 백업 파일 생성 및 압축, 30일 지난 백업 파일 삭제를 포함한 스크립트 제공.
  - 성공 및 실패 로그 기록 기능 포함.

- **관리 명령어 제공**
  - 수동 백업 수행, 백업 파일 확인, 로그 조회, 복원 명령어 등 추가 명세.

- **기타**
  - 백업 스크립트 실행 및 관리 명령어 내용을 문서에 명확하게 기록.
  - MariaDB 관리와 백업 프로세스를 쉽게 이해할 수 있도록 섹션 및 내용 구성.
1 day ago
박성영 93b15f3db0 ### feat: `Step 0` 및 `Step 1` 로직 공통화 및 비교 체커 로직 개선
- **`Step 0` 및 `Step 1` 공통 로직 추가**
  - `ComparisonOmServiceImpl`에서 `Step 0` 및 `Step 1` API 호출을 공통화:
    - `step0Response`와 `step1Response` 객체 생성 및 유효성 검증 추가.
    - 오류 발생 시 적절한 `log.warn` 및 `log.error` 출력.
    - 모든 검사 로직에서 공통 응답 데이터를 재사용하도록 수정.

- **체커(`Checker`) 클래스의 메서드 시그니처 수정**
  - `check` 메서드가 공통화된 응답 데이터(`step0Response`, `step1Response`)를 전달받도록 변경:
    - 기존 `check(CarFfnlgTrgtIncmpVO existingData, String userOrgCd)` →
      `check(CarFfnlgTrgtIncmpVO existingData, String userOrgCd, NewBasicResponse step0Response, NewBasicResponse step1Response)`.
    - `ProductUseOmChecker`, `OwnerTransferOmChecker`, `TransferOmChecker` 등 모든 비교 체커 반영.
    - 메서드 내 중복된 API 호출 제거 및 기존 응답 데이터 활용.

- **API 호출 로직 개선**
  - `createBasicRequest` 메서드 추가:
    - `vhrno`, `vin`, `levyCrtrYmd` 기반의 API 요청 객체를 생성하는 로직 캡슐화.
    - 호출부 간소화 및 재사용성 향상.

- **코드 및 처리 흐름 정리**
  - 기존 각 체커 내부에서 수행되던 API 호출 제거:
    - `Step 0` 및 `Step 1`은 메인 서비스에서 호출 후 응답 전달 방식으로 수정.
    - 주석 보완 및 로잉 일관성 개선.

- **불필요한 호출 및 데이터 처리 제거**
  - 중복된 API 호출 및 데이터 검증 로직 제거:
    - 기존 `step0Response`, `step1Response` 응답을 재활용하여 불필요한 호출 제거.
    - 검사 결과 처리 흐름을 단계별로 정리하여 가독성 강화.

- **기타**
  - 추가된 API 호출 및 유효성 검증으로 로직 안정성 강화.
  - 메인 서비스와 각 비교 로직 간 호출 체계를 명확히 구분.
1 day ago

@ -15,6 +15,11 @@
- [5. Systemd 서비스 설정](#5-systemd-서비스-설정)
- [5.1 서비스 파일 설정](#51-서비스-파일-설정)
- [5.2 Systemd 명령어](#52-systemd-명령어)
- [6. MariaDB 데이터베이스 백업](#6-mariadb-데이터베이스-백업)
- [6.1 백업 디렉토리 생성](#61-백업-디렉토리-생성)
- [6.2 백업 스크립트 생성](#62-백업-스크립트-생성)
- [6.3 Crontab 설정 (매일 밤 12시 자동 백업)](#63-crontab-설정-매일-밤-12시-자동-백업)
- [6.4 백업 관련 명령어](#64-백업-관련-명령어)
---
@ -162,3 +167,86 @@ systemctl restart vips
# 실시간 로그 확인
journalctl -u vips -f
```
---
## 6. MariaDB 데이터베이스 백업
**root 계정**에서 실행합니다.
### 6.1 백업 디렉토리 생성
```bash
mkdir -p /app/db/backup
chmod 755 /app/db/backup
```
### 6.2 백업 스크립트 생성
```bash
vi /app/db/backup/backup_vips.sh
```
**스크립트 내용:**
```bash
#!/bin/bash
# 백업 설정
BACKUP_DIR="/app/db/backup"
DB_NAME="vips"
DB_USER="vips"
DB_PASSWORD="xit5811807"
DB_PORT="53306"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${DATE}.sql"
# 백업 실행
mysqldump -u ${DB_USER} -p${DB_PASSWORD} -P ${DB_PORT} ${DB_NAME} > ${BACKUP_FILE}
# 백업 파일 압축
gzip ${BACKUP_FILE}
# 30일 이상 된 백업 파일 삭제
find ${BACKUP_DIR} -name "${DB_NAME}_*.sql.gz" -type f -mtime +30 -delete
# 백업 결과 로그
if [ $? -eq 0 ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - 백업 성공: ${BACKUP_FILE}.gz" >> ${BACKUP_DIR}/backup.log
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - 백업 실패" >> ${BACKUP_DIR}/backup.log
fi
```
**실행 권한 부여:**
```bash
chmod 700 /app/db/backup/backup_vips.sh
```
### 6.3 Crontab 설정 (매일 밤 12시 자동 백업)
```bash
# crontab 편집
crontab -e
# 아래 내용 추가
0 0 * * * /app/db/backup/backup_vips.sh
```
### 6.4 백업 관련 명령어
```bash
# 수동 백업 실행
/app/db/backup/backup_vips.sh
# 백업 파일 목록 확인
ls -lh /app/db/backup/
# 백업 로그 확인
tail -f /app/db/backup/backup.log
# crontab 설정 확인
crontab -l
# 백업 복원 (필요시)
gunzip /app/db/backup/vips_20240101_000000.sql.gz
mysql -u vips -p -P 53306 vips < /app/db/backup/vips_20240101_000000.sql
```

@ -1,6 +1,10 @@
package go.kr.project.carInspectionPenalty.registrationOm.service.impl;
import egovframework.util.SessionUtil;
import go.kr.project.api.model.request.NewBasicRequest;
import go.kr.project.api.model.response.NewBasicResponse;
import go.kr.project.api.service.ExternalVehicleApiService;
import go.kr.project.api.service.VmisCarBassMatterInqireLogService;
import go.kr.project.carInspectionPenalty.registrationOm.model.CarFfnlgTrgtIncmpVO;
import go.kr.project.carInspectionPenalty.registrationOm.service.ComparisonOmService;
import go.kr.project.carInspectionPenalty.registrationOm.service.impl.om_checker.*;
@ -10,6 +14,8 @@ import lombok.extern.slf4j.Slf4j;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
/**
*
*
@ -25,13 +31,18 @@ public class ComparisonOmServiceImpl extends EgovAbstractServiceImpl implements
private final TransferOmChecker transferOmChecker;
private final OwnerTransferOmChecker ownerTransferOmChecker;
private final ExternalVehicleApiService apiService;
private final VmisCarBassMatterInqireLogService bassMatterLogService;
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
/**
*
*
* <p> , .</p>
* <p> (levyCrtrYmd) existingData .</p>
*/
@Override
@Override
public String executeComparison(CarFfnlgTrgtIncmpVO existingData, LoginUserVO userInfo) {
String vhclno = existingData.getVhclno();
String levyCrtrYmd = existingData.getLevyCrtrYmd();
@ -40,22 +51,62 @@ public class ComparisonOmServiceImpl extends EgovAbstractServiceImpl implements
// 사용자 조직코드 추출
String userOrgCd = userInfo != null ? userInfo.getOrgCd() : null;
// ========== Step 0: 자동차기본정보 조회 (차량번호 + 오늘일자) - 한번만 호출 ==========
log.info("[공통] Step 0: 자동차기본정보 조회 - 차량번호: {}, 현재일", vhclno);
NewBasicResponse step0Response = null;
try {
NewBasicRequest step0Request = createBasicRequest(vhclno, null, LocalDate.now().format(DATE_FORMATTER));
step0Response = apiService.getBasicInfo(step0Request);
bassMatterLogService.updateCarFfnlgTrgtIdByTxIdNewTx(step0Response, existingData.getCarFfnlgTrgtIncmpId());
if (step0Response == null || step0Response.getRecord() == null || step0Response.getRecord().isEmpty()) {
log.warn("[공통] Step 0 응답 없음 - 차량번호: {}", vhclno);
log.info("========== 미필 비교 로직 종료 (Step 0 응답 없음): {} ==========", vhclno);
return null;
}
} catch (Exception e) {
log.error("[공통] Step 0 호출 중 오류 발생 - 차량번호: {}", vhclno, e);
log.info("========== 미필 비교 로직 종료 (Step 0 오류): {} ==========", vhclno);
return null;
}
// ========== Step 1: 자동차기본정보 조회 (차대번호 + 부과일자) - 한번만 호출 ==========
String step0vin = step0Response.getRecord().get(0).getVin();
String levyCrtrYmdFormatted = levyCrtrYmd.replace("-", "");
log.info("[공통] Step 1: 자동차기본정보 조회 - 차대번호: {}, 부과일자: {}", step0vin, levyCrtrYmdFormatted);
NewBasicResponse step1Response = null;
try {
NewBasicRequest step1Request = createBasicRequest(null, step0vin, levyCrtrYmdFormatted);
step1Response = apiService.getBasicInfo(step1Request);
bassMatterLogService.updateCarFfnlgTrgtIdByTxIdNewTx(step1Response, existingData.getCarFfnlgTrgtIncmpId());
if (step1Response == null || step1Response.getRecord() == null || step1Response.getRecord().isEmpty()) {
log.warn("[공통] Step 1 응답 없음 - 차대번호: {}", step0vin);
log.info("========== 미필 비교 로직 종료 (Step 1 응답 없음): {} ==========", vhclno);
return null;
}
} catch (Exception e) {
log.error("[공통] Step 1 호출 중 오류 발생 - 차대번호: {}", step0vin, e);
log.info("========== 미필 비교 로직 종료 (Step 1 오류): {} ==========", vhclno);
return null;
}
// ========== 1. 상품용 체크 - api-1번호출.소유자명.contains("상품용") ==========
String productUseResult = productUseOmChecker.check(existingData, userOrgCd);
String productUseResult = productUseOmChecker.check(existingData, userOrgCd, step0Response, step1Response);
if (productUseResult != null) {
log.info("========== 미필 비교 로직 종료 (상품용): {} ==========", vhclno);
return productUseResult;
}
// ========== 2. 이첩 체크 ==========
String transferResult = transferOmChecker.check(existingData, userOrgCd);
String transferResult = transferOmChecker.check(existingData, userOrgCd, step0Response, step1Response);
if (transferResult != null) {
log.info("========== 미필 비교 로직 종료 (이첩): {} ==========", vhclno);
return transferResult;
}
// ========== 3. 명의이전 소유자 확인 (검사유효기간 종료일 이후 명의이전) ==========
String ownerTransferResult = ownerTransferOmChecker.check(existingData, userOrgCd);
String ownerTransferResult = ownerTransferOmChecker.check(existingData, userOrgCd, step0Response, step1Response);
if (ownerTransferResult != null) {
log.info("========== 미필 비교 로직 종료 (명의이전 소유자 확인): {} ==========", vhclno);
return ownerTransferResult;
@ -64,4 +115,25 @@ public class ComparisonOmServiceImpl extends EgovAbstractServiceImpl implements
log.info("========== 미필 비교 로직 종료 (미적용): {} ==========", vhclno);
return null;
}
}
/**
*
*/
private NewBasicRequest createBasicRequest(String vhrno, String vin, String levyCrtrYmd) {
NewBasicRequest request = new NewBasicRequest();
NewBasicRequest.Record record = new NewBasicRequest.Record();
record.setLevyCrtrYmd(levyCrtrYmd);
if (vhrno != null) {
record.setVhrno(vhrno);
record.setInqSeCd("3"); // 3: 자동차번호
} else if (vin != null) {
record.setVin(vin);
record.setInqSeCd("2"); // 2: 차대번호
}
request.setRecord(java.util.Arrays.asList(record));
return request;
}
}

@ -1,5 +1,6 @@
package go.kr.project.carInspectionPenalty.registrationOm.service.impl.om_checker;
import go.kr.project.api.model.response.NewBasicResponse;
import go.kr.project.carInspectionPenalty.registrationOm.model.CarFfnlgTrgtIncmpVO;
/**
@ -15,7 +16,9 @@ public interface ComparisonOmChecker {
*
* @param existingData (levyCrtrYmd )
* @param userOrgCd
* @param step0Response Step 0 ( + )
* @param step1Response Step 1 ( + )
* @return null ()
*/
String check(CarFfnlgTrgtIncmpVO existingData, String userOrgCd);
String check(CarFfnlgTrgtIncmpVO existingData, String userOrgCd, NewBasicResponse step0Response, NewBasicResponse step1Response);
}

@ -52,7 +52,7 @@ public class OwnerTransferOmChecker extends AbstractComparisonOmChecker {
}
@Override
public String check(CarFfnlgTrgtIncmpVO existingData, String userOrgCd) {
public String check(CarFfnlgTrgtIncmpVO existingData, String userOrgCd, NewBasicResponse step0Response, NewBasicResponse step1Response) {
String vhclno = existingData.getVhclno();
String levyCrtrYmd = existingData.getLevyCrtrYmd().replace("-", ""); // 미필: 검사유효기간 종료일 + 146일
String inspVldPrd = existingData.getInspVldPrd(); // 검사유효기간
@ -80,12 +80,7 @@ public class OwnerTransferOmChecker extends AbstractComparisonOmChecker {
}
try {
log.info("[명의이전-미필] Step 0: 자동차기본정보 조회 - 차량번호: {}, 현재일", vhclno);
NewBasicRequest step0Request = createBasicRequest(vhclno, null, LocalDate.now().format(DATE_FORMATTER));
NewBasicResponse step0Response = apiService.getBasicInfo(step0Request);
bassMatterLogService.updateCarFfnlgTrgtIdByTxIdNewTx(step0Response, existingData.getCarFfnlgTrgtIncmpId());
// ========== Step 0, Step 1은 이미 메인 서비스에서 호출됨 ==========
if (step0Response == null || step0Response.getRecord() == null || step0Response.getRecord().isEmpty()) {
log.warn("[명의이전-미필] Step 0 응답 없음 - 차량번호: {}", vhclno);
return null;
@ -94,13 +89,6 @@ public class OwnerTransferOmChecker extends AbstractComparisonOmChecker {
NewBasicResponse.Record step0Record = step0Response.getRecord().get(0);
String step0vin = step0Record.getVin(); // 차대번호
// ========== Step 1: 자동차기본정보 조회 (차량번호, 부과일자=검사유효기간 종료일+146일) ==========
log.info("[명의이전-미필] Step 1: 자동차기본정보 조회 - 차대번호: {}, 부과일자: {}", step0vin, levyCrtrYmd);
NewBasicRequest step1Request = createBasicRequest(null, step0vin, levyCrtrYmd);
NewBasicResponse step1Response = apiService.getBasicInfo(step1Request);
bassMatterLogService.updateCarFfnlgTrgtIdByTxIdNewTx(step1Response, existingData.getCarFfnlgTrgtIncmpId());
if (step1Response == null || step1Response.getRecord() == null || step1Response.getRecord().isEmpty()) {
log.warn("[명의이전-미필] Step 1 응답 없음 - 차량번호: {}", vhclno);
return null;
@ -111,7 +99,6 @@ public class OwnerTransferOmChecker extends AbstractComparisonOmChecker {
String step1OwnerName = step1Record.getRprsOwnrNm(); // 부과일자 기준 소유자명
log.info("[명의이전-미필] Step 1 결과 - 차대번호: {}, 소유자명: {}", vin, step1OwnerName);
// 조건 1: 소유자명에 "상품용" 미포함 확인 (포함되면 다른 Checker에서 처리)
if (step1OwnerName != null && step1OwnerName.contains("상품용")) {
log.debug("[명의이전-미필] 소유자명에 '상품용' 포함 - 차량번호: {}, 소유자명: {}", vhclno, step1OwnerName);

@ -53,7 +53,7 @@ public class ProductUseOmChecker extends AbstractComparisonOmChecker {
}
@Override
public String check(CarFfnlgTrgtIncmpVO existingData, String userOrgCd) {
public String check(CarFfnlgTrgtIncmpVO existingData, String userOrgCd, NewBasicResponse step0Response, NewBasicResponse step1Response) {
String vhclno = existingData.getVhclno();
String levyCrtrYmd = existingData.getLevyCrtrYmd().replace("-", ""); // 미필: 검사유효기간 종료일 + 146일
String inspVldPrd = existingData.getInspVldPrd(); // 검사유효기간
@ -76,12 +76,7 @@ public class ProductUseOmChecker extends AbstractComparisonOmChecker {
}
try {
log.info("[상품용-미필] Step 0: 자동차기본정보 조회 - 차량번호: {}, 현재일", vhclno);
NewBasicRequest step0Request = createBasicRequest(vhclno, null, LocalDate.now().format(DATE_FORMATTER));
NewBasicResponse step0Response = apiService.getBasicInfo(step0Request);
bassMatterLogService.updateCarFfnlgTrgtIdByTxIdNewTx(step0Response, existingData.getCarFfnlgTrgtIncmpId());
// ========== Step 0, Step 1은 이미 메인 서비스에서 호출됨 ==========
if (step0Response == null || step0Response.getRecord() == null || step0Response.getRecord().isEmpty()) {
log.warn("[상품용-미필] Step 0 응답 없음 - 차량번호: {}", vhclno);
return null;
@ -90,13 +85,6 @@ public class ProductUseOmChecker extends AbstractComparisonOmChecker {
NewBasicResponse.Record step0Record = step0Response.getRecord().get(0);
String step0vin = step0Record.getVin(); // 차대번호
// ========== Step 1: 자동차기본정보 조회 (차량번호, 부과일자=검사유효기간 종료일+146일) ==========
log.info("[상품용-미필] Step 1: 자동차기본정보 조회 - 차대번호: {}, 부과일자: {}", step0vin, levyCrtrYmd);
NewBasicRequest step1Request = createBasicRequest(null, step0vin, levyCrtrYmd);
NewBasicResponse step1Response = apiService.getBasicInfo(step1Request);
bassMatterLogService.updateCarFfnlgTrgtIdByTxIdNewTx(step1Response, existingData.getCarFfnlgTrgtIncmpId());
if (step1Response == null || step1Response.getRecord() == null || step1Response.getRecord().isEmpty()) {
log.warn("[상품용-미필] Step 1 응답 없음 - 차량번호: {}", vhclno);
return null;

@ -44,7 +44,7 @@ public class TransferOmChecker extends AbstractComparisonOmChecker {
}
@Override
public String check(CarFfnlgTrgtIncmpVO existingData, String userOrgCd) {
public String check(CarFfnlgTrgtIncmpVO existingData, String userOrgCd, NewBasicResponse step0Response, NewBasicResponse step1Response) {
String vhclno = existingData.getVhclno();
try {
@ -62,34 +62,22 @@ public class TransferOmChecker extends AbstractComparisonOmChecker {
return null;
}
log.info("[상품용-미필] Step 0: 자동차기본정보 조회 - 차량번호: {}, 현재일", vhclno);
NewBasicRequest step0Request = createBasicRequest(vhclno, null, LocalDate.now().format(DATE_FORMATTER));
NewBasicResponse step0Response = apiService.getBasicInfo(step0Request);
bassMatterLogService.updateCarFfnlgTrgtIdByTxIdNewTx(step0Response, existingData.getCarFfnlgTrgtIncmpId());
// ========== Step 0, Step 1은 이미 메인 서비스에서 호출됨 ==========
if (step0Response == null || step0Response.getRecord() == null || step0Response.getRecord().isEmpty()) {
log.warn("[상품용-미필] Step 0 응답 없음 - 차량번호: {}", vhclno);
log.warn("[이첩-미필] Step 0 응답 없음 - 차량번호: {}", vhclno);
return null;
}
NewBasicResponse.Record step0Record = step0Response.getRecord().get(0);
String step0vin = step0Record.getVin(); // 차대번호
// 1단계: 자동차기본정보(차량번호, 부과일자=검사유효기간 + 146일)
// 부과일자는 이미 146일로 계산되어 있음
String step1Ymd = existingData.getLevyCrtrYmd();
log.info("[이첩-미필] 1단계 API 호출 - 차대번호: {}, 부과일자: {}", step0vin, step1Ymd);
NewBasicRequest step1Request = createBasicRequest(null, step0vin, step1Ymd);
NewBasicResponse step1Response = apiService.getBasicInfo(step1Request);
bassMatterLogService.updateCarFfnlgTrgtIdByTxIdNewTx(step1Response, existingData.getCarFfnlgTrgtIncmpId());
if (step1Response == null || step1Response.getRecord() == null || step1Response.getRecord().isEmpty()) {
log.warn("[이첩-미필] 1단계 응답 없음 - 차량번호: {}", vhclno);
log.warn("[이첩-미필] Step 1 응답 없음 - 차량번호: {}", vhclno);
return null;
}
NewBasicResponse.Record step1Record = step1Response.getRecord().get(0);
String step1Ymd = existingData.getLevyCrtrYmd(); // 부과일자
String step1RprsOwnrNm = step1Record.getRprsOwnrNm(); // 검사일 기준 소유자명
String step1RprsvOwnrIdecno = step1Record.getRprsvOwnrIdecno(); // 검사일 기준 소유자 회원번호
String step1UsgsrhldStdgCd = step1Record.getUsgsrhldStdgCd(); // 1단계 사용본거지법정동코드

Loading…
Cancel
Save