shp파일 a 링크로 다운로드할때 이력 저장 변경

This commit is contained in:
2026-02-26 15:25:10 +09:00
parent 2188d426d4
commit eccdfb17e6
13 changed files with 102 additions and 44 deletions

View File

@@ -5,7 +5,9 @@ import com.kamco.cd.kamcoback.common.download.dto.DownloadAuditEvent;
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
import com.kamco.cd.kamcoback.menu.service.MenuService;
import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity;
import com.kamco.cd.kamcoback.postgres.entity.MemberEntity;
import com.kamco.cd.kamcoback.postgres.repository.log.AuditLogRepository;
import com.kamco.cd.kamcoback.postgres.repository.members.MembersRepository;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
@@ -24,6 +26,7 @@ import org.springframework.transaction.annotation.Transactional;
public class DownloadAuditEventListener {
private final AuditLogRepository auditLogRepository;
private final MembersRepository membersRepository;
private final MenuService menuService;
private final ObjectMapper objectMapper;
@@ -42,9 +45,23 @@ public class DownloadAuditEventListener {
return;
}
Long userId = ev.userId();
if (userId == null) {
// a 링크로 들어온 download는 사번으로 파라미터가 전달 되므로 사번으로 user id 조회 하기
MemberEntity memberEntity =
membersRepository.findByEmployeeNo(ev.employeeNo()).orElse(null);
if (memberEntity == null) {
return; // 매핑 실패 시 로그 저장 안 함
}
userId = memberEntity.getId();
}
AuditLogEntity logEntity =
AuditLogEntity.forFileDownload(
ev.userId(), ev.requestUri(), menuUid, ev.ip(), ev.status(), ev.downloadUuid());
userId, ev.requestUri(), menuUid, ev.ip(), ev.status(), ev.downloadUuid());
auditLogRepository.save(logEntity);

View File

