### feat: 사용자 정보 병렬 처리 지원 및 비교 로직 수정

- **병렬 처리 시 사용자 정보 전달 구현**
  - 세션 기반 사용자 정보 조회 로직 추가: `SessionUtil.getLoginUser()`.
  - 사용자 정보를 병렬 처리의 각 작업으로 전달하기 위해 메소드 서명 수정:
    - `processOneTarget`, `executeComparison`에 `LoginUserVO` 매개변수 추가.

- **Comparison 서비스 로직 업데이트**
  - 기존 세션 종속 비교 로직을 호출부에서 사용자 정보를 전달하도록 수정:
    - `ComparisonOmServiceImpl`, `ComparisonServiceImpl` 코드 변경.
    - `ComparisonOmChecker`, `delay_checker`의 호출 방식 업데이트.

- **코드 리팩토링**
  - 중복된 세션 접근 코드를 `try-catch` 처리로 통합.
  - 불필요한 세션 의존성 최소화 및 호출부 주입 방식으로 변경.

- **병렬 처리 개선**
  - `CompletableFuture` 기반 병렬 처리에 사용자 정보가 올바르게 전달되도록 수정.
  - 스레드 풀 크기 최적화: `(CPU 코어 수 * 2)`.

- **기타**
  - 주석 추가 및 로그 개선: 세션 조회 실패 경고 로그 및 사용자 정보 전달 내역 로깅.
  - 기존 트랜잭션 처리 방식과 병렬 처리 간의 연계 유지.
main
박성영 4 days ago
parent edc0aa5e89
commit f6c70be983

@ -22,7 +22,8 @@ public interface ComparisonService {
* <p> .</p>
*
* @param existingData
* @param userInfo
* @return (02=, 03=, null=)
*/
String executeComparison(CarFfnlgTrgtVO existingData);
String executeComparison(CarFfnlgTrgtVO existingData, go.kr.project.login.model.LoginUserVO userInfo);
}

