diff --git a/Dockerfile-dev b/Dockerfile-dev index 5219a42c..994ea58a 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -1,6 +1,20 @@ # Stage 1: Build stage (gradle build는 Jenkins에서 이미 수행) FROM eclipse-temurin:21-jre-jammy +# GDAL 설치 +RUN apt-get update && apt-get install -y \ + gdal-bin \ + libgdal-dev \ + && rm -rf /var/lib/apt/lists/* + +ARG UID=1000 +ARG GID=1000 + +RUN groupadd -g ${GID} manager01 \ + && useradd -u ${UID} -g ${GID} -m manager01 + +USER manager01 + # 작업 디렉토리 설정 WORKDIR /app diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 107547b6..60706853 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -3,8 +3,12 @@ services: build: context: . dockerfile: Dockerfile-dev + args: + UID: 1000 # manager01 UID + GID: 1000 # manager01 GID image: kamco-changedetection-api:${IMAGE_TAG:-latest} container_name: kamco-changedetection-api + user: "1000:1000" ports: - "7100:8080" environment: @@ -14,6 +18,7 @@ services: - /mnt/nfs_share/images:/app/original-images - /mnt/nfs_share/model_output:/app/model-outputs - /mnt/nfs_share/train_dataset:/app/train-dataset + - /mnt/nfs_share/tmp:/app/tmp networks: - kamco-cds restart: unless-stopped diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/InnopamApiController.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/InnopamApiController.java new file mode 100644 index 00000000..13bd6456 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/Innopam/InnopamApiController.java @@ -0,0 +1,145 @@ +package com.kamco.cd.kamcoback.Innopam; + +import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto; +import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.Basic; +import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastReq; +import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastSearch; +import com.kamco.cd.kamcoback.Innopam.service.DetectMastService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "이노펨 mockup API", description = "이노펨 mockup API") +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/kcd/cdi/detect") +public class InnopamApiController { + + private final DetectMastService detectMastService; + + /** 탐지결과 등록 */ + @Operation(summary = "탐지결과 등록", description = "탐지결과 등록") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "201", + description = "등록 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = DetectMastReq.class))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @PostMapping("/mast/regist") + public DetectMastReq setChangeDetection( + @RequestBody @Valid DetectMastDto.DetectMastReq detectMast) { + detectMastService.saveDetectMast(detectMast); + return detectMast; + } + + @Operation(summary = "탐지결과 삭제", description = "탐지결과 삭제") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "201", + description = "등록 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = DetectMastReq.class))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @PostMapping("/mast/remove") + public String deleteChangeDetection(@RequestBody DetectMastReq detectMast) { + return "OK"; + } + + @Operation(summary = "탐지결과 등록목록 조회", description = "탐지결과 등록목록 조회") + @GetMapping("/mast/list") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "목록 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = Basic.class))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + public List selectChangeDetectionList( + @RequestParam(required = false) String cprsBfYr, + @RequestParam(required = false) String cprsAdYr, + @RequestParam(required = false) Integer dtctSno) { + DetectMastSearch detectMastSearch = new DetectMastSearch(); + detectMastSearch.setCprsAdYr(cprsAdYr); + detectMastSearch.setCprsBfYr(cprsBfYr); + detectMastSearch.setDtctSno(dtctSno); + return detectMastService.selectDetectMast(detectMastSearch); + } + + @Operation(summary = "탐지결과 등록목록 상세 조회", description = "탐지결과 등록목록 상세 조회") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "목록 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = Basic.class))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/mast/list/{dtctMstId}") + public Basic selectChangeDetectionDetail(@PathVariable Long dtctMstId) { + return detectMastService.selectDetectMast(dtctMstId); + } + + @Operation(summary = "탐지객체 PNU 리스트 조회", description = "탐지객체 PNU 리스트 조회") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "목록 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = Basic.class))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/pnu/{cprsBfYr}/{cprsAfYr}/{dtctSno}") + public void selectPnuList( + @PathVariable String cprsBfYr, @PathVariable String cprsAfYr, @PathVariable String dtctSno) { + DetectMastSearch detectMastSearch = new DetectMastSearch(); + detectMastSearch.setCprsAdYr(cprsAfYr); + detectMastSearch.setCprsBfYr(cprsBfYr); + detectMastSearch.setDtctSno(Integer.parseInt(dtctSno)); + detectMastService.findPnuData(detectMastSearch); + } + + /** + * 탐지객체 PNU 단건 조회 + * + * @param detectMast + */ + @GetMapping("/pnu/{cprsBfYr}/{cprsAfYr}/{dtctSno}/{featureId}") + public void selectPnuDetail(@RequestBody DetectMastDto detectMast) {} +} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/dto/DetectMastDto.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/dto/DetectMastDto.java new file mode 100644 index 00000000..77ef145e --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/Innopam/dto/DetectMastDto.java @@ -0,0 +1,91 @@ +package com.kamco.cd.kamcoback.Innopam.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class DetectMastDto { + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class Basic { + + private Long dtctMstId; + private String cprsBfYr; + private String cprsAdYr; + private Integer dtctSno; + private String pathNm; + private String crtEpno; + private String crtIp; + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class DetectMastReq { + + @NotBlank + @Schema(description = "before 연도", example = "2023") + private String cprsBfYr; + + @NotBlank + @Schema(description = "after 연도", example = "2024") + private String cprsAdYr; + + @NotBlank + @Schema(description = "차수(회차)", example = "4") + private Integer dtctSno; + + @NotBlank + @Schema(description = "파일경로", example = "/app/detect/result/2023_2024/4") + private String pathNm; + + @NotBlank + @Schema(description = "사원번호", example = "1234567") + private String crtEpno; + + @NotBlank + @Schema(description = "아이피", example = "0.0.0.0") + private String crtIp; + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class DetectMastSearch { + + private String cprsBfYr; + private String cprsAdYr; + private Integer dtctSno; + private String featureId; + } + + /** before 연도 */ + private String cprsBfYr; + + /** after 연도 */ + private String cprsAdYr; + + /** 차수 */ + private Integer dtctSno; + + /** shp 파일경로 */ + private String pathNm; + + /** 등록한 사람 사번 */ + private String crtEpno; + + /** 등록한 사람 ip */ + private String crtIp; +} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/core/DetectMastCoreService.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/core/DetectMastCoreService.java new file mode 100644 index 00000000..6125209b --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/core/DetectMastCoreService.java @@ -0,0 +1,62 @@ +package com.kamco.cd.kamcoback.Innopam.postgres.core; + +import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto; +import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.Basic; +import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastReq; +import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastSearch; +import com.kamco.cd.kamcoback.Innopam.postgres.entity.DetectMastEntity; +import com.kamco.cd.kamcoback.Innopam.postgres.repository.DetectMastRepository; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class DetectMastCoreService { + + private final DetectMastRepository detectMastRepository; + + public void saveDetectMast(DetectMastReq detectMast) { + DetectMastEntity detectMastEntity = new DetectMastEntity(); + detectMastEntity.setCprsBfYr(detectMast.getCprsBfYr()); + detectMastEntity.setCprsAdYr(detectMast.getCprsAdYr()); + detectMastEntity.setDtctSno(detectMast.getDtctSno()); + detectMastEntity.setPathNm(detectMast.getPathNm()); + detectMastEntity.setCrtEpno(detectMast.getCrtEpno()); + detectMastEntity.setCrtIp(detectMast.getCrtIp()); + detectMastRepository.save(detectMastEntity); + } + + public List selectDetectMast(DetectMastSearch detectMast) { + return detectMastRepository.findDetectMastList(detectMast).stream() + .map( + e -> + new DetectMastDto.Basic( + e.getId(), + e.getCprsBfYr(), + e.getCprsAdYr(), + e.getDtctSno(), + e.getPathNm(), + e.getCrtEpno(), + e.getCrtIp())) + .toList(); + } + + public Basic selectDetectMast(Long id) { + DetectMastEntity e = + detectMastRepository.findById(id).orElseThrow(() -> new RuntimeException("등록 데이터가 없습니다.")); + return new DetectMastDto.Basic( + e.getId(), + e.getCprsBfYr(), + e.getCprsAdYr(), + e.getDtctSno(), + e.getPathNm(), + e.getCrtEpno(), + e.getCrtIp()); + } + + public String findPnuData(DetectMastSearch detectMast) { + DetectMastEntity detectMastEntity = detectMastRepository.findPnuData(detectMast); + return detectMastEntity.getPathNm(); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/entity/DetectMastEntity.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/entity/DetectMastEntity.java new file mode 100644 index 00000000..5d326b83 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/entity/DetectMastEntity.java @@ -0,0 +1,85 @@ +package com.kamco.cd.kamcoback.Innopam.postgres.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.time.ZonedDateTime; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; + +@Getter +@Setter +@Entity +@Table(name = "detect_mast") +public class DetectMastEntity { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "detect_mast_id_gen") + @SequenceGenerator( + name = "detect_mast_id_gen", + sequenceName = "seq_detect_mast_id", + allocationSize = 1) + @Column(name = "dtct_mst_id", nullable = false) + private Long id; + + @NotNull + @ColumnDefault("gen_random_uuid()") + @Column(name = "dtct_mst_uuid", nullable = false) + private UUID dtctMstUuid = UUID.randomUUID(); + + @Size(max = 4) + @NotNull + @Column(name = "cprs_bf_yr", nullable = false, length = 4) + private String cprsBfYr; + + @Size(max = 4) + @NotNull + @Column(name = "cprs_ad_yr", nullable = false, length = 4) + private String cprsAdYr; + + @NotNull + @Column(name = "dtct_sno", nullable = false) + private Integer dtctSno; + + @NotNull + @Column(name = "path_nm", nullable = false, length = Integer.MAX_VALUE) + private String pathNm; + + @Size(max = 50) + @Column(name = "feature_id", length = 50) + private String featureId; + + @Size(max = 30) + @NotNull + @Column(name = "crt_epno", nullable = false, length = 30) + private String crtEpno; + + @Size(max = 45) + @NotNull + @Column(name = "crt_ip", nullable = false, length = 45) + private String crtIp; + + @NotNull + @ColumnDefault("now()") + @Column(name = "crt_dttm", nullable = false) + private ZonedDateTime crtDttm = ZonedDateTime.now(); + + @Size(max = 30) + @Column(name = "chg_epno", length = 30) + private String chgEpno; + + @Size(max = 45) + @Column(name = "chg_ip", length = 45) + private String chgIp; + + @Column(name = "chg_dttm") + private ZonedDateTime chgDttm; +} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepository.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepository.java new file mode 100644 index 00000000..c6aa24f3 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepository.java @@ -0,0 +1,7 @@ +package com.kamco.cd.kamcoback.Innopam.postgres.repository; + +import com.kamco.cd.kamcoback.Innopam.postgres.entity.DetectMastEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface DetectMastRepository + extends JpaRepository, DetectMastRepositoryCustom {} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryCustom.java new file mode 100644 index 00000000..93ce4fb4 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryCustom.java @@ -0,0 +1,12 @@ +package com.kamco.cd.kamcoback.Innopam.postgres.repository; + +import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastSearch; +import com.kamco.cd.kamcoback.Innopam.postgres.entity.DetectMastEntity; +import java.util.List; + +public interface DetectMastRepositoryCustom { + + public List findDetectMastList(DetectMastSearch detectMast); + + public DetectMastEntity findPnuData(DetectMastSearch detectMast); +} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryImpl.java new file mode 100644 index 00000000..c2c658e2 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryImpl.java @@ -0,0 +1,59 @@ +package com.kamco.cd.kamcoback.Innopam.postgres.repository; + +import static com.kamco.cd.kamcoback.Innopam.postgres.entity.QDetectMastEntity.detectMastEntity; + +import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastSearch; +import com.kamco.cd.kamcoback.Innopam.postgres.entity.DetectMastEntity; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class DetectMastRepositoryImpl implements DetectMastRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + @Override + public List findDetectMastList(DetectMastSearch detectMast) { + + BooleanBuilder whereBuilder = new BooleanBuilder(); + + if (StringUtils.isNotBlank(detectMast.getCprsAdYr())) { + whereBuilder.and(detectMastEntity.cprsAdYr.eq(detectMast.getCprsAdYr())); + } + + if (StringUtils.isNotBlank(detectMast.getCprsBfYr())) { + whereBuilder.and(detectMastEntity.cprsBfYr.eq(detectMast.getCprsBfYr())); + } + + if (detectMast.getDtctSno() != null) { + whereBuilder.and(detectMastEntity.dtctSno.eq(detectMast.getDtctSno())); + } + + return queryFactory.select(detectMastEntity).from(detectMastEntity).where(whereBuilder).fetch(); + } + + @Override + public DetectMastEntity findPnuData(DetectMastSearch detectMast) { + + BooleanBuilder whereBuilder = new BooleanBuilder(); + + whereBuilder.and(detectMastEntity.cprsAdYr.eq(detectMast.getCprsAdYr())); + whereBuilder.and(detectMastEntity.cprsBfYr.eq(detectMast.getCprsBfYr())); + whereBuilder.and(detectMastEntity.dtctSno.eq(detectMast.getDtctSno())); + + if (detectMast.getFeatureId() != null) { + whereBuilder.and(detectMastEntity.featureId.eq(detectMast.getFeatureId())); + } + + return queryFactory + .select(detectMastEntity) + .from(detectMastEntity) + .where(whereBuilder) + .fetchOne(); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/Innopam/service/DetectMastService.java b/src/main/java/com/kamco/cd/kamcoback/Innopam/service/DetectMastService.java new file mode 100644 index 00000000..9b1c9d08 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/Innopam/service/DetectMastService.java @@ -0,0 +1,59 @@ +package com.kamco.cd.kamcoback.Innopam.service; + +import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.Basic; +import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastReq; +import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastSearch; +import com.kamco.cd.kamcoback.Innopam.postgres.core.DetectMastCoreService; +import java.io.File; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class DetectMastService { + + private final DetectMastCoreService detectMastCoreService; + + @Transactional + public void saveDetectMast(DetectMastReq detectMast) { + detectMastCoreService.saveDetectMast(detectMast); + } + + public List selectDetectMast(DetectMastSearch detectMast) { + return detectMastCoreService.selectDetectMast(detectMast); + } + + public Basic selectDetectMast(Long id) { + return detectMastCoreService.selectDetectMast(id); + } + + public void findPnuData(DetectMastSearch detectMast) { + String pathNm = detectMastCoreService.findPnuData(detectMast); + + File dir = new File(pathNm); + if (dir.exists() && dir.isDirectory()) { + File[] files = dir.listFiles(); + + if (files != null) { + for (File file : files) { + System.out.println(file.getName()); + } + } + } + } + + public static String randomPnu() { + ThreadLocalRandom r = ThreadLocalRandom.current(); + + String lawCode = String.valueOf(r.nextLong(1000000000L, 9999999999L)); // 10자리 + String sanFlag = r.nextBoolean() ? "1" : "2"; // 산/대지 + String bon = String.format("%04d", r.nextInt(1, 10000)); // 본번 + String bu = String.format("%04d", r.nextInt(0, 10000)); // 부번 + + return lawCode + sanFlag + bon + bu; + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/auth/MenuAuthorizationManager.java b/src/main/java/com/kamco/cd/kamcoback/auth/MenuAuthorizationManager.java index 0cc3db39..a9e8b11c 100644 --- a/src/main/java/com/kamco/cd/kamcoback/auth/MenuAuthorizationManager.java +++ b/src/main/java/com/kamco/cd/kamcoback/auth/MenuAuthorizationManager.java @@ -1,13 +1,12 @@ package com.kamco.cd.kamcoback.auth; +import com.kamco.cd.kamcoback.common.enums.RoleType; import com.kamco.cd.kamcoback.postgres.entity.MenuEntity; import com.kamco.cd.kamcoback.postgres.repository.menu.MenuRepository; import jakarta.servlet.http.HttpServletRequest; import java.util.List; import java.util.function.Supplier; import lombok.RequiredArgsConstructor; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.core.Authentication; @@ -24,8 +23,6 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor public class MenuAuthorizationManager implements AuthorizationManager { - private static final Logger log = LogManager.getLogger(MenuAuthorizationManager.class); - private final MenuRepository menuAuthQueryRepository; @Override @@ -45,19 +42,50 @@ public class MenuAuthorizationManager implements AuthorizationManager allowedMenus = menuAuthQueryRepository.findAllowedMenuUrlsByRole(role); + boolean isAdmin = RoleType.ADMIN.getId().equalsIgnoreCase(role); + // URL별 권한 조회 + List matchedMenus = menuAuthQueryRepository.findMenusByRequestPath(requestPath); + + boolean isProtectedUrl = matchedMenus != null && !matchedMenus.isEmpty(); + + // URL별 권한에 라벨러, 검수자 권한이 있으면 , ADMIN도 false + if (isProtectedUrl) { + List allowedMenus = menuAuthQueryRepository.findAllowedMenuUrlsByRole(role); + if (allowedMenus == null || allowedMenus.isEmpty()) { + return new AuthorizationDecision(false); + } + + for (MenuEntity menu : allowedMenus) { + String baseUri = menu.getMenuUrl(); + if (baseUri == null || baseUri.isBlank()) { + continue; + } + + if (matchUri(baseUri, requestPath)) { + return new AuthorizationDecision(true); + } + } + return new AuthorizationDecision(false); + } + + // ADMIN은 전부 허용 + if (isAdmin) { + return new AuthorizationDecision(true); + } + + // 일반 role은 기존대로 매핑 기반 + List allowedMenus = menuAuthQueryRepository.findAllowedMenuUrlsByRole(role); if (allowedMenus == null || allowedMenus.isEmpty()) { return new AuthorizationDecision(false); } - // menu_url(prefix) 기반 접근 허용 판단 for (MenuEntity menu : allowedMenus) { String baseUri = menu.getMenuUrl(); if (baseUri == null || baseUri.isBlank()) { continue; } + if (matchUri(baseUri, requestPath)) { return new AuthorizationDecision(true); } diff --git a/src/main/java/com/kamco/cd/kamcoback/common/enums/ApiConfigEnum.java b/src/main/java/com/kamco/cd/kamcoback/common/enums/ApiConfigEnum.java new file mode 100644 index 00000000..30d8ea27 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/common/enums/ApiConfigEnum.java @@ -0,0 +1,22 @@ +package com.kamco.cd.kamcoback.common.enums; + +import lombok.EqualsAndHashCode; +import lombok.Getter; + +public class ApiConfigEnum { + + @Getter + @EqualsAndHashCode(of = "enumValue") + public static class EnumDto { + + private final T enumValue; + private final String id; + private final String text; + + public EnumDto(T enumValue, String id, String text) { + this.enumValue = enumValue; + this.id = id; + this.text = text; + } + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/common/enums/CommonUseStatus.java b/src/main/java/com/kamco/cd/kamcoback/common/enums/CommonUseStatus.java new file mode 100644 index 00000000..c099d74f --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/common/enums/CommonUseStatus.java @@ -0,0 +1,40 @@ +package com.kamco.cd.kamcoback.common.enums; + +import com.kamco.cd.kamcoback.common.utils.enums.EnumType; +import java.util.Arrays; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * Common usage status used across the system. + * + *