@@ -4,6 +4,7 @@ import java.util.UUID;
public record DownloadAuditEvent(
Long userId,
String employeeNo,
String requestUri,
String normalizedUri,
String ip,

View File

@@ -13,6 +13,7 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
/** 파일 다운로드 log 저장 */
@Slf4j
@Component
@RequiredArgsConstructor
@@ -30,9 +31,17 @@ public class FileDownloadInteceptor implements HandlerInterceptor {
if (request.getDispatcherType() != DispatcherType.REQUEST) return;
Long userId;
String employeeNo = "";
try {
// a 링크 다운로드일경우 userId가 없으므로 전달받은 사번을 넣는다
userId = userUtil.getId();
if (userId == null) return; // userId null 불가면 스킵
if (userId == null) {
employeeNo = request.getParameter("employeeNo");
if (employeeNo == null) {
return;
}
}
} catch (Exception e) {
log.warn("Download audit userId resolve failed. uri={}, err={}", uri, e.toString());
return;
@@ -48,8 +57,9 @@ public class FileDownloadInteceptor implements HandlerInterceptor {
return; // downloadUuid null 불가 -> 스킵
}
// log저장 DownloadAuditEventListener 클래스 호출
publisher.publishEvent(
new DownloadAuditEvent(userId, uri, normalizedUri, ip, status, downloadUuid));
new DownloadAuditEvent(userId, employeeNo, uri, normalizedUri, ip, status, downloadUuid));
}
private UUID extractUuidFromUri(String uri) {

View File

@@ -77,7 +77,7 @@ public class SecurityConfig {
// 다운로드는 인증 필요
.requestMatchers(HttpMethod.GET, DownloadPaths.PATTERNS)
.authenticated()
.permitAll()
// 메뉴 등록 ADMIN만 가능
.requestMatchers(HttpMethod.POST, "/api/menu/auth")

View File

@@ -1,4 +1,4 @@
package com.kamco.cd.kamcoback.inference.service;
package com.kamco.cd.kamcoback.inference;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RequestMapping;

View File

@@ -18,7 +18,6 @@ import com.kamco.cd.kamcoback.model.dto.ModelMngDto;
import com.kamco.cd.kamcoback.model.service.ModelMngService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -58,7 +57,8 @@ public class InferenceResultApiController {
private final ModelMngService modelMngService;
private final RangeDownloadResponder rangeDownloadResponder;
@Operation(summary = "추론관리 목록", description = "어드민 홈 > 추론관리 > 추론관리 > 추론관리 목록")
/** 추론관리 목록 화면에서 호출 */
@Operation(summary = "추론관리 목록", description = "추론관리 > 추론관리 목록 ")
@ApiResponses(
value = {
@ApiResponse(
@@ -90,7 +90,8 @@ public class InferenceResultApiController {
return ApiResponseDto.ok(analResList);
}
@Operation(summary = "추론 진행 여부 확인", description = "어드민 홈 > 추론관리 > 추론관리 > 추론관리 목록")
/** 추론관리 목록 화면에서 호출 */
@Operation(summary = "추론 진행 여부 확인", description = "추론관리 > 추론관리 목록")
@ApiResponses(
value = {
@ApiResponse(
@@ -112,7 +113,8 @@ public class InferenceResultApiController {
return ApiResponseDto.ok(inferenceResultService.getProcessing());
}
@Operation(summary = "년도 목록 조회", description = "어드민 홈 > 추론관리 > 추론목록 > 변화탐지 실행 정보 입력 > 년도 목록 조회")
/** 추론관리 목록 화면에서 호출 */
@Operation(summary = "년도 목록 조회", description = "추론관리 > 추론목록 > 변화탐지 실행 정보 입력 > 년도 목록 조회")
@ApiResponses(
value = {
@ApiResponse(
@@ -130,7 +132,8 @@ public class InferenceResultApiController {
return ApiResponseDto.ok(mapSheetMngService.findMapSheetMngDoneYyyyList());
}
@Operation(summary = "변화탐지 실행 정보 입력", description = "어드민 홈 > 추론관리 > 추론목록 > 변화탐지 실행 정보 입력")
/** 변화탐지 실행 정보 입력화면에서 호출 */
@Operation(summary = "변화탐지 실행 정보 입력", description = "추론관리 > 추론목록 > 변화탐지 실행 정보 입력")
@ApiResponses(
value = {
@ApiResponse(
@@ -155,7 +158,8 @@ public class InferenceResultApiController {
return ApiResponseDto.ok(uuid);
}
@Operation(summary = "추론 종료", description = "추론 종료")
/** 추론진행 현황 화면에서 호출 */
@Operation(summary = "추론 종료", description = "추론관리 > 추론목록 > 추론진행 현황")
@ApiResponses(
value = {
@ApiResponse(
@@ -174,7 +178,8 @@ public class InferenceResultApiController {
return ApiResponseDto.ok(uuid);
}
@Operation(summary = "분석 모델 선택 조회", description = "변화탐지 실행 정보 입력 모델선택 팝업 ")
/** 변화탐지 실행 정보 입력화면에서 호출 */
@Operation(summary = "분석 모델 선택 조회", description = "추론관리 > 추론목록 > 변화탐지 실행 정보 입력 > 모델선택 팝업 ")
@ApiResponses(
value = {
@ApiResponse(
@@ -205,7 +210,8 @@ public class InferenceResultApiController {
return ApiResponseDto.ok(result);
}
@Operation(summary = "추론관리 추론진행 서버 현황", description = "추론관리 추론진행 서버 현황")
/** 추론진행 현황 화면에서 호출 */
@Operation(summary = "추론관리 추론진행 서버 현황", description = "추론관리 > 추론목록 > 추론진행 현황")
@ApiResponses(
value = {
@ApiResponse(
@@ -224,7 +230,8 @@ public class InferenceResultApiController {
return ApiResponseDto.ok(inferenceResultService.getInferenceServerStatusList());
}
@Operation(summary = "추론관리 진행현황 상세", description = "어드민 홈 > 추론관리 > 추론관리 > 진행현황 상세")
/** 추론진행 현황 화면에서 호출 */
@Operation(summary = "추론관리 진행현황 상세", description = "추론관리 > 추론진행 현황")
@ApiResponses(
value = {
@ApiResponse(
@@ -248,7 +255,8 @@ public class InferenceResultApiController {
return ApiResponseDto.ok(inferenceResultService.getInferenceStatus(uuid));
}
@Operation(summary = "추론결과 기본정보", description = "추론결과 기본정보")
/** 추론결과 화면에서 호출 */
@Operation(summary = "추론결과 기본정보", description = "추론관리 > 추론결과")
@ApiResponses(
value = {
@ApiResponse(
@@ -269,7 +277,8 @@ public class InferenceResultApiController {
return ApiResponseDto.ok(inferenceResultService.getInferenceResultInfo(uuid));
}
@Operation(summary = "추론결과 분류별 탐지 건수", description = "추론결과 분류별 탐지 건수")
/** 추론결과 화면에서 호출 */
@Operation(summary = "추론결과 분류별 탐지 건수", description = "추론관리 > 추론결과")
@ApiResponses(
value = {
@ApiResponse(
@@ -290,6 +299,7 @@ public class InferenceResultApiController {
return ApiResponseDto.ok(inferenceResultService.getInferenceClassCountList(uuid));
}
/** 추론결과 화면에서 호출 */
@Operation(summary = "추론관리 분석결과 상세 목록", description = "추론관리 분석결과 상세 목록 geojson 데이터 조회")
@ApiResponses(
value = {
@@ -329,26 +339,13 @@ public class InferenceResultApiController {
return ApiResponseDto.ok(geomList);
}
@Operation(
summary = "shp 파일 다운로드",
description = "추론관리 분석결과 shp 파일 다운로드",
parameters = {
@Parameter(
name = "kamco-download-uuid",
in = ParameterIn.HEADER,
required = true,
description = "다운로드 요청 UUID",
schema =
@Schema(
type = "string",
format = "uuid",
example = "69c4e56c-e0bf-4742-9225-bba9aae39052"))
})
/** 추론결과 화면에서 호출 */
@Operation(summary = "shp 파일 다운로드", description = "추론관리 분석결과 shp 파일 다운로드")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "shp zip파일 다운로드",
description = "shp 파일 다운로드",
content =
@Content(
mediaType = "application/octet-stream",
@@ -357,13 +354,16 @@ public class InferenceResultApiController {
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@GetMapping("/download/{uuid}")
public ResponseEntity<?> download(@PathVariable UUID uuid, HttpServletRequest request)
public ResponseEntity<?> download(
@PathVariable UUID uuid,
@Parameter(description = "사번", example = "123456") @RequestParam String employeeNo,
HttpServletRequest request)
throws IOException {
String path;
String uid;
try {
// 추론결과 shp zip 파일 확인하여 다운로드 경로 생성
Map<String, Object> map = inferenceResultService.shpDownloadPath(uuid);
path = String.valueOf(map.get("path"));
uid = String.valueOf(map.get("uid"));
@@ -377,6 +377,7 @@ public class InferenceResultApiController {
return rangeDownloadResponder.buildZipResponse(zipPath, uid + ".zip", request);
}
/** 추론결과 화면에서 호출 */
@Operation(summary = "shp 파일 다운로드 이력 조회", description = "추론관리 분석결과 shp 파일 다운로드 이력 조회")
@GetMapping(value = "/download-audit/{uuid}")
@ApiResponses(
@@ -419,7 +420,8 @@ public class InferenceResultApiController {
return ApiResponseDto.ok(inferenceResultService.getDownloadAudit(searchReq, downloadReq));
}
@Operation(summary = "추론 실행중인 도엽 목록", description = "추론관리 실행중인 도엽명 5k 목록")
/** 추론진행 현황 화면에서 호출, 분석도엽 부분 옵션일때 분석중인 도엽 확인용 */
@Operation(summary = "추론관리 분석중인 도엽명 5k 목록", description = "추론관리 분석중인 도엽명 50k 목록")
@ApiResponses({
@ApiResponse(
responseCode = "200",

View File

@@ -107,7 +107,7 @@ public class InferenceResultService {
}
/**
* 추론 진행중인지 확인
* 추론 진행중인지 확인, 변화탐지 설정 등록 버튼 활성화 여부에 필요함
*
* @return
*/
@@ -952,10 +952,10 @@ public class InferenceResultService {
}
/**
* 추론결과 shp zip 파일 다운로드 경로 생성
* 추론결과 shp zip 파일 확인하여 다운로드 경로 생성
*
* @param uuid
* @return
* @param uuid 추론 uuid
* @return 32자 추론 uid, shp 파일 경로
*/
public Map<String, Object> shpDownloadPath(UUID uuid) {
InferenceLearnDto dto = inferenceResultCoreService.getInferenceUid(uuid);
@@ -981,7 +981,7 @@ public class InferenceResultService {
}
/**
* 실행중인 추론 도엽명 목록
* 분석중인 추론 도엽명 목록
*
* @param uuid uuid
* @return

View File

@@ -381,6 +381,9 @@ public class MapSheetMngService {
mapSheetMngCoreService.getSceneInference(yyyy);
}
/**
* @return
*/
public List<MngYyyyDto> findMapSheetMngDoneYyyyList() {
List<MngDto> mngList = mapSheetMngCoreService.findMapSheetMngList();

View File

@@ -46,6 +46,13 @@ public class AuditLogCoreService
return auditLogRepository.findLogByAccount(searchRange, searchValue);
}
/**
* 다운로드 이력 조회
*
* @param searchReq 페이징 파라미터
* @param downloadReq 다운로드 이력 팝업 검색 조건
* @return 다운로드 이력 정보 목록
*/
public Page<AuditLogDto.DownloadRes> findLogByAccount(
AuditLogDto.searchReq searchReq, DownloadReq downloadReq) {
return auditLogRepository.findDownloadLog(searchReq, downloadReq);

View File

@@ -527,10 +527,10 @@ public class InferenceResultCoreService {
}
/**
* uid 조회
* 추론 정보 조회 하여 batch id, 32자 uid 리턴
*
* @param uuid
* @return
* @param uuid 추론 uuid
* @return 추론정보
*/
public InferenceLearnDto getInferenceUid(UUID uuid) {
MapSheetLearnEntity entity = inferenceResultRepository.getInferenceUid(uuid).orElse(null);
@@ -547,7 +547,7 @@ public class InferenceResultCoreService {
}
/**
* 실행중인 추론 도엽명 목록
* 분석중인 추론 도엽명 목록
*
* @param uuid 추론 실행중인 uuid
* @return

View File

@@ -16,5 +16,11 @@ public interface InferenceResultRepositoryCustom {
Long getInferenceLearnIdByUuid(UUID uuid);
/**
* 추론 정보 조회
*
* @param uuid 추론 uuid
* @return 추론 정보
*/
Optional<MapSheetLearnEntity> getInferenceUid(UUID uuid);
}

View File

@@ -14,5 +14,11 @@ public interface MapSheetLearn5kRepositoryCustom {
List<Long> findCompleted5kList(UUID uuid, List<Long> completedIds, String type);
/**
* 추론 실행중일때 분석중인 도엽명 목록 조회
*
* @param uuid 추론 uuid
* @return 도엽명+50K 도엽번호
*/
List<String> getInferenceRunMapId(UUID uuid);
}

View File

@@ -13,6 +13,12 @@ public interface MembersRepositoryCustom {
boolean existsByEmployeeNo(String employeeNo);
/**
* 사번으로 사용자 조회
*
* @param employeeNo 사번
* @return 사용자 정보 조회
*/
Optional<MemberEntity> findByEmployeeNo(String employeeNo);
Optional<MemberEntity> findByUserId(String userId);