From 155b87ab4371ea192aec3a4a21e592aaa70c1b66 Mon Sep 17 00:00:00 2001 From: hoangtien2k3 Date: Fri, 21 Jun 2024 01:07:56 +0700 Subject: [PATCH] add: elasticsearch --- .env | 4 ++ docker-compose.yml | 14 ++++++ pom.xml | 4 ++ redis-data/dump.rdb | Bin 5770 -> 5770 bytes .../ShopappBackendApplication.java | 3 ++ .../controllers/ProductController.java | 12 +++++ .../shopappbackend/models/BaseEntity.java | 6 +++ .../shopappbackend/models/Product.java | 2 +- .../repositories/OrderRepository.java | 6 +-- .../repositories/ProductRepository.java | 10 ++-- .../repositories/ProductSearchRepository.java | 11 +++++ .../repositories/UserRepository.java | 7 +-- .../services/ProductRedisService.java | 6 +-- .../services/ProductService.java | 3 ++ .../services/impl/ProductServiceImpl.java | 17 +++++-- .../shopappbackend/utils/ConfixSql.java | 43 ++++++++++++++++++ src/main/resources/application.yml | 10 +++- 17 files changed, 134 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/hoangtien2k3/shopappbackend/repositories/ProductSearchRepository.java create mode 100644 src/main/java/com/hoangtien2k3/shopappbackend/utils/ConfixSql.java diff --git a/.env b/.env index 8486758..5104578 100644 --- a/.env +++ b/.env @@ -11,6 +11,10 @@ REDIS_TAG=7.2.3 REDIS_PORT=6379 REDIS_HOST=redis-container +# elasticsearch +ELASTICSEARCH_TAG=7.17.22 +ELASTICSEARCH_PORT=9200 + # neo4j NEO4J_TAG=4.4.34 NEO4J_HTTP_PORT=7474 diff --git a/docker-compose.yml b/docker-compose.yml index b008406..b28f76c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -32,6 +32,18 @@ services: networks: - shopapp-network + # elastic search + elasticsearch-container: + container_name: elasticsearch-container + image: elasticsearch:${ELASTICSEARCH_TAG} + ports: + - "${ELASTICSEARCH_PORT}:9200" + environment: + - "discovery.type=single-node" + - "xpack.security.enabled=false" + networks: + - shopapp-network + # neo4j neo4j-container: container_name: neo4j-container @@ -171,3 +183,5 @@ networks: # docker-compose up -d zookeeper-03 # docker-compose up -d kafka-broker-01 # docker-compose up -d shopapp-spring-container + + diff --git a/pom.xml b/pom.xml index 8a43008..dac551a 100644 --- a/pom.xml +++ b/pom.xml @@ -144,6 +144,10 @@ org.springframework.kafka spring-kafka + + + + diff --git a/redis-data/dump.rdb b/redis-data/dump.rdb index 42a8852ad95c340acb5fd2e7941d2502e4f52944..8c555ba96cd82540c15319444ac675cc4ccef5b7 100644 GIT binary patch delta 64 zcmV-G0Kfl=Es8CWFeK7bbY}Vpb#rB8Ep26O!YHZ@0Qv}FZ)PoGVRL1`0R8~`0|2po Wu@sS2DYGsWQ~?OW# deleteProductById(@PathVariable("id") Long id) { } } + // Endpoint to search products by keyword +// @GetMapping("/search") +// public Page searchProducts( +// @RequestParam String keyword, +// @RequestParam(defaultValue = "0") int page, +// @RequestParam(defaultValue = "10") int size +// ) { +// PageRequest pageRequest = PageRequest.of(page, size, Sort.by(Sort.Direction.ASC, "name")); +// return productService.searchProducts(keyword, pageRequest); +// } + // fack dữ liệu @PreAuthorize("hasRole('ROLE_ADMIN')") @PostMapping("/generate-faceker-products") diff --git a/src/main/java/com/hoangtien2k3/shopappbackend/models/BaseEntity.java b/src/main/java/com/hoangtien2k3/shopappbackend/models/BaseEntity.java index 739e9ac..f8a853a 100644 --- a/src/main/java/com/hoangtien2k3/shopappbackend/models/BaseEntity.java +++ b/src/main/java/com/hoangtien2k3/shopappbackend/models/BaseEntity.java @@ -11,6 +11,12 @@ @NoArgsConstructor @Getter @Setter +/** + * @MappedSuperclass + * Chia sẻ thuộc tính: kế thừa các thuộc tính, phương thức, và ánh xạ từ lớp siêu lớp mà không cần định nghĩa lại. + * Không tạo bảng riêng: Lớp được chú thích với @MappedSuperclass sẽ không tạo ra một bảng trong cơ sở dữ liệu. + * Thay vào đó, các thuộc tính của nó sẽ được ánh xạ vào các bảng của các lớp con. + * */ @MappedSuperclass public class BaseEntity { @JsonProperty("created_at") diff --git a/src/main/java/com/hoangtien2k3/shopappbackend/models/Product.java b/src/main/java/com/hoangtien2k3/shopappbackend/models/Product.java index dfbd3cc..76c0555 100644 --- a/src/main/java/com/hoangtien2k3/shopappbackend/models/Product.java +++ b/src/main/java/com/hoangtien2k3/shopappbackend/models/Product.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.annotation.JsonManagedReference; import jakarta.persistence.*; import lombok.*; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.util.ArrayList; import java.util.List; @@ -14,6 +13,7 @@ @Setter @Builder @Entity +//@Document(indexName = "products") @Table(name = "products") @EntityListeners(ProductListener.class) // Envent-driven approach SPRING DATA JPA public class Product extends BaseEntity { diff --git a/src/main/java/com/hoangtien2k3/shopappbackend/repositories/OrderRepository.java b/src/main/java/com/hoangtien2k3/shopappbackend/repositories/OrderRepository.java index 9d91cf5..b25770b 100644 --- a/src/main/java/com/hoangtien2k3/shopappbackend/repositories/OrderRepository.java +++ b/src/main/java/com/hoangtien2k3/shopappbackend/repositories/OrderRepository.java @@ -1,6 +1,7 @@ package com.hoangtien2k3.shopappbackend.repositories; import com.hoangtien2k3.shopappbackend.models.Order; +import com.hoangtien2k3.shopappbackend.utils.ConfixSql; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -13,9 +14,6 @@ public interface OrderRepository extends JpaRepository { List findByUserId(Long userId); // lẩy ra tất cả các order - @Query("SELECT o FROM Order o WHERE " + - "(:keyword IS NULL OR :keyword = '' OR o.fullName LIKE %:keyword% OR o.address LIKE %:keyword% " + - "OR o.note LIKE %:keyword%)" - ) + @Query(ConfixSql.Order.GET_ALL_ORDER) Page findByKeyword(String keyword, Pageable pageable); } diff --git a/src/main/java/com/hoangtien2k3/shopappbackend/repositories/ProductRepository.java b/src/main/java/com/hoangtien2k3/shopappbackend/repositories/ProductRepository.java index f250da4..9ffa4d6 100644 --- a/src/main/java/com/hoangtien2k3/shopappbackend/repositories/ProductRepository.java +++ b/src/main/java/com/hoangtien2k3/shopappbackend/repositories/ProductRepository.java @@ -1,6 +1,7 @@ package com.hoangtien2k3.shopappbackend.repositories; import com.hoangtien2k3.shopappbackend.models.Product; +import com.hoangtien2k3.shopappbackend.utils.ConfixSql; import org.springframework.data.domain.*; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -14,18 +15,15 @@ public interface ProductRepository extends JpaRepository { Page findAll(Pageable pageable); - @Query("SELECT p FROM Product p WHERE " + - "(:categoryId IS NULL OR :categoryId = 0 OR p.category.id = :categoryId) " + - "AND (:keyword IS NULL OR :keyword = '' OR LOWER(p.name) LIKE LOWER(CONCAT('%', :keyword, '%')) " + - "OR LOWER(p.description) LIKE LOWER(CONCAT('%', :keyword, '%')))") + @Query(ConfixSql.Product.SEARCH_PRODUCT_BY_KEYWORD) Page searchProducts(@Param("keyword") String keyword, @Param("categoryId") Long categoryId, Pageable pageable); - @Query("SELECT p FROM Product p LEFT JOIN FETCH p.productImages where p.id = :productId") + @Query(ConfixSql.Product.GET_DETAIL_PRODUCT) Optional getDetailProducts(@Param("productId") Long productId); - @Query("SELECT p FROM Product p where p.id IN :productIds") + @Query(ConfixSql.Product.FIND_PRODUCT_BY_IDS) List findProductByIds(@Param("productIds") List productIds); } diff --git a/src/main/java/com/hoangtien2k3/shopappbackend/repositories/ProductSearchRepository.java b/src/main/java/com/hoangtien2k3/shopappbackend/repositories/ProductSearchRepository.java new file mode 100644 index 0000000..fb57696 --- /dev/null +++ b/src/main/java/com/hoangtien2k3/shopappbackend/repositories/ProductSearchRepository.java @@ -0,0 +1,11 @@ +//package com.hoangtien2k3.shopappbackend.repositories; +// +//import com.hoangtien2k3.shopappbackend.models.Product; +//import org.springframework.context.annotation.Primary; +//import org.springframework.data.domain.Page; +//import org.springframework.data.domain.Pageable; +//import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; +// +//public interface ProductSearchRepository extends ElasticsearchRepository { +// Page findByNameContainingOrDescriptionContaining(String name, String description, Pageable pageable); +//} diff --git a/src/main/java/com/hoangtien2k3/shopappbackend/repositories/UserRepository.java b/src/main/java/com/hoangtien2k3/shopappbackend/repositories/UserRepository.java index e14fa60..3c5dfa4 100644 --- a/src/main/java/com/hoangtien2k3/shopappbackend/repositories/UserRepository.java +++ b/src/main/java/com/hoangtien2k3/shopappbackend/repositories/UserRepository.java @@ -1,6 +1,7 @@ package com.hoangtien2k3.shopappbackend.repositories; import com.hoangtien2k3.shopappbackend.models.User; +import com.hoangtien2k3.shopappbackend.utils.ConfixSql; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -15,10 +16,6 @@ public interface UserRepository extends JpaRepository { Optional findByPhoneNumber(String phoneNumber); // lấy ra tất cả user (ngoại trừ admin) với truyền admin - @Query("SELECT o FROM User o WHERE o.active = true AND (:keyword IS NULL OR :keyword = '' " + - "OR o.fullName LIKE %:keyword% " + - "OR o.address LIKE %:keyword% " + - "OR o.phoneNumber LIKE %:keyword%) " + - "AND LOWER(o.role.name) = 'user'") + @Query(ConfixSql.User.GET_ALL_USER) Page fillAll(@Param("keyword") String keyword, Pageable pageable); } diff --git a/src/main/java/com/hoangtien2k3/shopappbackend/services/ProductRedisService.java b/src/main/java/com/hoangtien2k3/shopappbackend/services/ProductRedisService.java index f7a2b60..06b4386 100644 --- a/src/main/java/com/hoangtien2k3/shopappbackend/services/ProductRedisService.java +++ b/src/main/java/com/hoangtien2k3/shopappbackend/services/ProductRedisService.java @@ -14,14 +14,12 @@ List getAllProducts(String keyword, Long categoryId, PageRequest pageRequest, String sortField, - String sortDirection - ) throws JsonProcessingException; + String sortDirection) throws JsonProcessingException; void saveAllProducts(List productResponses, String keyword, Long categoryId, PageRequest pageRequest, String sortField, - String sortDirection - ) throws JsonProcessingException; + String sortDirection) throws JsonProcessingException; } diff --git a/src/main/java/com/hoangtien2k3/shopappbackend/services/ProductService.java b/src/main/java/com/hoangtien2k3/shopappbackend/services/ProductService.java index f95b63b..d80caaa 100644 --- a/src/main/java/com/hoangtien2k3/shopappbackend/services/ProductService.java +++ b/src/main/java/com/hoangtien2k3/shopappbackend/services/ProductService.java @@ -37,4 +37,7 @@ ProductImage createProductImage(Long productId, Product getDetailProducts(long productId) throws Exception; List findProductsByIds(List productIds); + + // Elasticsearch +// Page searchProducts(String keyword, PageRequest pageRequest); } diff --git a/src/main/java/com/hoangtien2k3/shopappbackend/services/impl/ProductServiceImpl.java b/src/main/java/com/hoangtien2k3/shopappbackend/services/impl/ProductServiceImpl.java index c18e215..273ba46 100644 --- a/src/main/java/com/hoangtien2k3/shopappbackend/services/impl/ProductServiceImpl.java +++ b/src/main/java/com/hoangtien2k3/shopappbackend/services/impl/ProductServiceImpl.java @@ -12,9 +12,9 @@ import com.hoangtien2k3.shopappbackend.repositories.CategoryRepository; import com.hoangtien2k3.shopappbackend.repositories.ProductImageRepository; import com.hoangtien2k3.shopappbackend.repositories.ProductRepository; +//import com.hoangtien2k3.shopappbackend.repositories.ProductSearchRepository; import com.hoangtien2k3.shopappbackend.responses.product.ProductResponse; import com.hoangtien2k3.shopappbackend.services.ProductService; -import com.hoangtien2k3.shopappbackend.utils.LocalizationUtils; import com.hoangtien2k3.shopappbackend.utils.MessageKeys; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; @@ -29,13 +29,13 @@ @Service @RequiredArgsConstructor -public class ProductServiceImpl extends TranslateMessages - implements ProductService { +public class ProductServiceImpl extends TranslateMessages implements ProductService { private final ProductRepository productRepository; private final CategoryRepository categoryRepository; private final ProductImageRepository productImageRepository; private final ProductMapper productMapper; +// private final ProductSearchRepository productSearchRepository; @Override @Transactional @@ -151,4 +151,15 @@ public List findProductsByIds(List productIds) { return productRepository.findProductByIds(productIds); } +// @Override +// public Page searchProducts(String keyword, PageRequest pageRequest) { +// Pageable pageable = PageRequest.of( +// pageRequest.getPageNumber(), +// pageRequest.getPageSize(), +// Sort.by(Sort.Direction.ASC, "name") +// ); +// Page productPage = productSearchRepository.findByNameContainingOrDescriptionContaining(keyword, keyword, pageable); +// return productPage.map(ProductResponse::fromProduct); +// } + } diff --git a/src/main/java/com/hoangtien2k3/shopappbackend/utils/ConfixSql.java b/src/main/java/com/hoangtien2k3/shopappbackend/utils/ConfixSql.java new file mode 100644 index 0000000..0d25da1 --- /dev/null +++ b/src/main/java/com/hoangtien2k3/shopappbackend/utils/ConfixSql.java @@ -0,0 +1,43 @@ +package com.hoangtien2k3.shopappbackend.utils; + +public class ConfixSql { + + public interface Product { + // Tìm kiếm sản phẩm theo từ khóa và id danh mục + String SEARCH_PRODUCT_BY_KEYWORD = "SELECT p FROM Product p WHERE " + + "(:categoryId IS NULL OR :categoryId = 0 OR p.category.id = :categoryId) " + + "AND (:keyword IS NULL OR :keyword = '' OR LOWER(p.name) LIKE LOWER(CONCAT('%', :keyword, '%')) " + + "OR LOWER(p.description) LIKE LOWER(CONCAT('%', :keyword, '%')))"; + + // lấy ra chi tiết sản phẩm theo id + String GET_DETAIL_PRODUCT = "SELECT p FROM Product p LEFT JOIN FETCH p.productImages where p.id = :productId"; + + // tìm kiếm sản phẩm theo danh sách id + String FIND_PRODUCT_BY_IDS = "SELECT p FROM Product p where p.id IN :productIds"; + } + + public interface Category { + // lấy ra tất cả danh mục sản phẩm + String GET_ALL_CATEGORY = "SELECT c FROM Category c WHERE c.active = true"; + + // lấy ra danh mục sản phẩm theo id + String GET_CATEGORY_BY_ID = "SELECT c FROM Category c WHERE c.id = :categoryId"; + } + + public interface User { + // lấy ra tất cả user (ngoại trừ admin) với truyền admin + String GET_ALL_USER = "SELECT o FROM User o WHERE o.active = true AND (:keyword IS NULL OR :keyword = '' " + + "OR o.fullName LIKE %:keyword% " + + "OR o.address LIKE %:keyword% " + + "OR o.phoneNumber LIKE %:keyword%) " + + "AND LOWER(o.role.name) = 'user'"; + } + + public interface Order { + // lẩy ra tất cả các order + String GET_ALL_ORDER = "SELECT o FROM Order o WHERE " + + "(:keyword IS NULL OR :keyword = '' OR o.fullName LIKE %:keyword% OR o.address LIKE %:keyword% " + + "OR o.note LIKE %:keyword%)"; + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 360f4a4..639ea5e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -39,12 +39,20 @@ spring: baseline-on-migrate: true # phiên bản baseline = 1, không thực hiện bất kỳ thay đổi nào trong DB baseline-version: 0 # nó sẽ chạy V1__alter_some_tables.sql -> nghĩa là nó sẽ chạy cái version lớn hơn cái version hiện tại của chúng ta - #redis memory + data: + #redis memory redis: host: ${REDIS_HOST:localhost} port: ${REDIS_PORT:6379} + # elastic search +# elasticsearch: +# rest: +# uris: http://localhost:9200 +# repositories: +# enabled: true + # kafka kafka: bootstrap-servers: localhost:9092