This enum represents whether a resource is active, excluded from processing, or inactive. It + * is commonly used for filtering, business rules, and status management. + */ +@Getter +@AllArgsConstructor +public enum CommonUseStatus implements EnumType { + + // @formatter:off + USE("USE", "Active", 100) + /** Actively used and available */ + , + EXCEPT("EXCEPT", "Excluded", 200) + /** Explicitly excluded from use or processing */ + , + NOT_USE("NOT_USE", "Inactive", 999) +/** Not used or disabled */ +; + // @formatter:on + + private String id; + private String text; + private int ordering; + + public static CommonUseStatus getEnumById(String id) { + return Arrays.stream(CommonUseStatus.values()) + .filter(x -> x.getId().equals(id)) + .findFirst() + .orElse(CommonUseStatus.NOT_USE); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/config/SecurityConfig.java b/src/main/java/com/kamco/cd/kamcoback/config/SecurityConfig.java index 9ba95b4b..dca50109 100644 --- a/src/main/java/com/kamco/cd/kamcoback/config/SecurityConfig.java +++ b/src/main/java/com/kamco/cd/kamcoback/config/SecurityConfig.java @@ -79,9 +79,14 @@ public class SecurityConfig { "/api/members/*/password", "/v3/api-docs/**") .permitAll() + // 로그인한 사용자만 가능 + .requestMatchers("/api/user/**") + .authenticated() .anyRequest() - // .access(redisAuthorizationManager) - .authenticated()) + .access(menuAuthorizationManager) + + // .authenticated() + ) .addFilterBefore( jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultShpService.java b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultShpService.java index 326519aa..980a5a22 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultShpService.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultShpService.java @@ -5,6 +5,7 @@ import com.kamco.cd.kamcoback.inference.dto.WriteCnt; import com.kamco.cd.kamcoback.postgres.core.InferenceResultShpCoreService; import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,6 +17,9 @@ public class InferenceResultShpService { private final InferenceResultShpCoreService coreService; private final ShpWriter shpWriter; + @Value("${mapsheet.shp.baseurl}") + private String baseDir; + /** inference_results 테이블을 기준으로 분석 결과 테이블과 도형 테이블을 최신 상태로 반영한다. */ @Transactional public InferenceResultShpDto.InferenceCntDto saveInferenceResultData() { @@ -33,9 +37,6 @@ public class InferenceResultShpService { @Transactional public InferenceResultShpDto.FileCntDto createShpFile() { - // TODO 파일 경로는 정해지면 수정, properties 사용 - String baseDir = System.getProperty("user.home") + "/detect/result"; - // TODO 배치 실행으로 변경 필요 int batchSize = 100; int geomLimit = 500_000; diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiV2Controller.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiV2Controller.java new file mode 100644 index 00000000..9ddf3888 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiV2Controller.java @@ -0,0 +1,54 @@ +package com.kamco.cd.kamcoback.mapsheet; + +import com.kamco.cd.kamcoback.code.dto.CommonCodeDto; +import com.kamco.cd.kamcoback.config.api.ApiResponseDto; +import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; +import com.kamco.cd.kamcoback.mapsheet.service.MapSheetMngService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.time.Year; +import java.util.List; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "영상 관리", description = "영상 관리 API") +@RestController +@RequiredArgsConstructor +@RequestMapping({"/api/v2/mapsheet"}) +public class MapSheetMngApiV2Controller { + + private final MapSheetMngService mapSheetMngService; + + @Operation(summary = "영상 데이터 관리 년도 목록", description = "영상 데이터 관리 년도 목록") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = CommonCodeDto.Basic.class))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/mng-year-list") + public ApiResponseDto getListMapListYYYYLimit10() { + + List years = mapSheetMngService.getListMapListYYYYLimit10(); + // 현재 년도 가져온다 + int currentYear = Year.now().getValue(); + + // 현재년도와 같거나 큰 년도를 가져온다. + Optional result = years.stream().filter(y -> y >= currentYear).min(Integer::compareTo); + + return ApiResponseDto.ok(new MapSheetMngDto.ResisterYearList(result.orElse(null), years)); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/MapSheetMngDto.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/MapSheetMngDto.java index 920c7edc..1e22b6e4 100644 --- a/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/MapSheetMngDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/MapSheetMngDto.java @@ -2,11 +2,14 @@ package com.kamco.cd.kamcoback.mapsheet.dto; import com.kamco.cd.kamcoback.common.enums.MngStateType; import com.kamco.cd.kamcoback.common.enums.SyncStateType; +import com.kamco.cd.kamcoback.common.utils.enums.EnumType; import com.kamco.cd.kamcoback.common.utils.enums.Enums; import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm; import io.swagger.v3.oas.annotations.media.Schema; import java.time.ZonedDateTime; +import java.util.List; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -269,6 +272,7 @@ public class MapSheetMngDto { @Getter @Setter public static class SyncCheckStateReqUpdateDto { + private Long hstUid; private String filePath; private String syncCheckTfwFileName; @@ -335,4 +339,71 @@ public class MapSheetMngDto { private Long hstUid; private Long fileSize; } + + @Schema(name = "ResisterYearList", description = "영상파일 등록을 위한 연도 list") + @Getter + public static class ResisterYearList { + + private Integer current; + private List years; + + public ResisterYearList(Integer current, List years) { + this.current = current; + this.years = years; + } + } + + @Getter + @AllArgsConstructor + public enum MapSheetState implements EnumType { + // @formatter:off + DONE("완료"), + NOTYET("처리대기"); + // @formatter:on + + private final String message; + + @Override + public String getId() { + return name(); + } + + @Override + public String getText() { + return message; + } + } + + // 연도리스틀 조회시 사용하는 request Dto + @Getter + @Setter + @NoArgsConstructor + public static class YearSearchReq { + + private String status; + + // 페이징 파라미터 + private int page = 0; + private int size = 20; + private String sort; + + @Builder + public YearSearchReq(String status, int page, int size, String sort) { + this.status = status; + this.page = page; + this.size = size; + this.sort = sort; + } + + public Pageable toPageable() { + if (sort != null && !sort.isEmpty()) { + String[] sortParams = sort.split(","); + String property = sortParams[0]; + Sort.Direction direction = + sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC; + return PageRequest.of(page, size, Sort.by(direction, property)); + } + return PageRequest.of(page, size); + } + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java index b1ad4255..19613312 100644 --- a/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java @@ -12,13 +12,16 @@ import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.ErrorDataDto; import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.ErrorSearchReq; import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngDto; import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngFilesDto; +import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.YearSearchReq; import com.kamco.cd.kamcoback.postgres.core.MapSheetMngCoreService; +import com.kamco.cd.kamcoback.postgres.entity.YearEntity; import jakarta.validation.Valid; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.util.Comparator; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; @@ -51,6 +54,16 @@ public class MapSheetMngService { return mapSheetMngCoreService.findMapSheetMngYyyyList(); } + public List getListMapListYYYYLimit10() { + + YearSearchReq req = YearSearchReq.builder().status("NOTYET").page(0).size(10).build(); + // List조회 + Page years = mapSheetMngCoreService.getListMapListYYYYWithPaging(req); + return years.map(YearEntity::getYyyy).getContent().stream() + .sorted(Comparator.reverseOrder()) + .toList(); + } + public MngDto findMapSheetMng(int mngYyyy) { return mapSheetMngCoreService.findMapSheetMng(mngYyyy); } diff --git a/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java b/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java index b03b08cd..8af2bb91 100644 --- a/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java @@ -1,5 +1,6 @@ package com.kamco.cd.kamcoback.members.dto; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.kamco.cd.kamcoback.common.enums.RoleType; import com.kamco.cd.kamcoback.common.enums.StatusType; import com.kamco.cd.kamcoback.common.utils.enums.Enums; @@ -181,4 +182,84 @@ public class MembersDto { private String employeeNo; private String role; } + + @Getter + public static class RoleEntity { + + private final RoleType type; + private final String name; + + public RoleEntity(RoleType status) { + this.type = status; + this.name = status.getText(); + } + } + + @Getter + public static class StatusEntity { + + private final StatusType type; + private final String name; + + public StatusEntity(StatusType status) { + this.type = status; + this.name = status.getText(); + } + } + + @Getter + public static class EntityData { + + @JsonIgnore private Long id; + private UUID uuid; + private String name; + private String employeeNo; + private RoleEntity role; + private StatusEntity status; + @JsonFormatDttm private ZonedDateTime createdDttm; + @JsonFormatDttm private ZonedDateTime firstLoginDttm; + @JsonFormatDttm private ZonedDateTime lastLoginDttm; + @JsonFormatDttm private ZonedDateTime statusChgDttm; + + private Boolean isReset; + + public EntityData( + Long id, + UUID uuid, + RoleType role, + String name, + String employeeNo, + StatusType status, + ZonedDateTime createdDttm, + ZonedDateTime firstLoginDttm, + ZonedDateTime lastLoginDttm, + ZonedDateTime statusChgDttm, + Boolean isReset) { + this.id = id; + this.uuid = uuid; + this.name = name; + this.employeeNo = employeeNo; + this.status = new StatusEntity(status); + this.createdDttm = createdDttm; + this.firstLoginDttm = firstLoginDttm; + this.lastLoginDttm = lastLoginDttm; + this.statusChgDttm = statusChgDttm; + this.isReset = isReset; + this.role = new RoleEntity(role); + } + + private String getUserRoleName(String roleId) { + RoleType type = Enums.fromId(RoleType.class, roleId); + return type.getText(); + } + + private String getStatusName(String status, Boolean pwdResetYn) { + StatusType type = Enums.fromId(StatusType.class, status); + pwdResetYn = pwdResetYn != null && pwdResetYn; + if (type.equals(StatusType.PENDING) && pwdResetYn) { + type = StatusType.ACTIVE; + } + return type.getText(); + } + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapInkxMngCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapInkxMngCoreService.java index cdcba289..67e2dfa3 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapInkxMngCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapInkxMngCoreService.java @@ -1,7 +1,10 @@ package com.kamco.cd.kamcoback.postgres.core; +import com.kamco.cd.kamcoback.common.enums.CommonUseStatus; import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode; import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ResponseObj; +import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheet; +import com.kamco.cd.kamcoback.postgres.entity.MapInkx50kEntity; import com.kamco.cd.kamcoback.postgres.entity.MapInkx5kEntity; import com.kamco.cd.kamcoback.postgres.repository.scene.MapInkx50kRepository; import com.kamco.cd.kamcoback.postgres.repository.scene.MapInkx5kRepository; @@ -9,12 +12,16 @@ import com.kamco.cd.kamcoback.scene.dto.MapInkxMngDto; import com.kamco.cd.kamcoback.scene.dto.MapInkxMngDto.UseInferReq; import jakarta.persistence.EntityNotFoundException; import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.Optional; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.locationtech.jts.geom.Polygon; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +@Slf4j @Service @RequiredArgsConstructor public class MapInkxMngCoreService { @@ -24,7 +31,7 @@ public class MapInkxMngCoreService { // 목록 public Page findMapInkxMngList( - MapInkxMngDto.searchReq searchReq, String useInference, String searchVal) { + MapInkxMngDto.searchReq searchReq, CommonUseStatus useInference, String searchVal) { return mapInkx5kRepository.findMapInkxMngList(searchReq, useInference, searchVal); } @@ -37,21 +44,20 @@ public class MapInkxMngCoreService { return new ResponseObj(ApiResponseCode.DUPLICATE_DATA, "이미 등록된 도엽코드 입니다."); } - Integer fid50k = mapInkx50kRepository.findByMapidCdParentNo(req.getMapidcdNo()); - if (fid50k == null) { + MapInkx50kEntity mapInkx50k = mapInkx50kRepository.findByMapidCdParentNo(req.getMapidcdNo()); + if (mapInkx50k == null) { return new ResponseObj(ApiResponseCode.NOT_FOUND_DATA, "1:50,000 도엽의 정보가 없습니다. 관리자에게 문의하세요."); } MapInkx5kEntity entity = - new MapInkx5kEntity( - req.getMapidcdNo(), req.getMapidNm(), map_polygon, fid50k.longValue(), "USE" // 기본은 USE로 - ); + new MapInkx5kEntity(req.getMapidcdNo(), req.getMapidNm(), map_polygon, mapInkx50k); mapInkx5kRepository.save(entity); return new ResponseObj(ApiResponseCode.OK, ""); } + // 도엽의 사용여부를 변경한다. public ResponseObj updateUseInference(@Valid UseInferReq useInferReq) { Optional entity = Optional.ofNullable( @@ -62,4 +68,37 @@ public class MapInkxMngCoreService { entity.get().updateUseInference(useInferReq.getUseInference()); return new ResponseObj(ApiResponseCode.OK, ""); } + + /** + * Updates the inference usage status of a given map sheet (도엽) based on the provided scene ID and + * usage status. 도엽의 사용여부를 변경한다. + * + * @param sceneId5k the unique identifier for the map sheet whose usage status is being updated + * @param useStatus the new usage status to be set for the specified map sheet + * @return a ResponseObj indicating the outcome of the operation, including a response code and + * message + * @throws EntityNotFoundException if no map sheet is found for the provided scene ID + */ + @Transactional + public MapSheet updateUseInference( + @NotNull String sceneId5k, @NotNull CommonUseStatus useStatus) { + + log.debug("[updateUseInference]CHANGE_SCENE STATUS start: {}", sceneId5k); + + // 5k도엽 정보를 가져온다. + MapInkx5kEntity getScene5k = + mapInkx5kRepository + .findByMapidCdNoInfo(sceneId5k) + .orElseThrow(() -> new EntityNotFoundException("도엽정보를 찾을 수 없습니다.")); + + log.debug( + "[updateUseInference]CHANGE_SCENE STATUS: {} |BEFORE {} |AFTER {}", + sceneId5k, + getScene5k.getUseInference(), + useStatus); + // 상태를 업데이트한다. + getScene5k.updateUseInference(useStatus); + + return getScene5k.toEntity(); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapSheetMngCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapSheetMngCoreService.java index 9850f882..678f06e0 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapSheetMngCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapSheetMngCoreService.java @@ -1,8 +1,10 @@ package com.kamco.cd.kamcoback.postgres.core; import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; +import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.YearSearchReq; import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngEntity; import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngHstEntity; +import com.kamco.cd.kamcoback.postgres.entity.YearEntity; import com.kamco.cd.kamcoback.postgres.repository.mapsheet.MapSheetMngRepository; import jakarta.persistence.EntityNotFoundException; import jakarta.validation.Valid; @@ -13,6 +15,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor @@ -31,6 +34,18 @@ public class MapSheetMngCoreService { return mapSheetMngRepository.findMapSheetMngYyyyList(); } + /** + * 영상등록이 가능한 연도리스트 + * + * @param req + * @return + */ + @Transactional(readOnly = true) + public Page getListMapListYYYYWithPaging(YearSearchReq req) { + + return mapSheetMngRepository.getYears(req); + } + public MapSheetMngDto.MngDto findMapSheetMng(int mngYyyy) { return mapSheetMngRepository.findMapSheetMng(mngYyyy); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java index cc0e13c1..699b40e6 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java @@ -22,6 +22,7 @@ import org.mindrot.jbcrypt.BCrypt; import org.springframework.data.domain.Page; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor @@ -168,4 +169,18 @@ public class MembersCoreService { public boolean existsByEmployeeNo(String employeeNo) { return membersRepository.existsByEmployeeNo(employeeNo); } + + /** + * 회원정보 조회 (단건 ) by uuid + * + * @param uuid + */ + @Transactional(readOnly = true) + public MembersDto.EntityData getUserInfoByUuid(String memberUuid) { + MemberEntity member = + membersRepository + .findByUUID(UUID.fromString(memberUuid)) + .orElseThrow(MemberNotFoundException::new); + return member.toEntity(); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapInkx5kEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapInkx5kEntity.java index d2d7fdb5..80247365 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapInkx5kEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapInkx5kEntity.java @@ -1,13 +1,19 @@ package com.kamco.cd.kamcoback.postgres.entity; +import com.kamco.cd.kamcoback.common.enums.CommonUseStatus; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheet; import com.kamco.cd.kamcoback.postgres.CommonDateEntity; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.SequenceGenerator; import jakarta.persistence.Table; import lombok.Getter; @@ -39,22 +45,28 @@ public class MapInkx5kEntity extends CommonDateEntity { @Column(name = "geom") private Geometry geom; - @Column(name = "fid_k50") - private Long fidK50; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "fid_k50", referencedColumnName = "fid") + private MapInkx50kEntity mapInkx50k; + // 사용상태 USE, @Column(name = "use_inference") - private String useInference; + @Enumerated(EnumType.STRING) + private CommonUseStatus useInference; + // Constructor public MapInkx5kEntity( - String mapidcdNo, String mapidNm, Geometry geom, Long fidK50, String useInference) { + String mapidcdNo, String mapidNm, Geometry geom, MapInkx50kEntity mapInkx50k) { this.mapidcdNo = mapidcdNo; this.mapidNm = mapidNm; this.geom = geom; - this.fidK50 = fidK50; - this.useInference = useInference; + this.mapInkx50k = mapInkx50k; + // 생성시 default 사용함 (사용,제외,사용안함) + this.useInference = CommonUseStatus.USE; } - public void updateUseInference(String useInference) { + // 변경 사용상태 (추론사용여부) + public void updateUseInference(CommonUseStatus useInference) { this.useInference = useInference; } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalDataInferenceGeomEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalDataInferenceGeomEntity.java index 7ce986d6..f41d8191 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalDataInferenceGeomEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalDataInferenceGeomEntity.java @@ -146,4 +146,10 @@ public class MapSheetAnalDataInferenceGeomEntity { @Column(name = "file_created_dttm") private ZonedDateTime fileCreatedDttm; + + @Column(name = "pass_yn") + private Boolean passYn; + + @Column(name = "pass_yn_dttm") + private ZonedDateTime passYnDttm; } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetMngHstEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetMngHstEntity.java index ad81fbc7..2cf1f359 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetMngHstEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetMngHstEntity.java @@ -1,37 +1,92 @@ package com.kamco.cd.kamcoback.postgres.entity; import com.kamco.cd.kamcoback.postgres.CommonDateEntity; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import jakarta.validation.constraints.Size; import java.time.ZonedDateTime; +import lombok.AccessLevel; import lombok.Getter; -import lombok.Setter; +import lombok.NoArgsConstructor; +/** + * This class represents the entity for managing the history of map sheets. It is mapped to the + * database table "tb_map_sheet_mng_hst" and contains various properties related to the 1:5k map + * sheet information, as well as metadata for file synchronization and management. + * + *

This entity: - Includes a primary key (hstUid) for unique identification. - Maintains + * information associated with map sheets such as code, name, scale ratio, and paths. - Tracks + * states, timestamps, and data synchronization details. - Maintains relationships with the + * `MapInkx5kEntity` entity through a many-to-one association. - Provides functionality to update + * file information and sizes (`tifSizeBytes`, `tfwSizeBytes`, and `totalSizeBytes`). + * + *

It extends the `CommonDateEntity` class to include common date management fields, such as + * creation and modification timestamps. + * + *

The `@Getter` annotation generates getter methods for all fields, while the access to setters + * is restricted to enforce controlled modifications. The entity uses `@NoArgsConstructor` with + * `AccessLevel.PROTECTED` to restrict direct instantiation. The `updateFileInfos` method allows + * dynamic updates of specific file information. + * + *

Fields include: - hstUid: Unique identifier for the history record. - mngYyyy: Year associated + * with the management record. - mapInkx5kByCode: Reference to the related `MapInkx5kEntity` object. + * - mapSheetNum: Map sheet number identifying specific map. - mapSheetName: Name of the map sheet. + * - mapSheetCodeSrc: Source code of the map sheet. - scaleRatio: Scale ratio of the map. - + * dataState: State/status of the map sheet data. - dataStateDttm: Timestamp of the data state. - + * useInference: Indicator or metadata for inference usage. - useInferenceDttm: Timestamp for + * inference-related use. - mapSheetPath: Path or location of the map sheet file. - refMapSheetNum: + * Reference to a related map sheet number. - createdUid: User ID of the record creator. - + * updatedUid: User ID of the last updater. - syncState and related fields: Fields to manage + * synchronization states and processes. - tifSizeBytes, tfwSizeBytes, totalSizeBytes: Fields to + * track file size details. - sync file name fields: Stores names of files relevant for + * synchronization and verification. + * + *

This entity is essential for tracking and managing map sheet revisions, status, and usage in a + * system leveraging 1:5k map data. + */ @Getter -@Setter +// entity의 접근제어를 위해 @setter를 사용 x +// @Setter +@NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity +// 영상관리이력 @Table(name = "tb_map_sheet_mng_hst") public class MapSheetMngHstEntity extends CommonDateEntity { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "hst_uid") - private Long hstUid; + private Long hstUid; // id @Column(name = "mng_yyyy") - private Integer mngYyyy; + private Integer mngYyyy; // 년도 - @Column(name = "map_sheet_code") - private Integer mapSheetCode; + // JPA 연관관계: MapInkx5k 참조 (PK 기반) 소속도엽번호 1:5k + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "map_sheet_code", referencedColumnName = "fid") + private MapInkx5kEntity mapInkx5kByCode; + // TODO 1:5k 관련 정보 추후 제거 필요 @Column(name = "map_sheet_num") - private String mapSheetNum; + private String mapSheetNum; // 도엽번호 @Column(name = "map_sheet_name") private String mapSheetName; + // TODO END + + // 도엽파일이 저장된 경로 @Column(name = "map_sheet_code_src") private Integer mapSheetCodeSrc; + // 도엽비율? @Column(name = "scale_ratio") private Integer scaleRatio; @@ -103,4 +158,13 @@ public class MapSheetMngHstEntity extends CommonDateEntity { @Size(max = 100) @Column(name = "sync_check_tfw_file_name", length = 100) private String syncCheckTfwFileName; + + // 파일정보 업데이트 + public void updateFileInfos(Long tifSizeBytes, Long tfwSizeBytes) { + tifSizeBytes = tifSizeBytes == null ? 0L : tifSizeBytes; + tfwSizeBytes = tfwSizeBytes == null ? 0L : tfwSizeBytes; + this.tifSizeBytes = tifSizeBytes; + this.tfwSizeBytes = tfwSizeBytes; + this.totalSizeBytes = tifSizeBytes + tfwSizeBytes; + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberEntity.java index d2088ad9..1d97dd2c 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberEntity.java @@ -1,6 +1,8 @@ package com.kamco.cd.kamcoback.postgres.entity; +import com.kamco.cd.kamcoback.common.enums.RoleType; import com.kamco.cd.kamcoback.common.enums.StatusType; +import com.kamco.cd.kamcoback.members.dto.MembersDto.EntityData; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -14,8 +16,10 @@ import java.util.Objects; import java.util.UUID; import lombok.Getter; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import org.hibernate.annotations.ColumnDefault; +@Slf4j @Getter @Setter @Entity @@ -100,4 +104,19 @@ public class MemberEntity { this.status = newStatus; this.statusChgDttm = ZonedDateTime.now(); } + + public EntityData toEntity() { + return new EntityData( + id, + uuid, + RoleType.valueOf(userRole), + name, + employeeNo, + StatusType.valueOf(status), + createdDttm, + firstLoginDttm, + lastLoginDttm, + statusChgDttm, + pwdResetYn); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryCustom.java index f23fdd18..e5729585 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryCustom.java @@ -1,7 +1,9 @@ package com.kamco.cd.kamcoback.postgres.repository.mapsheet; import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; +import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.YearSearchReq; import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngHstEntity; +import com.kamco.cd.kamcoback.postgres.entity.YearEntity; import jakarta.validation.Valid; import java.util.List; import java.util.Optional; @@ -61,4 +63,6 @@ public interface MapSheetMngRepositoryCustom { void updateHstFileSizes(Long hstUid, long tifSizeBytes, long tfwSizeBytes, long totalSizeBytes); int findByYearFileNameFileCount(int mngYyyy, String fileName); + + Page getYears(YearSearchReq req); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryImpl.java index 1226813b..8fc981c8 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryImpl.java @@ -8,7 +8,10 @@ import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngHstEntity.mapSh import static com.kamco.cd.kamcoback.postgres.entity.QYearEntity.yearEntity; import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; +import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.YearSearchReq; import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngHstEntity; +import com.kamco.cd.kamcoback.postgres.entity.QYearEntity; +import com.kamco.cd.kamcoback.postgres.entity.YearEntity; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.Projections; import com.querydsl.core.types.dsl.BooleanExpression; @@ -390,10 +393,9 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport queryFactory .select(mapSheetMngHstEntity.hstUid.count()) .from(mapSheetMngHstEntity) - .innerJoin(mapInkx5kEntity) - .on(mapSheetMngHstEntity.mapSheetCode.eq(mapInkx5kEntity.fid)) - .leftJoin(mapInkx50kEntity) - .on(mapInkx5kEntity.fidK50.eq(mapInkx50kEntity.fid.longValue())) + .innerJoin(mapInkx5kEntity, mapSheetMngHstEntity.mapInkx5kByCode) + .fetchJoin() + .leftJoin(mapInkx5kEntity.mapInkx50k, mapInkx50kEntity) .where(whereBuilder) .fetchOne(); @@ -795,6 +797,35 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport query.executeUpdate(); } + @Override + public Page getYears(YearSearchReq req) { + Pageable pageable = req.toPageable(); + // LISTS + List content = + queryFactory + .selectFrom(yearEntity) + .where(eqYearStatus(yearEntity, req.getStatus())) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .orderBy(yearEntity.yyyy.asc()) + .fetch(); + // count 쿼리 + Long total = + queryFactory + .select(yearEntity.yyyy.count()) + .from(yearEntity) + .where(eqYearStatus(yearEntity, req.getStatus())) + .fetchOne(); + return new PageImpl<>(content, pageable, total); + } + + private BooleanExpression eqYearStatus(QYearEntity years, String status) { + if (status == null) { + return null; + } + return years.status.eq(status); + } + private NumberExpression rowNum() { return Expressions.numberTemplate( Integer.class, "row_number() over(order by {0} desc)", mapSheetMngHstEntity.createdDate); diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryCustom.java index 775ff647..c1e7db63 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryCustom.java @@ -22,4 +22,12 @@ public interface MenuRepositoryCustom { * @return */ List findAllowedMenuUrlsByRole(String role); + + /** + * url별 역할 + * + * @param requestPath + * @return + */ + List findMenusByRequestPath(String requestPath); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryImpl.java index 62a91213..b4919fd4 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/menu/MenuRepositoryImpl.java @@ -79,4 +79,21 @@ public class MenuRepositoryImpl implements MenuRepositoryCustom { .orderBy(menuEntity.menuOrder.asc().nullsLast()) .fetch(); } + + @Override + public List findMenusByRequestPath(String requestPath) { + return queryFactory + .selectDistinct(menuEntity) + .from(menuMappEntity) + .join(menuMappEntity.menuUid, menuEntity) + .where( + menuMappEntity.deleted.isFalse(), + menuEntity.deleted.isFalse(), + menuEntity.isUse.isTrue(), + menuEntity.menuUrl.isNotNull(), + menuEntity.menuUrl.isNotEmpty(), + menuEntity.menuUrl.eq(requestPath)) + .orderBy(menuEntity.menuOrder.asc().nullsLast()) + .fetch(); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx50kRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx50kRepositoryCustom.java index 88365a86..5aad0915 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx50kRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx50kRepositoryCustom.java @@ -1,6 +1,8 @@ package com.kamco.cd.kamcoback.postgres.repository.scene; +import com.kamco.cd.kamcoback.postgres.entity.MapInkx50kEntity; + public interface MapInkx50kRepositoryCustom { - Integer findByMapidCdParentNo(String mapidcdNo); + MapInkx50kEntity findByMapidCdParentNo(String mapidcdNo); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx50kRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx50kRepositoryImpl.java index 53c10966..072d8404 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx50kRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx50kRepositoryImpl.java @@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.postgres.repository.scene; import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx50kEntity.mapInkx50kEntity; +import com.kamco.cd.kamcoback.postgres.entity.MapInkx50kEntity; import com.kamco.cd.kamcoback.postgres.entity.MapInkx5kEntity; import com.querydsl.jpa.impl.JPAQueryFactory; import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; @@ -17,11 +18,10 @@ public class MapInkx50kRepositoryImpl extends QuerydslRepositorySupport } @Override - public Integer findByMapidCdParentNo(String mapidcdNo) { + public MapInkx50kEntity findByMapidCdParentNo(String mapidcdNo) { String parentCd = mapidcdNo.substring(0, 5); return queryFactory - .select(mapInkx50kEntity.fid) - .from(mapInkx50kEntity) + .selectFrom(mapInkx50kEntity) .where(mapInkx50kEntity.mapidcdNo.eq(parentCd)) .fetchOne(); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx5kRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx5kRepositoryCustom.java index b1c642cb..50bdf94f 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx5kRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx5kRepositoryCustom.java @@ -1,5 +1,6 @@ package com.kamco.cd.kamcoback.postgres.repository.scene; +import com.kamco.cd.kamcoback.common.enums.CommonUseStatus; import com.kamco.cd.kamcoback.postgres.entity.MapInkx5kEntity; import com.kamco.cd.kamcoback.scene.dto.MapInkxMngDto; import com.kamco.cd.kamcoback.scene.dto.MapInkxMngDto.MapList; @@ -12,7 +13,7 @@ public interface MapInkx5kRepositoryCustom { List listGetScenes5k(List codes); Page findMapInkxMngList( - MapInkxMngDto.searchReq searchReq, String useInference, String searchVal); + MapInkxMngDto.searchReq searchReq, CommonUseStatus useInference, String searchVal); Long findByMapidCdNoExists(String mapidcdNo); diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx5kRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx5kRepositoryImpl.java index 2f957b8a..6485e9c1 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx5kRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/scene/MapInkx5kRepositoryImpl.java @@ -3,6 +3,7 @@ package com.kamco.cd.kamcoback.postgres.repository.scene; import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx50kEntity.mapInkx50kEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx5kEntity.mapInkx5kEntity; +import com.kamco.cd.kamcoback.common.enums.CommonUseStatus; import com.kamco.cd.kamcoback.postgres.entity.MapInkx5kEntity; import com.kamco.cd.kamcoback.postgres.entity.QMapInkx5kEntity; import com.kamco.cd.kamcoback.scene.dto.MapInkxMngDto; @@ -42,7 +43,7 @@ public class MapInkx5kRepositoryImpl extends QuerydslRepositorySupport @Override public Page findMapInkxMngList( - searchReq searchReq, String useInference, String searchVal) { + searchReq searchReq, CommonUseStatus useInference, String searchVal) { Pageable pageable = searchReq.toPageable(); List foundContent = @@ -65,8 +66,7 @@ public class MapInkx5kRepositoryImpl extends QuerydslRepositorySupport // mapInkx5kEntity.modifiedDate), mapInkx5kEntity.useInference)) .from(mapInkx5kEntity) - .innerJoin(mapInkx50kEntity) - .on(mapInkx5kEntity.fidK50.intValue().eq(mapInkx50kEntity.fid)) + .innerJoin(mapInkx5kEntity.mapInkx50k, mapInkx50kEntity) .where(searchUseInference(useInference), searchValueMapCdNm(searchVal)) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) @@ -77,8 +77,7 @@ public class MapInkx5kRepositoryImpl extends QuerydslRepositorySupport queryFactory .select(mapInkx5kEntity.count()) .from(mapInkx5kEntity) - .innerJoin(mapInkx50kEntity) - .on(mapInkx5kEntity.fidK50.intValue().eq(mapInkx50kEntity.fid)) + .innerJoin(mapInkx5kEntity.mapInkx50k, mapInkx50kEntity) .where(searchUseInference(useInference), searchValueMapCdNm(searchVal)) .fetchOne(); @@ -103,7 +102,7 @@ public class MapInkx5kRepositoryImpl extends QuerydslRepositorySupport .fetchOne()); } - private BooleanExpression searchUseInference(String useInference) { + private BooleanExpression searchUseInference(CommonUseStatus useInference) { if (Objects.isNull(useInference)) { return null; } diff --git a/src/main/java/com/kamco/cd/kamcoback/scene/MapInkxMngApiController.java b/src/main/java/com/kamco/cd/kamcoback/scene/MapInkxMngApiController.java index 3bb3b361..3648e707 100644 --- a/src/main/java/com/kamco/cd/kamcoback/scene/MapInkxMngApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/scene/MapInkxMngApiController.java @@ -1,7 +1,10 @@ package com.kamco.cd.kamcoback.scene; import com.kamco.cd.kamcoback.code.dto.CommonCodeDto; +import com.kamco.cd.kamcoback.common.enums.CommonUseStatus; import com.kamco.cd.kamcoback.config.api.ApiResponseDto; +import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode; +import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ResponseObj; import com.kamco.cd.kamcoback.scene.dto.MapInkxMngDto; import com.kamco.cd.kamcoback.scene.service.MapInkxMngService; import io.swagger.v3.oas.annotations.Operation; @@ -44,9 +47,9 @@ public class MapInkxMngApiController { }) @GetMapping public ApiResponseDto> findMapInkxMngList( - @RequestParam int page, + @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size, - @RequestParam(required = false) String useInference, + @RequestParam(required = false) CommonUseStatus useInference, @RequestParam(required = false) String searchVal) { MapInkxMngDto.searchReq searchReq = new MapInkxMngDto.searchReq(page, size, ""); return ApiResponseDto.ok( @@ -108,6 +111,7 @@ public class MapInkxMngApiController { @RequestBody @Valid MapInkxMngDto.UseInferReq useInferReq) { - return ApiResponseDto.okObject(mapInkxMngService.updateUseInference(useInferReq)); + mapInkxMngService.updateUseInference(useInferReq); + return ApiResponseDto.okObject(new ResponseObj(ApiResponseCode.OK, "")); } } diff --git a/src/main/java/com/kamco/cd/kamcoback/scene/dto/MapInkxMngDto.java b/src/main/java/com/kamco/cd/kamcoback/scene/dto/MapInkxMngDto.java index 5c8baf05..caa995a6 100644 --- a/src/main/java/com/kamco/cd/kamcoback/scene/dto/MapInkxMngDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/scene/dto/MapInkxMngDto.java @@ -1,9 +1,11 @@ package com.kamco.cd.kamcoback.scene.dto; import com.fasterxml.jackson.databind.JsonNode; +import com.kamco.cd.kamcoback.common.enums.CommonUseStatus; import com.kamco.cd.kamcoback.common.utils.enums.CodeExpose; import com.kamco.cd.kamcoback.common.utils.enums.EnumType; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.persistence.EntityNotFoundException; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; @@ -48,7 +50,6 @@ public class MapInkxMngDto { private String mapidcdNo; private String mapidNm; private JsonNode geom; - private Long fidK50; private String useInference; private ZonedDateTime createdDttm; private ZonedDateTime updatedDttm; @@ -78,7 +79,7 @@ public class MapInkxMngDto { String mapidNm, ZonedDateTime createdDttmTime, ZonedDateTime updatedDttmTime, - String useInference) { + CommonUseStatus useInference) { this.rowNum = rowNum; this.mapidcdNo5k = mapidcdNo5k; this.mapidcdNo50k = mapidcdNo50k; @@ -90,10 +91,7 @@ public class MapInkxMngDto { this.updatedDttm = fmt.format(updatedDttmTime); this.createdDttmTime = createdDttmTime; this.updatedDttmTime = updatedDttmTime; - this.useInference = - useInference.equals("USE") - ? UseInferenceType.USE.getDesc() - : UseInferenceType.EXCEPT.getDesc(); + this.useInference = useInference.getId(); } } @@ -152,6 +150,18 @@ public class MapInkxMngDto { public static class UseInferReq { private String mapidcdNo; - private String useInference; + private CommonUseStatus useInference; // 변경하고자하는 상태 + + public void valid() { + if (mapidcdNo == null || mapidcdNo.isEmpty()) { + throw new IllegalArgumentException("도엽번호는 필수 입력값입니다."); + } + // 공백제거 + mapidcdNo = mapidcdNo.trim(); + + if (!mapidcdNo.matches("^\\d{8}$")) { + throw new EntityNotFoundException("도엽번호는 8자리 숫자로 구성되어야 합니다."); + } + } } } diff --git a/src/main/java/com/kamco/cd/kamcoback/scene/service/MapInkxMngService.java b/src/main/java/com/kamco/cd/kamcoback/scene/service/MapInkxMngService.java index b39bc323..5cd06c7c 100644 --- a/src/main/java/com/kamco/cd/kamcoback/scene/service/MapInkxMngService.java +++ b/src/main/java/com/kamco/cd/kamcoback/scene/service/MapInkxMngService.java @@ -1,6 +1,8 @@ package com.kamco.cd.kamcoback.scene.service; +import com.kamco.cd.kamcoback.common.enums.CommonUseStatus; import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ResponseObj; +import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheet; import com.kamco.cd.kamcoback.postgres.core.MapInkxMngCoreService; import com.kamco.cd.kamcoback.scene.dto.MapInkxMngDto; import com.kamco.cd.kamcoback.scene.dto.MapInkxMngDto.MapList; @@ -15,6 +17,7 @@ import org.locationtech.jts.geom.LinearRing; import org.locationtech.jts.geom.PrecisionModel; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor @@ -23,7 +26,7 @@ public class MapInkxMngService { private final MapInkxMngCoreService mapInkxMngCoreService; public Page findMapInkxMngList( - MapInkxMngDto.searchReq searchReq, String useInference, String searchVal) { + MapInkxMngDto.searchReq searchReq, CommonUseStatus useInference, String searchVal) { return mapInkxMngCoreService.findMapInkxMngList(searchReq, useInference, searchVal); } @@ -52,7 +55,10 @@ public class MapInkxMngService { return mapInkxMngCoreService.saveMapInkx5k(req, GEOMETRY_FACTORY.createPolygon(shell)); } - public ResponseObj updateUseInference(@Valid UseInferReq useInferReq) { - return mapInkxMngCoreService.updateUseInference(useInferReq); + // 도엽의 상태를 업데이트한다. + @Transactional + public MapSheet updateUseInference(@Valid UseInferReq useInferReq) { + return mapInkxMngCoreService.updateUseInference( + useInferReq.getMapidcdNo(), useInferReq.getUseInference()); } } diff --git a/src/main/java/com/kamco/cd/kamcoback/user/UserApiController.java b/src/main/java/com/kamco/cd/kamcoback/user/UserApiController.java new file mode 100644 index 00000000..c9d30696 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/user/UserApiController.java @@ -0,0 +1,53 @@ +package com.kamco.cd.kamcoback.user; + +import com.kamco.cd.kamcoback.config.api.ApiResponseDto; +import com.kamco.cd.kamcoback.members.dto.MembersDto; +import com.kamco.cd.kamcoback.user.service.UserInfoService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "사용자 정보", description = "사용자 정보 조회 API") +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/user") +public class UserApiController { + + private final UserInfoService userInfoService; + + @Operation( + summary = "현재 로그인 사용자 정보 조회", + description = "JWT 토큰에서 사용자 ID를 추출하여 현재 로그인한 사용자의 정보를 조회합니다.") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = MembersDto.EntityData.class))), + @ApiResponse( + responseCode = "401", + description = "인증 실패 (토큰 없음 또는 유효하지 않음)", + content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/iam") + public ApiResponseDto iam() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + String memberUuid = authentication.getName(); // JWT의 sub 값 (사용자 ID) + + // Member의 정보를 조회해서 리턴한다. + return ApiResponseDto.createOK(userInfoService.getUserInfoByUuid(memberUuid)); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/user/service/UserInfoService.java b/src/main/java/com/kamco/cd/kamcoback/user/service/UserInfoService.java new file mode 100644 index 00000000..2d93153a --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/user/service/UserInfoService.java @@ -0,0 +1,26 @@ +package com.kamco.cd.kamcoback.user.service; + +import com.kamco.cd.kamcoback.members.dto.MembersDto; +import com.kamco.cd.kamcoback.postgres.core.MembersCoreService; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Service +@Transactional(readOnly = true) +public class UserInfoService { + + private final MembersCoreService membersCoreService; + + /** + * 회원정보 조회 (단건 ) by uuid + * + * @param uuid + * @return + */ + public MembersDto.EntityData getUserInfoByUuid(@NotNull String uuid) { + return membersCoreService.getUserInfoByUuid(uuid); + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 6c7b17f0..4a00ed71 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -73,4 +73,6 @@ logging: mapsheet: upload: skipGdalValidation: true + shp: + baseurl: /app/detect/result diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 054d08ac..37250f1e 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -25,9 +25,9 @@ spring: data: redis: - host: localhost + host: 192.168.2.109 port: 6379 - password: 1234 + password: kamco servlet: multipart: @@ -53,3 +53,9 @@ token: springdoc: swagger-ui: persist-authorization: true # 스웨거 새로고침해도 토큰 유지, 로컬스토리지에 저장 + +mapsheet: + upload: + skipGdalValidation: true + shp: + baseurl: /Users/bokmin/detect/result diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index e989c2b4..7c633ecd 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -30,5 +30,9 @@ token: refresh-cookie-name: kamco # 개발용 쿠키 이름 refresh-cookie-secure: true # 로컬 http 테스트면 false - +mapsheet: + upload: + skipGdalValidation: true + shp: + baseurl: /app/detect/result