@ -934,6 +934,15 @@ public class CarFfnlgTrgtServiceImpl extends EgovAbstractServiceImpl implements
throw new IllegalArgumentException("선택된 데이터가 없습니다.");
}
// 세션에서 사용자 정보 조회 (병렬처리 전에 메인 스레드에서 조회)
go.kr.project.login.model.LoginUserVO userInfo = null;
try {
userInfo = SessionUtil.getLoginUser();
} catch (Exception e) {
log.warn("세션에서 사용자 정보 조회 실패", e);
}
final go.kr.project.login.model.LoginUserVO finalUserInfo = userInfo;
// I/O 작업이므로 CPU 코어 수의 2배로 스레드 풀 생성
int threadPoolSize = Runtime.getRuntime().availableProcessors() * 2;
ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);
@ -943,7 +952,7 @@ public class CarFfnlgTrgtServiceImpl extends EgovAbstractServiceImpl implements
try {
// 병렬로 각 건 처리
List<CompletableFuture<Map<String, Object>>> futures = targetList.stream()
.map(target -> CompletableFuture.supplyAsync(() -> processOneTarget(target), executor))
.map(target -> CompletableFuture.supplyAsync(() -> processOneTarget(target, finalUserInfo), executor))
.collect(Collectors.toList());
// 모든 작업 완료 대기
@ -1015,7 +1024,7 @@ public class CarFfnlgTrgtServiceImpl extends EgovAbstractServiceImpl implements
* @param target
* @return
*/
private Map<String, Object> processOneTarget(Map<String, String> target) {
private Map<String, Object> processOneTarget(Map<String, String> target, go.kr.project.login.model.LoginUserVO userInfo) {
String carFfnlgTrgtId = target.get("carFfnlgTrgtId");
String vhclno = target.get("vhclno");
String inspYmd = target.get("inspYmd");
@ -1050,7 +1059,7 @@ public class CarFfnlgTrgtServiceImpl extends EgovAbstractServiceImpl implements
}
// 3. 비교 로직 실행
return comparisonService.executeComparison(existingData);
return comparisonService.executeComparison(existingData, userInfo);
} catch (Exception e) {
// 트랜잭션 롤백

@ -34,7 +34,7 @@ public class ComparisonServiceImpl extends EgovAbstractServiceImpl implements Co
* <p> , .</p>
*/
@Override
public String executeComparison(CarFfnlgTrgtVO existingData) {
public String executeComparison(CarFfnlgTrgtVO existingData, LoginUserVO userInfo) {
// ========== 특수문자 '*' 제거 (전출차량, 재검여부 표시용) ==========
// 차량번호에서 '*' 제거
if (existingData.getVhclno() != null) {
@ -51,8 +51,7 @@ public class ComparisonServiceImpl extends EgovAbstractServiceImpl implements Co
String vhclno = existingData.getVhclno();
log.info("========== 비교 로직 시작: {} ==========", vhclno);
// ========== 세션에서 사용자 정보 조회 ==========
LoginUserVO userInfo = SessionUtil.getLoginUser();
// 사용자 조직코드 추출
String userOrgCd = userInfo != null ? userInfo.getOrgCd() : null;
// ========== 1. 상품용 체크 - api-1번호출.소유자명.contains("상품용") ==========

@ -24,7 +24,8 @@ public interface ComparisonOmService {
* <p> levyCrtrYmd() .</p>
*
* @param existingData (levyCrtrYmd )
* @param userInfo
* @return (02=, 03=, null=)
*/
String executeComparison(CarFfnlgTrgtIncmpVO existingData);
String executeComparison(CarFfnlgTrgtIncmpVO existingData, go.kr.project.login.model.LoginUserVO userInfo);
}

@ -436,6 +436,15 @@ public class CarFfnlgTrgtIncmpServiceImpl extends EgovAbstractServiceImpl implem
}
log.info("부과일자 가산일: {}일", plusDay);
// 세션에서 사용자 정보 조회 (병렬처리 전에 메인 스레드에서 조회)
go.kr.project.login.model.LoginUserVO userInfo = null;
try {
userInfo = egovframework.util.SessionUtil.getLoginUser();
} catch (Exception e) {
log.warn("세션에서 사용자 정보 조회 실패", e);
}
final go.kr.project.login.model.LoginUserVO finalUserInfo = userInfo;
// I/O 작업이므로 CPU 코어 수의 2배로 스레드 풀 생성
int threadPoolSize = Runtime.getRuntime().availableProcessors() * 2;
ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);
@ -445,7 +454,7 @@ public class CarFfnlgTrgtIncmpServiceImpl extends EgovAbstractServiceImpl implem
try {
// 병렬로 각 건 처리
List<CompletableFuture<Map<String, Object>>> futures = targetList.stream()
.map(target -> CompletableFuture.supplyAsync(() -> processOneTarget(target, plusDay), executor))
.map(target -> CompletableFuture.supplyAsync(() -> processOneTarget(target, plusDay, finalUserInfo), executor))
.collect(Collectors.toList());
// 모든 작업 완료 대기
@ -518,7 +527,7 @@ public class CarFfnlgTrgtIncmpServiceImpl extends EgovAbstractServiceImpl implem
* @param plusDay
* @return
*/
private Map<String, Object> processOneTarget(Map<String, String> target, int plusDay) {
private Map<String, Object> processOneTarget(Map<String, String> target, int plusDay, go.kr.project.login.model.LoginUserVO userInfo) {
String carFfnlgTrgtIncmpId = target.get("carFfnlgTrgtIncmpId");
String vhclno = target.get("vhclno");
String inspVldPrd = target.get("inspVldPrd");
@ -558,7 +567,7 @@ public class CarFfnlgTrgtIncmpServiceImpl extends EgovAbstractServiceImpl implem
log.info("부과일자 계산 완료 - 검사유효기간: {}, 부과일자: {}", inspVldPrd, levyCrtrYmd);
// 4. 비교 로직 실행
return comparisonOmService.executeComparison(existingData);
return comparisonOmService.executeComparison(existingData, userInfo);
} catch (Exception e) {
// 트랜잭션 롤백

@ -32,13 +32,12 @@ public class ComparisonOmServiceImpl extends EgovAbstractServiceImpl implements
* <p> (levyCrtrYmd) existingData .</p>
*/
@Override
public String executeComparison(CarFfnlgTrgtIncmpVO existingData) {
public String executeComparison(CarFfnlgTrgtIncmpVO existingData, LoginUserVO userInfo) {
String vhclno = existingData.getVhclno();
String levyCrtrYmd = existingData.getLevyCrtrYmd();
log.info("========== 미필 비교 로직 시작: {}, 부과일자: {} ==========", vhclno, levyCrtrYmd);
// ========== 세션에서 사용자 정보 조회 ==========
LoginUserVO userInfo = SessionUtil.getLoginUser();
// 사용자 조직코드 추출
String userOrgCd = userInfo != null ? userInfo.getOrgCd() : null;
// ========== 1. 상품용 체크 - api-1번호출.소유자명.contains("상품용") ==========

Loading…
Cancel
Save