From 00bab5106d887f22571a81b4691495b9529ccf5b Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Fri, 11 Oct 2024 12:38:20 +0900 Subject: [PATCH 01/24] =?UTF-8?q?rename:=20dto=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flab/nutridiary/product/controller/ProductController.java | 4 ++-- .../java/flab/nutridiary/product/domain/ProductMapper.java | 2 +- .../product/dto/{ => request}/NewProductRequest.java | 2 +- .../product/dto/{ => response}/NewProductResponse.java | 2 +- .../nutridiary/product/service/ProductRegisterService.java | 4 ++-- .../nutridiary/product/controller/ProductControllerTest.java | 2 +- .../flab/nutridiary/product/domain/ProductMapperTest.java | 2 +- .../product/service/ProductRegisterServiceTest.java | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) rename src/main/java/flab/nutridiary/product/dto/{ => request}/NewProductRequest.java (98%) rename src/main/java/flab/nutridiary/product/dto/{ => response}/NewProductResponse.java (86%) diff --git a/src/main/java/flab/nutridiary/product/controller/ProductController.java b/src/main/java/flab/nutridiary/product/controller/ProductController.java index 1921f70..1331f14 100644 --- a/src/main/java/flab/nutridiary/product/controller/ProductController.java +++ b/src/main/java/flab/nutridiary/product/controller/ProductController.java @@ -1,8 +1,8 @@ package flab.nutridiary.product.controller; import flab.nutridiary.commom.dto.ApiResponse; -import flab.nutridiary.product.dto.NewProductRequest; -import flab.nutridiary.product.dto.NewProductResponse; +import flab.nutridiary.product.dto.request.NewProductRequest; +import flab.nutridiary.product.dto.response.NewProductResponse; import flab.nutridiary.product.service.ProductRegisterService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/flab/nutridiary/product/domain/ProductMapper.java b/src/main/java/flab/nutridiary/product/domain/ProductMapper.java index 0dde560..b1a99a1 100644 --- a/src/main/java/flab/nutridiary/product/domain/ProductMapper.java +++ b/src/main/java/flab/nutridiary/product/domain/ProductMapper.java @@ -1,6 +1,6 @@ package flab.nutridiary.product.domain; -import flab.nutridiary.product.dto.NewProductRequest; +import flab.nutridiary.product.dto.request.NewProductRequest; import org.springframework.stereotype.Component; import java.math.BigDecimal; diff --git a/src/main/java/flab/nutridiary/product/dto/NewProductRequest.java b/src/main/java/flab/nutridiary/product/dto/request/NewProductRequest.java similarity index 98% rename from src/main/java/flab/nutridiary/product/dto/NewProductRequest.java rename to src/main/java/flab/nutridiary/product/dto/request/NewProductRequest.java index d01d212..02a935c 100644 --- a/src/main/java/flab/nutridiary/product/dto/NewProductRequest.java +++ b/src/main/java/flab/nutridiary/product/dto/request/NewProductRequest.java @@ -1,4 +1,4 @@ -package flab.nutridiary.product.dto; +package flab.nutridiary.product.dto.request; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/flab/nutridiary/product/dto/NewProductResponse.java b/src/main/java/flab/nutridiary/product/dto/response/NewProductResponse.java similarity index 86% rename from src/main/java/flab/nutridiary/product/dto/NewProductResponse.java rename to src/main/java/flab/nutridiary/product/dto/response/NewProductResponse.java index 1e5437a..2580be9 100644 --- a/src/main/java/flab/nutridiary/product/dto/NewProductResponse.java +++ b/src/main/java/flab/nutridiary/product/dto/response/NewProductResponse.java @@ -1,4 +1,4 @@ -package flab.nutridiary.product.dto; +package flab.nutridiary.product.dto.response; import lombok.Getter; diff --git a/src/main/java/flab/nutridiary/product/service/ProductRegisterService.java b/src/main/java/flab/nutridiary/product/service/ProductRegisterService.java index 2c80f8a..fb7b5d1 100644 --- a/src/main/java/flab/nutridiary/product/service/ProductRegisterService.java +++ b/src/main/java/flab/nutridiary/product/service/ProductRegisterService.java @@ -2,8 +2,8 @@ import flab.nutridiary.product.domain.Product; import flab.nutridiary.product.domain.ProductMapper; -import flab.nutridiary.product.dto.NewProductRequest; -import flab.nutridiary.product.dto.NewProductResponse; +import flab.nutridiary.product.dto.request.NewProductRequest; +import flab.nutridiary.product.dto.response.NewProductResponse; import flab.nutridiary.product.repository.ProductRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/src/test/java/flab/nutridiary/product/controller/ProductControllerTest.java b/src/test/java/flab/nutridiary/product/controller/ProductControllerTest.java index bed04e4..e25d544 100644 --- a/src/test/java/flab/nutridiary/product/controller/ProductControllerTest.java +++ b/src/test/java/flab/nutridiary/product/controller/ProductControllerTest.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import flab.nutridiary.product.domain.Product; -import flab.nutridiary.product.dto.NewProductRequest; +import flab.nutridiary.product.dto.request.NewProductRequest; import flab.nutridiary.product.repository.ProductRepository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/flab/nutridiary/product/domain/ProductMapperTest.java b/src/test/java/flab/nutridiary/product/domain/ProductMapperTest.java index 79c8e70..4acc490 100644 --- a/src/test/java/flab/nutridiary/product/domain/ProductMapperTest.java +++ b/src/test/java/flab/nutridiary/product/domain/ProductMapperTest.java @@ -1,7 +1,7 @@ package flab.nutridiary.product.domain; import flab.nutridiary.commom.generic.Nutrition; -import flab.nutridiary.product.dto.NewProductRequest; +import flab.nutridiary.product.dto.request.NewProductRequest; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/flab/nutridiary/product/service/ProductRegisterServiceTest.java b/src/test/java/flab/nutridiary/product/service/ProductRegisterServiceTest.java index 3ca179e..ff4b638 100644 --- a/src/test/java/flab/nutridiary/product/service/ProductRegisterServiceTest.java +++ b/src/test/java/flab/nutridiary/product/service/ProductRegisterServiceTest.java @@ -3,8 +3,8 @@ import flab.nutridiary.commom.generic.Nutrition; import flab.nutridiary.product.domain.ServingUnit; import flab.nutridiary.product.domain.Product; -import flab.nutridiary.product.dto.NewProductRequest; -import flab.nutridiary.product.dto.NewProductResponse; +import flab.nutridiary.product.dto.request.NewProductRequest; +import flab.nutridiary.product.dto.response.NewProductResponse; import flab.nutridiary.product.repository.ProductRepository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; From eaf8193eab01ec1bfe6303152194db2f0d2500b6 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:48:59 +0900 Subject: [PATCH 02/24] =?UTF-8?q?feat:=20=EC=8B=9D=ED=92=88=EB=AA=85?= =?UTF-8?q?=EA=B3=BC=20=EC=A0=9C=EC=A1=B0=EC=82=AC=EB=AA=85=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=8B=9D=ED=92=88=EC=9D=84=20=EA=B2=80=EC=83=89?= =?UTF-8?q?=ED=95=9C=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/controller/ProductController.java | 15 +++++++-- .../dto/response/ProductSearchResponse.java | 16 ++++++++++ .../repository/ProductSearchRepository.java | 9 ++++++ .../JdbcTemplateProductSearchRepository.java | 31 +++++++++++++++++++ .../product/service/ProductSearchService.java | 18 +++++++++++ src/main/resources/db/schema.sql | 4 ++- 6 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java create mode 100644 src/main/java/flab/nutridiary/product/repository/ProductSearchRepository.java create mode 100644 src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java create mode 100644 src/main/java/flab/nutridiary/product/service/ProductSearchService.java diff --git a/src/main/java/flab/nutridiary/product/controller/ProductController.java b/src/main/java/flab/nutridiary/product/controller/ProductController.java index 1331f14..29c6435 100644 --- a/src/main/java/flab/nutridiary/product/controller/ProductController.java +++ b/src/main/java/flab/nutridiary/product/controller/ProductController.java @@ -3,21 +3,30 @@ import flab.nutridiary.commom.dto.ApiResponse; import flab.nutridiary.product.dto.request.NewProductRequest; import flab.nutridiary.product.dto.response.NewProductResponse; +import flab.nutridiary.product.dto.response.ProductSearchResponse; import flab.nutridiary.product.service.ProductRegisterService; +import flab.nutridiary.product.service.ProductSearchService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.List; @RestController @RequiredArgsConstructor public class ProductController { private final ProductRegisterService productRegisterService; + private final ProductSearchService productSearchService; @PostMapping("/product/new") public ApiResponse addProduct(@RequestBody @Valid NewProductRequest productRequest) { return ApiResponse.success(productRegisterService.process(productRequest)); } + + //todo : 전문검색 글자 2글자가능하도록, 검색결과 페이징?, 이미지가 필요할까? + @GetMapping("/product") + public ApiResponse> searchProduct(@RequestParam(name = "search") String condition) { + return ApiResponse.success(productSearchService.search(condition)); + } } diff --git a/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java b/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java new file mode 100644 index 0000000..eb123da --- /dev/null +++ b/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java @@ -0,0 +1,16 @@ +package flab.nutridiary.product.dto.response; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +@RequiredArgsConstructor +@Getter +@EqualsAndHashCode +@ToString +public class ProductSearchResponse { + private final Long productId; + private final String productName; + private final String productCorp; +} \ No newline at end of file diff --git a/src/main/java/flab/nutridiary/product/repository/ProductSearchRepository.java b/src/main/java/flab/nutridiary/product/repository/ProductSearchRepository.java new file mode 100644 index 0000000..9abe1cb --- /dev/null +++ b/src/main/java/flab/nutridiary/product/repository/ProductSearchRepository.java @@ -0,0 +1,9 @@ +package flab.nutridiary.product.repository; + +import flab.nutridiary.product.dto.response.ProductSearchResponse; + +import java.util.List; + +public interface ProductSearchRepository { + List findFullTextSearch(String keyword); +} diff --git a/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java b/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java new file mode 100644 index 0000000..597ca49 --- /dev/null +++ b/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java @@ -0,0 +1,31 @@ +package flab.nutridiary.product.repository.query; + +import flab.nutridiary.product.dto.response.ProductSearchResponse; +import flab.nutridiary.product.repository.ProductSearchRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.jdbc.core.DataClassRowMapper; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +@Transactional +public class JdbcTemplateProductSearchRepository implements ProductSearchRepository { + private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; + DataClassRowMapper beanPropertyRowMapper = new DataClassRowMapper<>(ProductSearchResponse.class); + + @Override + public List findFullTextSearch(String keyword) { + String sql = "SELECT " + + "p.product_id, p.product_name, p.product_corp " + + "FROM product p " + + "WHERE MATCH (p.product_name, p.product_corp) AGAINST (:keyword)"; + MapSqlParameterSource parameters = new MapSqlParameterSource() + .addValue("keyword", keyword); + return namedParameterJdbcTemplate.query(sql, parameters, beanPropertyRowMapper); + } +} diff --git a/src/main/java/flab/nutridiary/product/service/ProductSearchService.java b/src/main/java/flab/nutridiary/product/service/ProductSearchService.java new file mode 100644 index 0000000..f5a230f --- /dev/null +++ b/src/main/java/flab/nutridiary/product/service/ProductSearchService.java @@ -0,0 +1,18 @@ +package flab.nutridiary.product.service; + +import flab.nutridiary.product.dto.response.ProductSearchResponse; +import flab.nutridiary.product.repository.ProductSearchRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@RequiredArgsConstructor +@Service +public class ProductSearchService { + private final ProductSearchRepository productSearchRepository; + + public List search(String condition) { + return productSearchRepository.findFullTextSearch(condition); + } +} diff --git a/src/main/resources/db/schema.sql b/src/main/resources/db/schema.sql index d8be234..ad3e2d5 100644 --- a/src/main/resources/db/schema.sql +++ b/src/main/resources/db/schema.sql @@ -15,7 +15,9 @@ CREATE TABLE product ( nutrition_facts VARCHAR(255), member_id BIGINT NOT NULL, created_at DATETIME NOT NULL, - updated_at DATETIME NOT NULL + updated_at DATETIME NOT NULL, + FULLTEXT (product_name, product_corp) + ); CREATE TABLE diary ( From b8db9cc97d9fb85518916393539da827a4831dce Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Sun, 20 Oct 2024 13:06:26 +0900 Subject: [PATCH 03/24] =?UTF-8?q?fix:=20@Transactional=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flab/nutridiary/diary/repository/DiaryRepositoryImpl.java | 4 +++- .../nutridiary/product/repository/ProductRepositoryImpl.java | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/flab/nutridiary/diary/repository/DiaryRepositoryImpl.java b/src/main/java/flab/nutridiary/diary/repository/DiaryRepositoryImpl.java index 52ffb30..2affb9e 100644 --- a/src/main/java/flab/nutridiary/diary/repository/DiaryRepositoryImpl.java +++ b/src/main/java/flab/nutridiary/diary/repository/DiaryRepositoryImpl.java @@ -3,12 +3,14 @@ import flab.nutridiary.diary.domain.Diary; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; import java.util.Optional; -@Repository @RequiredArgsConstructor +@Transactional +@Repository public class DiaryRepositoryImpl implements DiaryRepository{ private final DiaryCrudRepository diaryCrudRepository; diff --git a/src/main/java/flab/nutridiary/product/repository/ProductRepositoryImpl.java b/src/main/java/flab/nutridiary/product/repository/ProductRepositoryImpl.java index 3ea14d5..ac75ea7 100644 --- a/src/main/java/flab/nutridiary/product/repository/ProductRepositoryImpl.java +++ b/src/main/java/flab/nutridiary/product/repository/ProductRepositoryImpl.java @@ -4,11 +4,13 @@ import flab.nutridiary.product.service.ProductValidatorRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import java.util.Optional; -@Repository @RequiredArgsConstructor +@Transactional +@Repository public class ProductRepositoryImpl implements ProductRepository, ProductValidatorRepository { private final ProductCrudRepository productCrudRepository; From 613ce608fb4c4a24441dffbf01299c8eb30a2ba9 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Sun, 20 Oct 2024 13:39:52 +0900 Subject: [PATCH 04/24] =?UTF-8?q?refactor:=20JdbcAuditing=20=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=83=9D=EC=84=B1=EC=9D=BC,=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=9D=BC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nutridiary/product/domain/Product.java | 7 ++++--- .../domain/ProductBeforeSaveCallBack.java | 20 ------------------- 2 files changed, 4 insertions(+), 23 deletions(-) delete mode 100644 src/main/java/flab/nutridiary/product/domain/ProductBeforeSaveCallBack.java diff --git a/src/main/java/flab/nutridiary/product/domain/Product.java b/src/main/java/flab/nutridiary/product/domain/Product.java index e533741..02bd2ba 100644 --- a/src/main/java/flab/nutridiary/product/domain/Product.java +++ b/src/main/java/flab/nutridiary/product/domain/Product.java @@ -2,9 +2,10 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; import lombok.ToString; +import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.relational.core.mapping.Column; import java.time.LocalDateTime; @@ -29,10 +30,10 @@ public class Product { private Long memberId = 1L; - @Setter + @CreatedDate private LocalDateTime createdAt; - @Setter + @LastModifiedDate private LocalDateTime updatedAt; @Builder diff --git a/src/main/java/flab/nutridiary/product/domain/ProductBeforeSaveCallBack.java b/src/main/java/flab/nutridiary/product/domain/ProductBeforeSaveCallBack.java deleted file mode 100644 index 29445ea..0000000 --- a/src/main/java/flab/nutridiary/product/domain/ProductBeforeSaveCallBack.java +++ /dev/null @@ -1,20 +0,0 @@ -package flab.nutridiary.product.domain; - -import org.springframework.data.relational.core.conversion.MutableAggregateChange; -import org.springframework.data.relational.core.mapping.event.BeforeSaveCallback; -import org.springframework.stereotype.Component; - -import java.time.LocalDateTime; - -@Component -public class ProductBeforeSaveCallBack implements BeforeSaveCallback { - - @Override - public Product onBeforeSave(Product product, MutableAggregateChange aggregateChange) { - if (product.getCreatedAt() == null) { - product.setCreatedAt(LocalDateTime.now()); - } - product.setUpdatedAt(LocalDateTime.now()); - return product; - } -} \ No newline at end of file From 4a598c9a6a92e6efb0aff40cd2636df292a39473 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Sun, 20 Oct 2024 13:40:15 +0900 Subject: [PATCH 05/24] =?UTF-8?q?chore:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20import=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flab/nutridiary/review/repository/ReviewRepositoryImpl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/flab/nutridiary/review/repository/ReviewRepositoryImpl.java b/src/main/java/flab/nutridiary/review/repository/ReviewRepositoryImpl.java index 01a5e67..961baeb 100644 --- a/src/main/java/flab/nutridiary/review/repository/ReviewRepositoryImpl.java +++ b/src/main/java/flab/nutridiary/review/repository/ReviewRepositoryImpl.java @@ -1,9 +1,7 @@ package flab.nutridiary.review.repository; -import flab.nutridiary.product.domain.Product; import flab.nutridiary.review.domain.Review; import lombok.RequiredArgsConstructor; -import org.springframework.data.jdbc.core.mapping.AggregateReference; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; From 3af69600f287e3a757a4608ea302949839d275d4 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:10:13 +0900 Subject: [PATCH 06/24] =?UTF-8?q?chore:=20=EB=8D=94=EB=AF=B8=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=B6=94=EA=B0=80=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dummy/InsertProductDietTagDummy.java | 63 ++++++++++++++++++ .../nutridiary/dummy/InsertProductDummy.java | 65 +++++++++++++++++++ .../nutridiary/dummy/InsertReviewDummy.java | 65 +++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java create mode 100644 src/test/java/flab/nutridiary/dummy/InsertProductDummy.java create mode 100644 src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java diff --git a/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java b/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java new file mode 100644 index 0000000..874d498 --- /dev/null +++ b/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java @@ -0,0 +1,63 @@ +package flab.nutridiary.dummy; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +@SpringBootTest +public class InsertProductDietTagDummy { + @Autowired + private JdbcTemplate jdbcTemplate; + + private final int batchSize = 1000; + private final int threadCount = 5; + private final int totalDataCount = 20000000; + + private final String productDietTagSQL = "INSERT INTO product_diet_tag (product_id, diet_tag_id, created_at, updated_at) VALUES (?, ?, ?, ?)"; + + @Test + public void insertProductDataInParallel() throws InterruptedException { + ExecutorService executorService = Executors.newFixedThreadPool(threadCount); + int chunkSize = totalDataCount / threadCount; + + for (int i = 0; i < threadCount; i++) { + int start = i * chunkSize + 1; + int end = (i == threadCount - 1) ? totalDataCount : (i + 1) * chunkSize; + + executorService.submit(() -> insertChunk(productDietTagSQL, start, end)); + } + + executorService.shutdown(); + executorService.awaitTermination(1, TimeUnit.HOURS); // 스레드가 모두 종료될 때까지 대기 + } + + public void insertChunk(String sql, int start, int end) { + List batchArgs = new ArrayList<>(); + + for (int i = start; i <= end; i++) { + int productId = (i % 8) * 100000 + i % 100000; + int dietTagId = i % 10 + 1; + String createdAt = "2024-09-01 00:00:00"; + String updatedAt = "2024-09-01 00:00:00"; + batchArgs.add(new Object[]{productId, dietTagId, createdAt, updatedAt}); + + if (batchArgs.size() % batchSize == 0) { + jdbcTemplate.batchUpdate(sql, batchArgs); + batchArgs.clear(); + } + } + + if (!batchArgs.isEmpty()) { + jdbcTemplate.batchUpdate(sql, batchArgs); + } + + System.out.println("스레드가 " + start + "부터 " + end + "까지 데이터를 삽입했습니다."); + } +} diff --git a/src/test/java/flab/nutridiary/dummy/InsertProductDummy.java b/src/test/java/flab/nutridiary/dummy/InsertProductDummy.java new file mode 100644 index 0000000..5bccaeb --- /dev/null +++ b/src/test/java/flab/nutridiary/dummy/InsertProductDummy.java @@ -0,0 +1,65 @@ +package flab.nutridiary.dummy; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +@SpringBootTest +public class InsertProductDummy { + @Autowired + private JdbcTemplate jdbcTemplate; + + private final int batchSize = 1000; + private final int threadCount = 5; + private final String[] productNames = {"스팀 닭가슴살 칠리맛", "크리스피 닭가슴살 핫도그", "전복 내장 미역국", "닭가슴살 양배추쌈", "무봤나 반마리 삼계탕", "제육 덮밥", "맥앤치즈볼", "스팸마일드", "삼양라면", "당면 고기만두", "동치미 물냉면"}; + private final String[] productCorps = {"코스트코", "롯데리아", "맥도날드", "버거킹", "KFC", "파리바게트", "CU", "GS25", "세븐일레븐", "이마트", "홈플러스"}; + + private final String productSQL = "INSERT INTO product (product_name, product_corp, member_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?)"; + + @Test + public void insertProductDataInParallel() throws InterruptedException { + ExecutorService executorService = Executors.newFixedThreadPool(threadCount); + int chunkSize = 1000000 / threadCount; + + for (int i = 0; i < threadCount; i++) { + int start = i * chunkSize + 1; + int end = (i == threadCount - 1) ? 1000000 : (i + 1) * chunkSize; + + executorService.submit(() -> insertChunk(productSQL, start, end)); + } + + executorService.shutdown(); + executorService.awaitTermination(1, TimeUnit.HOURS); // 스레드가 모두 종료될 때까지 대기 + } + + public void insertChunk(String sql, int start, int end) { + List batchArgs = new ArrayList<>(); + + for (int i = start; i <= end; i++) { + String productName = i + "productName " + productNames[i % productNames.length] + i; + String productCorp = i + "productCorp " + productCorps[i % productCorps.length] + i; + int memberId = i; + String createdAt = "2024-09-01 00:00:00"; + String updatedAt = "2024-09-01 00:00:00"; + batchArgs.add(new Object[]{productName, productCorp, memberId, createdAt, updatedAt}); + + if (batchArgs.size() % batchSize == 0) { + jdbcTemplate.batchUpdate(sql, batchArgs); + batchArgs.clear(); + } + } + + if (!batchArgs.isEmpty()) { + jdbcTemplate.batchUpdate(sql, batchArgs); + } + + System.out.println("스레드가 " + start + "부터 " + end + "까지 데이터를 삽입했습니다."); + } +} diff --git a/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java b/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java new file mode 100644 index 0000000..f8a0c90 --- /dev/null +++ b/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java @@ -0,0 +1,65 @@ +package flab.nutridiary.dummy; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +@SpringBootTest +public class InsertReviewDummy { + @Autowired + private JdbcTemplate jdbcTemplate; + + private final int batchSize = 1000; + private final int threadCount = 5; + private final int totalDataCount = 10000000; + + private final String reviewSQL = "INSERT INTO review (product_id, member_id, content, rating, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)"; + + @Test + public void insertProductDataInParallel() throws InterruptedException { + ExecutorService executorService = Executors.newFixedThreadPool(threadCount); + int chunkSize = totalDataCount / threadCount; + + for (int i = 0; i < threadCount; i++) { + int start = i * chunkSize + 1; + int end = (i == threadCount - 1) ? totalDataCount : (i + 1) * chunkSize; + + executorService.submit(() -> insertChunk(reviewSQL, start, end)); + } + + executorService.shutdown(); + executorService.awaitTermination(1, TimeUnit.HOURS); // 스레드가 모두 종료될 때까지 대기 + } + + public void insertChunk(String sql, int start, int end) { + List batchArgs = new ArrayList<>(); + + for (int i = start; i <= end; i++) { + int productId = (i % 8) * 100000 + i % 100000; + int memberId = i; + String content = i + "content " + i; + int rating = i % 5 + 1; + String createdAt = "2024-09-01 00:00:00"; + String updatedAt = "2024-09-01 00:00:00"; + batchArgs.add(new Object[]{productId, memberId, content, rating, createdAt, updatedAt}); + + if (batchArgs.size() % batchSize == 0) { + jdbcTemplate.batchUpdate(sql, batchArgs); + batchArgs.clear(); + } + } + + if (!batchArgs.isEmpty()) { + jdbcTemplate.batchUpdate(sql, batchArgs); + } + + System.out.println("스레드가 " + start + "부터 " + end + "까지 데이터를 삽입했습니다."); + } +} From 5ba467d418df671f3f0b9991fba0abdd6227d1dc Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Mon, 21 Oct 2024 21:07:48 +0900 Subject: [PATCH 07/24] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EA=B0=AF=EC=88=98=EC=99=80=20=ED=95=A8=EA=BB=98=20=EC=8B=9D?= =?UTF-8?q?=ED=92=88=20=EA=B2=80=EC=83=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/controller/ProductController.java | 9 +++---- .../dto/response/ProductSearchResponse.java | 1 + .../repository/ProductSearchRepository.java | 6 ++--- .../JdbcTemplateProductSearchRepository.java | 27 ++++++++++++++++--- .../product/service/ProductSearchService.java | 8 +++--- src/main/resources/application.yml | 2 +- src/main/resources/db/schema.sql | 3 +-- 7 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/main/java/flab/nutridiary/product/controller/ProductController.java b/src/main/java/flab/nutridiary/product/controller/ProductController.java index 29c6435..936b798 100644 --- a/src/main/java/flab/nutridiary/product/controller/ProductController.java +++ b/src/main/java/flab/nutridiary/product/controller/ProductController.java @@ -8,10 +8,10 @@ import flab.nutridiary.product.service.ProductSearchService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.web.bind.annotation.*; -import java.util.List; - @RestController @RequiredArgsConstructor public class ProductController { @@ -24,9 +24,8 @@ public ApiResponse addProduct(@RequestBody @Valid NewProduct return ApiResponse.success(productRegisterService.process(productRequest)); } - //todo : 전문검색 글자 2글자가능하도록, 검색결과 페이징?, 이미지가 필요할까? @GetMapping("/product") - public ApiResponse> searchProduct(@RequestParam(name = "search") String condition) { - return ApiResponse.success(productSearchService.search(condition)); + public ApiResponse> searchProduct(@RequestParam(name = "search") String condition, Pageable pageable) { + return ApiResponse.success(productSearchService.search(condition, pageable)); } } diff --git a/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java b/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java index eb123da..9bea070 100644 --- a/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java +++ b/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java @@ -13,4 +13,5 @@ public class ProductSearchResponse { private final Long productId; private final String productName; private final String productCorp; + private final Integer reviewCount; } \ No newline at end of file diff --git a/src/main/java/flab/nutridiary/product/repository/ProductSearchRepository.java b/src/main/java/flab/nutridiary/product/repository/ProductSearchRepository.java index 9abe1cb..0bf873a 100644 --- a/src/main/java/flab/nutridiary/product/repository/ProductSearchRepository.java +++ b/src/main/java/flab/nutridiary/product/repository/ProductSearchRepository.java @@ -1,9 +1,9 @@ package flab.nutridiary.product.repository; import flab.nutridiary.product.dto.response.ProductSearchResponse; - -import java.util.List; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; public interface ProductSearchRepository { - List findFullTextSearch(String keyword); + Page findFullTextSearch(String keyword, Pageable pageable); } diff --git a/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java b/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java index 597ca49..3358600 100644 --- a/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java +++ b/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java @@ -3,6 +3,9 @@ import flab.nutridiary.product.dto.response.ProductSearchResponse; import flab.nutridiary.product.repository.ProductSearchRepository; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; import org.springframework.jdbc.core.DataClassRowMapper; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -18,14 +21,32 @@ public class JdbcTemplateProductSearchRepository implements ProductSearchReposit private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; DataClassRowMapper beanPropertyRowMapper = new DataClassRowMapper<>(ProductSearchResponse.class); + @Override - public List findFullTextSearch(String keyword) { + public Page findFullTextSearch(String keyword, Pageable pageable) { + Integer total = getTotalCount(keyword); + String sql = "SELECT " + - "p.product_id, p.product_name, p.product_corp " + + "p.product_id, p.product_name, p.product_corp, IFNULL(review_count, 0) AS review_count " + + "FROM product p " + + "LEFT JOIN (SELECT product_id, COUNT(*) AS review_count FROM review GROUP BY product_id) r ON p.product_id = r.product_id " + + "WHERE MATCH (p.product_name, p.product_corp) AGAINST (:keyword)" + + "LIMIT :offset, :limit"; + MapSqlParameterSource parameters = new MapSqlParameterSource() + .addValue("keyword", keyword) + .addValue("offset", pageable.getOffset()) + .addValue("limit", pageable.getPageSize()); + List queried = namedParameterJdbcTemplate.query(sql, parameters, beanPropertyRowMapper); + return new PageImpl<>(queried, pageable, total); + } + + private Integer getTotalCount(String keyword) { + String sql = "SELECT COUNT(*) " + "FROM product p " + + "LEFT JOIN (SELECT product_id, COUNT(*) AS review_count FROM review GROUP BY product_id) r ON p.product_id = r.product_id " + "WHERE MATCH (p.product_name, p.product_corp) AGAINST (:keyword)"; MapSqlParameterSource parameters = new MapSqlParameterSource() .addValue("keyword", keyword); - return namedParameterJdbcTemplate.query(sql, parameters, beanPropertyRowMapper); + return namedParameterJdbcTemplate.queryForObject(sql, parameters, Integer.class); } } diff --git a/src/main/java/flab/nutridiary/product/service/ProductSearchService.java b/src/main/java/flab/nutridiary/product/service/ProductSearchService.java index f5a230f..dab03eb 100644 --- a/src/main/java/flab/nutridiary/product/service/ProductSearchService.java +++ b/src/main/java/flab/nutridiary/product/service/ProductSearchService.java @@ -3,16 +3,16 @@ import flab.nutridiary.product.dto.response.ProductSearchResponse; import flab.nutridiary.product.repository.ProductSearchRepository; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; -import java.util.List; - @RequiredArgsConstructor @Service public class ProductSearchService { private final ProductSearchRepository productSearchRepository; - public List search(String condition) { - return productSearchRepository.findFullTextSearch(condition); + public Page search(String condition, Pageable pageable) { + return productSearchRepository.findFullTextSearch(condition, pageable); } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index f277f34..fc40544 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -55,7 +55,7 @@ spring: driver-class-name: com.mysql.cj.jdbc.Driver sql: init: - mode: always + mode: never schema-locations: classpath:db/schema.sql data-locations: optional:classpath:db/data.sql diff --git a/src/main/resources/db/schema.sql b/src/main/resources/db/schema.sql index ad3e2d5..31aeb74 100644 --- a/src/main/resources/db/schema.sql +++ b/src/main/resources/db/schema.sql @@ -16,8 +16,7 @@ CREATE TABLE product ( member_id BIGINT NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, - FULLTEXT (product_name, product_corp) - + FULLTEXT (product_name, product_corp) WITH PARSER ngram ); CREATE TABLE diary ( From 9f7055fe010242a58fc28215e02220f369d17b5f Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Mon, 21 Oct 2024 21:36:25 +0900 Subject: [PATCH 08/24] =?UTF-8?q?chore:=20=EB=8D=94=EB=AF=B8=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=82=BD=EC=9E=85=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dummy/InsertProductDietTagDummy.java | 111 ++++++++---------- .../nutridiary/dummy/InsertProductDummy.java | 104 ++++++++-------- .../nutridiary/dummy/InsertReviewDummy.java | 104 ++++++++-------- 3 files changed, 154 insertions(+), 165 deletions(-) diff --git a/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java b/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java index 874d498..b1b91f4 100644 --- a/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java +++ b/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java @@ -1,63 +1,52 @@ package flab.nutridiary.dummy; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.jdbc.core.JdbcTemplate; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -@SpringBootTest -public class InsertProductDietTagDummy { - @Autowired - private JdbcTemplate jdbcTemplate; - - private final int batchSize = 1000; - private final int threadCount = 5; - private final int totalDataCount = 20000000; - - private final String productDietTagSQL = "INSERT INTO product_diet_tag (product_id, diet_tag_id, created_at, updated_at) VALUES (?, ?, ?, ?)"; - - @Test - public void insertProductDataInParallel() throws InterruptedException { - ExecutorService executorService = Executors.newFixedThreadPool(threadCount); - int chunkSize = totalDataCount / threadCount; - - for (int i = 0; i < threadCount; i++) { - int start = i * chunkSize + 1; - int end = (i == threadCount - 1) ? totalDataCount : (i + 1) * chunkSize; - - executorService.submit(() -> insertChunk(productDietTagSQL, start, end)); - } - - executorService.shutdown(); - executorService.awaitTermination(1, TimeUnit.HOURS); // 스레드가 모두 종료될 때까지 대기 - } - - public void insertChunk(String sql, int start, int end) { - List batchArgs = new ArrayList<>(); - - for (int i = start; i <= end; i++) { - int productId = (i % 8) * 100000 + i % 100000; - int dietTagId = i % 10 + 1; - String createdAt = "2024-09-01 00:00:00"; - String updatedAt = "2024-09-01 00:00:00"; - batchArgs.add(new Object[]{productId, dietTagId, createdAt, updatedAt}); - - if (batchArgs.size() % batchSize == 0) { - jdbcTemplate.batchUpdate(sql, batchArgs); - batchArgs.clear(); - } - } - - if (!batchArgs.isEmpty()) { - jdbcTemplate.batchUpdate(sql, batchArgs); - } - - System.out.println("스레드가 " + start + "부터 " + end + "까지 데이터를 삽입했습니다."); - } -} +//@SpringBootTest +//public class InsertProductDietTagDummy { +// @Autowired +// private JdbcTemplate jdbcTemplate; +// +// private final int batchSize = 1000; +// private final int threadCount = 5; +// private final int totalDataCount = 20000000; +// +// private final String productDietTagSQL = "INSERT INTO product_diet_tag (product_id, diet_tag_id, created_at, updated_at) VALUES (?, ?, ?, ?)"; +// +// @Test +// public void insertProductDataInParallel() throws InterruptedException { +// ExecutorService executorService = Executors.newFixedThreadPool(threadCount); +// int chunkSize = totalDataCount / threadCount; +// +// for (int i = 0; i < threadCount; i++) { +// int start = i * chunkSize + 1; +// int end = (i == threadCount - 1) ? totalDataCount : (i + 1) * chunkSize; +// +// executorService.submit(() -> insertChunk(productDietTagSQL, start, end)); +// } +// +// executorService.shutdown(); +// executorService.awaitTermination(1, TimeUnit.HOURS); // 스레드가 모두 종료될 때까지 대기 +// } +// +// public void insertChunk(String sql, int start, int end) { +// List batchArgs = new ArrayList<>(); +// +// for (int i = start; i <= end; i++) { +// int productId = (i % 8) * 100000 + i % 100000; +// int dietTagId = i % 10 + 1; +// String createdAt = "2024-09-01 00:00:00"; +// String updatedAt = "2024-09-01 00:00:00"; +// batchArgs.add(new Object[]{productId, dietTagId, createdAt, updatedAt}); +// +// if (batchArgs.size() % batchSize == 0) { +// jdbcTemplate.batchUpdate(sql, batchArgs); +// batchArgs.clear(); +// } +// } +// +// if (!batchArgs.isEmpty()) { +// jdbcTemplate.batchUpdate(sql, batchArgs); +// } +// +// System.out.println("스레드가 " + start + "부터 " + end + "까지 데이터를 삽입했습니다."); +// } +//} diff --git a/src/test/java/flab/nutridiary/dummy/InsertProductDummy.java b/src/test/java/flab/nutridiary/dummy/InsertProductDummy.java index 5bccaeb..05ec984 100644 --- a/src/test/java/flab/nutridiary/dummy/InsertProductDummy.java +++ b/src/test/java/flab/nutridiary/dummy/InsertProductDummy.java @@ -11,55 +11,55 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -@SpringBootTest -public class InsertProductDummy { - @Autowired - private JdbcTemplate jdbcTemplate; - - private final int batchSize = 1000; - private final int threadCount = 5; - private final String[] productNames = {"스팀 닭가슴살 칠리맛", "크리스피 닭가슴살 핫도그", "전복 내장 미역국", "닭가슴살 양배추쌈", "무봤나 반마리 삼계탕", "제육 덮밥", "맥앤치즈볼", "스팸마일드", "삼양라면", "당면 고기만두", "동치미 물냉면"}; - private final String[] productCorps = {"코스트코", "롯데리아", "맥도날드", "버거킹", "KFC", "파리바게트", "CU", "GS25", "세븐일레븐", "이마트", "홈플러스"}; - - private final String productSQL = "INSERT INTO product (product_name, product_corp, member_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?)"; - - @Test - public void insertProductDataInParallel() throws InterruptedException { - ExecutorService executorService = Executors.newFixedThreadPool(threadCount); - int chunkSize = 1000000 / threadCount; - - for (int i = 0; i < threadCount; i++) { - int start = i * chunkSize + 1; - int end = (i == threadCount - 1) ? 1000000 : (i + 1) * chunkSize; - - executorService.submit(() -> insertChunk(productSQL, start, end)); - } - - executorService.shutdown(); - executorService.awaitTermination(1, TimeUnit.HOURS); // 스레드가 모두 종료될 때까지 대기 - } - - public void insertChunk(String sql, int start, int end) { - List batchArgs = new ArrayList<>(); - - for (int i = start; i <= end; i++) { - String productName = i + "productName " + productNames[i % productNames.length] + i; - String productCorp = i + "productCorp " + productCorps[i % productCorps.length] + i; - int memberId = i; - String createdAt = "2024-09-01 00:00:00"; - String updatedAt = "2024-09-01 00:00:00"; - batchArgs.add(new Object[]{productName, productCorp, memberId, createdAt, updatedAt}); - - if (batchArgs.size() % batchSize == 0) { - jdbcTemplate.batchUpdate(sql, batchArgs); - batchArgs.clear(); - } - } - - if (!batchArgs.isEmpty()) { - jdbcTemplate.batchUpdate(sql, batchArgs); - } - - System.out.println("스레드가 " + start + "부터 " + end + "까지 데이터를 삽입했습니다."); - } -} +//@SpringBootTest +//public class InsertProductDummy { +// @Autowired +// private JdbcTemplate jdbcTemplate; +// +// private final int batchSize = 1000; +// private final int threadCount = 5; +// private final String[] productNames = {"스팀 닭가슴살 칠리맛", "크리스피 닭가슴살 핫도그", "전복 내장 미역국", "닭가슴살 양배추쌈", "무봤나 반마리 삼계탕", "제육 덮밥", "맥앤치즈볼", "스팸마일드", "삼양라면", "당면 고기만두", "동치미 물냉면"}; +// private final String[] productCorps = {"코스트코", "롯데리아", "맥도날드", "버거킹", "KFC", "파리바게트", "CU", "GS25", "세븐일레븐", "이마트", "홈플러스"}; +// +// private final String productSQL = "INSERT INTO product (product_name, product_corp, member_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?)"; +// +// @Test +// public void insertProductDataInParallel() throws InterruptedException { +// ExecutorService executorService = Executors.newFixedThreadPool(threadCount); +// int chunkSize = 1000000 / threadCount; +// +// for (int i = 0; i < threadCount; i++) { +// int start = i * chunkSize + 1; +// int end = (i == threadCount - 1) ? 1000000 : (i + 1) * chunkSize; +// +// executorService.submit(() -> insertChunk(productSQL, start, end)); +// } +// +// executorService.shutdown(); +// executorService.awaitTermination(1, TimeUnit.HOURS); // 스레드가 모두 종료될 때까지 대기 +// } +// +// public void insertChunk(String sql, int start, int end) { +// List batchArgs = new ArrayList<>(); +// +// for (int i = start; i <= end; i++) { +// String productName = i + "productName " + productNames[i % productNames.length] + i; +// String productCorp = i + "productCorp " + productCorps[i % productCorps.length] + i; +// int memberId = i; +// String createdAt = "2024-09-01 00:00:00"; +// String updatedAt = "2024-09-01 00:00:00"; +// batchArgs.add(new Object[]{productName, productCorp, memberId, createdAt, updatedAt}); +// +// if (batchArgs.size() % batchSize == 0) { +// jdbcTemplate.batchUpdate(sql, batchArgs); +// batchArgs.clear(); +// } +// } +// +// if (!batchArgs.isEmpty()) { +// jdbcTemplate.batchUpdate(sql, batchArgs); +// } +// +// System.out.println("스레드가 " + start + "부터 " + end + "까지 데이터를 삽입했습니다."); +// } +//} diff --git a/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java b/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java index f8a0c90..b3c4cba 100644 --- a/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java +++ b/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java @@ -11,55 +11,55 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -@SpringBootTest -public class InsertReviewDummy { - @Autowired - private JdbcTemplate jdbcTemplate; - - private final int batchSize = 1000; - private final int threadCount = 5; - private final int totalDataCount = 10000000; - - private final String reviewSQL = "INSERT INTO review (product_id, member_id, content, rating, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)"; - - @Test - public void insertProductDataInParallel() throws InterruptedException { - ExecutorService executorService = Executors.newFixedThreadPool(threadCount); - int chunkSize = totalDataCount / threadCount; - - for (int i = 0; i < threadCount; i++) { - int start = i * chunkSize + 1; - int end = (i == threadCount - 1) ? totalDataCount : (i + 1) * chunkSize; - - executorService.submit(() -> insertChunk(reviewSQL, start, end)); - } - - executorService.shutdown(); - executorService.awaitTermination(1, TimeUnit.HOURS); // 스레드가 모두 종료될 때까지 대기 - } - - public void insertChunk(String sql, int start, int end) { - List batchArgs = new ArrayList<>(); - - for (int i = start; i <= end; i++) { - int productId = (i % 8) * 100000 + i % 100000; - int memberId = i; - String content = i + "content " + i; - int rating = i % 5 + 1; - String createdAt = "2024-09-01 00:00:00"; - String updatedAt = "2024-09-01 00:00:00"; - batchArgs.add(new Object[]{productId, memberId, content, rating, createdAt, updatedAt}); - - if (batchArgs.size() % batchSize == 0) { - jdbcTemplate.batchUpdate(sql, batchArgs); - batchArgs.clear(); - } - } - - if (!batchArgs.isEmpty()) { - jdbcTemplate.batchUpdate(sql, batchArgs); - } - - System.out.println("스레드가 " + start + "부터 " + end + "까지 데이터를 삽입했습니다."); - } -} +//@SpringBootTest +//public class InsertReviewDummy { +// @Autowired +// private JdbcTemplate jdbcTemplate; +// +// private final int batchSize = 1000; +// private final int threadCount = 5; +// private final int totalDataCount = 10000000; +// +// private final String reviewSQL = "INSERT INTO review (product_id, member_id, content, rating, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)"; +// +// @Test +// public void insertProductDataInParallel() throws InterruptedException { +// ExecutorService executorService = Executors.newFixedThreadPool(threadCount); +// int chunkSize = totalDataCount / threadCount; +// +// for (int i = 0; i < threadCount; i++) { +// int start = i * chunkSize + 1; +// int end = (i == threadCount - 1) ? totalDataCount : (i + 1) * chunkSize; +// +// executorService.submit(() -> insertChunk(reviewSQL, start, end)); +// } +// +// executorService.shutdown(); +// executorService.awaitTermination(1, TimeUnit.HOURS); // 스레드가 모두 종료될 때까지 대기 +// } +// +// public void insertChunk(String sql, int start, int end) { +// List batchArgs = new ArrayList<>(); +// +// for (int i = start; i <= end; i++) { +// int productId = (i % 8) * 100000 + i % 100000; +// int memberId = i; +// String content = i + "content " + i; +// int rating = i % 5 + 1; +// String createdAt = "2024-09-01 00:00:00"; +// String updatedAt = "2024-09-01 00:00:00"; +// batchArgs.add(new Object[]{productId, memberId, content, rating, createdAt, updatedAt}); +// +// if (batchArgs.size() % batchSize == 0) { +// jdbcTemplate.batchUpdate(sql, batchArgs); +// batchArgs.clear(); +// } +// } +// +// if (!batchArgs.isEmpty()) { +// jdbcTemplate.batchUpdate(sql, batchArgs); +// } +// +// System.out.println("스레드가 " + start + "부터 " + end + "까지 데이터를 삽입했습니다."); +// } +//} From 993b3e4b991ccaf0990adce9ed80461846b1a435 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Tue, 22 Oct 2024 16:28:36 +0900 Subject: [PATCH 09/24] =?UTF-8?q?refactor:=20=EC=8B=9D=ED=92=88=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=EC=BF=BC=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/query/JdbcTemplateProductSearchRepository.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java b/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java index 3358600..b201364 100644 --- a/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java +++ b/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java @@ -27,9 +27,8 @@ public Page findFullTextSearch(String keyword, Pageable p Integer total = getTotalCount(keyword); String sql = "SELECT " + - "p.product_id, p.product_name, p.product_corp, IFNULL(review_count, 0) AS review_count " + + "p.product_id, p.product_name, p.product_corp, (SELECT COUNT(*) FROM review r where r.product_id = p.product_id) AS review_count " + "FROM product p " + - "LEFT JOIN (SELECT product_id, COUNT(*) AS review_count FROM review GROUP BY product_id) r ON p.product_id = r.product_id " + "WHERE MATCH (p.product_name, p.product_corp) AGAINST (:keyword)" + "LIMIT :offset, :limit"; MapSqlParameterSource parameters = new MapSqlParameterSource() @@ -43,7 +42,6 @@ public Page findFullTextSearch(String keyword, Pageable p private Integer getTotalCount(String keyword) { String sql = "SELECT COUNT(*) " + "FROM product p " + - "LEFT JOIN (SELECT product_id, COUNT(*) AS review_count FROM review GROUP BY product_id) r ON p.product_id = r.product_id " + "WHERE MATCH (p.product_name, p.product_corp) AGAINST (:keyword)"; MapSqlParameterSource parameters = new MapSqlParameterSource() .addValue("keyword", keyword); From 8014928e64781e28ea1af42fa2fabbb8e65939be Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Tue, 22 Oct 2024 17:02:55 +0900 Subject: [PATCH 10/24] =?UTF-8?q?refactor:=20=EC=99=B8=EB=9E=98=ED=82=A4?= =?UTF-8?q?=EB=A5=BC=20=EC=A0=9C=EA=B1=B0=ED=95=9C=20=EB=B6=80=EB=B6=84?= =?UTF-8?q?=EC=97=90=20=EC=9D=B8=EB=8D=B1=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/db/schema.sql | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/resources/db/schema.sql b/src/main/resources/db/schema.sql index 31aeb74..3be01ba 100644 --- a/src/main/resources/db/schema.sql +++ b/src/main/resources/db/schema.sql @@ -18,6 +18,7 @@ CREATE TABLE product ( updated_at DATETIME NOT NULL, FULLTEXT (product_name, product_corp) WITH PARSER ngram ); +CREATE INDEX idx_member_id ON product (member_id); CREATE TABLE diary ( diary_id BIGINT PRIMARY KEY AUTO_INCREMENT, @@ -25,6 +26,7 @@ CREATE TABLE diary ( diary_date DATE NOT NULL, CONSTRAINT uc_diary_date UNIQUE (member_id, diary_date) ); +CREATE INDEX idx_member_id ON diary (member_id); CREATE TABLE diary_record ( diary_record_id BIGINT PRIMARY KEY AUTO_INCREMENT, @@ -35,6 +37,8 @@ CREATE TABLE diary_record ( client_choice_serving_unit_description VARCHAR(255), calculated_nutrition VARCHAR(255) ); +CREATE INDEX idx_diary_id ON diary_record (diary_id); +CREATE INDEX idx_product_id ON diary_record (product_id); CREATE TABLE review ( review_id BIGINT PRIMARY KEY AUTO_INCREMENT, @@ -64,6 +68,7 @@ CREATE TABLE product_diet_tag ( created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL ); +CREATE INDEX idx_product_id ON product_diet_tag (product_id); CREATE TABLE store ( store_id BIGINT PRIMARY KEY AUTO_INCREMENT, @@ -80,3 +85,5 @@ CREATE TABLE product_store ( created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL ); +CREATE INDEX idx_product_id ON product_store (product_id); +CREATE INDEX idx_store_id ON product_store (store_id); From 215c04f5906d7606db20a35f040528540122d3b2 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Tue, 22 Oct 2024 20:59:06 +0900 Subject: [PATCH 11/24] =?UTF-8?q?refactor:=20=EC=8B=9D=ED=92=88=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=EC=8B=9C=20top3=20diet=20tag=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/ProductSearchResponse.java | 16 ++++++++++++++-- .../JdbcTemplateProductSearchRepository.java | 5 ++++- src/main/resources/application.yml | 2 +- .../dummy/InsertProductDietTagDummy.java | 13 ++++++++----- .../nutridiary/dummy/InsertReviewDummy.java | 19 +++++-------------- 5 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java b/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java index 9bea070..e937bdc 100644 --- a/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java +++ b/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java @@ -2,10 +2,11 @@ import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.RequiredArgsConstructor; import lombok.ToString; -@RequiredArgsConstructor +import java.math.BigDecimal; +import java.math.RoundingMode; + @Getter @EqualsAndHashCode @ToString @@ -14,4 +15,15 @@ public class ProductSearchResponse { private final String productName; private final String productCorp; private final Integer reviewCount; + private final BigDecimal reviewAvgRating; + private final String top3_diet_tag_names; + + public ProductSearchResponse(Long productId, String productName, String productCorp, Integer reviewCount, BigDecimal reviewAvgRating, String top3_diet_tag_names) { + this.productId = productId; + this.productName = productName; + this.productCorp = productCorp; + this.reviewCount = reviewCount; + this.reviewAvgRating = reviewAvgRating.setScale(1, RoundingMode.HALF_UP); + this.top3_diet_tag_names = top3_diet_tag_names; + } } \ No newline at end of file diff --git a/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java b/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java index b201364..e4f669c 100644 --- a/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java +++ b/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java @@ -27,7 +27,10 @@ public Page findFullTextSearch(String keyword, Pageable p Integer total = getTotalCount(keyword); String sql = "SELECT " + - "p.product_id, p.product_name, p.product_corp, (SELECT COUNT(*) FROM review r where r.product_id = p.product_id) AS review_count " + + "p.product_id, p.product_name, p.product_corp, " + + "(SELECT COUNT(*) FROM review r WHERE r.product_id = p.product_id) AS review_count, " + + "(SELECT AVG(r.rating) FROM review r WHERE r.product_id = p.product_id) AS review_avg_rating, " + + "(SELECT GROUP_CONCAT(diet_tag_name) FROM (SELECT diet_tag_name FROM product_diet_tag pdt where pdt.product_id = p.product_id GROUP BY diet_tag_name ORDER BY COUNT(diet_tag_name) DESC LIMIT 3) AS top3_diet_tag) AS top3_diet_tag_names " + "FROM product p " + "WHERE MATCH (p.product_name, p.product_corp) AGAINST (:keyword)" + "LIMIT :offset, :limit"; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index fc40544..77b5666 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -72,7 +72,7 @@ logging: org: springframework: jdbc: - core: debug + core: error --- spring: diff --git a/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java b/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java index b1b91f4..a1bcdb9 100644 --- a/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java +++ b/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java @@ -5,11 +5,13 @@ // @Autowired // private JdbcTemplate jdbcTemplate; // -// private final int batchSize = 1000; -// private final int threadCount = 5; +// private final int batchSize = 5000; +// private final int threadCount = 10; // private final int totalDataCount = 20000000; +// private final Random random = new Random(); // -// private final String productDietTagSQL = "INSERT INTO product_diet_tag (product_id, diet_tag_id, created_at, updated_at) VALUES (?, ?, ?, ?)"; +// private final String productDietTagSQL = "INSERT INTO product_diet_tag (product_id, diet_tag_id, diet_tag_name, created_at, updated_at) VALUES (?, ?, ?, ?, ?)"; +// private final String[] diet_tag_names = {"저칼로리", "저탄수화물", "무탄수화물", "저단백질", "고단백질", "무설탕", "저지방", "고지방", "저탄고지", "기토제닉"}; // // @Test // public void insertProductDataInParallel() throws InterruptedException { @@ -31,11 +33,12 @@ // List batchArgs = new ArrayList<>(); // // for (int i = start; i <= end; i++) { -// int productId = (i % 8) * 100000 + i % 100000; +// int productId = random.nextInt(1000000); // int dietTagId = i % 10 + 1; +// String dietTagName = diet_tag_names[dietTagId - 1]; // String createdAt = "2024-09-01 00:00:00"; // String updatedAt = "2024-09-01 00:00:00"; -// batchArgs.add(new Object[]{productId, dietTagId, createdAt, updatedAt}); +// batchArgs.add(new Object[]{productId, dietTagId, dietTagName, createdAt, updatedAt}); // // if (batchArgs.size() % batchSize == 0) { // jdbcTemplate.batchUpdate(sql, batchArgs); diff --git a/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java b/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java index b3c4cba..0a6c7d1 100644 --- a/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java +++ b/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java @@ -1,24 +1,15 @@ package flab.nutridiary.dummy; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.jdbc.core.JdbcTemplate; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - //@SpringBootTest //public class InsertReviewDummy { // @Autowired // private JdbcTemplate jdbcTemplate; // -// private final int batchSize = 1000; -// private final int threadCount = 5; +// private final int batchSize = 5000; +// private final int threadCount = 10; // private final int totalDataCount = 10000000; +// private final Random random = new Random(); +// // // private final String reviewSQL = "INSERT INTO review (product_id, member_id, content, rating, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)"; // @@ -42,7 +33,7 @@ // List batchArgs = new ArrayList<>(); // // for (int i = start; i <= end; i++) { -// int productId = (i % 8) * 100000 + i % 100000; +// int productId = random.nextInt(1000000); // int memberId = i; // String content = i + "content " + i; // int rating = i % 5 + 1; From e04f4e9aab88fa9649a81271a5ba33453914a25c Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Wed, 23 Oct 2024 01:17:25 +0900 Subject: [PATCH 12/24] =?UTF-8?q?rename:=20file=20=EC=A0=80=EC=9E=A5=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=ED=8C=A8=ED=82=A4=EC=A7=80=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/flab/nutridiary/commom/config/S3Config.java | 2 +- src/main/java/flab/nutridiary/{commom => }/file/FileStore.java | 2 +- .../java/flab/nutridiary/{commom => }/file/S3FileStore.java | 2 +- .../flab/nutridiary/review/service/ReviewResisterService.java | 2 +- src/test/java/flab/nutridiary/commom/config/S3Config.java | 2 +- src/test/java/flab/nutridiary/commom/file/FakeFileStore.java | 1 + 6 files changed, 6 insertions(+), 5 deletions(-) rename src/main/java/flab/nutridiary/{commom => }/file/FileStore.java (84%) rename src/main/java/flab/nutridiary/{commom => }/file/S3FileStore.java (98%) diff --git a/src/main/java/flab/nutridiary/commom/config/S3Config.java b/src/main/java/flab/nutridiary/commom/config/S3Config.java index 976b83f..a00644b 100644 --- a/src/main/java/flab/nutridiary/commom/config/S3Config.java +++ b/src/main/java/flab/nutridiary/commom/config/S3Config.java @@ -3,7 +3,7 @@ import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3Client; -import flab.nutridiary.commom.file.S3FileStore; +import flab.nutridiary.file.S3FileStore; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/flab/nutridiary/commom/file/FileStore.java b/src/main/java/flab/nutridiary/file/FileStore.java similarity index 84% rename from src/main/java/flab/nutridiary/commom/file/FileStore.java rename to src/main/java/flab/nutridiary/file/FileStore.java index a4f1925..9fb4969 100644 --- a/src/main/java/flab/nutridiary/commom/file/FileStore.java +++ b/src/main/java/flab/nutridiary/file/FileStore.java @@ -1,4 +1,4 @@ -package flab.nutridiary.commom.file; +package flab.nutridiary.file; import org.springframework.web.multipart.MultipartFile; diff --git a/src/main/java/flab/nutridiary/commom/file/S3FileStore.java b/src/main/java/flab/nutridiary/file/S3FileStore.java similarity index 98% rename from src/main/java/flab/nutridiary/commom/file/S3FileStore.java rename to src/main/java/flab/nutridiary/file/S3FileStore.java index 7626233..3744715 100644 --- a/src/main/java/flab/nutridiary/commom/file/S3FileStore.java +++ b/src/main/java/flab/nutridiary/file/S3FileStore.java @@ -1,4 +1,4 @@ -package flab.nutridiary.commom.file; +package flab.nutridiary.file; import com.amazonaws.services.s3.AmazonS3; diff --git a/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java b/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java index a054b48..264dc8b 100644 --- a/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java +++ b/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java @@ -1,7 +1,7 @@ package flab.nutridiary.review.service; import flab.nutridiary.commom.exception.BusinessException; -import flab.nutridiary.commom.file.FileStore; +import flab.nutridiary.file.FileStore; import flab.nutridiary.productDietTag.ProductDietTag; import flab.nutridiary.productDietTag.ProductDietTagRepository; import flab.nutridiary.productStore.ProductStore; diff --git a/src/test/java/flab/nutridiary/commom/config/S3Config.java b/src/test/java/flab/nutridiary/commom/config/S3Config.java index b5c1549..eae324a 100644 --- a/src/test/java/flab/nutridiary/commom/config/S3Config.java +++ b/src/test/java/flab/nutridiary/commom/config/S3Config.java @@ -1,6 +1,6 @@ package flab.nutridiary.commom.config; -import flab.nutridiary.commom.file.FileStore; +import flab.nutridiary.file.FileStore; import flab.nutridiary.commom.file.FakeFileStore; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/test/java/flab/nutridiary/commom/file/FakeFileStore.java b/src/test/java/flab/nutridiary/commom/file/FakeFileStore.java index d98470e..8b84638 100644 --- a/src/test/java/flab/nutridiary/commom/file/FakeFileStore.java +++ b/src/test/java/flab/nutridiary/commom/file/FakeFileStore.java @@ -1,6 +1,7 @@ package flab.nutridiary.commom.file; import flab.nutridiary.commom.exception.SystemException; +import flab.nutridiary.file.FileStore; import org.springframework.web.multipart.MultipartFile; import java.io.File; From d47292b8dc5c721e2c84091ec6d8de0303b53855 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Fri, 15 Nov 2024 02:03:31 +0900 Subject: [PATCH 13/24] =?UTF-8?q?refactor:=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=EC=84=B8=EC=8A=A4=20=EB=B3=80=EA=B2=BD.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 리뷰 작성시 태그의 카운트 증가 --- .../dto/response/ProductSearchResponse.java | 14 +++---- .../JdbcTemplateProductSearchRepository.java | 2 +- .../productDietTag/ProductDietTag.java | 16 +++++++- .../ProductDietTagRepository.java | 3 ++ .../dto/request/CreateReviewRequest.java | 6 ++- .../review/service/ReviewResisterService.java | 39 +++++++++++++++---- src/main/resources/db/schema.sql | 1 + .../dummy/InsertProductDietTagDummy.java | 35 +++++++++++------ .../nutridiary/dummy/InsertProductDummy.java | 26 ++++++------- .../nutridiary/dummy/InsertReviewDummy.java | 16 +++++++- .../service/ReviewResisterServiceTest.java | 6 ++- 11 files changed, 117 insertions(+), 47 deletions(-) diff --git a/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java b/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java index e937bdc..3daa559 100644 --- a/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java +++ b/src/main/java/flab/nutridiary/product/dto/response/ProductSearchResponse.java @@ -11,19 +11,19 @@ @EqualsAndHashCode @ToString public class ProductSearchResponse { - private final Long productId; - private final String productName; - private final String productCorp; - private final Integer reviewCount; - private final BigDecimal reviewAvgRating; - private final String top3_diet_tag_names; + private Long productId; + private String productName; + private String productCorp; + private Integer reviewCount; + private BigDecimal reviewAvgRating; + private String top3_diet_tag_names; public ProductSearchResponse(Long productId, String productName, String productCorp, Integer reviewCount, BigDecimal reviewAvgRating, String top3_diet_tag_names) { this.productId = productId; this.productName = productName; this.productCorp = productCorp; this.reviewCount = reviewCount; - this.reviewAvgRating = reviewAvgRating.setScale(1, RoundingMode.HALF_UP); + this.reviewAvgRating = reviewAvgRating == null ? BigDecimal.ZERO : reviewAvgRating.setScale(1, RoundingMode.HALF_UP); this.top3_diet_tag_names = top3_diet_tag_names; } } \ No newline at end of file diff --git a/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java b/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java index e4f669c..2a85640 100644 --- a/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java +++ b/src/main/java/flab/nutridiary/product/repository/query/JdbcTemplateProductSearchRepository.java @@ -30,7 +30,7 @@ public Page findFullTextSearch(String keyword, Pageable p "p.product_id, p.product_name, p.product_corp, " + "(SELECT COUNT(*) FROM review r WHERE r.product_id = p.product_id) AS review_count, " + "(SELECT AVG(r.rating) FROM review r WHERE r.product_id = p.product_id) AS review_avg_rating, " + - "(SELECT GROUP_CONCAT(diet_tag_name) FROM (SELECT diet_tag_name FROM product_diet_tag pdt where pdt.product_id = p.product_id GROUP BY diet_tag_name ORDER BY COUNT(diet_tag_name) DESC LIMIT 3) AS top3_diet_tag) AS top3_diet_tag_names " + + "(SELECT GROUP_CONCAT(diet_plan) FROM (SELECT dt.diet_plan FROM product_diet_tag pdt JOIN diet_tag dt ON pdt.diet_tag_id = dt.diet_tag_id where pdt.product_id = p.product_id ORDER BY pdt.tag_count DESC LIMIT 3) AS top3_diet_tag) AS top3_diet_tag_names " + "FROM product p " + "WHERE MATCH (p.product_name, p.product_corp) AGAINST (:keyword)" + "LIMIT :offset, :limit"; diff --git a/src/main/java/flab/nutridiary/productDietTag/ProductDietTag.java b/src/main/java/flab/nutridiary/productDietTag/ProductDietTag.java index 6863fe7..25e900d 100644 --- a/src/main/java/flab/nutridiary/productDietTag/ProductDietTag.java +++ b/src/main/java/flab/nutridiary/productDietTag/ProductDietTag.java @@ -11,8 +11,8 @@ import java.time.LocalDateTime; -@ToString @Getter +@ToString @NoArgsConstructor public class ProductDietTag { @Id @Column("product_diet_tag_id") @@ -22,6 +22,9 @@ public class ProductDietTag { private AggregateReference productId; + @Getter + private Long tagCount; + @CreatedDate private LocalDateTime createdAt; @@ -29,8 +32,17 @@ public class ProductDietTag { private LocalDateTime updatedAt; @Builder - public ProductDietTag(Long dietTagId, Long productId) { + public ProductDietTag(Long dietTagId, Long productId, Long tagCount) { this.dietTagId = AggregateReference.to(dietTagId); this.productId = AggregateReference.to(productId); + this.tagCount = tagCount; + } + + public void increaseTagCount() { + this.tagCount++; + } + + public Long getDietTagId() { + return dietTagId.getId(); } } diff --git a/src/main/java/flab/nutridiary/productDietTag/ProductDietTagRepository.java b/src/main/java/flab/nutridiary/productDietTag/ProductDietTagRepository.java index e197d24..ac0a5ce 100644 --- a/src/main/java/flab/nutridiary/productDietTag/ProductDietTagRepository.java +++ b/src/main/java/flab/nutridiary/productDietTag/ProductDietTagRepository.java @@ -2,5 +2,8 @@ import org.springframework.data.repository.CrudRepository; +import java.util.List; + public interface ProductDietTagRepository extends CrudRepository { + List findByProductId(Long productId); } diff --git a/src/main/java/flab/nutridiary/review/dto/request/CreateReviewRequest.java b/src/main/java/flab/nutridiary/review/dto/request/CreateReviewRequest.java index 341e09f..2f7d655 100644 --- a/src/main/java/flab/nutridiary/review/dto/request/CreateReviewRequest.java +++ b/src/main/java/flab/nutridiary/review/dto/request/CreateReviewRequest.java @@ -8,6 +8,8 @@ import lombok.ToString; import org.springframework.web.multipart.MultipartFile; +import java.util.List; + @ToString @Getter public class CreateReviewRequest { @@ -18,7 +20,7 @@ public class CreateReviewRequest { private String content; @NotNull(message = "식단 태그 ID를 입력해주세요.") - private Long dietTagId; + private List dietTagId; @NotNull(message = "매장 ID를 입력해주세요.") private Long storeId; @@ -31,7 +33,7 @@ public class CreateReviewRequest { private short rating; @Builder - public CreateReviewRequest(Long productId, String content, Long dietTagId, Long storeId, MultipartFile image, short rating) { + public CreateReviewRequest(Long productId, String content, List dietTagId, Long storeId, MultipartFile image, short rating) { this.productId = productId; this.content = content; this.dietTagId = dietTagId; diff --git a/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java b/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java index 264dc8b..458e6bb 100644 --- a/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java +++ b/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java @@ -14,7 +14,12 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; import static flab.nutridiary.commom.exception.StatusConst.DUPLICATED_PRODUCT_REVIEW; @@ -40,20 +45,40 @@ public CreateReviewResponse create(Long memberId, CreateReviewRequest createRevi return CreateReviewResponse.of(savedReview.getId()); } - private ProductStore saveProductStore(CreateReviewRequest request) { - return productStoreRepository.save(ProductStore.builder() + private void saveProductStore(CreateReviewRequest request) { + productStoreRepository.save(ProductStore.builder() .productId(request.getProductId()) .storeId(request.getStoreId()) .build()); } - private ProductDietTag saveProductDietTag(CreateReviewRequest request) { - return productDietTagRepository.save(ProductDietTag.builder() - .productId(request.getProductId()) - .dietTagId(request.getDietTagId()) - .build()); + private void saveProductDietTag(CreateReviewRequest request) { + List existingTags = productDietTagRepository.findByProductId(request.getProductId()); + List requestTagIds = request.getDietTagId(); + + Map existingTagMap = existingTags.stream() + .collect(Collectors.toMap(ProductDietTag::getDietTagId, Function.identity())); + + List tagsToSave = new ArrayList<>(); + + for (Long tagId : requestTagIds) { + if (existingTagMap.containsKey(tagId)) { + existingTagMap.get(tagId).increaseTagCount(); + } else { + // 새로운 태그는 리스트에 추가 + tagsToSave.add(ProductDietTag.builder() + .productId(request.getProductId()) + .dietTagId(tagId) + .build()); + } + } + + // 변경된 태그들을 저장 + tagsToSave.addAll(existingTags); // 수정된 기존 태그도 포함 + productDietTagRepository.saveAll(tagsToSave); } + private Review createReview(CreateReviewRequest request) { String imageUrl = Optional.ofNullable(request.getImage()) .map(fileStore::uploadReviewImage) diff --git a/src/main/resources/db/schema.sql b/src/main/resources/db/schema.sql index 3be01ba..a145e61 100644 --- a/src/main/resources/db/schema.sql +++ b/src/main/resources/db/schema.sql @@ -65,6 +65,7 @@ CREATE TABLE product_diet_tag ( product_diet_tag_id BIGINT PRIMARY KEY AUTO_INCREMENT, product_id BIGINT, diet_tag_id BIGINT, + tag_count BIGINT, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL ); diff --git a/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java b/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java index a1bcdb9..4459dc5 100644 --- a/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java +++ b/src/test/java/flab/nutridiary/dummy/InsertProductDietTagDummy.java @@ -1,5 +1,17 @@ -package flab.nutridiary.dummy; - +//package flab.nutridiary.dummy; +// +//import org.junit.jupiter.api.Test; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.boot.test.context.SpringBootTest; +//import org.springframework.jdbc.core.JdbcTemplate; +// +//import java.util.ArrayList; +//import java.util.List; +//import java.util.Random; +//import java.util.concurrent.ExecutorService; +//import java.util.concurrent.Executors; +//import java.util.concurrent.TimeUnit; +// //@SpringBootTest //public class InsertProductDietTagDummy { // @Autowired @@ -7,10 +19,10 @@ // // private final int batchSize = 5000; // private final int threadCount = 10; -// private final int totalDataCount = 20000000; +// private final int totalDataCount = 1000000; // private final Random random = new Random(); // -// private final String productDietTagSQL = "INSERT INTO product_diet_tag (product_id, diet_tag_id, diet_tag_name, created_at, updated_at) VALUES (?, ?, ?, ?, ?)"; +// private final String productDietTagSQL = "INSERT INTO product_diet_tag (product_id, diet_tag_id, tag_count, created_at, updated_at) VALUES (?, ?, ?, ?, ?)"; // private final String[] diet_tag_names = {"저칼로리", "저탄수화물", "무탄수화물", "저단백질", "고단백질", "무설탕", "저지방", "고지방", "저탄고지", "기토제닉"}; // // @Test @@ -33,13 +45,14 @@ // List batchArgs = new ArrayList<>(); // // for (int i = start; i <= end; i++) { -// int productId = random.nextInt(1000000); -// int dietTagId = i % 10 + 1; -// String dietTagName = diet_tag_names[dietTagId - 1]; -// String createdAt = "2024-09-01 00:00:00"; -// String updatedAt = "2024-09-01 00:00:00"; -// batchArgs.add(new Object[]{productId, dietTagId, dietTagName, createdAt, updatedAt}); -// +// int productId = i; +// for (int j = 1 ; j <= 10 ; j++){ +// int dietTagId = j; +// Long tagCount = random.nextLong(300); +// String createdAt = "2024-09-01 00:00:00"; +// String updatedAt = "2024-09-01 00:00:00"; +// batchArgs.add(new Object[]{productId, dietTagId, tagCount, createdAt, updatedAt}); +// } // if (batchArgs.size() % batchSize == 0) { // jdbcTemplate.batchUpdate(sql, batchArgs); // batchArgs.clear(); diff --git a/src/test/java/flab/nutridiary/dummy/InsertProductDummy.java b/src/test/java/flab/nutridiary/dummy/InsertProductDummy.java index 05ec984..3512768 100644 --- a/src/test/java/flab/nutridiary/dummy/InsertProductDummy.java +++ b/src/test/java/flab/nutridiary/dummy/InsertProductDummy.java @@ -1,16 +1,16 @@ -package flab.nutridiary.dummy; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.jdbc.core.JdbcTemplate; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - +//package flab.nutridiary.dummy; +// +//import org.junit.jupiter.api.Test; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.boot.test.context.SpringBootTest; +//import org.springframework.jdbc.core.JdbcTemplate; +// +//import java.util.ArrayList; +//import java.util.List; +//import java.util.concurrent.ExecutorService; +//import java.util.concurrent.Executors; +//import java.util.concurrent.TimeUnit; +// //@SpringBootTest //public class InsertProductDummy { // @Autowired diff --git a/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java b/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java index 0a6c7d1..91b861d 100644 --- a/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java +++ b/src/test/java/flab/nutridiary/dummy/InsertReviewDummy.java @@ -1,5 +1,17 @@ -package flab.nutridiary.dummy; - +//package flab.nutridiary.dummy; +// +//import org.junit.jupiter.api.Test; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.boot.test.context.SpringBootTest; +//import org.springframework.jdbc.core.JdbcTemplate; +// +//import java.util.ArrayList; +//import java.util.List; +//import java.util.Random; +//import java.util.concurrent.ExecutorService; +//import java.util.concurrent.Executors; +//import java.util.concurrent.TimeUnit; +// //@SpringBootTest //public class InsertReviewDummy { // @Autowired diff --git a/src/test/java/flab/nutridiary/review/service/ReviewResisterServiceTest.java b/src/test/java/flab/nutridiary/review/service/ReviewResisterServiceTest.java index bc90424..f7adb16 100644 --- a/src/test/java/flab/nutridiary/review/service/ReviewResisterServiceTest.java +++ b/src/test/java/flab/nutridiary/review/service/ReviewResisterServiceTest.java @@ -10,6 +10,8 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.transaction.annotation.Transactional; +import java.util.List; + import static org.junit.jupiter.api.Assertions.*; @ActiveProfiles("test") @@ -27,7 +29,7 @@ void create() throws Exception { CreateReviewRequest request = CreateReviewRequest.builder() .productId(1L) .content("맛있어요") - .dietTagId(1L) + .dietTagId(List.of(1L)) .storeId(1L) .image(null) .rating((short) 5) @@ -48,7 +50,7 @@ void ex() throws Exception { CreateReviewRequest request = CreateReviewRequest.builder() .productId(1L) .content("맛있어요") - .dietTagId(1L) + .dietTagId(List.of(1L)) .storeId(1L) .image(null) .rating((short) 5) From 22571d6651d85a541b6929bda97e10dc34b88ce1 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Sun, 1 Dec 2024 19:32:16 +0900 Subject: [PATCH 14/24] =?UTF-8?q?feat:=20=EB=8F=84=EC=BB=A4=20=EC=BB=A8?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EB=84=88=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 9d7a71f..fe32bd6 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -22,6 +22,15 @@ spring: username: ${MYSQL_USERNAME} password: ${MYSQL_PASSWORD} driver-class-name: com.mysql.cj.jdbc.Driver + hikari: + maximum-pool-size: 10 # 커넥션 풀의 최대 크기 설정 + max-lifetime: 55000 # 커넥션 최대 생존 시간 설정 (ms) 55초 + connection-timeout: 30000 # pool 에서 커넥션을 받기위해 대기하는 시간 (ms) + data-source-properties: + socketTimeout: 30 + + + sql: init: mode: always @@ -66,15 +75,15 @@ spring: on-profile: test datasource: - url: jdbc:h2:mem:nutridiary - username: sa - password: - driver-class-name: org.h2.Driver + url: jdbc:tc:mysql:8.0.36:///nutridiary?TC_DAEMON=true + + main: + allow-bean-definition-overriding: true + sql: init: mode: always schema-locations: classpath:db/schema.sql -# data-locations: optional:classpath:db/data.sql logging: level: @@ -89,14 +98,6 @@ spring: activate: on-profile: common - datasource: - hikari: - maximum-pool-size: 10 # 커넥션 풀의 최대 크기 설정 - max-lifetime: 55000 # 커넥션 최대 생존 시간 설정 (ms) 55초 - connection-timeout: 30000 # pool 에서 커넥션을 받기위해 대기하는 시간 (ms) - data-source-properties: - socketTimeout: 30 - cloud: aws: s3: From 05debe27475e5dea01cf099b5990f77d9f807303 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Mon, 2 Dec 2024 00:32:19 +0900 Subject: [PATCH 15/24] =?UTF-8?q?refactor:=20jacoco=EC=9D=84=20=ED=99=9C?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EC=97=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=BB=A4=EB=B2=84=EB=A6=AC=EC=A7=80?= =?UTF-8?q?=EB=A5=BC=20=EC=B8=A1=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/build.gradle b/build.gradle index 53dd65f..f4c26ef 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ plugins { id 'java' id 'org.springframework.boot' version '3.3.2' id 'io.spring.dependency-management' version '1.1.6' + id 'jacoco' } group = 'flab' @@ -47,4 +48,51 @@ dependencies { tasks.named('test') { useJUnitPlatform() + finalizedBy jacocoTestReport } + +jacocoTestReport { + dependsOn test + reports { + html.required = true + html.destination file("jacoco/report.html") + } +// finalizedBy 'jacocoTestCoverageVerification' +} + +// jacoco 커버리지 검증 설정 +//jacocoTestCoverageVerification { +// violationRules { +// rule { +// enabled = true // 커버리지 적용 여부 +// element = 'CLASS' // 커버리지 적용 단위 +// +// // 라인 커버리지 설정 +// // 적용 대상 전체 소스 코드들을 한줄 한줄 따졌을 때 테스트 코드가 작성되어 있는 줄의 빈도 +// // 테스트 코드가 작성되어 있는 비율이 90% 이상이어야 함 +// limit { +// counter = 'LINE' +// value = 'COVEREDRATIO' +// minimum = 0.80 +// } +// +// // 브랜치 커버리지 설정 +// // if-else 등을 활용하여 발생되는 분기들 중 테스트 코드가 작성되어 있는 빈도 +// // 테스트 코드가 작성되어 있는 비율이 90% 이상이어야 함 +// limit { +// counter = 'BRANCH' +// value = 'COVEREDRATIO' +// minimum = 0.80 +// } +// +// // 라인 최대 갯수 설정 +// // 빈 줄을 제외하고 하나의 자바 파일에서 작성될 수 있는 최대 라인 갯수 +// // 한 파일에 최대 500줄까지 작성되어야 함 +// limit { +// counter = 'LINE' +// value = 'TOTALCOUNT' +// maximum = 500 +// } +// } +// } +//} \ No newline at end of file From 78d8ff697b9dfd9d66af4e21c5bf5d01f237e24d Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Mon, 2 Dec 2024 00:45:16 +0900 Subject: [PATCH 16/24] =?UTF-8?q?chore:=20jacoco=20=ED=8F=B4=EB=8D=94=20gi?= =?UTF-8?q?tignore=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c2065bc..2ba23f5 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ out/ ### VS Code ### .vscode/ + +### jacoco ### +jacoco/ \ No newline at end of file From 890355d37fd8d55669b630393a09fb5c5bc8864e Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Thu, 5 Dec 2024 18:18:16 +0900 Subject: [PATCH 17/24] =?UTF-8?q?chore:=20Jdk=2017=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f4c26ef..8552cd4 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ version = '0.0.1-SNAPSHOT' java { toolchain { - languageVersion = JavaLanguageVersion.of(21) + languageVersion = JavaLanguageVersion.of(17) } } From 7d49debaf787403ba2a9768a20fa7f9586584530 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Thu, 5 Dec 2024 18:24:13 +0900 Subject: [PATCH 18/24] =?UTF-8?q?fix:=20Jdk=2017=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../diary/controller/DiaryControllerTest.java | 10 +++++----- .../product/controller/ProductControllerTest.java | 4 ++-- .../product/service/ProductRegisterServiceTest.java | 7 +++---- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/test/java/flab/nutridiary/diary/controller/DiaryControllerTest.java b/src/test/java/flab/nutridiary/diary/controller/DiaryControllerTest.java index 20fbb3c..406284d 100644 --- a/src/test/java/flab/nutridiary/diary/controller/DiaryControllerTest.java +++ b/src/test/java/flab/nutridiary/diary/controller/DiaryControllerTest.java @@ -83,7 +83,7 @@ void init() { @Test void createDiary() throws Exception { // given - DiaryRegisterRequest diaryRegisterRequest = new DiaryRegisterRequest(savedProductIds.getFirst(), "BREAKFAST", valueOf(1), "gram", LocalDate.of(2024, 8, 10)); + DiaryRegisterRequest diaryRegisterRequest = new DiaryRegisterRequest(savedProductIds.get(0), "BREAKFAST", valueOf(1), "gram", LocalDate.of(2024, 8, 10)); // when then mockMvc.perform( @@ -103,7 +103,7 @@ void addDiaryRecord() throws Exception { // given Diary diary = new Diary(LocalDate.of(2024, 8, 10), DiaryRecord.builder() - .productId(savedProductIds.getFirst()) + .productId(savedProductIds.get(0)) .mealType(MealType.BREAKFAST) .quantity(valueOf(1)) .clientChoiceServingUnitDescription("컵") @@ -111,7 +111,7 @@ void addDiaryRecord() throws Exception { .build()); Long diaryId = diaryRepository.save(diary).getId(); - AddDiaryRecordRequest addDiaryRecordRequest = new AddDiaryRecordRequest(savedProductIds.getFirst(), "BREAKFAST", BigDecimal.valueOf(10), "gram"); + AddDiaryRecordRequest addDiaryRecordRequest = new AddDiaryRecordRequest(savedProductIds.get(0), "BREAKFAST", BigDecimal.valueOf(10), "gram"); // when then mockMvc.perform( @@ -129,7 +129,7 @@ void addDiaryRecord() throws Exception { @Test void addDiaryRecordWithInvalidServingUnit() throws Exception { // given - DiaryRegisterRequest diaryRegisterRequest = new DiaryRegisterRequest(savedProductIds.getFirst(), "BREAKFAST", valueOf(1), "InvalidServingUnit", LocalDate.of(2024, 8, 10)); + DiaryRegisterRequest diaryRegisterRequest = new DiaryRegisterRequest(savedProductIds.get(0), "BREAKFAST", valueOf(1), "InvalidServingUnit", LocalDate.of(2024, 8, 10)); // when then mockMvc.perform( @@ -147,7 +147,7 @@ void addDiaryRecordWithInvalidServingUnit() throws Exception { @Test void mealType() throws Exception { // given - DiaryRegisterRequest diaryRegisterRequest = new DiaryRegisterRequest(savedProductIds.getFirst(), "WRONG", valueOf(1), "gram", LocalDate.of(2024, 8, 10)); + DiaryRegisterRequest diaryRegisterRequest = new DiaryRegisterRequest(savedProductIds.get(0), "WRONG", valueOf(1), "gram", LocalDate.of(2024, 8, 10)); // when then mockMvc.perform( diff --git a/src/test/java/flab/nutridiary/product/controller/ProductControllerTest.java b/src/test/java/flab/nutridiary/product/controller/ProductControllerTest.java index e25d544..a2a828a 100644 --- a/src/test/java/flab/nutridiary/product/controller/ProductControllerTest.java +++ b/src/test/java/flab/nutridiary/product/controller/ProductControllerTest.java @@ -42,7 +42,7 @@ void addProduct() throws Exception { NewProductRequest newProductRequest = NewProductRequest.builder() .productName("상품명") .corpName("업체명") - .productDefaultServingSize(BigDecimal.TWO) + .productDefaultServingSize(BigDecimal.valueOf(2)) .productDefaultServingUnit("컵") .productTotalWeightGram(BigDecimal.valueOf(90)) .calories(BigDecimal.valueOf(120)) @@ -104,7 +104,7 @@ void validation() throws Exception { NewProductRequest newProductRequest = NewProductRequest.builder() .productName("상품명") .corpName("업체명") - .productDefaultServingSize(BigDecimal.TWO) + .productDefaultServingSize(BigDecimal.valueOf(2)) .productTotalWeightGram(BigDecimal.valueOf(-1)) .calories(BigDecimal.valueOf(120)) .carbohydrate(BigDecimal.valueOf(15.5)) diff --git a/src/test/java/flab/nutridiary/product/service/ProductRegisterServiceTest.java b/src/test/java/flab/nutridiary/product/service/ProductRegisterServiceTest.java index ff4b638..7d7805e 100644 --- a/src/test/java/flab/nutridiary/product/service/ProductRegisterServiceTest.java +++ b/src/test/java/flab/nutridiary/product/service/ProductRegisterServiceTest.java @@ -17,7 +17,6 @@ import java.util.ArrayList; import java.util.List; -import static java.math.BigDecimal.TWO; import static java.math.BigDecimal.valueOf; import static org.assertj.core.api.Assertions.assertThat; @@ -40,7 +39,7 @@ void saveTest() throws Exception { NewProductRequest newProductRequest = NewProductRequest.builder() .productName("상품명") .corpName("업체명") - .productDefaultServingSize(TWO) + .productDefaultServingSize(BigDecimal.valueOf(2)) .productDefaultServingUnit("컵") .productTotalWeightGram(valueOf(90)) .calories(valueOf(120)) @@ -67,7 +66,7 @@ void validServingUnit() throws Exception { NewProductRequest newProductRequest = NewProductRequest.builder() .productName("상품명") .corpName("업체명") - .productDefaultServingSize(TWO) + .productDefaultServingSize(BigDecimal.valueOf(2)) .productDefaultServingUnit("컵") .productTotalWeightGram(valueOf(90)) .calories(valueOf(120)) @@ -84,6 +83,6 @@ void validServingUnit() throws Exception { assertThat(savedProduct.getNutritionFacts().getAllowedProductServingUnits()) .isEqualTo(new ArrayList<>( List.of(ServingUnit.asOneServingUnit("컵"), - ServingUnit.ofGram(TWO, BigDecimal.valueOf(90))))); + ServingUnit.ofGram(BigDecimal.valueOf(2), BigDecimal.valueOf(90))))); } } \ No newline at end of file From a1b0d63b83568c33f77bfa5823407bc190854ba8 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Thu, 12 Dec 2024 21:10:26 +0900 Subject: [PATCH 19/24] =?UTF-8?q?feat:=20=EB=AA=A8=EB=93=A0=20Store?= =?UTF-8?q?=EC=9D=84=20=EC=A1=B0=ED=9A=8C=ED=95=9C=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../store/controller/StoreController.java | 22 ++++++++++++++++ .../flab/nutridiary/store/dto/StoreName.java | 20 +++++++++++++++ .../store/dto/response/AllStore.java | 19 ++++++++++++++ .../store/repository/JdbcStoreRepository.java | 10 ++++++++ .../store/repository/StoreRepository.java | 9 +++++++ .../store/repository/StoreRepositoryImpl.java | 21 ++++++++++++++++ .../store/service/StoreReadService.java | 25 +++++++++++++++++++ 7 files changed, 126 insertions(+) create mode 100644 src/main/java/flab/nutridiary/store/controller/StoreController.java create mode 100644 src/main/java/flab/nutridiary/store/dto/StoreName.java create mode 100644 src/main/java/flab/nutridiary/store/dto/response/AllStore.java create mode 100644 src/main/java/flab/nutridiary/store/repository/JdbcStoreRepository.java create mode 100644 src/main/java/flab/nutridiary/store/repository/StoreRepository.java create mode 100644 src/main/java/flab/nutridiary/store/repository/StoreRepositoryImpl.java create mode 100644 src/main/java/flab/nutridiary/store/service/StoreReadService.java diff --git a/src/main/java/flab/nutridiary/store/controller/StoreController.java b/src/main/java/flab/nutridiary/store/controller/StoreController.java new file mode 100644 index 0000000..def53f8 --- /dev/null +++ b/src/main/java/flab/nutridiary/store/controller/StoreController.java @@ -0,0 +1,22 @@ +package flab.nutridiary.store.controller; + +import flab.nutridiary.commom.dto.ApiResponse; +import flab.nutridiary.store.dto.response.AllStore; +import flab.nutridiary.store.service.StoreReadService; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@Getter +@RequiredArgsConstructor +@RestController +public class StoreController { + + private final StoreReadService storeReadService; + + @GetMapping("/store") + public ApiResponse getAllStore() { + return ApiResponse.success(storeReadService.getAllStore()); + } +} diff --git a/src/main/java/flab/nutridiary/store/dto/StoreName.java b/src/main/java/flab/nutridiary/store/dto/StoreName.java new file mode 100644 index 0000000..78db221 --- /dev/null +++ b/src/main/java/flab/nutridiary/store/dto/StoreName.java @@ -0,0 +1,20 @@ +package flab.nutridiary.store.dto; + +import lombok.Getter; +import lombok.ToString; + +@ToString +@Getter +public class StoreName { + private final Long id; + private final String name; + + private StoreName(Long id, String name) { + this.id = id; + this.name = name; + } + + public static StoreName of(Long id, String name) { + return new StoreName(id, name); + } +} diff --git a/src/main/java/flab/nutridiary/store/dto/response/AllStore.java b/src/main/java/flab/nutridiary/store/dto/response/AllStore.java new file mode 100644 index 0000000..894adb1 --- /dev/null +++ b/src/main/java/flab/nutridiary/store/dto/response/AllStore.java @@ -0,0 +1,19 @@ +package flab.nutridiary.store.dto.response; + +import flab.nutridiary.store.dto.StoreName; +import lombok.Getter; + +import java.util.List; + +@Getter +public class AllStore { + private final List storeNames; + + private AllStore(List storeNames) { + this.storeNames = storeNames; + } + + public static AllStore of(List storeNames) { + return new AllStore(storeNames); + } +} diff --git a/src/main/java/flab/nutridiary/store/repository/JdbcStoreRepository.java b/src/main/java/flab/nutridiary/store/repository/JdbcStoreRepository.java new file mode 100644 index 0000000..8c42909 --- /dev/null +++ b/src/main/java/flab/nutridiary/store/repository/JdbcStoreRepository.java @@ -0,0 +1,10 @@ +package flab.nutridiary.store.repository; + +import flab.nutridiary.store.domain.Store; +import org.springframework.data.repository.CrudRepository; + +import java.util.List; + +public interface JdbcStoreRepository extends CrudRepository { + List findAll(); +} diff --git a/src/main/java/flab/nutridiary/store/repository/StoreRepository.java b/src/main/java/flab/nutridiary/store/repository/StoreRepository.java new file mode 100644 index 0000000..ddc69b3 --- /dev/null +++ b/src/main/java/flab/nutridiary/store/repository/StoreRepository.java @@ -0,0 +1,9 @@ +package flab.nutridiary.store.repository; + +import flab.nutridiary.store.domain.Store; + +import java.util.List; + +public interface StoreRepository { + List findAll(); +} diff --git a/src/main/java/flab/nutridiary/store/repository/StoreRepositoryImpl.java b/src/main/java/flab/nutridiary/store/repository/StoreRepositoryImpl.java new file mode 100644 index 0000000..259e412 --- /dev/null +++ b/src/main/java/flab/nutridiary/store/repository/StoreRepositoryImpl.java @@ -0,0 +1,21 @@ +package flab.nutridiary.store.repository; + +import flab.nutridiary.store.domain.Store; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Transactional +@Repository +@RequiredArgsConstructor +public class StoreRepositoryImpl implements StoreRepository { + + private final JdbcStoreRepository jdbcStoreRepository; + + @Override + public List findAll() { + return jdbcStoreRepository.findAll(); + } +} diff --git a/src/main/java/flab/nutridiary/store/service/StoreReadService.java b/src/main/java/flab/nutridiary/store/service/StoreReadService.java new file mode 100644 index 0000000..b72c0b6 --- /dev/null +++ b/src/main/java/flab/nutridiary/store/service/StoreReadService.java @@ -0,0 +1,25 @@ +package flab.nutridiary.store.service; + +import flab.nutridiary.store.dto.StoreName; +import flab.nutridiary.store.dto.response.AllStore; +import flab.nutridiary.store.repository.StoreRepository; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Getter +@RequiredArgsConstructor +@Transactional +@Service +public class StoreReadService { + private final StoreRepository storeRepository; + + public AllStore getAllStore() { + return AllStore.of(storeRepository.findAll() + .stream() + .map(store -> StoreName.of(store.getId(), store.getStoreName())) + .toList()); + } + +} From 182e9de2b8957df7a971abe82a1ec7d166219251 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Thu, 12 Dec 2024 21:31:53 +0900 Subject: [PATCH 20/24] =?UTF-8?q?fix:=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nutridiary/productStore/ProductStoreRepository.java | 6 ------ .../nutridiary/productStore/{ => domain}/ProductStore.java | 2 +- .../repository/JdbcProductStoreRepository.java | 7 +++++++ .../nutridiary/review/service/ReviewResisterService.java | 6 +++--- 4 files changed, 11 insertions(+), 10 deletions(-) delete mode 100644 src/main/java/flab/nutridiary/productStore/ProductStoreRepository.java rename src/main/java/flab/nutridiary/productStore/{ => domain}/ProductStore.java (95%) create mode 100644 src/main/java/flab/nutridiary/productStore/repository/JdbcProductStoreRepository.java diff --git a/src/main/java/flab/nutridiary/productStore/ProductStoreRepository.java b/src/main/java/flab/nutridiary/productStore/ProductStoreRepository.java deleted file mode 100644 index 47b4ec3..0000000 --- a/src/main/java/flab/nutridiary/productStore/ProductStoreRepository.java +++ /dev/null @@ -1,6 +0,0 @@ -package flab.nutridiary.productStore; - -import org.springframework.data.repository.CrudRepository; - -public interface ProductStoreRepository extends CrudRepository { -} diff --git a/src/main/java/flab/nutridiary/productStore/ProductStore.java b/src/main/java/flab/nutridiary/productStore/domain/ProductStore.java similarity index 95% rename from src/main/java/flab/nutridiary/productStore/ProductStore.java rename to src/main/java/flab/nutridiary/productStore/domain/ProductStore.java index 617a45e..171afda 100644 --- a/src/main/java/flab/nutridiary/productStore/ProductStore.java +++ b/src/main/java/flab/nutridiary/productStore/domain/ProductStore.java @@ -1,4 +1,4 @@ -package flab.nutridiary.productStore; +package flab.nutridiary.productStore.domain; import flab.nutridiary.product.domain.Product; import flab.nutridiary.store.domain.Store; diff --git a/src/main/java/flab/nutridiary/productStore/repository/JdbcProductStoreRepository.java b/src/main/java/flab/nutridiary/productStore/repository/JdbcProductStoreRepository.java new file mode 100644 index 0000000..23fe109 --- /dev/null +++ b/src/main/java/flab/nutridiary/productStore/repository/JdbcProductStoreRepository.java @@ -0,0 +1,7 @@ +package flab.nutridiary.productStore.repository; + +import flab.nutridiary.productStore.domain.ProductStore; +import org.springframework.data.repository.CrudRepository; + +public interface JdbcProductStoreRepository extends CrudRepository { +} diff --git a/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java b/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java index 458e6bb..0c434b2 100644 --- a/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java +++ b/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java @@ -4,8 +4,8 @@ import flab.nutridiary.file.FileStore; import flab.nutridiary.productDietTag.ProductDietTag; import flab.nutridiary.productDietTag.ProductDietTagRepository; -import flab.nutridiary.productStore.ProductStore; -import flab.nutridiary.productStore.ProductStoreRepository; +import flab.nutridiary.productStore.domain.ProductStore; +import flab.nutridiary.productStore.repository.JdbcProductStoreRepository; import flab.nutridiary.review.domain.Review; import flab.nutridiary.review.dto.request.CreateReviewRequest; import flab.nutridiary.review.dto.response.CreateReviewResponse; @@ -27,7 +27,7 @@ @RequiredArgsConstructor @Service public class ReviewResisterService { - private final ProductStoreRepository productStoreRepository; + private final JdbcProductStoreRepository productStoreRepository; private final ProductDietTagRepository productDietTagRepository; private final ReviewRepository reviewRepository; private final FileStore fileStore; From b0a074919c1f56842a07959991dd06501a5bfbc4 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Fri, 13 Dec 2024 01:25:32 +0900 Subject: [PATCH 21/24] =?UTF-8?q?feat:=20productIds=EB=A1=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=ED=95=98=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/repository/ProductCrudRepository.java | 6 ++++++ .../nutridiary/product/repository/ProductRepository.java | 2 ++ .../product/repository/ProductRepositoryImpl.java | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/src/main/java/flab/nutridiary/product/repository/ProductCrudRepository.java b/src/main/java/flab/nutridiary/product/repository/ProductCrudRepository.java index 8d4547a..d793bad 100644 --- a/src/main/java/flab/nutridiary/product/repository/ProductCrudRepository.java +++ b/src/main/java/flab/nutridiary/product/repository/ProductCrudRepository.java @@ -1,8 +1,14 @@ package flab.nutridiary.product.repository; import flab.nutridiary.product.domain.Product; +import org.springframework.data.jdbc.repository.query.Query; import org.springframework.data.repository.CrudRepository; +import java.util.List; + public interface ProductCrudRepository extends CrudRepository { int countByProductNormalizedName(String normalizedName); + + @Query("SELECT * FROM product WHERE product_id IN (:productIds)") + List findByIds(List productIds); } diff --git a/src/main/java/flab/nutridiary/product/repository/ProductRepository.java b/src/main/java/flab/nutridiary/product/repository/ProductRepository.java index 1ee08ab..50fd79a 100644 --- a/src/main/java/flab/nutridiary/product/repository/ProductRepository.java +++ b/src/main/java/flab/nutridiary/product/repository/ProductRepository.java @@ -2,9 +2,11 @@ import flab.nutridiary.product.domain.Product; +import java.util.List; import java.util.Optional; public interface ProductRepository { Product save(Product product); Optional findById(Long id); + List findByIds(List ids); } diff --git a/src/main/java/flab/nutridiary/product/repository/ProductRepositoryImpl.java b/src/main/java/flab/nutridiary/product/repository/ProductRepositoryImpl.java index ac75ea7..09a60a4 100644 --- a/src/main/java/flab/nutridiary/product/repository/ProductRepositoryImpl.java +++ b/src/main/java/flab/nutridiary/product/repository/ProductRepositoryImpl.java @@ -6,6 +6,7 @@ import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; +import java.util.List; import java.util.Optional; @RequiredArgsConstructor @@ -25,6 +26,11 @@ public Optional findById(Long id) { return productCrudRepository.findById(id); } + @Override + public List findByIds(List ids) { + return productCrudRepository.findByIds(ids); + } + @Override public Boolean isExistDuplicatedProductByNormalizedName(String normalizedName) { return productCrudRepository.countByProductNormalizedName(normalizedName) > 0; From 41fcbb23c18cd50e13e10b7f72534def3f6cea1e Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Fri, 13 Dec 2024 01:27:47 +0900 Subject: [PATCH 22/24] =?UTF-8?q?rename:=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=8A=A4=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/{ProductStore.java => StoreProduct.java} | 12 ++++++++++-- .../repository/JdbcProductStoreRepository.java | 7 ------- .../review/service/ReviewResisterService.java | 8 ++++---- ...StoreRepository.java => StoreCrudRepository.java} | 2 +- .../store/repository/StoreRepositoryImpl.java | 4 ++-- 5 files changed, 17 insertions(+), 16 deletions(-) rename src/main/java/flab/nutridiary/productStore/domain/{ProductStore.java => StoreProduct.java} (80%) delete mode 100644 src/main/java/flab/nutridiary/productStore/repository/JdbcProductStoreRepository.java rename src/main/java/flab/nutridiary/store/repository/{JdbcStoreRepository.java => StoreCrudRepository.java} (76%) diff --git a/src/main/java/flab/nutridiary/productStore/domain/ProductStore.java b/src/main/java/flab/nutridiary/productStore/domain/StoreProduct.java similarity index 80% rename from src/main/java/flab/nutridiary/productStore/domain/ProductStore.java rename to src/main/java/flab/nutridiary/productStore/domain/StoreProduct.java index 171afda..7a97022 100644 --- a/src/main/java/flab/nutridiary/productStore/domain/ProductStore.java +++ b/src/main/java/flab/nutridiary/productStore/domain/StoreProduct.java @@ -14,7 +14,7 @@ @ToString @Getter @NoArgsConstructor -public class ProductStore { +public class StoreProduct { @Id @Column("product_store_id") private Long id; @@ -29,8 +29,16 @@ public class ProductStore { private LocalDateTime updatedAt; @Builder - public ProductStore(Long storeId, Long productId) { + public StoreProduct(Long storeId, Long productId) { this.storeId = AggregateReference.to(storeId); this.productId = AggregateReference.to(productId); } + + public Long getStoreId() { + return storeId.getId(); + } + + public Long getProductId() { + return productId.getId(); + } } diff --git a/src/main/java/flab/nutridiary/productStore/repository/JdbcProductStoreRepository.java b/src/main/java/flab/nutridiary/productStore/repository/JdbcProductStoreRepository.java deleted file mode 100644 index 23fe109..0000000 --- a/src/main/java/flab/nutridiary/productStore/repository/JdbcProductStoreRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package flab.nutridiary.productStore.repository; - -import flab.nutridiary.productStore.domain.ProductStore; -import org.springframework.data.repository.CrudRepository; - -public interface JdbcProductStoreRepository extends CrudRepository { -} diff --git a/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java b/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java index 0c434b2..37870f7 100644 --- a/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java +++ b/src/main/java/flab/nutridiary/review/service/ReviewResisterService.java @@ -4,8 +4,8 @@ import flab.nutridiary.file.FileStore; import flab.nutridiary.productDietTag.ProductDietTag; import flab.nutridiary.productDietTag.ProductDietTagRepository; -import flab.nutridiary.productStore.domain.ProductStore; -import flab.nutridiary.productStore.repository.JdbcProductStoreRepository; +import flab.nutridiary.productStore.domain.StoreProduct; +import flab.nutridiary.productStore.repository.StoreProductCrudRepository; import flab.nutridiary.review.domain.Review; import flab.nutridiary.review.dto.request.CreateReviewRequest; import flab.nutridiary.review.dto.response.CreateReviewResponse; @@ -27,7 +27,7 @@ @RequiredArgsConstructor @Service public class ReviewResisterService { - private final JdbcProductStoreRepository productStoreRepository; + private final StoreProductCrudRepository productStoreRepository; private final ProductDietTagRepository productDietTagRepository; private final ReviewRepository reviewRepository; private final FileStore fileStore; @@ -46,7 +46,7 @@ public CreateReviewResponse create(Long memberId, CreateReviewRequest createRevi } private void saveProductStore(CreateReviewRequest request) { - productStoreRepository.save(ProductStore.builder() + productStoreRepository.save(StoreProduct.builder() .productId(request.getProductId()) .storeId(request.getStoreId()) .build()); diff --git a/src/main/java/flab/nutridiary/store/repository/JdbcStoreRepository.java b/src/main/java/flab/nutridiary/store/repository/StoreCrudRepository.java similarity index 76% rename from src/main/java/flab/nutridiary/store/repository/JdbcStoreRepository.java rename to src/main/java/flab/nutridiary/store/repository/StoreCrudRepository.java index 8c42909..8e3f714 100644 --- a/src/main/java/flab/nutridiary/store/repository/JdbcStoreRepository.java +++ b/src/main/java/flab/nutridiary/store/repository/StoreCrudRepository.java @@ -5,6 +5,6 @@ import java.util.List; -public interface JdbcStoreRepository extends CrudRepository { +public interface StoreCrudRepository extends CrudRepository { List findAll(); } diff --git a/src/main/java/flab/nutridiary/store/repository/StoreRepositoryImpl.java b/src/main/java/flab/nutridiary/store/repository/StoreRepositoryImpl.java index 259e412..06aaaf9 100644 --- a/src/main/java/flab/nutridiary/store/repository/StoreRepositoryImpl.java +++ b/src/main/java/flab/nutridiary/store/repository/StoreRepositoryImpl.java @@ -12,10 +12,10 @@ @RequiredArgsConstructor public class StoreRepositoryImpl implements StoreRepository { - private final JdbcStoreRepository jdbcStoreRepository; + private final StoreCrudRepository storeCrudRepository; @Override public List findAll() { - return jdbcStoreRepository.findAll(); + return storeCrudRepository.findAll(); } } From fe9eb420c8e56291fef1bf18a5bd7a2c8cc99f60 Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Fri, 13 Dec 2024 01:48:23 +0900 Subject: [PATCH 23/24] =?UTF-8?q?rename:=20ProductStore=EC=97=90=EC=84=9C?= =?UTF-8?q?=20StoreProduct=EB=A1=9C=20=EC=8A=A4=ED=82=A4=EB=A7=88=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/db/schema.sql | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/resources/db/schema.sql b/src/main/resources/db/schema.sql index a145e61..303750c 100644 --- a/src/main/resources/db/schema.sql +++ b/src/main/resources/db/schema.sql @@ -5,7 +5,7 @@ DROP TABLE IF EXISTS review; DROP TABLE IF EXISTS diet_tag; DROP TABLE IF EXISTS product_diet_tag; DROP TABLE IF EXISTS store; -DROP TABLE IF EXISTS product_store; +DROP TABLE IF EXISTS store_product; CREATE TABLE product ( product_id BIGINT PRIMARY KEY AUTO_INCREMENT, @@ -78,13 +78,13 @@ CREATE TABLE store ( updated_at DATETIME NOT NULL ); -CREATE TABLE product_store ( - product_store_id BIGINT PRIMARY KEY AUTO_INCREMENT, +CREATE TABLE store_product ( + store_product_id BIGINT PRIMARY KEY AUTO_INCREMENT, product_id BIGINT, store_id BIGINT, status VARCHAR(255), created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL ); -CREATE INDEX idx_product_id ON product_store (product_id); -CREATE INDEX idx_store_id ON product_store (store_id); +CREATE INDEX idx_product_id ON store_product (product_id); +CREATE INDEX idx_store_id ON store_product (store_id); From 92184d85e864d6a390a1e49fcf19a7ed6d67764d Mon Sep 17 00:00:00 2001 From: koo995 <107671886+koo995@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:25:31 +0900 Subject: [PATCH 24/24] =?UTF-8?q?feat:=20store=EC=97=90=20=ED=95=B4?= =?UTF-8?q?=EB=8B=B9=ED=95=98=EB=8A=94=20=EC=8B=9D=ED=92=88=EB=93=A4?= =?UTF-8?q?=EC=9D=84=20=EC=A1=B0=ED=9A=8C=ED=95=9C=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commom/exception/StatusConst.java | 3 +- .../productStore/domain/StoreProduct.java | 2 +- .../dto/StoreProductResponse.java | 39 +++++++++++++++++++ .../StoreProductCrudRepository.java | 10 +++++ .../repository/StoreProductRepository.java | 9 +++++ .../StoreProductRepositoryImpl.java | 22 +++++++++++ .../store/controller/StoreController.java | 7 ++++ .../store/service/StoreReadService.java | 22 +++++++++++ 8 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 src/main/java/flab/nutridiary/productStore/dto/StoreProductResponse.java create mode 100644 src/main/java/flab/nutridiary/productStore/repository/StoreProductCrudRepository.java create mode 100644 src/main/java/flab/nutridiary/productStore/repository/StoreProductRepository.java create mode 100644 src/main/java/flab/nutridiary/productStore/repository/StoreProductRepositoryImpl.java diff --git a/src/main/java/flab/nutridiary/commom/exception/StatusConst.java b/src/main/java/flab/nutridiary/commom/exception/StatusConst.java index 78e9314..c3f3463 100644 --- a/src/main/java/flab/nutridiary/commom/exception/StatusConst.java +++ b/src/main/java/flab/nutridiary/commom/exception/StatusConst.java @@ -15,7 +15,8 @@ public enum StatusConst { DUPLICATED_DIARY(4005, "이미 등록된 다이어리입니다."), VALIDATION_CHECK_FAIL(6001, "유효성 검사에 실패했습니다."), NOT_ALLOWED_SERVING_UNIT(6002, "허용되지 않은 서빙 단위입니다."), - DUPLICATED_PRODUCT_REVIEW(4006, "이미 등록된 리뷰입니다."); + DUPLICATED_PRODUCT_REVIEW(4006, "이미 등록된 리뷰입니다."), + STORE_PRODUCT_NOT_FOUND(4007, "해당 매장에 등록된 상품이 없습니다."),; private final int statusCode; private final String message; diff --git a/src/main/java/flab/nutridiary/productStore/domain/StoreProduct.java b/src/main/java/flab/nutridiary/productStore/domain/StoreProduct.java index 7a97022..99eed0f 100644 --- a/src/main/java/flab/nutridiary/productStore/domain/StoreProduct.java +++ b/src/main/java/flab/nutridiary/productStore/domain/StoreProduct.java @@ -15,7 +15,7 @@ @Getter @NoArgsConstructor public class StoreProduct { - @Id @Column("product_store_id") + @Id @Column("store_product_id") private Long id; private AggregateReference storeId; diff --git a/src/main/java/flab/nutridiary/productStore/dto/StoreProductResponse.java b/src/main/java/flab/nutridiary/productStore/dto/StoreProductResponse.java new file mode 100644 index 0000000..7242930 --- /dev/null +++ b/src/main/java/flab/nutridiary/productStore/dto/StoreProductResponse.java @@ -0,0 +1,39 @@ +package flab.nutridiary.productStore.dto; + +import flab.nutridiary.product.domain.Product; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.List; + +@Getter +@RequiredArgsConstructor +public class StoreProductResponse { + private final Long storeId; + private final List products; + + public static StoreProductResponse of(Long storeId, List products) { + List productInfos = products.stream() + .map(product -> ProductInfo.of(product.getId(), product.getProductName(), product.getProductCorp())) + .toList(); + + return new StoreProductResponse(storeId, productInfos); + } + + @Getter + public static class ProductInfo { + private final Long productId; + private final String productName; + private final String productCorp; + + private ProductInfo(Long productId, String productName, String productCorp) { + this.productId = productId; + this.productName = productName; + this.productCorp = productCorp; + } + + public static ProductInfo of(Long productId, String productName, String productCorp) { + return new ProductInfo(productId, productName, productCorp); + } + } +} diff --git a/src/main/java/flab/nutridiary/productStore/repository/StoreProductCrudRepository.java b/src/main/java/flab/nutridiary/productStore/repository/StoreProductCrudRepository.java new file mode 100644 index 0000000..c67529c --- /dev/null +++ b/src/main/java/flab/nutridiary/productStore/repository/StoreProductCrudRepository.java @@ -0,0 +1,10 @@ +package flab.nutridiary.productStore.repository; + +import flab.nutridiary.productStore.domain.StoreProduct; +import org.springframework.data.repository.CrudRepository; + +import java.util.List; + +public interface StoreProductCrudRepository extends CrudRepository { + List findByStoreId(Long storeId); +} diff --git a/src/main/java/flab/nutridiary/productStore/repository/StoreProductRepository.java b/src/main/java/flab/nutridiary/productStore/repository/StoreProductRepository.java new file mode 100644 index 0000000..9f2f91d --- /dev/null +++ b/src/main/java/flab/nutridiary/productStore/repository/StoreProductRepository.java @@ -0,0 +1,9 @@ +package flab.nutridiary.productStore.repository; + +import flab.nutridiary.productStore.domain.StoreProduct; + +import java.util.List; + +public interface StoreProductRepository { + List findByStoreId(Long storeId); +} diff --git a/src/main/java/flab/nutridiary/productStore/repository/StoreProductRepositoryImpl.java b/src/main/java/flab/nutridiary/productStore/repository/StoreProductRepositoryImpl.java new file mode 100644 index 0000000..5219e84 --- /dev/null +++ b/src/main/java/flab/nutridiary/productStore/repository/StoreProductRepositoryImpl.java @@ -0,0 +1,22 @@ +package flab.nutridiary.productStore.repository; + +import flab.nutridiary.productStore.domain.StoreProduct; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Getter +@RequiredArgsConstructor +@Transactional +@Repository +public class StoreProductRepositoryImpl implements StoreProductRepository { + private final StoreProductCrudRepository storeProductCrudRepository; + + @Override + public List findByStoreId(Long storeId) { + return storeProductCrudRepository.findByStoreId(storeId); + } +} diff --git a/src/main/java/flab/nutridiary/store/controller/StoreController.java b/src/main/java/flab/nutridiary/store/controller/StoreController.java index def53f8..4e72a8f 100644 --- a/src/main/java/flab/nutridiary/store/controller/StoreController.java +++ b/src/main/java/flab/nutridiary/store/controller/StoreController.java @@ -1,11 +1,13 @@ package flab.nutridiary.store.controller; import flab.nutridiary.commom.dto.ApiResponse; +import flab.nutridiary.productStore.dto.StoreProductResponse; import flab.nutridiary.store.dto.response.AllStore; import flab.nutridiary.store.service.StoreReadService; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @Getter @@ -19,4 +21,9 @@ public class StoreController { public ApiResponse getAllStore() { return ApiResponse.success(storeReadService.getAllStore()); } + + @GetMapping("/store/{store_id}") + public ApiResponse getStoreProduct(@PathVariable(name = "store_id") Long storeId) { + return ApiResponse.success(storeReadService.getStoreProduct(storeId)); + } } diff --git a/src/main/java/flab/nutridiary/store/service/StoreReadService.java b/src/main/java/flab/nutridiary/store/service/StoreReadService.java index b72c0b6..f0d0b2d 100644 --- a/src/main/java/flab/nutridiary/store/service/StoreReadService.java +++ b/src/main/java/flab/nutridiary/store/service/StoreReadService.java @@ -1,5 +1,10 @@ package flab.nutridiary.store.service; +import flab.nutridiary.commom.exception.BusinessException; +import flab.nutridiary.product.domain.Product; +import flab.nutridiary.product.repository.ProductRepository; +import flab.nutridiary.productStore.dto.StoreProductResponse; +import flab.nutridiary.productStore.repository.StoreProductRepository; import flab.nutridiary.store.dto.StoreName; import flab.nutridiary.store.dto.response.AllStore; import flab.nutridiary.store.repository.StoreRepository; @@ -8,12 +13,18 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; + +import static flab.nutridiary.commom.exception.StatusConst.STORE_PRODUCT_NOT_FOUND; + @Getter @RequiredArgsConstructor @Transactional @Service public class StoreReadService { private final StoreRepository storeRepository; + private final StoreProductRepository storeProductRepository; + private final ProductRepository productRepository; public AllStore getAllStore() { return AllStore.of(storeRepository.findAll() @@ -22,4 +33,15 @@ public AllStore getAllStore() { .toList()); } + public StoreProductResponse getStoreProduct(Long storeId) { + List productIds = storeProductRepository.findByStoreId(storeId) + .stream() + .map(storeProduct -> storeProduct.getProductId()) + .toList(); + if (productIds.isEmpty()) { + throw new BusinessException(STORE_PRODUCT_NOT_FOUND); + } + List products = productRepository.findByIds(productIds); + return StoreProductResponse.of(storeId, products); + } }