diff --git a/.gitignore b/.gitignore index 4539816f..8b38af75 100644 --- a/.gitignore +++ b/.gitignore @@ -59,4 +59,7 @@ application.yml ### node ### node_modules/ package-lock.json -package.json \ No newline at end of file +package.json + +### temp directory ### +/temp/ \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index f8b314df..3317eb62 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,9 +20,7 @@ java { } -val querydslDir = "$buildDir/generated/querydsl" -sourceSets["main"].java.srcDirs(querydslDir) configurations { compileOnly { @@ -101,11 +99,7 @@ extensions.configure("jacoco") { toolVersion = "0.8.10" } -// QueryDSL Q 클래스 생성 위치 -tasks.withType { - options.annotationProcessorGeneratedSourcesDirectory = file(querydslDir) - options.annotationProcessorPath = configurations.annotationProcessor.get() -} + tasks.test { useJUnitPlatform() diff --git a/src/main/java/until/the/eternity/auctionhistory/application/scheduler/AuctionHistoryScheduler.java b/src/main/java/until/the/eternity/auctionhistory/application/scheduler/AuctionHistoryScheduler.java index e697ea72..1aa7008b 100644 --- a/src/main/java/until/the/eternity/auctionhistory/application/scheduler/AuctionHistoryScheduler.java +++ b/src/main/java/until/the/eternity/auctionhistory/application/scheduler/AuctionHistoryScheduler.java @@ -1,7 +1,5 @@ package until.the.eternity.auctionhistory.application.scheduler; -import java.util.ArrayList; -import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; @@ -13,6 +11,9 @@ import until.the.eternity.auctionhistory.interfaces.external.dto.OpenApiAuctionHistoryResponse; import until.the.eternity.common.enums.ItemCategory; +import java.util.ArrayList; +import java.util.List; + @Slf4j @Component @RequiredArgsConstructor diff --git a/src/main/java/until/the/eternity/auctionhistory/application/service/AuctionHistoryService.java b/src/main/java/until/the/eternity/auctionhistory/application/service/AuctionHistoryService.java index 562fa593..c94eb726 100644 --- a/src/main/java/until/the/eternity/auctionhistory/application/service/AuctionHistoryService.java +++ b/src/main/java/until/the/eternity/auctionhistory/application/service/AuctionHistoryService.java @@ -1,6 +1,5 @@ package until.the.eternity.auctionhistory.application.service; -import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; @@ -15,6 +14,8 @@ import until.the.eternity.common.request.PageRequestDto; import until.the.eternity.common.response.PageResponseDto; +import java.util.List; + @Service @RequiredArgsConstructor @Slf4j @@ -33,7 +34,7 @@ public PageResponseDto> search( } @Transactional(readOnly = true) - public AuctionHistoryDetailResponse findByIdOrElseThrow(Long id) { + public AuctionHistoryDetailResponse findByIdOrElseThrow(String id) { AuctionHistory auctionHistory = repository .findById(id) diff --git a/src/main/java/until/the/eternity/auctionhistory/application/service/fetcher/AuctionHistoryFetcher.java b/src/main/java/until/the/eternity/auctionhistory/application/service/fetcher/AuctionHistoryFetcher.java index a790ec4d..c0774dae 100644 --- a/src/main/java/until/the/eternity/auctionhistory/application/service/fetcher/AuctionHistoryFetcher.java +++ b/src/main/java/until/the/eternity/auctionhistory/application/service/fetcher/AuctionHistoryFetcher.java @@ -1,7 +1,5 @@ package until.the.eternity.auctionhistory.application.service.fetcher; -import java.util.ArrayList; -import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -11,6 +9,9 @@ import until.the.eternity.auctionhistory.interfaces.external.dto.OpenApiAuctionHistoryResponse; import until.the.eternity.common.enums.ItemCategory; +import java.util.ArrayList; +import java.util.List; + @Slf4j @Component @RequiredArgsConstructor diff --git a/src/main/java/until/the/eternity/auctionhistory/application/service/persister/AuctionHistoryPersister.java b/src/main/java/until/the/eternity/auctionhistory/application/service/persister/AuctionHistoryPersister.java index ea4da107..9eefb683 100644 --- a/src/main/java/until/the/eternity/auctionhistory/application/service/persister/AuctionHistoryPersister.java +++ b/src/main/java/until/the/eternity/auctionhistory/application/service/persister/AuctionHistoryPersister.java @@ -1,6 +1,5 @@ package until.the.eternity.auctionhistory.application.service.persister; -import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -11,6 +10,8 @@ import until.the.eternity.auctionhistory.interfaces.external.dto.OpenApiAuctionHistoryResponse; import until.the.eternity.common.enums.ItemCategory; +import java.util.List; + @Slf4j @RequiredArgsConstructor @Component @@ -25,6 +26,8 @@ public List filterOutExisting( List entities = mapper.toEntityList(duplicateChecker.filterExisting(dtoList), category); + entities.forEach(AuctionHistory::linkItemOptions); + if (entities.isEmpty()) { log.info("> [SCHEDULE] [{}] No new auction history to save", category.getSubCategory()); } else { diff --git a/src/main/java/until/the/eternity/auctionhistory/domain/entity/AuctionHistory.java b/src/main/java/until/the/eternity/auctionhistory/domain/entity/AuctionHistory.java index f9174a12..84c57b29 100644 --- a/src/main/java/until/the/eternity/auctionhistory/domain/entity/AuctionHistory.java +++ b/src/main/java/until/the/eternity/auctionhistory/domain/entity/AuctionHistory.java @@ -1,11 +1,12 @@ package until.the.eternity.auctionhistory.domain.entity; import jakarta.persistence.*; -import java.time.Instant; -import java.util.List; import lombok.*; import until.the.eternity.itemoption.domain.entity.ItemOption; +import java.time.Instant; +import java.util.List; + @Entity @Table(name = "auction_history") @Getter @@ -16,8 +17,8 @@ public class AuctionHistory { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Column(name = "auction_buy_id", nullable = false) + private String auctionBuyId; @Column(name = "item_name", nullable = false) private String itemName; @@ -34,9 +35,6 @@ public class AuctionHistory { @Column(name = "date_auction_buy", nullable = false) private Instant dateAuctionBuy; - @Column(name = "auction_buy_id", nullable = false, unique = true) - private String auctionBuyId; - @OneToMany(mappedBy = "auctionHistory", cascade = CascadeType.ALL, orphanRemoval = true) private List itemOptions; diff --git a/src/main/java/until/the/eternity/auctionhistory/domain/mapper/AuctionHistoryMapper.java b/src/main/java/until/the/eternity/auctionhistory/domain/mapper/AuctionHistoryMapper.java index 977d6f66..d2c3343d 100644 --- a/src/main/java/until/the/eternity/auctionhistory/domain/mapper/AuctionHistoryMapper.java +++ b/src/main/java/until/the/eternity/auctionhistory/domain/mapper/AuctionHistoryMapper.java @@ -1,6 +1,5 @@ package until.the.eternity.auctionhistory.domain.mapper; -import java.util.List; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import until.the.eternity.auctionhistory.domain.entity.AuctionHistory; @@ -8,6 +7,8 @@ import until.the.eternity.auctionhistory.interfaces.rest.dto.response.ItemOptionResponse; import until.the.eternity.itemoption.domain.entity.ItemOption; +import java.util.List; + /** * AuctionHistory Entity to internal.responseDto transfer mapper class 데이터 흐름은 external.responseDto * -> entity -> internal.responseDto 단방향으로 흐름 @@ -20,6 +21,8 @@ public interface AuctionHistoryMapper { AuctionHistoryDetailResponse toDto(AuctionHistory entity); // 하위 매핑 + @Mapping(target = "auctionHistory", ignore = true) + @Mapping(target = "auctionItem", ignore = true) ItemOption toEntity(ItemOptionResponse dto); ItemOptionResponse toDto(ItemOption entity); diff --git a/src/main/java/until/the/eternity/auctionhistory/domain/mapper/OpenApiAuctionHistoryMapper.java b/src/main/java/until/the/eternity/auctionhistory/domain/mapper/OpenApiAuctionHistoryMapper.java index 403a26f0..74daefd2 100644 --- a/src/main/java/until/the/eternity/auctionhistory/domain/mapper/OpenApiAuctionHistoryMapper.java +++ b/src/main/java/until/the/eternity/auctionhistory/domain/mapper/OpenApiAuctionHistoryMapper.java @@ -1,17 +1,17 @@ package until.the.eternity.auctionhistory.domain.mapper; -import java.time.Instant; -import java.util.List; import org.mapstruct.*; import until.the.eternity.auctionhistory.domain.entity.AuctionHistory; import until.the.eternity.auctionhistory.interfaces.external.dto.OpenApiAuctionHistoryResponse; import until.the.eternity.common.enums.ItemCategory; +import java.time.Instant; +import java.util.List; + @Mapper(componentModel = "spring", uses = OpenApiItemOptionMapper.class) public interface OpenApiAuctionHistoryMapper { @Named("toEntity(OpenApiAuctionHistoryResponse, ItemCategory)") - @Mapping(target = "id", ignore = true) @Mapping( source = "dateAuctionBuy", target = "dateAuctionBuy", diff --git a/src/main/java/until/the/eternity/auctionhistory/domain/repository/AuctionHistoryRepositoryPort.java b/src/main/java/until/the/eternity/auctionhistory/domain/repository/AuctionHistoryRepositoryPort.java index 3c19c293..0bd06c81 100644 --- a/src/main/java/until/the/eternity/auctionhistory/domain/repository/AuctionHistoryRepositoryPort.java +++ b/src/main/java/until/the/eternity/auctionhistory/domain/repository/AuctionHistoryRepositoryPort.java @@ -1,14 +1,15 @@ package until.the.eternity.auctionhistory.domain.repository; -import java.time.Instant; -import java.util.List; -import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import until.the.eternity.auctionhistory.domain.entity.AuctionHistory; import until.the.eternity.auctionhistory.interfaces.rest.dto.request.AuctionHistorySearchRequest; import until.the.eternity.common.enums.ItemCategory; +import java.time.Instant; +import java.util.List; +import java.util.Optional; + /** 경매장 거래 내역 POJO Repository - Mock 또는 Stub 으로 대체해 단위 테스트 용이성 확보 */ public interface AuctionHistoryRepositoryPort { @@ -16,7 +17,7 @@ public interface AuctionHistoryRepositoryPort { Page search(AuctionHistorySearchRequest condition, Pageable pageable); - Optional findByIdWithOptions(Long id); + Optional findByIdWithOptions(String id); boolean existsByAuctionBuyIds(List ids); @@ -24,7 +25,7 @@ public interface AuctionHistoryRepositoryPort { boolean existsByAuctionBuyIdIn(List ids); - Optional findById(Long id); + Optional findById(String id); void saveAll(List newEntities); diff --git a/src/main/java/until/the/eternity/auctionhistory/domain/service/AuctionHistoryDuplicateChecker.java b/src/main/java/until/the/eternity/auctionhistory/domain/service/AuctionHistoryDuplicateChecker.java index 4db1cc37..5eac2b0e 100644 --- a/src/main/java/until/the/eternity/auctionhistory/domain/service/AuctionHistoryDuplicateChecker.java +++ b/src/main/java/until/the/eternity/auctionhistory/domain/service/AuctionHistoryDuplicateChecker.java @@ -1,7 +1,5 @@ package until.the.eternity.auctionhistory.domain.service; -import java.time.Instant; -import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -9,6 +7,9 @@ import until.the.eternity.auctionhistory.interfaces.external.dto.OpenApiAuctionHistoryResponse; import until.the.eternity.common.enums.ItemCategory; +import java.time.Instant; +import java.util.List; + @Slf4j @Component @RequiredArgsConstructor diff --git a/src/main/java/until/the/eternity/auctionhistory/domain/service/fetcher/AuctionHistoryFetcherPort.java b/src/main/java/until/the/eternity/auctionhistory/domain/service/fetcher/AuctionHistoryFetcherPort.java index 5b649be4..cf00412a 100644 --- a/src/main/java/until/the/eternity/auctionhistory/domain/service/fetcher/AuctionHistoryFetcherPort.java +++ b/src/main/java/until/the/eternity/auctionhistory/domain/service/fetcher/AuctionHistoryFetcherPort.java @@ -1,9 +1,10 @@ package until.the.eternity.auctionhistory.domain.service.fetcher; -import java.util.List; import until.the.eternity.auctionhistory.interfaces.external.dto.OpenApiAuctionHistoryResponse; import until.the.eternity.common.enums.ItemCategory; +import java.util.List; + public interface AuctionHistoryFetcherPort { List fetch(ItemCategory category); } diff --git a/src/main/java/until/the/eternity/auctionhistory/domain/service/persister/AuctionHistoryPersisterPort.java b/src/main/java/until/the/eternity/auctionhistory/domain/service/persister/AuctionHistoryPersisterPort.java index 636f4c2d..44f59205 100644 --- a/src/main/java/until/the/eternity/auctionhistory/domain/service/persister/AuctionHistoryPersisterPort.java +++ b/src/main/java/until/the/eternity/auctionhistory/domain/service/persister/AuctionHistoryPersisterPort.java @@ -1,10 +1,11 @@ package until.the.eternity.auctionhistory.domain.service.persister; -import java.util.List; import until.the.eternity.auctionhistory.domain.entity.AuctionHistory; import until.the.eternity.auctionhistory.interfaces.external.dto.OpenApiAuctionHistoryResponse; import until.the.eternity.common.enums.ItemCategory; +import java.util.List; + public interface AuctionHistoryPersisterPort { List filterOutExisting( diff --git a/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryJpaRepository.java b/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryJpaRepository.java index d6ab5a15..96abc507 100644 --- a/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryJpaRepository.java +++ b/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryJpaRepository.java @@ -1,8 +1,5 @@ package until.the.eternity.auctionhistory.infrastructure.persistence; -import java.time.Instant; -import java.util.List; -import java.util.Optional; import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; @@ -10,9 +7,13 @@ import org.springframework.stereotype.Repository; import until.the.eternity.auctionhistory.domain.entity.AuctionHistory; +import java.time.Instant; +import java.util.List; +import java.util.Optional; + @Repository public interface AuctionHistoryJpaRepository - extends JpaRepository, JpaSpecificationExecutor { + extends JpaRepository, JpaSpecificationExecutor { List findAllByAuctionBuyIdIn(List auctionBuyIds); @@ -35,5 +36,5 @@ select MAX(a.dateAuctionBuy) Optional findLatestDateAuctionBuyBySubCategory(String topCategory, String subCategory); @EntityGraph(attributePaths = "itemOptions") - Optional findWithItemOptionsById(Long id); + Optional findWithItemOptionsByAuctionBuyId(String id); } diff --git a/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryQueryDslRepository.java b/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryQueryDslRepository.java index 9271563b..757bfd36 100644 --- a/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryQueryDslRepository.java +++ b/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryQueryDslRepository.java @@ -2,7 +2,6 @@ import com.querydsl.core.BooleanBuilder; import com.querydsl.jpa.impl.JPAQueryFactory; -import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; @@ -12,6 +11,8 @@ import until.the.eternity.auctionhistory.domain.entity.QAuctionHistory; import until.the.eternity.auctionhistory.interfaces.rest.dto.request.AuctionHistorySearchRequest; +import java.util.List; + @Component @RequiredArgsConstructor class AuctionHistoryQueryDslRepository { diff --git a/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryRepositoryPortImpl.java b/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryRepositoryPortImpl.java index 0311a2a6..0d3ff4f0 100644 --- a/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryRepositoryPortImpl.java +++ b/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryRepositoryPortImpl.java @@ -1,17 +1,21 @@ package until.the.eternity.auctionhistory.infrastructure.persistence; -import java.time.Instant; -import java.util.List; -import java.util.Optional; +import jakarta.persistence.EntityManager; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import until.the.eternity.auctionhistory.domain.entity.AuctionHistory; import until.the.eternity.auctionhistory.domain.repository.AuctionHistoryRepositoryPort; import until.the.eternity.auctionhistory.interfaces.rest.dto.request.AuctionHistorySearchRequest; import until.the.eternity.common.enums.ItemCategory; +import java.time.Instant; +import java.util.List; +import java.util.Optional; + /** AuctionHistoryRepository Interface 구현체 */ @Repository @RequiredArgsConstructor @@ -19,6 +23,10 @@ public class AuctionHistoryRepositoryPortImpl implements AuctionHistoryRepositor private final AuctionHistoryJpaRepository jpaRepository; private final AuctionHistoryQueryDslRepository queryDslRepository; + private final EntityManager em; + + @Value("${spring.jpa.properties.hibernate.jdbc.batch_size:500}") + private int batchSize; @Override public List findAllByAuctionBuyIds(List auctionBuyIds) { @@ -31,8 +39,8 @@ public Page search(AuctionHistorySearchRequest condition, Pageab } @Override - public Optional findByIdWithOptions(Long id) { - return jpaRepository.findWithItemOptionsById(id); + public Optional findByIdWithOptions(String id) { + return jpaRepository.findWithItemOptionsByAuctionBuyId(id); } @Override @@ -51,13 +59,24 @@ public boolean existsByAuctionBuyIdIn(List ids) { } @Override - public Optional findById(Long id) { + public Optional findById(String id) { return jpaRepository.findById(id); } @Override + @Transactional public void saveAll(List newEntities) { - jpaRepository.saveAll(newEntities); + if (newEntities.isEmpty()) { + return; + } + + for (int i = 0; i < newEntities.size(); i += batchSize) { + int toIndex = Math.min(i + batchSize, newEntities.size()); + List subList = newEntities.subList(i, toIndex); + jpaRepository.saveAll(subList); + em.flush(); + em.clear(); + } } @Override diff --git a/src/main/java/until/the/eternity/auctionhistory/interfaces/external/dto/OpenApiAuctionHistoryListResponse.java b/src/main/java/until/the/eternity/auctionhistory/interfaces/external/dto/OpenApiAuctionHistoryListResponse.java index e194aeb7..c49a6b2b 100644 --- a/src/main/java/until/the/eternity/auctionhistory/interfaces/external/dto/OpenApiAuctionHistoryListResponse.java +++ b/src/main/java/until/the/eternity/auctionhistory/interfaces/external/dto/OpenApiAuctionHistoryListResponse.java @@ -1,6 +1,7 @@ package until.the.eternity.auctionhistory.interfaces.external.dto; import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.List; public record OpenApiAuctionHistoryListResponse( diff --git a/src/main/java/until/the/eternity/auctionhistory/interfaces/external/dto/OpenApiAuctionHistoryResponse.java b/src/main/java/until/the/eternity/auctionhistory/interfaces/external/dto/OpenApiAuctionHistoryResponse.java index 12e6b109..c29c0d78 100644 --- a/src/main/java/until/the/eternity/auctionhistory/interfaces/external/dto/OpenApiAuctionHistoryResponse.java +++ b/src/main/java/until/the/eternity/auctionhistory/interfaces/external/dto/OpenApiAuctionHistoryResponse.java @@ -2,9 +2,10 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; +import until.the.eternity.itemoption.domain.dto.external.OpenApiItemOptionResponse; + import java.time.Instant; import java.util.List; -import until.the.eternity.itemoption.domain.dto.external.OpenApiItemOptionResponse; public record OpenApiAuctionHistoryResponse( @JsonProperty("item_name") String itemName, diff --git a/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/controller/AuctionHistoryController.java b/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/controller/AuctionHistoryController.java index 149e427a..d51f0b07 100644 --- a/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/controller/AuctionHistoryController.java +++ b/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/controller/AuctionHistoryController.java @@ -36,7 +36,7 @@ public ResponseEntity> findById( - @PathVariable Long id) { + @PathVariable String id) { AuctionHistoryDetailResponse result = service.findByIdOrElseThrow(id); return ResponseEntity.ok(result); } diff --git a/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/dto/response/AuctionHistoryDetailResponse.java b/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/dto/response/AuctionHistoryDetailResponse.java index f940fdfd..d694c60c 100644 --- a/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/dto/response/AuctionHistoryDetailResponse.java +++ b/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/dto/response/AuctionHistoryDetailResponse.java @@ -1,11 +1,11 @@ package until.the.eternity.auctionhistory.interfaces.rest.dto.response; import com.fasterxml.jackson.annotation.JsonFormat; + import java.time.Instant; import java.util.List; public record AuctionHistoryDetailResponse( - Long id, String itemName, String itemDisplayName, Long itemCount, diff --git a/src/main/java/until/the/eternity/auctionitem/domain/entity/AuctionItem.java b/src/main/java/until/the/eternity/auctionitem/domain/entity/AuctionItem.java index 7a4f4118..0d5202c6 100644 --- a/src/main/java/until/the/eternity/auctionitem/domain/entity/AuctionItem.java +++ b/src/main/java/until/the/eternity/auctionitem/domain/entity/AuctionItem.java @@ -1,11 +1,12 @@ package until.the.eternity.auctionitem.domain.entity; import jakarta.persistence.*; -import java.time.LocalDateTime; -import java.util.List; import lombok.*; import until.the.eternity.itemoption.domain.entity.ItemOption; +import java.time.LocalDateTime; +import java.util.List; + @Entity @Table(name = "auction_item") @Getter diff --git a/src/main/java/until/the/eternity/common/enums/ItemCategory.java b/src/main/java/until/the/eternity/common/enums/ItemCategory.java index 87801b67..4143ae3c 100644 --- a/src/main/java/until/the/eternity/common/enums/ItemCategory.java +++ b/src/main/java/until/the/eternity/common/enums/ItemCategory.java @@ -1,11 +1,12 @@ package until.the.eternity.common.enums; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + import java.util.Arrays; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; -import lombok.Getter; -import lombok.RequiredArgsConstructor; @Getter @RequiredArgsConstructor diff --git a/src/main/java/until/the/eternity/common/exception/GlobalExceptionCode.java b/src/main/java/until/the/eternity/common/exception/GlobalExceptionCode.java index 21c217b0..1169e930 100644 --- a/src/main/java/until/the/eternity/common/exception/GlobalExceptionCode.java +++ b/src/main/java/until/the/eternity/common/exception/GlobalExceptionCode.java @@ -1,11 +1,11 @@ package until.the.eternity.common.exception; -import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; - import lombok.Getter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; + @Getter @RequiredArgsConstructor public enum GlobalExceptionCode implements ExceptionCode { diff --git a/src/main/java/until/the/eternity/common/exception/GlobalExceptionHandler.java b/src/main/java/until/the/eternity/common/exception/GlobalExceptionHandler.java index 4cf5af10..bc069d00 100644 --- a/src/main/java/until/the/eternity/common/exception/GlobalExceptionHandler.java +++ b/src/main/java/until/the/eternity/common/exception/GlobalExceptionHandler.java @@ -1,7 +1,5 @@ package until.the.eternity.common.exception; -import static until.the.eternity.common.exception.GlobalExceptionCode.SERVER_ERROR; - import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -9,6 +7,8 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import until.the.eternity.common.response.ApiResponse; +import static until.the.eternity.common.exception.GlobalExceptionCode.SERVER_ERROR; + @Slf4j @RestControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { diff --git a/src/main/java/until/the/eternity/common/response/ApiResponse.java b/src/main/java/until/the/eternity/common/response/ApiResponse.java index c7f83b13..c7b99b00 100644 --- a/src/main/java/until/the/eternity/common/response/ApiResponse.java +++ b/src/main/java/until/the/eternity/common/response/ApiResponse.java @@ -1,9 +1,10 @@ package until.the.eternity.common.response; -import java.time.Instant; import lombok.Builder; import lombok.Getter; +import java.time.Instant; + @Getter public class ApiResponse { diff --git a/src/main/java/until/the/eternity/common/response/PageResponseDto.java b/src/main/java/until/the/eternity/common/response/PageResponseDto.java index c142faac..0919ce20 100644 --- a/src/main/java/until/the/eternity/common/response/PageResponseDto.java +++ b/src/main/java/until/the/eternity/common/response/PageResponseDto.java @@ -1,6 +1,7 @@ package until.the.eternity.common.response; import io.swagger.v3.oas.annotations.media.Schema; + import java.util.List; @Schema(description = "페이지 응답 객체") diff --git a/src/main/java/until/the/eternity/config/openapi/OpenApiFilters.java b/src/main/java/until/the/eternity/config/openapi/OpenApiFilters.java index af0147a8..29ca38fe 100644 --- a/src/main/java/until/the/eternity/config/openapi/OpenApiFilters.java +++ b/src/main/java/until/the/eternity/config/openapi/OpenApiFilters.java @@ -1,12 +1,13 @@ package until.the.eternity.config.openapi; -import java.time.Duration; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.client.ExchangeFilterFunction; import reactor.core.publisher.Mono; +import java.time.Duration; + @Slf4j @Component @RequiredArgsConstructor diff --git a/src/main/java/until/the/eternity/config/openapi/OpenApiRetryPolicy.java b/src/main/java/until/the/eternity/config/openapi/OpenApiRetryPolicy.java index 8c9d0cff..a419df7c 100644 --- a/src/main/java/until/the/eternity/config/openapi/OpenApiRetryPolicy.java +++ b/src/main/java/until/the/eternity/config/openapi/OpenApiRetryPolicy.java @@ -1,11 +1,12 @@ package until.the.eternity.config.openapi; -import java.time.Duration; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.client.WebClientResponseException; import reactor.util.retry.Retry; import reactor.util.retry.RetryBackoffSpec; +import java.time.Duration; + /** Nexon OPEN API 전용 재시도(Back-off) 정책. */ @Component public class OpenApiRetryPolicy { diff --git a/src/main/java/until/the/eternity/config/openapi/OpenApiWebClientProperties.java b/src/main/java/until/the/eternity/config/openapi/OpenApiWebClientProperties.java index 9d51746d..f8d79043 100644 --- a/src/main/java/until/the/eternity/config/openapi/OpenApiWebClientProperties.java +++ b/src/main/java/until/the/eternity/config/openapi/OpenApiWebClientProperties.java @@ -2,10 +2,11 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Positive; -import java.time.Duration; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.validation.annotation.Validated; +import java.time.Duration; + /** 외부 API용 WebClient 설정값 홀더 application.yml 사용) */ @Validated @ConfigurationProperties(prefix = "openapi.nexon") diff --git a/src/main/java/until/the/eternity/hornBugle/domain/entity/HornBugleWorldHistory.java b/src/main/java/until/the/eternity/hornBugle/domain/entity/HornBugleWorldHistory.java index 0ab19420..ca38a0ef 100644 --- a/src/main/java/until/the/eternity/hornBugle/domain/entity/HornBugleWorldHistory.java +++ b/src/main/java/until/the/eternity/hornBugle/domain/entity/HornBugleWorldHistory.java @@ -1,9 +1,10 @@ package until.the.eternity.hornBugle.domain.entity; import jakarta.persistence.*; -import java.time.LocalDateTime; import lombok.*; +import java.time.LocalDateTime; + @Entity @Table(name = "horn_bugle_world_history") @Getter diff --git a/src/main/java/until/the/eternity/itemminprice/controller/ItemDailyMinPriceController.java b/src/main/java/until/the/eternity/itemminprice/controller/ItemDailyMinPriceController.java index 6c03fb72..4a0f6e78 100644 --- a/src/main/java/until/the/eternity/itemminprice/controller/ItemDailyMinPriceController.java +++ b/src/main/java/until/the/eternity/itemminprice/controller/ItemDailyMinPriceController.java @@ -2,7 +2,6 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; -import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; @@ -13,6 +12,8 @@ import until.the.eternity.itemminprice.domain.dto.response.ItemDailyMinPriceResponseDto; import until.the.eternity.itemminprice.service.ItemDailyMinPriceService; +import java.util.List; + @Slf4j @RestController @RequiredArgsConstructor diff --git a/src/main/java/until/the/eternity/itemminprice/domain/dto/response/ItemDailyMinPriceResponseDto.java b/src/main/java/until/the/eternity/itemminprice/domain/dto/response/ItemDailyMinPriceResponseDto.java index e5fcf6f5..d0ef6d5d 100644 --- a/src/main/java/until/the/eternity/itemminprice/domain/dto/response/ItemDailyMinPriceResponseDto.java +++ b/src/main/java/until/the/eternity/itemminprice/domain/dto/response/ItemDailyMinPriceResponseDto.java @@ -1,6 +1,7 @@ package until.the.eternity.itemminprice.domain.dto.response; import io.swagger.v3.oas.annotations.media.Schema; + import java.time.LocalDate; import java.time.LocalDateTime; diff --git a/src/main/java/until/the/eternity/itemminprice/domain/entity/ItemDailyMinPrice.java b/src/main/java/until/the/eternity/itemminprice/domain/entity/ItemDailyMinPrice.java index a3dec6fe..72de26b8 100644 --- a/src/main/java/until/the/eternity/itemminprice/domain/entity/ItemDailyMinPrice.java +++ b/src/main/java/until/the/eternity/itemminprice/domain/entity/ItemDailyMinPrice.java @@ -2,9 +2,10 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.*; +import lombok.*; + import java.time.LocalDate; import java.time.LocalDateTime; -import lombok.*; @Entity @Table( diff --git a/src/main/java/until/the/eternity/itemminprice/domain/mapper/ItemDailyMinPriceMapper.java b/src/main/java/until/the/eternity/itemminprice/domain/mapper/ItemDailyMinPriceMapper.java index 2f54a40b..596ddc4b 100644 --- a/src/main/java/until/the/eternity/itemminprice/domain/mapper/ItemDailyMinPriceMapper.java +++ b/src/main/java/until/the/eternity/itemminprice/domain/mapper/ItemDailyMinPriceMapper.java @@ -1,6 +1,5 @@ package until.the.eternity.itemminprice.domain.mapper; -import java.util.List; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingTarget; @@ -8,6 +7,8 @@ import until.the.eternity.itemminprice.domain.dto.response.ItemDailyMinPriceResponseDto; import until.the.eternity.itemminprice.domain.entity.ItemDailyMinPrice; +import java.util.List; + @Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) public interface ItemDailyMinPriceMapper { diff --git a/src/main/java/until/the/eternity/itemminprice/service/ItemDailyMinPriceService.java b/src/main/java/until/the/eternity/itemminprice/service/ItemDailyMinPriceService.java index 6c5c6aae..83095e05 100644 --- a/src/main/java/until/the/eternity/itemminprice/service/ItemDailyMinPriceService.java +++ b/src/main/java/until/the/eternity/itemminprice/service/ItemDailyMinPriceService.java @@ -1,7 +1,5 @@ package until.the.eternity.itemminprice.service; -import java.util.List; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -11,6 +9,9 @@ import until.the.eternity.itemminprice.domain.mapper.ItemDailyMinPriceMapper; import until.the.eternity.itemminprice.repository.ItemDailyMinPriceRepository; +import java.util.List; +import java.util.stream.Collectors; + @Slf4j @Service @RequiredArgsConstructor diff --git a/src/main/java/until/the/eternity/itemoption/domain/entity/ItemOption.java b/src/main/java/until/the/eternity/itemoption/domain/entity/ItemOption.java index 56128ce6..1eeaf6e6 100644 --- a/src/main/java/until/the/eternity/itemoption/domain/entity/ItemOption.java +++ b/src/main/java/until/the/eternity/itemoption/domain/entity/ItemOption.java @@ -8,6 +8,8 @@ import until.the.eternity.auctionhistory.domain.entity.AuctionHistory; import until.the.eternity.auctionitem.domain.entity.AuctionItem; +import java.util.UUID; + @Entity @Table(name = "auction_item_option") @Getter @@ -17,11 +19,14 @@ public class ItemOption { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + @Column(name = "id") + private String id; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "auction_history_id", nullable = true) + @JoinColumn( + name = "auction_history_id", + referencedColumnName = "auction_buy_id", + nullable = false) private AuctionHistory auctionHistory; @ManyToOne(fetch = FetchType.LAZY) @@ -43,6 +48,11 @@ public class ItemOption { @Column(name = "option_desc", columnDefinition = "TEXT") private String optionDesc; + @PrePersist + public void createId() { + this.id = UUID.randomUUID().toString(); + } + public void setAuctionHistory(AuctionHistory auctionHistory) { // 1️⃣ 이전 연관관계 정리 diff --git a/src/main/resources/application-sample.yml b/src/main/resources/application-sample.yml index c2872d88..943a7449 100644 --- a/src/main/resources/application-sample.yml +++ b/src/main/resources/application-sample.yml @@ -23,7 +23,7 @@ spring: static-locations: classpath:/static/ datasource: driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://localhost:${DB_PORT}/${DB_SCHEMA} + url: jdbc:mysql://localhost:${DB_PORT}/${DB_SCHEMA}?rewriteBatchedStatements=true username: ${DB_USER} password: ${DB_PASSWORD} jpa: diff --git a/src/main/resources/db/migration/V4__change_auction_history_pk.sql b/src/main/resources/db/migration/V4__change_auction_history_pk.sql new file mode 100644 index 00000000..e3bfdfe2 --- /dev/null +++ b/src/main/resources/db/migration/V4__change_auction_history_pk.sql @@ -0,0 +1,19 @@ +-- auction_item_option의 FK 제약 조건(fk_option_history)을 삭제 +ALTER TABLE auction_item_option + DROP FOREIGN KEY fk_option_history; + +-- auction_history의 PK 변경 후 기존 id 제거 +ALTER TABLE auction_history + DROP PRIMARY KEY, + ADD PRIMARY KEY (auction_buy_id), + DROP COLUMN id; + +-- auction_item_option comment 변경 +ALTER TABLE auction_item_option + MODIFY auction_history_id varchar(255) NULL COMMENT 'auction_history 테이블의 외래 키 (auction_history.auction_buy_id)'; + +-- auction_item_option -> auction_history 제약 조건 추가 +ALTER TABLE auction_item_option + ADD CONSTRAINT fk_option_history + FOREIGN KEY (auction_history_id) REFERENCES auction_history (auction_buy_id) + ON DELETE CASCADE; \ No newline at end of file diff --git a/src/main/resources/db/migration/V5__change_item_option_pk.sql b/src/main/resources/db/migration/V5__change_item_option_pk.sql new file mode 100644 index 00000000..06964304 --- /dev/null +++ b/src/main/resources/db/migration/V5__change_item_option_pk.sql @@ -0,0 +1,19 @@ +-- 기존 FK, PK 제약 조건 삭제 +ALTER TABLE auction_item_option + DROP FOREIGN KEY fk_option_history, + DROP PRIMARY KEY; + +-- 기존 id 컬럼 삭제 +ALTER TABLE auction_item_option + DROP COLUMN id; + +-- 새로운 PK 컬럼 추가 +ALTER TABLE auction_item_option + ADD COLUMN item_option_id VARCHAR(36) NOT NULL COMMENT 'ItemOption의 고유 식별자 (UUID)' FIRST, + ADD PRIMARY KEY (item_option_id); + +-- FK 제약 조건 다시 추가 +ALTER TABLE auction_item_option + ADD CONSTRAINT fk_option_history + FOREIGN KEY (auction_history_id) REFERENCES auction_history (auction_buy_id) + ON DELETE CASCADE; diff --git a/src/main/resources/db/migration/V6__change_item_option_column_name.sql b/src/main/resources/db/migration/V6__change_item_option_column_name.sql new file mode 100644 index 00000000..d69b4e0c --- /dev/null +++ b/src/main/resources/db/migration/V6__change_item_option_column_name.sql @@ -0,0 +1,2 @@ +ALTER TABLE auction_item_option + CHANGE COLUMN item_option_id id VARCHAR(36) NOT NULL COMMENT 'ItemOption의 고유 식별자 (UUID)'; \ No newline at end of file diff --git a/src/test/java/until/the/eternity/auctionhistory/application/service/AuctionHistoryServiceTest.java b/src/test/java/until/the/eternity/auctionhistory/application/service/AuctionHistoryServiceTest.java index cf7ad34d..958796ba 100644 --- a/src/test/java/until/the/eternity/auctionhistory/application/service/AuctionHistoryServiceTest.java +++ b/src/test/java/until/the/eternity/auctionhistory/application/service/AuctionHistoryServiceTest.java @@ -1,11 +1,5 @@ package until.the.eternity.auctionhistory.application.service; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.*; - -import java.util.List; -import java.util.Optional; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -27,6 +21,13 @@ import until.the.eternity.common.request.PageRequestDto; import until.the.eternity.common.response.PageResponseDto; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.*; + @ExtendWith(MockitoExtension.class) class AuctionHistoryServiceTest { @@ -68,7 +69,7 @@ void search_should_return_paged_response() { @DisplayName("데이터가 존재하면 findByIdOrElseThrow는 dto를 반환한다") void findByIdOrElseThrow_should_return_dto_when_entity_exists() { // given - Long id = 1L; + String id = "test-id"; AuctionHistory entity = new AuctionHistory(); AuctionHistoryDetailResponse dto = mock(AuctionHistoryDetailResponse.class); @@ -89,7 +90,7 @@ void findByIdOrElseThrow_should_return_dto_when_entity_exists() { @DisplayName("검색 경매장 거래 내역 ID가 존재하지 않으면 예외처리를 한다") void findByIdOrElseThrow_should_throw_exception_when_not_found() { // given - Long id = 999L; + String id = "non-existing-id"; when(repositoryPort.findById(id)).thenReturn(Optional.empty()); // expect diff --git a/src/test/java/until/the/eternity/auctionhistory/application/service/fetcher/AuctionHistoryFetcherTest.java b/src/test/java/until/the/eternity/auctionhistory/application/service/fetcher/AuctionHistoryFetcherTest.java index a5b89c0c..87dbdbc1 100644 --- a/src/test/java/until/the/eternity/auctionhistory/application/service/fetcher/AuctionHistoryFetcherTest.java +++ b/src/test/java/until/the/eternity/auctionhistory/application/service/fetcher/AuctionHistoryFetcherTest.java @@ -1,12 +1,5 @@ package until.the.eternity.auctionhistory.application.service.fetcher; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; - -import java.time.Instant; -import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -21,6 +14,14 @@ import until.the.eternity.auctionhistory.interfaces.external.dto.OpenApiAuctionHistoryResponse; import until.the.eternity.common.enums.ItemCategory; +import java.time.Instant; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + @ExtendWith(MockitoExtension.class) class AuctionHistoryFetcherTest { diff --git a/src/test/java/until/the/eternity/auctionhistory/application/service/persister/AuctionHistoryPersisterTest.java b/src/test/java/until/the/eternity/auctionhistory/application/service/persister/AuctionHistoryPersisterTest.java index 0501bc5b..63edf84b 100644 --- a/src/test/java/until/the/eternity/auctionhistory/application/service/persister/AuctionHistoryPersisterTest.java +++ b/src/test/java/until/the/eternity/auctionhistory/application/service/persister/AuctionHistoryPersisterTest.java @@ -1,11 +1,5 @@ package until.the.eternity.auctionhistory.application.service.persister; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -19,6 +13,13 @@ import until.the.eternity.auctionhistory.interfaces.external.dto.OpenApiAuctionHistoryResponse; import until.the.eternity.common.enums.ItemCategory; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + @ExtendWith(MockitoExtension.class) class AuctionHistoryPersisterTest {