diff --git a/src/main/java/com/kamco/cd/kamcoback/common/api/HelloApiController.java b/src/main/java/com/kamco/cd/kamcoback/common/api/HelloApiController.java deleted file mode 100644 index c836b1fc..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/common/api/HelloApiController.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.kamco.cd.kamcoback.common.api; - -import com.kamco.cd.kamcoback.common.api.HelloDto.Res; -import com.kamco.cd.kamcoback.common.service.ExternalJarRunner; -import com.kamco.cd.kamcoback.common.service.HelloService; -import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient; -import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient.ExternalCallResult; -import io.swagger.v3.oas.annotations.Parameter; -import java.util.List; -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@Log4j2 -@RequiredArgsConstructor -@RestController -@RequestMapping("/api/hello") -public class HelloApiController { - - private final HelloService helloService; - private final ExternalJarRunner externalJarRunner; - private final ExternalHttpClient externalHttpClient; - - @GetMapping - public HelloDto.Res hello(HelloDto.Req req) { - req.valid(); - - Res res = helloService.sayHello(req); - - return res; - } - - @GetMapping("/shp") - public void shp( - @Parameter(description = "jar 경로", example = "jar/makeshp-1.0.0.jar") @RequestParam - String jarPath, - @Parameter(description = "batchIds", example = "252,253,257") @RequestParam String batchIds, - @Parameter(description = "32길이 문자열 값", example = "") @RequestParam(required = false) - String inferenceId, - @Parameter(description = "5K 도엽번호", example = "") @RequestParam(required = false) - String mapIds) { - externalJarRunner.run(jarPath, batchIds, inferenceId, mapIds); - } - - @GetMapping("/batch/{batchId}") - public String batch(@PathVariable String batchId) { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - headers.setAccept(List.of(MediaType.APPLICATION_JSON)); - String url = "http://10.100.0.11:8000/batches" + "/" + batchId; - ExternalCallResult result = - externalHttpClient.call(url, HttpMethod.GET, null, headers, String.class); - - int status = result.statusCode(); - if (status == 404) { - log.info("Batch not found. batchId={}", batchId); - return null; - } - if (status < 200 || status >= 300) { - return null; - } - return result.toString(); - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/common/api/HelloDto.java b/src/main/java/com/kamco/cd/kamcoback/common/api/HelloDto.java deleted file mode 100644 index f7668196..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/common/api/HelloDto.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.kamco.cd.kamcoback.common.api; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -public class HelloDto { - - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class Req { - private String id; - - public void valid() { - if (id == null) { - throw new IllegalArgumentException(id); - } - } - } - - @Getter - public static class Res { - private String id; - private String name; - - @Builder - public Res(String id, String name) { - this.id = id; - this.name = name; - } - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/common/service/ExternalJarRunner.java b/src/main/java/com/kamco/cd/kamcoback/common/service/ExternalJarRunner.java index 06835b2e..5eb83d70 100644 --- a/src/main/java/com/kamco/cd/kamcoback/common/service/ExternalJarRunner.java +++ b/src/main/java/com/kamco/cd/kamcoback/common/service/ExternalJarRunner.java @@ -18,27 +18,38 @@ public class ExternalJarRunner { /** * shp 파일 생성 * - * @param jarPath jar 경로 - * @param batchIds 배치 아이디 + * @param jarPath jar 경로 + * @param batchIds 배치 아이디 * @param inferenceId uid - * @param mapIds 도엽 Id + * @param mapIds 추론 실행한 도엽 ids + * @param mode

MERGED - batch-ids 에 해당하는 **모든 데이터를 하나의 Shapefile로 병합 생성, + *

MAP_IDS - 명시적으로 전달한 map-ids만 대상으로 Shapefile 생성, + *

RESOLVE - batch-ids 기준으로 **JAR 내부에서 map_ids를 조회**한 뒤 Shapefile 생성 */ - public void run(String jarPath, String batchIds, String inferenceId, String mapIds) { + public void run(String jarPath, String batchIds, String inferenceId, String mapIds, String mode) { List args = new ArrayList<>(); addArg(args, "converter.inference-id", inferenceId); - addArg(args, "converter.map-ids", mapIds); addArg(args, "converter.batch-ids", batchIds); + if (mapIds != null && !mapIds.isEmpty()) { + addArg(args, "converter.map-ids", mapIds); + } + + if (mode != null && !mode.isEmpty()) { + addArg(args, "converter.mode", mode); + } + execJar(jarPath, args); } + /** * geoserver 등록 * - * @param jarPath jar 파일경로 + * @param jarPath jar 파일경로 * @param register shp 경로 - * @param layer geoserver에 등록될 레이어 이름 + * @param layer geoserver에 등록될 레이어 이름 */ public void run(String jarPath, String register, String layer) { List args = new ArrayList<>(); @@ -65,7 +76,7 @@ public class ExternalJarRunner { Process p = pb.start(); try (BufferedReader br = - new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8))) { + new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8))) { String line; while ((line = br.readLine()) != null) { out.append(line).append('\n'); diff --git a/src/main/java/com/kamco/cd/kamcoback/common/service/HelloService.java b/src/main/java/com/kamco/cd/kamcoback/common/service/HelloService.java deleted file mode 100644 index a3b4b4f5..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/common/service/HelloService.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.kamco.cd.kamcoback.common.service; - -import com.kamco.cd.kamcoback.common.api.HelloDto; -import java.util.UUID; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -public class HelloService { - - public HelloDto.Res sayHello(HelloDto.Req req) { - log.info("hello"); - String name = UUID.randomUUID().toString(); - return HelloDto.Res.builder().id(req.getId()).name(name).build(); - } -} 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 d6a2a1c7..c5b6555b 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 @@ -2,7 +2,6 @@ package com.kamco.cd.kamcoback.inference.service; import com.kamco.cd.kamcoback.inference.dto.InferenceResultShpDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultShpDto.CreateShpRequest; -import com.kamco.cd.kamcoback.inference.dto.InferenceResultsTestingDto; import com.kamco.cd.kamcoback.postgres.core.InferenceResultCoreService; import com.kamco.cd.kamcoback.postgres.core.InferenceResultShpCoreService; import com.kamco.cd.kamcoback.scheduler.service.ShpPipelineService; @@ -31,7 +30,9 @@ public class InferenceResultShpService { @Value("${file.dataset-dir}") private String datasetDir; - /** inference_results 테이블을 기준으로 분석 결과 테이블과 도형 테이블을 최신 상태로 반영한다. */ + /** + * inference_results 테이블을 기준으로 분석 결과 테이블과 도형 테이블을 최신 상태로 반영한다. + */ @Transactional public InferenceResultShpDto.InferenceCntDto saveInferenceResultData(Long id) { return coreService.buildInferenceData(id); @@ -49,25 +50,9 @@ public class InferenceResultShpService { batchIds.add(req.getM2BatchId()); batchIds.add(req.getM3BatchId()); - List resultList = - inferenceResultCoreService.getInferenceResults(batchIds); - String inferenceId = ""; - StringBuilder sb = new StringBuilder(); - - for (InferenceResultsTestingDto.ShpDto dto : resultList) { - if (dto.getMapId() == null) { - continue; - } - if (!sb.isEmpty()) { - sb.append(","); - } - sb.append("\"").append(dto.getMapId()).append("\""); - } - inferenceId = uid; - String mapIds = sb.toString(); String batchId = req.getM1BatchId() + "," + req.getM2BatchId() + "," + req.getM3BatchId(); // shp 파일 비동기 생성 - shpPipelineService.runPipeline(jarPath, datasetDir, batchId, inferenceId, mapIds); + shpPipelineService.runPipeline(jarPath, datasetDir, batchId, uid); } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/AnimalCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/AnimalCoreService.java deleted file mode 100644 index 86807dab..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/AnimalCoreService.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.kamco.cd.kamcoback.postgres.core; - -import com.kamco.cd.kamcoback.common.service.BaseCoreService; -import com.kamco.cd.kamcoback.postgres.entity.AnimalEntity; -import com.kamco.cd.kamcoback.postgres.entity.ZooEntity; -import com.kamco.cd.kamcoback.postgres.repository.AnimalRepository; -import com.kamco.cd.kamcoback.postgres.repository.ZooRepository; -import com.kamco.cd.kamcoback.zoo.dto.AnimalDto; -import jakarta.persistence.EntityNotFoundException; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class AnimalCoreService - implements BaseCoreService { - - private final AnimalRepository animalRepository; - private final ZooRepository zooRepository; - - @Transactional(readOnly = true) - public AnimalDto.Basic getDataByUuid(String uuid) { - AnimalEntity getZoo = - animalRepository - .getAnimalByUuid(uuid) - .orElseThrow(() -> new EntityNotFoundException("Zoo not found with uuid: " + uuid)); - return getZoo.toDto(); - } - - // AddReq를 받는 추가 메서드 - @Transactional - public AnimalDto.Basic create(AnimalDto.AddReq req) { - ZooEntity zoo = null; - if (req.getZooUuid() != null) { - zoo = - zooRepository - .getZooByUuid(req.getZooUuid()) - .orElseThrow( - () -> - new EntityNotFoundException("Zoo not found with uuid: " + req.getZooUuid())); - } - AnimalEntity entity = new AnimalEntity(req.getCategory(), req.getSpecies(), req.getName(), zoo); - AnimalEntity saved = animalRepository.save(entity); - return saved.toDto(); - } - - @Override - @Transactional - public void remove(Long id) { - AnimalEntity getAnimal = - animalRepository - .getAnimalByUid(id) - .orElseThrow(() -> new EntityNotFoundException("getAnimal not found with id: " + id)); - getAnimal.deleted(); - } - - @Override - public AnimalDto.Basic getOneById(Long id) { - AnimalEntity getAnimal = - animalRepository - .getAnimalByUid(id) - .orElseThrow(() -> new EntityNotFoundException("Zoo not found with id: " + id)); - return getAnimal.toDto(); - } - - @Override - public Page search(AnimalDto.SearchReq searchReq) { - - Page animalEntities = animalRepository.listAnimal(searchReq); - return animalEntities.map(AnimalEntity::toDto); - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/ZooCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/ZooCoreService.java deleted file mode 100644 index c8092c7b..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/ZooCoreService.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.kamco.cd.kamcoback.postgres.core; - -import com.kamco.cd.kamcoback.common.service.BaseCoreService; -import com.kamco.cd.kamcoback.postgres.entity.ZooEntity; -import com.kamco.cd.kamcoback.postgres.repository.ZooRepository; -import com.kamco.cd.kamcoback.zoo.dto.ZooDto; -import jakarta.persistence.EntityNotFoundException; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class ZooCoreService implements BaseCoreService { - - private final ZooRepository zooRepository; - - @Transactional(readOnly = true) - public ZooDto.Detail getDataByUuid(String uuid) { - ZooEntity zoo = - zooRepository - .getZooByUuid(uuid) - .orElseThrow(() -> new EntityNotFoundException("Zoo not found with uuid: " + uuid)); - return toDetailDto(zoo); - } - - // AddReq를 받는 추가 메서드 - @Transactional - public ZooDto.Detail create(ZooDto.AddReq req) { - ZooEntity entity = new ZooEntity(req.getName(), req.getLocation(), req.getDescription()); - ZooEntity saved = zooRepository.save(entity); - return toDetailDto(saved); - } - - @Override - @Transactional - public void remove(Long id) { - ZooEntity zoo = - zooRepository - .getZooByUid(id) - .orElseThrow(() -> new EntityNotFoundException("Zoo not found with id: " + id)); - zoo.deleted(); - } - - @Override - public ZooDto.Detail getOneById(Long id) { - ZooEntity zoo = - zooRepository - .getZooByUid(id) - .orElseThrow(() -> new EntityNotFoundException("Zoo not found with id: " + id)); - return toDetailDto(zoo); - } - - @Override - public Page search(ZooDto.SearchReq searchReq) { - Page zooEntities = zooRepository.listZoo(searchReq); - - // N+1 문제 해결: 한 번의 쿼리로 모든 Zoo의 animal count 조회 - List zooIds = - zooEntities.getContent().stream().map(ZooEntity::getUid).collect(Collectors.toList()); - - Map animalCountMap = zooRepository.countActiveAnimalsByZooIds(zooIds); - - // DTO 변환 - List details = - zooEntities.getContent().stream() - .map(zoo -> toDetailDtoWithCountMap(zoo, animalCountMap)) - .collect(Collectors.toList()); - - return new PageImpl<>(details, zooEntities.getPageable(), zooEntities.getTotalElements()); - } - - // Entity -> Detail DTO 변환 (동물 개수 포함) - 단건 조회용 - private ZooDto.Detail toDetailDto(ZooEntity zoo) { - Long activeAnimalCount = zooRepository.countActiveAnimals(zoo.getUid()); - return new ZooDto.Detail( - zoo.getUid(), - zoo.getUuid().toString(), - zoo.getName(), - zoo.getLocation(), - zoo.getDescription(), - zoo.getCreatedDate(), - zoo.getModifiedDate(), - activeAnimalCount); - } - - // Entity -> Detail DTO 변환 (동물 개수 포함) - 배치 조회용 (N+1 해결) - private ZooDto.Detail toDetailDtoWithCountMap(ZooEntity zoo, Map countMap) { - Long activeAnimalCount = countMap.getOrDefault(zoo.getUid(), 0L); - return new ZooDto.Detail( - zoo.getUid(), - zoo.getUuid().toString(), - zoo.getName(), - zoo.getLocation(), - zoo.getDescription(), - zoo.getCreatedDate(), - zoo.getModifiedDate(), - activeAnimalCount); - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/AnimalEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/AnimalEntity.java deleted file mode 100644 index c6d78000..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/AnimalEntity.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.kamco.cd.kamcoback.postgres.entity; - -import com.kamco.cd.kamcoback.postgres.CommonDateEntity; -import com.kamco.cd.kamcoback.zoo.dto.AnimalDto; -import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.Category; -import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.Species; -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.Table; -import java.util.UUID; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -// 기본구조 관련 - -@Entity -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(name = "tb_animal") -public class AnimalEntity extends CommonDateEntity { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long uid; - - @Column(unique = true) - private UUID uuid; - - @Enumerated(EnumType.STRING) - private Category category; - - @Enumerated(EnumType.STRING) - private Species species; - - private String name; - private Boolean isDeleted; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "zoo_id") - private ZooEntity zoo; - - // Construct - public AnimalEntity(Category category, Species species, String name, ZooEntity zoo) { - this.uuid = UUID.randomUUID(); - this.category = category; - this.species = species; - this.name = name; - this.isDeleted = false; - this.zoo = zoo; - } - - public AnimalDto.Basic toDto() { - return new AnimalDto.Basic( - this.uid, - this.uuid.toString(), - this.name, - this.category, - this.species, - super.getCreatedDate(), - super.getModifiedDate()); - } - - public void deleted() { - this.isDeleted = true; - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/ZooEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/ZooEntity.java deleted file mode 100644 index 9d7f18b4..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/ZooEntity.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.kamco.cd.kamcoback.postgres.entity; - -import com.kamco.cd.kamcoback.postgres.CommonDateEntity; -import jakarta.persistence.CascadeType; -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.OneToMany; -import jakarta.persistence.Table; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Entity -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(name = "tb_zoo") -public class ZooEntity extends CommonDateEntity { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long uid; - - @Column(unique = true, nullable = false) - private UUID uuid; - - @Column(nullable = false, length = 200) - private String name; - - @Column(length = 300) - private String location; - - @Column(columnDefinition = "TEXT") - private String description; - - @Column(nullable = false) - private Boolean isDeleted; - - @OneToMany(mappedBy = "zoo", fetch = FetchType.LAZY, cascade = CascadeType.ALL) - private List animals = new ArrayList<>(); - - // Constructor - public ZooEntity(String name, String location, String description) { - this.uuid = UUID.randomUUID(); - this.name = name; - this.location = location; - this.description = description; - this.isDeleted = false; - } - - // 논리 삭제 - public void deleted() { - this.isDeleted = true; - } - - // 현재 활성 동물 개수 조회 (삭제되지 않은 동물만) - public long getActiveAnimalCount() { - return animals.stream().filter(animal -> !animal.getIsDeleted()).count(); - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/AnimalRepository.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/AnimalRepository.java deleted file mode 100644 index c549fecf..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/AnimalRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.kamco.cd.kamcoback.postgres.repository; - -import com.kamco.cd.kamcoback.postgres.entity.AnimalEntity; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface AnimalRepository - extends JpaRepository, AnimalRepositoryCustom {} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/AnimalRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/AnimalRepositoryCustom.java deleted file mode 100644 index 7e95efc0..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/AnimalRepositoryCustom.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.kamco.cd.kamcoback.postgres.repository; - -import com.kamco.cd.kamcoback.postgres.entity.AnimalEntity; -import com.kamco.cd.kamcoback.zoo.dto.AnimalDto; -import java.util.Optional; -import org.springframework.data.domain.Page; - -public interface AnimalRepositoryCustom { - - Optional getAnimalByUid(Long uid); - - Optional getAnimalByUuid(String uuid); - - Page listAnimal(AnimalDto.SearchReq req); -} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/AnimalRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/AnimalRepositoryImpl.java deleted file mode 100644 index 5e9b4826..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/AnimalRepositoryImpl.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.kamco.cd.kamcoback.postgres.repository; - -import com.kamco.cd.kamcoback.postgres.entity.AnimalEntity; -import com.kamco.cd.kamcoback.postgres.entity.QAnimalEntity; -import com.kamco.cd.kamcoback.zoo.dto.AnimalDto; -import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.Category; -import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.Species; -import com.querydsl.core.types.dsl.BooleanExpression; -import com.querydsl.jpa.impl.JPAQueryFactory; -import java.util.List; -import java.util.Optional; -import java.util.UUID; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; - -public class AnimalRepositoryImpl extends QuerydslRepositorySupport - implements AnimalRepositoryCustom { - - private final JPAQueryFactory queryFactory; - - public AnimalRepositoryImpl(JPAQueryFactory queryFactory) { - super(AnimalEntity.class); - this.queryFactory = queryFactory; - } - - public Optional getAnimalByUid(Long uid) { - QAnimalEntity animal = QAnimalEntity.animalEntity; - - return Optional.ofNullable( - queryFactory.selectFrom(animal).where(animal.uid.eq(uid)).fetchFirst()); - } - - public Optional getAnimalByUuid(String uuid) { - QAnimalEntity animal = QAnimalEntity.animalEntity; - - return Optional.ofNullable( - queryFactory.selectFrom(animal).where(animal.uuid.eq(UUID.fromString(uuid))).fetchFirst()); - } - - @Override - public Page listAnimal(AnimalDto.SearchReq req) { - QAnimalEntity animal = QAnimalEntity.animalEntity; - - Pageable pageable = req.toPageable(); - - List content = - queryFactory - .selectFrom(animal) - .where( - animal.isDeleted.eq(false), - eqCategory(animal, req.getCategory()), - eqSpecies(animal, req.getSpecies()), - likeName(animal, req.getName())) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) - .orderBy(animal.createdDate.desc()) - .fetch(); - - // count 쿼리 - Long total = - queryFactory - .select(animal.count()) - .from(animal) - .where( - animal.isDeleted.eq(false), - eqCategory(animal, req.getCategory()), - eqSpecies(animal, req.getSpecies()), - likeName(animal, req.getName())) - .fetchOne(); - - return new PageImpl<>(content, pageable, total); - } - - private BooleanExpression likeName(QAnimalEntity animal, String nameStr) { - if (nameStr == null || nameStr.isEmpty()) { - return null; - } - return animal.name.containsIgnoreCase(nameStr.trim()); - } - - private BooleanExpression eqCategory(QAnimalEntity animal, Category category) { - if (category == null) { - return null; - } - return animal.category.eq(category); - } - - private BooleanExpression eqSpecies(QAnimalEntity animal, Species species) { - if (species == null) { - return null; - } - return animal.species.eq(species); - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/ZooRepository.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/ZooRepository.java deleted file mode 100644 index a2ee0cdd..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/ZooRepository.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.kamco.cd.kamcoback.postgres.repository; - -import com.kamco.cd.kamcoback.postgres.entity.ZooEntity; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface ZooRepository extends JpaRepository, ZooRepositoryCustom {} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/ZooRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/ZooRepositoryCustom.java deleted file mode 100644 index 51e17ebb..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/ZooRepositoryCustom.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.kamco.cd.kamcoback.postgres.repository; - -import com.kamco.cd.kamcoback.postgres.entity.ZooEntity; -import com.kamco.cd.kamcoback.zoo.dto.ZooDto; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import org.springframework.data.domain.Page; - -public interface ZooRepositoryCustom { - - Page listZoo(ZooDto.SearchReq searchReq); - - Optional getZooByUuid(String uuid); - - Optional getZooByUid(Long uid); - - Long countActiveAnimals(Long zooId); - - /** - * 여러 Zoo의 활성 동물 수를 한 번에 조회 (N+1 문제 해결) - * - * @param zooIds Zoo ID 목록 - * @return Map - */ - Map countActiveAnimalsByZooIds(List zooIds); -} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/ZooRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/ZooRepositoryImpl.java deleted file mode 100644 index 2dd41c02..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/ZooRepositoryImpl.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.kamco.cd.kamcoback.postgres.repository; - -import com.kamco.cd.kamcoback.postgres.entity.QAnimalEntity; -import com.kamco.cd.kamcoback.postgres.entity.QZooEntity; -import com.kamco.cd.kamcoback.postgres.entity.ZooEntity; -import com.kamco.cd.kamcoback.zoo.dto.ZooDto; -import com.querydsl.core.types.dsl.BooleanExpression; -import com.querydsl.jpa.impl.JPAQuery; -import com.querydsl.jpa.impl.JPAQueryFactory; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Repository; - -@Repository -@RequiredArgsConstructor -public class ZooRepositoryImpl implements ZooRepositoryCustom { - - private final JPAQueryFactory queryFactory; - private final QZooEntity qZoo = QZooEntity.zooEntity; - private final QAnimalEntity qAnimal = QAnimalEntity.animalEntity; - - @Override - public Page listZoo(ZooDto.SearchReq searchReq) { - Pageable pageable = searchReq.toPageable(); - - JPAQuery query = - queryFactory - .selectFrom(qZoo) - .where( - qZoo.isDeleted.eq(false), - nameContains(searchReq.getName()), - locationContains(searchReq.getLocation())); - - long total = query.fetchCount(); - - List content = - query - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) - .orderBy(qZoo.createdDate.desc()) - .fetch(); - - return new PageImpl<>(content, pageable, total); - } - - @Override - public Optional getZooByUuid(String uuid) { - return Optional.ofNullable( - queryFactory - .selectFrom(qZoo) - .where(qZoo.uuid.eq(UUID.fromString(uuid)), qZoo.isDeleted.eq(false)) - .fetchOne()); - } - - @Override - public Optional getZooByUid(Long uid) { - return Optional.ofNullable( - queryFactory.selectFrom(qZoo).where(qZoo.uid.eq(uid), qZoo.isDeleted.eq(false)).fetchOne()); - } - - @Override - public Long countActiveAnimals(Long zooId) { - Long count = - queryFactory - .select(qAnimal.count()) - .from(qAnimal) - .where(qAnimal.zoo.uid.eq(zooId), qAnimal.isDeleted.eq(false)) - .fetchOne(); - - return count != null ? count : 0L; - } - - @Override - public Map countActiveAnimalsByZooIds(List zooIds) { - if (zooIds == null || zooIds.isEmpty()) { - return new HashMap<>(); - } - - // QueryDSL group by로 한 번에 조회 - List results = - queryFactory - .select(qAnimal.zoo.uid, qAnimal.count()) - .from(qAnimal) - .where(qAnimal.zoo.uid.in(zooIds), qAnimal.isDeleted.eq(false)) - .groupBy(qAnimal.zoo.uid) - .fetch(); - - // Map으로 변환 - Map countMap = new HashMap<>(); - for (com.querydsl.core.Tuple tuple : results) { - Long zooId = tuple.get(qAnimal.zoo.uid); - Long count = tuple.get(qAnimal.count()); - if (zooId != null && count != null) { - countMap.put(zooId, count); - } - } - - // 조회되지 않은 Zoo는 0으로 설정 - for (Long zooId : zooIds) { - countMap.putIfAbsent(zooId, 0L); - } - - return countMap; - } - - private BooleanExpression nameContains(String name) { - return name != null && !name.isEmpty() ? qZoo.name.contains(name) : null; - } - - private BooleanExpression locationContains(String location) { - return location != null && !location.isEmpty() ? qZoo.location.contains(location) : null; - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java index 7192b10d..e27e1c52 100644 --- a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java +++ b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java @@ -10,7 +10,6 @@ import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.InferenceBatchShe import com.kamco.cd.kamcoback.inference.dto.InferenceProgressDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.SaveInferenceAiDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.Status; -import com.kamco.cd.kamcoback.inference.dto.InferenceResultsTestingDto; import com.kamco.cd.kamcoback.inference.dto.InferenceSendDto; import com.kamco.cd.kamcoback.postgres.core.InferenceResultCoreService; import com.kamco.cd.kamcoback.scheduler.dto.BatchStatusDto; @@ -59,7 +58,9 @@ public class MapSheetInferenceJobService { @Value("${file.dataset-dir}") private String datasetDir; - /** 추론 진행 배치 1분 60_000 */ + /** + * 추론 진행 배치 1분 60_000 + */ @Scheduled(fixedDelay = 60_000) public void runBatch() { if (isLocalProfile()) { @@ -144,7 +145,7 @@ public class MapSheetInferenceJobService { String url = batchUrl + "/" + batchId; ExternalCallResult result = - externalHttpClient.call(url, HttpMethod.GET, null, jsonHeaders(), String.class); + externalHttpClient.call(url, HttpMethod.GET, null, jsonHeaders(), String.class); int status = result.statusCode(); if (status == 404) { @@ -169,7 +170,7 @@ public class MapSheetInferenceJobService { String url = inferenceUrl + "/" + jobId; ExternalCallResult result = - externalHttpClient.call(url, HttpMethod.GET, null, jsonHeaders(), String.class); + externalHttpClient.call(url, HttpMethod.GET, null, jsonHeaders(), String.class); int status = result.statusCode(); if (status == 404) { @@ -250,26 +251,10 @@ public class MapSheetInferenceJobService { batchIds.add(sheet.getM2BatchId()); batchIds.add(sheet.getM3BatchId()); - List resultList = - inferenceResultCoreService.getInferenceResults(batchIds); - String inferenceId = ""; - StringBuilder sb = new StringBuilder(); - - for (InferenceResultsTestingDto.ShpDto dto : resultList) { - if (dto.getMapId() == null) { - continue; - } - if (!sb.isEmpty()) { - sb.append(","); - } - sb.append("\"").append(dto.getMapId()).append("\""); - } - inferenceId = sheet.getUid(); - String mapIds = sb.toString(); String batchId = sheet.getM1BatchId() + "," + sheet.getM2BatchId() + "," + sheet.getM3BatchId(); // shp 파일 비동기 생성 - shpPipelineService.runPipeline(jarPath, datasetDir, batchId, inferenceId, mapIds); + shpPipelineService.runPipeline(jarPath, datasetDir, batchId, sheet.getUid()); } /** @@ -343,28 +328,28 @@ public class MapSheetInferenceJobService { // 추론 실행 api 파라미터 조회 InferenceProgressDto progressDto = - inferenceResultCoreService.getInferenceAiResultById(id, modelUuid); + inferenceResultCoreService.getInferenceAiResultById(id, modelUuid); // ai 에 맞는 모델 명으로 변경 String inferenceType = modelToInferenceType(type); InferenceSendDto.pred_requests_areas predRequestsAreas = - new InferenceSendDto.pred_requests_areas(); + new InferenceSendDto.pred_requests_areas(); predRequestsAreas.setInput1_year(progressDto.getPred_requests_areas().getInput1_year()); predRequestsAreas.setInput2_year(progressDto.getPred_requests_areas().getInput2_year()); predRequestsAreas.setInput1_scene_path( - progressDto.getPred_requests_areas().getInput1_scene_path()); + progressDto.getPred_requests_areas().getInput1_scene_path()); predRequestsAreas.setInput2_scene_path( - progressDto.getPred_requests_areas().getInput2_scene_path()); + progressDto.getPred_requests_areas().getInput2_scene_path()); InferenceSendDto m = new InferenceSendDto(); m.setPred_requests_areas(predRequestsAreas); m.setModel_version(progressDto.getModelVersion()); m.setCd_model_path(progressDto.getCdModelPath() + "/" + progressDto.getCdModelFileName()); m.setCd_model_config( - progressDto.getCdModelConfigPath() + "/" + progressDto.getCdModelConfigFileName()); + progressDto.getCdModelConfigPath() + "/" + progressDto.getCdModelConfigFileName()); m.setCls_model_path( - progressDto.getCdModelClsPath() + "/" + progressDto.getCdModelClsFileName()); + progressDto.getCdModelClsPath() + "/" + progressDto.getCdModelClsFileName()); m.setCls_model_version(progressDto.getClsModelVersion()); m.setCd_model_type(inferenceType); m.setPriority(progressDto.getPriority()); @@ -432,7 +417,7 @@ public class MapSheetInferenceJobService { headers.setAccept(List.of(MediaType.APPLICATION_JSON)); ExternalCallResult result = - externalHttpClient.call(inferenceUrl, HttpMethod.POST, dto, headers, String.class); + externalHttpClient.call(inferenceUrl, HttpMethod.POST, dto, headers, String.class); if (result.statusCode() < 200 || result.statusCode() >= 300) { log.error("Inference API failed. status={}, body={}", result.statusCode(), result.body()); @@ -442,7 +427,8 @@ public class MapSheetInferenceJobService { // 4) 응답 파싱 try { List> list = - objectMapper.readValue(result.body(), new TypeReference<>() {}); + objectMapper.readValue(result.body(), new TypeReference<>() { + }); if (list.isEmpty()) { throw new IllegalStateException("Inference response is empty"); @@ -470,9 +456,11 @@ public class MapSheetInferenceJobService { return "local".equalsIgnoreCase(profile); } - /** 모델별 추론 종료 update */ + /** + * 모델별 추론 종료 update + */ private void updateProcessingEndTimeByModel( - BatchStatusDto dto, UUID uuid, ZonedDateTime dateTime, String type) { + BatchStatusDto dto, UUID uuid, ZonedDateTime dateTime, String type) { SaveInferenceAiDto saveInferenceAiDto = new SaveInferenceAiDto(); saveInferenceAiDto.setUuid(uuid); saveInferenceAiDto.setUpdateUid(0L); @@ -506,16 +494,16 @@ public class MapSheetInferenceJobService { /** * 도엽별 실패여부 업데이트 * - * @param dto batch 정보 + * @param dto batch 정보 * @param uuid uuid * @param type 모델 타입 */ private void saveFail5k(BatchStatusDto dto, UUID uuid, String type) { List failedIds = - Optional.ofNullable(dto.getFailedIds()).orElse(List.of()).stream() - .map(Long::valueOf) - .toList(); + Optional.ofNullable(dto.getFailedIds()).orElse(List.of()).stream() + .map(Long::valueOf) + .toList(); List jobIds = inferenceResultCoreService.findFail5kList(uuid, failedIds, type); @@ -540,16 +528,16 @@ public class MapSheetInferenceJobService { /** * 도엽별 job id 저장 * - * @param dto batch 정보 + * @param dto batch 정보 * @param uuid uuid * @param type 모델 타입 */ private void saveCompleted5k(BatchStatusDto dto, UUID uuid, String type) { List completedIds = - Optional.ofNullable(dto.getCompletedIds()).orElse(List.of()).stream() - .map(Long::valueOf) - .toList(); + Optional.ofNullable(dto.getCompletedIds()).orElse(List.of()).stream() + .map(Long::valueOf) + .toList(); List jobIds = inferenceResultCoreService.findCompleted5kList(uuid, completedIds, type); diff --git a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/ShpPipelineService.java b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/ShpPipelineService.java index 9f839048..3f4a86ff 100644 --- a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/ShpPipelineService.java +++ b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/ShpPipelineService.java @@ -17,7 +17,7 @@ public class ShpPipelineService { @Async("shpExecutor") public void runPipeline( - String jarPath, String datasetDir, String batchId, String inferenceId, String mapIds) { + String jarPath, String datasetDir, String batchId, String inferenceId) { // inferenceId 기준 동시 실행 제한 if (!shpKeyLock.tryLock(inferenceId)) { @@ -27,15 +27,14 @@ public class ShpPipelineService { try { // uid 기준 merge shp, geojson 파일 생성 - externalJarRunner.run(jarPath, batchId, inferenceId, ""); + externalJarRunner.run(jarPath, batchId, inferenceId, "", "MERGED"); // uid 기준 shp 파일 geoserver 등록 String register = datasetDir + "/" + inferenceId + "/merge/" + inferenceId + ".shp"; externalJarRunner.run(jarPath, register, inferenceId); // uid 기준 도엽별 shp, geojson 파일 생성 - // TODO 도엽별은 속도 확인 후 다시 체크 - externalJarRunner.run(jarPath, batchId, inferenceId, mapIds); + externalJarRunner.run(jarPath, batchId, inferenceId, "", "RESOLVE"); log.info("SHP pipeline finished. inferenceId={}", inferenceId); diff --git a/src/main/java/com/kamco/cd/kamcoback/zoo/AnimalApiController.java b/src/main/java/com/kamco/cd/kamcoback/zoo/AnimalApiController.java deleted file mode 100644 index c028653c..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/zoo/AnimalApiController.java +++ /dev/null @@ -1,176 +0,0 @@ -package com.kamco.cd.kamcoback.zoo; - -import com.kamco.cd.kamcoback.config.api.ApiResponseDto; -import com.kamco.cd.kamcoback.zoo.dto.AnimalDto; -import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.Basic; -import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.Category; -import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.Species; -import com.kamco.cd.kamcoback.zoo.service.AnimalService; -import io.swagger.v3.oas.annotations.Hidden; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -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.data.domain.Page; -import org.springframework.web.bind.annotation.DeleteMapping; -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; - -@Hidden -@Tag(name = "Animal", description = "동물 관리 API") -@RequiredArgsConstructor -@RestController -@RequestMapping({"/api/animals", "/v1/api/animals"}) -public class AnimalApiController { - - private final AnimalService animalService; - - /** - * 동물 생성 - * - * @param req 동물 생성 요청 - * @return 생성된 동물 정보 - */ - @Operation(summary = "동물 생성", description = "새로운 동물 정보를 등록합니다.") - @ApiResponses( - value = { - @ApiResponse( - responseCode = "201", - description = "동물 생성 성공", - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = AnimalDto.Basic.class))), - @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) - @PostMapping - public ApiResponseDto createAnimal( - @io.swagger.v3.oas.annotations.parameters.RequestBody( - description = "동물 생성 요청 정보", - required = true, - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = AnimalDto.AddReq.class))) - @RequestBody - AnimalDto.AddReq req) { - AnimalDto.Basic created = animalService.createAnimal(req); - return ApiResponseDto.createOK(created); - } - - /** - * UUID로 동물 조회 - * - * @param uuid 동물 UUID - * @return 동물 정보 - */ - @Operation(summary = "동물 단건 조회", description = "UUID로 특정 동물의 상세 정보를 조회합니다.") - @ApiResponses( - value = { - @ApiResponse( - responseCode = "200", - description = "조회 성공", - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = AnimalDto.Basic.class))), - @ApiResponse(responseCode = "404", description = "동물을 찾을 수 없음", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) - @GetMapping("/{uuid}") - public ApiResponseDto getAnimal( - @Parameter( - description = "조회할 동물의 UUID", - required = true, - example = "550e8400-e29b-41d4-a716-446655440000") - @PathVariable - String uuid) { - Long id = animalService.getAnimalByUuid(uuid); - AnimalDto.Basic animal = animalService.getAnimal(id); - return ApiResponseDto.ok(animal); - } - - /** - * UUID로 동물 삭제 (논리 삭제) - * - * @param uuid 동물 UUID - * @return 삭제 성공 메시지 - */ - @Operation(summary = "동물 삭제", description = "UUID로 특정 동물을 삭제합니다 (논리 삭제).") - @ApiResponses( - value = { - @ApiResponse(responseCode = "204", description = "삭제 성공", content = @Content), - @ApiResponse(responseCode = "404", description = "동물을 찾을 수 없음", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) - @DeleteMapping("/{uuid}") - public ApiResponseDto deleteAnimal( - @Parameter( - description = "삭제할 동물의 UUID", - required = true, - example = "550e8400-e29b-41d4-a716-446655440000") - @PathVariable - String uuid) { - Long id = animalService.getAnimalByUuid(uuid); - animalService.deleteAnimal(id); - return ApiResponseDto.deleteOk(uuid); - } - - /** - * 동물 검색 (페이징) - * - * @param name 동물 이름 (선택) - * @param category 서식지 타입 (선택) - * @param species 동물종 (선택) 개, 고양이등. - * @param page 페이지 번호 (기본값: 0) - * @param size 페이지 크기 (기본값: 20) - * @param sort 정렬 조건 (예: "name,asc") - * @return 페이징 처리된 동물 목록 - */ - @Operation( - summary = "동물 검색", - description = - "다양한 조건으로 동물을 검색하고 페이징된 결과를 반환합니다. 모든 검색 조건은 선택적이며, 조건 없이 호출하면 전체 동물 목록을 반환합니다.") - @ApiResponses( - value = { - @ApiResponse( - responseCode = "200", - description = "검색 성공", - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = Page.class))), - @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) - @GetMapping - public ApiResponseDto> searchAnimals( - @Parameter(description = "동물 이름 (부분 일치 검색)", example = "호랑이") @RequestParam(required = false) - String name, - @Parameter(description = "서식지 카테고리", example = "MAMMAL") @RequestParam(required = false) - Category category, - @Parameter(description = "동물 종", example = "TIGER") @RequestParam(required = false) - Species species, - @Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0") - int page, - @Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20") - int size, - @Parameter(description = "정렬 조건 (형식: 필드명,방향)", example = "name,asc") - @RequestParam(required = false) - String sort) { - AnimalDto.SearchReq searchReq = - new AnimalDto.SearchReq(name, category, species, page, size, sort); - Page animals = animalService.search(searchReq); - return ApiResponseDto.ok(animals); - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/zoo/ZooApiController.java b/src/main/java/com/kamco/cd/kamcoback/zoo/ZooApiController.java deleted file mode 100644 index 223c7ecb..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/zoo/ZooApiController.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.kamco.cd.kamcoback.zoo; - -import com.kamco.cd.kamcoback.config.api.ApiResponseDto; -import com.kamco.cd.kamcoback.zoo.dto.ZooDto; -import com.kamco.cd.kamcoback.zoo.dto.ZooDto.Detail; -import com.kamco.cd.kamcoback.zoo.service.ZooService; -import io.swagger.v3.oas.annotations.Hidden; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -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.data.domain.Page; -import org.springframework.web.bind.annotation.DeleteMapping; -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; - -@Hidden -@Tag(name = "Zoo", description = "동물원 관리 API") -@RequiredArgsConstructor -@RestController -@RequestMapping({"/api/zoos", "/v1/api/zoos"}) -public class ZooApiController { - - private final ZooService zooService; - - /** - * 동물원 생성 - * - * @param req 동물원 생성 요청 - * @return 생성된 동물원 정보 (동물 개수 포함) - */ - @Operation(summary = "동물원 생성", description = "새로운 동물원 정보를 등록합니다.") - @ApiResponses( - value = { - @ApiResponse( - responseCode = "201", - description = "동물원 생성 성공", - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = ZooDto.Detail.class))), - @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) - @PostMapping - public ApiResponseDto createZoo( - @io.swagger.v3.oas.annotations.parameters.RequestBody( - description = "동물원 생성 요청 정보", - required = true, - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = ZooDto.AddReq.class))) - @RequestBody - ZooDto.AddReq req) { - ZooDto.Detail created = zooService.createZoo(req); - return ApiResponseDto.createOK(created); - } - - /** - * UUID로 동물원 조회 - * - * @param uuid 동물원 UUID - * @return 동물원 정보 (현재 동물 개수 포함) - */ - @Operation(summary = "동물원 단건 조회", description = "UUID로 특정 동물원의 상세 정보를 조회합니다.") - @ApiResponses( - value = { - @ApiResponse( - responseCode = "200", - description = "조회 성공", - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = ZooDto.Detail.class))), - @ApiResponse(responseCode = "404", description = "동물원을 찾을 수 없음", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) - @GetMapping("/{uuid}") - public ApiResponseDto getZoo( - @Parameter( - description = "조회할 동물원의 UUID", - required = true, - example = "550e8400-e29b-41d4-a716-446655440000") - @PathVariable - String uuid) { - Long id = zooService.getZooByUuid(uuid); - ZooDto.Detail zoo = zooService.getZoo(id); - return ApiResponseDto.ok(zoo); - } - - /** - * UUID로 동물원 삭제 (논리 삭제) - * - * @param uuid 동물원 UUID - * @return 삭제 성공 메시지 - */ - @Operation(summary = "동물원 삭제", description = "UUID로 특정 동물원을 삭제합니다 (논리 삭제).") - @ApiResponses( - value = { - @ApiResponse(responseCode = "204", description = "삭제 성공", content = @Content), - @ApiResponse(responseCode = "404", description = "동물원을 찾을 수 없음", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) - @DeleteMapping("/{uuid}") - public ApiResponseDto deleteZoo( - @Parameter( - description = "삭제할 동물원의 UUID", - required = true, - example = "550e8400-e29b-41d4-a716-446655440000") - @PathVariable - String uuid) { - Long id = zooService.getZooByUuid(uuid); - zooService.deleteZoo(id); - return ApiResponseDto.deleteOk(uuid); - } - - /** - * 동물원 검색 (페이징) - * - * @param name 동물원 이름 (선택) - * @param location 위치 (선택) - * @param page 페이지 번호 (기본값: 0) - * @param size 페이지 크기 (기본값: 20) - * @param sort 정렬 조건 (예: "name,asc") - * @return 페이징 처리된 동물원 목록 (각 동물원의 현재 동물 개수 포함) - */ - @Operation( - summary = "동물원 검색", - description = - "다양한 조건으로 동물원을 검색하고 페이징된 결과를 반환합니다. 모든 검색 조건은 선택적이며, 조건 없이 호출하면 전체 동물원 목록을 반환합니다.") - @ApiResponses( - value = { - @ApiResponse( - responseCode = "200", - description = "검색 성공", - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = Page.class))), - @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) - @GetMapping - public ApiResponseDto> searchZoos( - @Parameter(description = "동물원 이름 (부분 일치 검색)", example = "서울동물원") - @RequestParam(required = false) - String name, - @Parameter(description = "위치", example = "서울") @RequestParam(required = false) - String location, - @Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0") - int page, - @Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20") - int size, - @Parameter(description = "정렬 조건 (형식: 필드명,방향)", example = "name,asc") - @RequestParam(required = false) - String sort) { - ZooDto.SearchReq searchReq = new ZooDto.SearchReq(name, location, page, size, sort); - Page zoos = zooService.search(searchReq); - return ApiResponseDto.ok(zoos); - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/zoo/dto/AnimalDto.java b/src/main/java/com/kamco/cd/kamcoback/zoo/dto/AnimalDto.java deleted file mode 100644 index 9e23ae92..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/zoo/dto/AnimalDto.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.kamco.cd.kamcoback.zoo.dto; - -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.kamco.cd.kamcoback.common.utils.enums.EnumType; -import io.swagger.v3.oas.annotations.media.Schema; -import java.time.ZonedDateTime; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; - -public class AnimalDto { - - @Schema(name = "AnimalAddReq", description = "동물 생성 요청") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class AddReq { - - private Category category; - private Species species; - private String name; - private String zooUuid; // 동물원 UUID (선택) - } - - @Schema(name = "AnimalBasic", description = "동물 기본 정보") - @Getter - public static class Basic { - - @JsonIgnore private Long id; - private String uuid; - private Category category; - private Species species; - private String name; - - @JsonFormat( - shape = JsonFormat.Shape.STRING, - pattern = "yyyy-MM-dd'T'HH:mm:ssXXX", - timezone = "Asia/Seoul") - private ZonedDateTime createdDate; - - @JsonFormat( - shape = JsonFormat.Shape.STRING, - pattern = "yyyy-MM-dd'T'HH:mm:ssXXX", - timezone = "Asia/Seoul") - private ZonedDateTime modifiedDate; - - public Basic( - Long id, - String uuid, - String name, - Category category, - Species species, - ZonedDateTime createdDate, - ZonedDateTime modifiedDate) { - this.id = id; - this.uuid = uuid; - this.name = name; - this.category = category; - this.species = species; - this.createdDate = createdDate; - this.modifiedDate = modifiedDate; - } - } - - @Getter - @AllArgsConstructor - public enum Category implements EnumType { - // @formatter:off - MAMMALS("100", "포유류"), // 땅에 사는 동물 - BIRDS("200", "조류"), // 하늘을 나는 동물 - FISH("300", "어류"), - AMPHIBIANS("400", "양서류"), - REPTILES("500", "파충류"), - INSECTS("500", "곤충"), - INVERTEBRATES("500", "무척추동물"), - ; - // @formatter:on - private final String id; - private final String text; - } - - @Getter - @AllArgsConstructor - public enum Species implements EnumType { - // @formatter:off - DOG("101", "개"), - CAT("102", "강아지"), - DOVE("201", "비둘기"), - EAGLE("202", "독수리"), - SALMON("301", "연어"), - TUNA("302", "참치"), - ; - // @formatter:on - private final String id; - private final String text; - } - - @Schema(name = "AnimalSearchReq", description = "동물 검색 요청") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class SearchReq { - - // 검색 조건 - private String name; - private Category category; - private Species species; - - // 페이징 파라미터 - private int page = 0; - private int size = 20; - private String 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/zoo/dto/ZooDto.java b/src/main/java/com/kamco/cd/kamcoback/zoo/dto/ZooDto.java deleted file mode 100644 index 293fa602..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/zoo/dto/ZooDto.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.kamco.cd.kamcoback.zoo.dto; - -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonIgnore; -import io.swagger.v3.oas.annotations.media.Schema; -import java.time.ZonedDateTime; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; - -public class ZooDto { - - @Schema(name = "ZooAddReq", description = "동물원 생성 요청") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class AddReq { - - private String name; - private String location; - private String description; - } - - @Schema(name = "ZooBasic", description = "동물원 기본 정보") - @Getter - public static class Basic { - - @JsonIgnore private Long id; - private String uuid; - private String name; - private String location; - private String description; - - @JsonFormat( - shape = JsonFormat.Shape.STRING, - pattern = "yyyy-MM-dd'T'HH:mm:ssXXX", - timezone = "Asia/Seoul") - private ZonedDateTime createdDate; - - @JsonFormat( - shape = JsonFormat.Shape.STRING, - pattern = "yyyy-MM-dd'T'HH:mm:ssXXX", - timezone = "Asia/Seoul") - private ZonedDateTime modifiedDate; - - public Basic( - Long id, - String uuid, - String name, - String location, - String description, - ZonedDateTime createdDate, - ZonedDateTime modifiedDate) { - this.id = id; - this.uuid = uuid; - this.name = name; - this.location = location; - this.description = description; - this.createdDate = createdDate; - this.modifiedDate = modifiedDate; - } - } - - @Schema(name = "ZooDetail", description = "동물원 상세 정보 (동물 개수 포함)") - @Getter - public static class Detail extends Basic { - - private Long activeAnimalCount; - - public Detail( - Long id, - String uuid, - String name, - String location, - String description, - ZonedDateTime createdDate, - ZonedDateTime modifiedDate, - Long activeAnimalCount) { - super(id, uuid, name, location, description, createdDate, modifiedDate); - this.activeAnimalCount = activeAnimalCount; - } - } - - @Schema(name = "ZooSearchReq", description = "동물원 검색 요청") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class SearchReq { - - // 검색 조건 - private String name; - private String location; - - // 페이징 파라미터 - private int page = 0; - private int size = 20; - private String 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/zoo/service/AnimalService.java b/src/main/java/com/kamco/cd/kamcoback/zoo/service/AnimalService.java deleted file mode 100644 index 6b719586..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/zoo/service/AnimalService.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.kamco.cd.kamcoback.zoo.service; - -import com.kamco.cd.kamcoback.postgres.core.AnimalCoreService; -import com.kamco.cd.kamcoback.zoo.dto.AnimalDto; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@RequiredArgsConstructor -@Service -@Transactional(readOnly = true) -public class AnimalService { - - private final AnimalCoreService zooCoreService; - - // 동물의 UUID로 id조회 - public Long getAnimalByUuid(String uuid) { - return zooCoreService.getDataByUuid(uuid).getId(); - } - - /** - * 동물 생성 - * - * @param req 동물 생성 요청 - * @return 생성된 동물 정보 - */ - @Transactional - public AnimalDto.Basic createAnimal(AnimalDto.AddReq req) { - return zooCoreService.create(req); - } - - /** - * 동물 삭제 (논리 삭제) - * - * @param id 동물 ID - */ - @Transactional - public void deleteAnimal(Long id) { - zooCoreService.remove(id); - } - - /** - * 동물 단건 조회 - * - * @param id 동물 ID - * @return 동물 정보 - */ - public AnimalDto.Basic getAnimal(Long id) { - return zooCoreService.getOneById(id); - } - - /** - * 동물 검색 (페이징) - * - * @param searchReq 검색 조건 - * @return 페이징 처리된 동물 목록 - */ - public Page search(AnimalDto.SearchReq searchReq) { - return zooCoreService.search(searchReq); - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/zoo/service/ZooService.java b/src/main/java/com/kamco/cd/kamcoback/zoo/service/ZooService.java deleted file mode 100644 index b3f1ba94..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/zoo/service/ZooService.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.kamco.cd.kamcoback.zoo.service; - -import com.kamco.cd.kamcoback.postgres.core.ZooCoreService; -import com.kamco.cd.kamcoback.zoo.dto.ZooDto; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@RequiredArgsConstructor -@Service -@Transactional(readOnly = true) -public class ZooService { - - private final ZooCoreService zooCoreService; - - // 동물원의 UUID로 id조회 - public Long getZooByUuid(String uuid) { - return zooCoreService.getDataByUuid(uuid).getId(); - } - - /** - * 동물원 생성 - * - * @param req 동물원 생성 요청 - * @return 생성된 동물원 정보 (동물 개수 포함) - */ - @Transactional - public ZooDto.Detail createZoo(ZooDto.AddReq req) { - return zooCoreService.create(req); - } - - /** - * 동물원 삭제 (논리 삭제) - * - * @param id 동물원 ID - */ - @Transactional - public void deleteZoo(Long id) { - zooCoreService.remove(id); - } - - /** - * 동물원 단건 조회 - * - * @param id 동물원 ID - * @return 동물원 정보 (동물 개수 포함) - */ - public ZooDto.Detail getZoo(Long id) { - return zooCoreService.getOneById(id); - } - - /** - * 동물원 검색 (페이징) - * - * @param searchReq 검색 조건 - * @return 페이징 처리된 동물원 목록 (각 동물원의 동물 개수 포함) - */ - public Page search(ZooDto.SearchReq searchReq) { - return zooCoreService.search(searchReq); - } -}