From ff2c54d38e117f9071ad7d64ab90a7f796d51e74 Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 30 Dec 2025 18:32:21 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=EC=9D=B4=EB=85=B8=ED=8E=A8=20=EB=AA=A9?= =?UTF-8?q?=EC=97=85=20=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Innopam/InnopamApiController.java | 145 ++++++++++++++++++ .../kamcoback/Innopam/dto/DetectMastDto.java | 91 +++++++++++ .../postgres/core/DetectMastCoreService.java | 62 ++++++++ .../postgres/entity/DetectMastEntity.java | 85 ++++++++++ .../repository/DetectMastRepository.java | 7 + .../DetectMastRepositoryCustom.java | 12 ++ .../repository/DetectMastRepositoryImpl.java | 59 +++++++ .../Innopam/service/DetectMastService.java | 59 +++++++ 8 files changed, 520 insertions(+) create mode 100644 src/main/java/com/kamco/cd/kamcoback/Innopam/InnopamApiController.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/Innopam/dto/DetectMastDto.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/core/DetectMastCoreService.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/entity/DetectMastEntity.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepository.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryCustom.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/Innopam/postgres/repository/DetectMastRepositoryImpl.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/Innopam/service/DetectMastService.java 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; + } +} From 0f7dda261b82f483b808504e84a97f31fd0f07ab Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Wed, 31 Dec 2025 09:10:11 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=EB=9D=BC=EB=B2=A8=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=ED=95=A0=EB=8B=B9=20=EB=A1=9C=EC=A7=81=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../label/LabelAllocateApiController.java | 76 ++++++++++++++++ .../kamcoback/label/dto/LabelAllocateDto.java | 48 ++++++++++ .../label/service/LabelAllocateService.java | 90 +++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java diff --git a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java new file mode 100644 index 00000000..29e5ab8f --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java @@ -0,0 +1,76 @@ +package com.kamco.cd.kamcoback.label; + +import com.kamco.cd.kamcoback.config.api.ApiResponseDto; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.Sheet; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetUser; +import com.kamco.cd.kamcoback.label.service.LabelAllocateService; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.ArrayList; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +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.RestController; + +@Slf4j +@Tag(name = "라벨링 작업 관리", description = "라벨링 작업 관리") +@RequestMapping({"/api/label/mng"}) +@RequiredArgsConstructor +@RestController +public class LabelAllocateApiController { + + // 라벨링 수량 할당하는 로직 테스트 + @PostMapping("/allocate") + public ApiResponseDto labelAllocate(@RequestBody LabelAllocateDto dto) { + + //도엽별 카운트 쿼리 + List sheets = List.of( + new Sheet("1", 261), + new Sheet("2", 500), + new Sheet("3", 350), + new Sheet("4", 250), + new Sheet("5", 380), + new Sheet("6", 459) + ); + + //사용자별 할당 입력한 값 + List targets = List.of( + new TargetUser("A", 1000), + new TargetUser("B", 500), + new TargetUser("C", 700) + ); + + LabelAllocateService.allocate(new ArrayList<>(sheets), new ArrayList<>(targets)); + + targets.forEach(t -> { + log.info("[" + t.getUserId() + "]"); + t.getAssigned().forEach(u -> { + log.info(" - 도엽: " + u.getSheetId() + " (" + u.getCount() + ")"); + }); + }); + /** + * [A] 입력한 수 : 1000 + * - 도엽: 2 (500) + * - 도엽: 6 (459) + * - 도엽: 5 (41) + * + * [B] 입력한 수 : 500 + * - 도엽: 5 (339) + * - 도엽: 3 (161) + * + * [C] 입력한 수 : 700 + * - 도엽: 3 (189) + * - 도엽: 1 (261) + * - 도엽: 4 (250) + */ + //A 에게 도엽 2 asc 해서 500건 할당 -> 도엽 6 asc 해서 459 할당 -> 도엽 5 asc 해서 41건 할당 -> insert + //B 에게 도엽 5 위에 41건 할당한 것 빼고 asc 해서 339건 할당 -> 도엽 3 asc 해서 161건 할당 -> insert + //.... for문에서 할당한 것 빼고 asc 해서 건수만큼 할당 insert 하고 다음 으로 넘어가기 + + return ApiResponseDto.ok(null); + } + +} diff --git a/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java b/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java new file mode 100644 index 00000000..612e3592 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java @@ -0,0 +1,48 @@ +package com.kamco.cd.kamcoback.label.dto; + +import java.util.ArrayList; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +public class LabelAllocateDto { + + @Getter + @AllArgsConstructor + public static class Sheet { + + private final String sheetId; + private int count; + + public void decrease(int amount) { + this.count -= amount; + } + } + + @Getter + public static class TargetUser { + + private final String userId; + private final int demand; + private final List assigned = new ArrayList<>(); + private int allocated = 0; + @Setter + private int shortage = 0; + + public TargetUser(String userId, int demand) { + this.userId = userId; + this.demand = demand; + } + + public int getRemainDemand() { + return demand - allocated; + } + + public void assign(String sheetId, int count) { + assigned.add(new Sheet(sheetId, count)); + allocated += count; + } + + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java b/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java new file mode 100644 index 00000000..9336893c --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java @@ -0,0 +1,90 @@ +package com.kamco.cd.kamcoback.label.service; + +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.Sheet; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetUser; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class LabelAllocateService { + + public static void allocate(List sheets, List targetUsers) { + + // 1️⃣ 실제 도엽 기준 할당 + allocateSheets(sheets, targetUsers); + + // 2️⃣ 전체 부족분 비율 계산 + distributeShortage(targetUsers); //항상 마지막에 한 번만 호출해야함 + + } + + public static void allocateSheets( + List sheets, + List targets + ) { + // 도엽 큰 것부터 (선택 사항) + sheets.sort(Comparator.comparingInt(Sheet::getCount).reversed()); + + for (TargetUser target : targets) { + Iterator it = sheets.iterator(); + + while (it.hasNext() && target.getRemainDemand() > 0) { + Sheet sheet = it.next(); + + int assignable = Math.min( + sheet.getCount(), + target.getRemainDemand() + ); + + if (assignable > 0) { + target.assign(sheet.getSheetId(), assignable); + sheet.decrease(assignable); + } + + if (sheet.getCount() == 0) { + it.remove(); + } + } + } + } + + public static void distributeShortage(List targets) { + + int totalDemand = targets.stream() + .mapToInt(TargetUser::getDemand) + .sum(); + + int totalAllocated = targets.stream() + .mapToInt(t -> t.getAllocated()) + .sum(); + + int shortage = totalDemand - totalAllocated; + + if (shortage <= 0) { + return; + } + + int distributed = 0; + + for (int i = 0; i < targets.size(); i++) { + TargetUser t = targets.get(i); + + // 마지막 타겟이 나머지 가져가게 (반올림 오차 방지) + int share; + if (i == targets.size() - 1) { + share = shortage - distributed; + } else { + double ratio = (double) t.getDemand() / totalDemand; + share = (int) Math.round(shortage * ratio); + distributed += share; + } + + t.setShortage(share); + } + } + +} From e7df2e7d86581d7dee220fb22a8ec55dcc979ffa Mon Sep 17 00:00:00 2001 From: teddy Date: Wed, 31 Dec 2025 09:25:02 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=EA=B0=9C=EB=B0=9C=EC=84=9C=EB=B2=84=20shp?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 4a00ed71..579b7a42 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -74,5 +74,5 @@ mapsheet: upload: skipGdalValidation: true shp: - baseurl: /app/detect/result + baseurl: /app/tmp/detect/result From 0df6151777a0c1c2c3c6149a8a1666e5be53ca28 Mon Sep 17 00:00:00 2001 From: teddy Date: Wed, 31 Dec 2025 09:25:30 +0900 Subject: [PATCH 4/4] =?UTF-8?q?spotless=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../label/LabelAllocateApiController.java | 63 ++++++++----------- .../kamcoback/label/dto/LabelAllocateDto.java | 6 +- .../label/service/LabelAllocateService.java | 22 ++----- 3 files changed, 34 insertions(+), 57 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java index 29e5ab8f..5a739715 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java @@ -26,51 +26,42 @@ public class LabelAllocateApiController { @PostMapping("/allocate") public ApiResponseDto labelAllocate(@RequestBody LabelAllocateDto dto) { - //도엽별 카운트 쿼리 - List sheets = List.of( - new Sheet("1", 261), - new Sheet("2", 500), - new Sheet("3", 350), - new Sheet("4", 250), - new Sheet("5", 380), - new Sheet("6", 459) - ); + // 도엽별 카운트 쿼리 + List sheets = + List.of( + new Sheet("1", 261), + new Sheet("2", 500), + new Sheet("3", 350), + new Sheet("4", 250), + new Sheet("5", 380), + new Sheet("6", 459)); - //사용자별 할당 입력한 값 - List targets = List.of( - new TargetUser("A", 1000), - new TargetUser("B", 500), - new TargetUser("C", 700) - ); + // 사용자별 할당 입력한 값 + List targets = + List.of(new TargetUser("A", 1000), new TargetUser("B", 500), new TargetUser("C", 700)); LabelAllocateService.allocate(new ArrayList<>(sheets), new ArrayList<>(targets)); - targets.forEach(t -> { - log.info("[" + t.getUserId() + "]"); - t.getAssigned().forEach(u -> { - log.info(" - 도엽: " + u.getSheetId() + " (" + u.getCount() + ")"); - }); - }); + targets.forEach( + t -> { + log.info("[" + t.getUserId() + "]"); + t.getAssigned() + .forEach( + u -> { + log.info(" - 도엽: " + u.getSheetId() + " (" + u.getCount() + ")"); + }); + }); /** - * [A] 입력한 수 : 1000 - * - 도엽: 2 (500) - * - 도엽: 6 (459) - * - 도엽: 5 (41) + * [A] 입력한 수 : 1000 - 도엽: 2 (500) - 도엽: 6 (459) - 도엽: 5 (41) * - * [B] 입력한 수 : 500 - * - 도엽: 5 (339) - * - 도엽: 3 (161) + *

[B] 입력한 수 : 500 - 도엽: 5 (339) - 도엽: 3 (161) * - * [C] 입력한 수 : 700 - * - 도엽: 3 (189) - * - 도엽: 1 (261) - * - 도엽: 4 (250) + *

[C] 입력한 수 : 700 - 도엽: 3 (189) - 도엽: 1 (261) - 도엽: 4 (250) */ - //A 에게 도엽 2 asc 해서 500건 할당 -> 도엽 6 asc 해서 459 할당 -> 도엽 5 asc 해서 41건 할당 -> insert - //B 에게 도엽 5 위에 41건 할당한 것 빼고 asc 해서 339건 할당 -> 도엽 3 asc 해서 161건 할당 -> insert - //.... for문에서 할당한 것 빼고 asc 해서 건수만큼 할당 insert 하고 다음 으로 넘어가기 + // A 에게 도엽 2 asc 해서 500건 할당 -> 도엽 6 asc 해서 459 할당 -> 도엽 5 asc 해서 41건 할당 -> insert + // B 에게 도엽 5 위에 41건 할당한 것 빼고 asc 해서 339건 할당 -> 도엽 3 asc 해서 161건 할당 -> insert + // .... for문에서 할당한 것 빼고 asc 해서 건수만큼 할당 insert 하고 다음 으로 넘어가기 return ApiResponseDto.ok(null); } - } diff --git a/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java b/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java index 612e3592..a6802547 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java @@ -27,8 +27,7 @@ public class LabelAllocateDto { private final int demand; private final List assigned = new ArrayList<>(); private int allocated = 0; - @Setter - private int shortage = 0; + @Setter private int shortage = 0; public TargetUser(String userId, int demand) { this.userId = userId; @@ -38,11 +37,10 @@ public class LabelAllocateDto { public int getRemainDemand() { return demand - allocated; } - + public void assign(String sheetId, int count) { assigned.add(new Sheet(sheetId, count)); allocated += count; } - } } diff --git a/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java b/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java index 9336893c..547284b6 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java @@ -18,14 +18,10 @@ public class LabelAllocateService { allocateSheets(sheets, targetUsers); // 2️⃣ 전체 부족분 비율 계산 - distributeShortage(targetUsers); //항상 마지막에 한 번만 호출해야함 - + distributeShortage(targetUsers); // 항상 마지막에 한 번만 호출해야함 } - public static void allocateSheets( - List sheets, - List targets - ) { + public static void allocateSheets(List sheets, List targets) { // 도엽 큰 것부터 (선택 사항) sheets.sort(Comparator.comparingInt(Sheet::getCount).reversed()); @@ -35,10 +31,7 @@ public class LabelAllocateService { while (it.hasNext() && target.getRemainDemand() > 0) { Sheet sheet = it.next(); - int assignable = Math.min( - sheet.getCount(), - target.getRemainDemand() - ); + int assignable = Math.min(sheet.getCount(), target.getRemainDemand()); if (assignable > 0) { target.assign(sheet.getSheetId(), assignable); @@ -54,13 +47,9 @@ public class LabelAllocateService { public static void distributeShortage(List targets) { - int totalDemand = targets.stream() - .mapToInt(TargetUser::getDemand) - .sum(); + int totalDemand = targets.stream().mapToInt(TargetUser::getDemand).sum(); - int totalAllocated = targets.stream() - .mapToInt(t -> t.getAllocated()) - .sum(); + int totalAllocated = targets.stream().mapToInt(t -> t.getAllocated()).sum(); int shortage = totalDemand - totalAllocated; @@ -86,5 +75,4 @@ public class LabelAllocateService { t.setShortage(share); } } - }