迁移搜索服务
This commit is contained in:
parent
72ed490334
commit
128b9dc21a
@ -208,6 +208,7 @@
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo</artifactId>
|
||||
<version>${dubbo.version}</version>
|
||||
<!-- <version>2.7.8</version>-->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
@ -247,6 +248,13 @@
|
||||
<version>${xxl-job.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-client -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.alibaba.nacos</groupId>-->
|
||||
<!-- <artifactId>nacos-client</artifactId>-->
|
||||
<!-- <version>1.3.1</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- Transaction 相关 -->
|
||||
<dependency>
|
||||
<groupId>io.seata</groupId>
|
||||
|
@ -71,8 +71,21 @@
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
<!-- <exclusions>-->
|
||||
<!-- <exclusion>-->
|
||||
<!-- <artifactId>nacos-client</artifactId>-->
|
||||
<!-- <groupId>com.alibaba.nacos</groupId>-->
|
||||
<!-- </exclusion>-->
|
||||
<!-- </exclusions>-->
|
||||
</dependency>
|
||||
|
||||
<!-- TODO 芋艿 解决 1.3.1 beta 的问题 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.alibaba.nacos</groupId>-->
|
||||
<!-- <artifactId>nacos-client</artifactId>-->
|
||||
<!-- <version>1.3.1</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
|
@ -11,4 +11,5 @@ spring:
|
||||
dubbo:
|
||||
# Dubbo 注册中心
|
||||
registry:
|
||||
address: spring-cloud://400-infra.server.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址
|
||||
# address: spring-cloud://400-infra.server.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址
|
||||
address: nacos://400-infra.server.iocoder.cn:8848?namespace=dev # 指定 Dubbo 服务注册中心的地址
|
||||
|
@ -11,6 +11,5 @@ spring:
|
||||
dubbo:
|
||||
# Dubbo 注册中心
|
||||
registry:
|
||||
# address: spring-cloud://400-infra.server.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址
|
||||
# address: spring-cloud://400-infra.server.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址
|
||||
address: nacos://400-infra.server.iocoder.cn:8848?namespace=dev # 指定 Dubbo 服务注册中心的地址
|
||||
|
||||
|
@ -56,10 +56,10 @@ public interface ProductSpuRpc {
|
||||
/**
|
||||
* 顺序获得商品 SPU 编号数组
|
||||
*
|
||||
* @param limit 数量
|
||||
* @param lastSpuId 最后一个商品 SPU 编号
|
||||
* @param limit 数量
|
||||
* @return 商品 SPU 编号数组
|
||||
*/
|
||||
CommonResult<List<Integer>> listProductSpuIds(Integer limit, Integer lastSpuId);
|
||||
CommonResult<List<Integer>> listProductSpuIds(Integer lastSpuId, Integer limit);
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface ProductSpuMapper extends BaseMapper<ProductSpuDO> {
|
||||
|
||||
@ -25,4 +27,9 @@ public interface ProductSpuMapper extends BaseMapper<ProductSpuDO> {
|
||||
return selectPage(new Page<>(pageBO.getPageNo(), pageBO.getPageSize()), query);
|
||||
}
|
||||
|
||||
default List<ProductSpuDO> selectListByIdGt(Integer id, Integer limit) {
|
||||
return selectList(new QueryWrapperX<ProductSpuDO>().gtIfPresent("id", id)
|
||||
.orderByAsc("id").last("LIMIT " + limit));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -165,12 +165,12 @@ public class ProductSpuManager {
|
||||
/**
|
||||
* 顺序获得商品 SPU 编号数组
|
||||
*
|
||||
* @param limit 数量
|
||||
* @param lastSpuId 最后一个商品 SPU 编号
|
||||
* @param limit 数量
|
||||
* @return 商品 SPU 编号数组
|
||||
*/
|
||||
public List<Integer> listProductSpuIds(Integer limit, Integer lastSpuId) {
|
||||
return productAttrService.listProductSpuIds(limit, lastSpuId);
|
||||
public List<Integer> listProductSpuIds(Integer lastSpuId, Integer limit) {
|
||||
return productSpuService.listProductSpuIds(lastSpuId, limit);
|
||||
}
|
||||
|
||||
private List<ProductAttrKeyValueBO> checkProductAttr(List<ProductSkuCreateOrUpdateBO> skuBOs) {
|
||||
|
@ -50,8 +50,8 @@ public class ProductSpuRpcImpl implements ProductSpuRpc {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<Integer>> listProductSpuIds(Integer limit, Integer lastSpuId) {
|
||||
return success(productSpuManager.listProductSpuIds(limit, lastSpuId));
|
||||
public CommonResult<List<Integer>> listProductSpuIds(Integer lastSpuId, Integer limit) {
|
||||
return success(productSpuManager.listProductSpuIds(lastSpuId, limit));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -208,18 +208,4 @@ public class ProductAttrService {
|
||||
return ProductAttrConvert.INSTANCE.convertList03(productAttrValueDOs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 顺序获得商品 SPU 编号数组
|
||||
*
|
||||
* 一般情况下,该接口我们用于提供顺序的 SPU 编号数组,以便调用方进一步根据自己需要获取商品信息
|
||||
* 例如说,搜索服务会不断获取商品编号,重建该商品编号的索引
|
||||
*
|
||||
* @param limit 数量
|
||||
* @param lastSpuId 最后一个商品 SPU 编号
|
||||
* @return 商品 SPU 编号数组
|
||||
*/
|
||||
public List<Integer> listProductSpuIds(Integer limit, Integer lastSpuId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.iocoder.mall.productservice.service.spu;
|
||||
|
||||
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.util.CollectionUtils;
|
||||
import cn.iocoder.common.framework.vo.PageResult;
|
||||
import cn.iocoder.mall.productservice.convert.spu.ProductSpuConvert;
|
||||
import cn.iocoder.mall.productservice.dal.mysql.dataobject.spu.ProductSpuDO;
|
||||
@ -91,4 +92,18 @@ public class ProductSpuService {
|
||||
return ProductSpuConvert.INSTANCE.convertPage(productSpuDOPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 顺序获得商品 SPU 编号数组
|
||||
*
|
||||
* 一般情况下,该接口我们用于提供顺序的 SPU 编号数组,以便调用方进一步根据自己需要获取商品信息
|
||||
* 例如说,搜索服务会不断获取商品编号,重建该商品编号的索引
|
||||
*
|
||||
* @param lastSpuId 最后一个商品 SPU 编号
|
||||
* @param limit 数量
|
||||
* @return 商品 SPU 编号数组
|
||||
*/
|
||||
public List<Integer> listProductSpuIds(Integer lastSpuId, Integer limit) {
|
||||
return CollectionUtils.convertList(productSpuMapper.selectListByIdGt(lastSpuId, limit), ProductSpuDO::getId);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
package cn.iocoder.mall.product.dao;
|
||||
|
||||
import cn.iocoder.mall.product.dataobject.ProductSpuDO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface ProductSpuMapper {
|
||||
|
||||
/**
|
||||
* 获得大于 id 的商品编号数组
|
||||
*
|
||||
* @param id 商品编号
|
||||
* @param limit 数量
|
||||
* @return 商品编号数组
|
||||
*/
|
||||
List<Integer> selectIdListByIdGt(@Param("id") Integer id,
|
||||
@Param("limit") Integer limit);
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.iocoder.mall.product.dao.ProductSpuMapper">
|
||||
|
||||
<sql id="FIELDS">
|
||||
id, name, sell_point, description, cid,
|
||||
pic_urls, visible, sort, price, quantity,
|
||||
create_time
|
||||
</sql>
|
||||
|
||||
<select id="selectIdListByIdGt" parameterType="Integer" resultType="Integer">
|
||||
SELECT
|
||||
<include refid="FIELDS" />
|
||||
FROM product_spu
|
||||
<where>
|
||||
<if test="id != null">
|
||||
id > #{id}
|
||||
</if>
|
||||
AND deleted = 0
|
||||
</where>
|
||||
ORDER BY id ASC
|
||||
LIMIT #{limit}
|
||||
</select>
|
||||
|
||||
</mapper>
|
@ -1 +1,4 @@
|
||||
/**
|
||||
* 占位,避免包折叠
|
||||
*/
|
||||
package cn.iocoder.mall.searchservice.enums;
|
||||
|
@ -0,0 +1,19 @@
|
||||
package cn.iocoder.mall.searchservice.enums.product;
|
||||
|
||||
/**
|
||||
* 搜索商品条件的字段枚举
|
||||
*/
|
||||
public enum SearchProductConditionFieldEnum {
|
||||
|
||||
CATEGORY("category");
|
||||
|
||||
/**
|
||||
* 字段
|
||||
*/
|
||||
private final String field;
|
||||
|
||||
SearchProductConditionFieldEnum(String field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
}
|
@ -1 +1,4 @@
|
||||
/**
|
||||
* 占位,避免包折叠
|
||||
*/
|
||||
package cn.iocoder.mall.searchservice.rpc;
|
||||
|
@ -57,6 +57,13 @@
|
||||
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
@ -11,6 +11,8 @@ import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SearchProductConvert {
|
||||
|
||||
@ -30,8 +32,11 @@ public interface SearchProductConvert {
|
||||
|
||||
ESProductDO convert(SearchProductSaveBO bean);
|
||||
|
||||
@Mapping(source = "content", target = "list")
|
||||
@Mapping(source = "getTotalElements", target = "total")
|
||||
PageResult<SearchProductBO> convert(Page<ESProductDO> searchPage);
|
||||
List<SearchProductBO> convertList(List<ESProductDO> list);
|
||||
|
||||
default PageResult<SearchProductBO> convertPage(Page<ESProductDO> searchPage) {
|
||||
return new PageResult<SearchProductBO>().setList(convertList(searchPage.getContent()))
|
||||
.setTotal(searchPage.getTotalElements());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ import java.util.List;
|
||||
@Slf4j
|
||||
public class SearchProductManager {
|
||||
|
||||
private static final Integer REBUILD_FETCH_PER_SIZE = 100;
|
||||
|
||||
@DubboReference(version = "${dubbo.consumer.ProductSpuRpc.version}")
|
||||
private ProductSpuRpc productSpuRpc;
|
||||
@DubboReference(version = "${dubbo.consumer.ProductSkuRpc.version}")
|
||||
@ -37,6 +39,40 @@ public class SearchProductManager {
|
||||
@Autowired
|
||||
private SearchProductService searchProductService;
|
||||
|
||||
/**
|
||||
* 重建所有商品的 ES 索引
|
||||
*
|
||||
* @return 重建数量
|
||||
*/
|
||||
public Integer rebuild() {
|
||||
// TODO 芋艿,因为目前商品比较少,所以写的很粗暴。等未来重构
|
||||
Integer lastId = null;
|
||||
int rebuildCounts = 0;
|
||||
while (true) {
|
||||
// 从商品服务,增量获取商品列表编号
|
||||
CommonResult<List<Integer>> listProductSpuIdsResult = productSpuRpc.listProductSpuIds(lastId, REBUILD_FETCH_PER_SIZE);
|
||||
listProductSpuIdsResult.checkError();
|
||||
List<Integer> spuIds = listProductSpuIdsResult.getData();
|
||||
// 逐个重建索引到 ES 中
|
||||
spuIds.forEach(this::saveProduct);
|
||||
// 设置新的 lastId ,或者结束
|
||||
rebuildCounts += listProductSpuIdsResult.getData().size();
|
||||
if (spuIds.size() < REBUILD_FETCH_PER_SIZE) {
|
||||
break;
|
||||
} else {
|
||||
lastId = spuIds.get(spuIds.size() - 1);
|
||||
}
|
||||
}
|
||||
// 返回成功
|
||||
return rebuildCounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建指定商品的 ES 索引
|
||||
*
|
||||
* @param id 商品 SPU 编号
|
||||
* @return 是否重建成功
|
||||
*/
|
||||
public Boolean saveProduct(Integer id) {
|
||||
// 获得商品 SPU
|
||||
CommonResult<ProductSpuRespDTO> productSpuResult = productSpuRpc.getProductSpu(id);
|
||||
|
@ -8,12 +8,15 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* 商品更新 Topic 的消费者,重建对应的商品的 ES 索引
|
||||
*/
|
||||
@Service
|
||||
@RocketMQMessageListener(
|
||||
topic = ProductUpdateMessage.TOPIC,
|
||||
consumerGroup = "${spring.application.name}-consumer-group-" + ProductUpdateMessage.TOPIC
|
||||
)
|
||||
public class PayTransactionPaySuccessConsumer implements RocketMQListener<ProductUpdateMessage> {
|
||||
public class ProductUpdateConsumer implements RocketMQListener<ProductUpdateMessage> {
|
||||
|
||||
@Autowired
|
||||
private SearchProductManager productSearchManager;
|
@ -1,4 +1,4 @@
|
||||
/**
|
||||
* 占位
|
||||
* 占位,避免包折叠
|
||||
*/
|
||||
package cn.iocoder.mall.searchservice.service;
|
||||
|
@ -7,6 +7,7 @@ import cn.iocoder.common.framework.vo.SortingField;
|
||||
import cn.iocoder.mall.searchservice.convert.product.SearchProductConvert;
|
||||
import cn.iocoder.mall.searchservice.dal.es.dataobject.ESProductDO;
|
||||
import cn.iocoder.mall.searchservice.dal.es.repository.ESProductRepository;
|
||||
import cn.iocoder.mall.searchservice.enums.product.SearchProductConditionFieldEnum;
|
||||
import cn.iocoder.mall.searchservice.enums.product.SearchProductPageQuerySortFieldEnum;
|
||||
import cn.iocoder.mall.searchservice.service.product.bo.SearchProductBO;
|
||||
import cn.iocoder.mall.searchservice.service.product.bo.SearchProductConditionBO;
|
||||
@ -47,7 +48,7 @@ public class SearchProductService {
|
||||
Page<ESProductDO> searchPage = productRepository.search(pageQueryBO.getCid(), pageQueryBO.getKeyword(),
|
||||
pageQueryBO.getPageNo(), pageQueryBO.getPageSize(), pageQueryBO.getSorts());
|
||||
// 转换结果
|
||||
return SearchProductConvert.INSTANCE.convert(searchPage);
|
||||
return SearchProductConvert.INSTANCE.convertPage(searchPage);
|
||||
}
|
||||
|
||||
private void checkSortFieldInvalid(List<SortingField> sorts) {
|
||||
@ -74,11 +75,11 @@ public class SearchProductService {
|
||||
* 在我们搜索商品时,需要获得关键字可选择的分类、品牌等等搜索条件,方便用户进一步检索
|
||||
*
|
||||
* @param keyword 关键字
|
||||
* @param fields 需要返回的搜索条件。目前可传入的参数为
|
||||
* @param fields 需要返回的搜索条件{@link SearchProductConditionFieldEnum}。目前可传入的参数为
|
||||
* 1. category :商品分类,会返回商品分类编号
|
||||
* @return 搜索条件
|
||||
*/
|
||||
public SearchProductConditionBO getSearchCondition(String keyword, Collection<String> fields) {
|
||||
public SearchProductConditionBO getSearchProductCondition(String keyword, Collection<String> fields) {
|
||||
// 创建 ES 搜索条件
|
||||
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
|
||||
// 筛选
|
||||
|
@ -16,3 +16,6 @@ dubbo:
|
||||
# Dubbo 服务提供者的配置
|
||||
provider:
|
||||
tag: ${DUBBO_TAG} # Dubbo 路由分组
|
||||
# Dubbo 服务消费者的配置
|
||||
consumer:
|
||||
tag: ${DUBBO_TAG} # Dubbo 路由分组
|
||||
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 占位
|
||||
*/
|
||||
package cn.iocoder.mall.searchservice.manager;
|
@ -1,31 +1,35 @@
|
||||
package cn.iocoder.mall.search.biz.api;
|
||||
package cn.iocoder.mall.searchservice.manager.product;
|
||||
|
||||
import cn.iocoder.mall.search.biz.dao.ProductRepository;
|
||||
import cn.iocoder.mall.searchservice.dal.es.repository.ESProductRepository;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* {@link SearchProductManager} 的测试类,目前是集成测试类
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
|
||||
public class ProductSearchServiceImplTest {
|
||||
|
||||
@Autowired
|
||||
private ProductSearchServiceImpl productSearchService;
|
||||
@Autowired
|
||||
private ProductRepository productRepository;
|
||||
public class SearchProductManagerTest {
|
||||
|
||||
static {
|
||||
System.setProperty("es.set.netty.runtime.available.processors", "false");
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private SearchProductManager searchProductManager;
|
||||
|
||||
@Autowired
|
||||
private ESProductRepository esProductRepository;
|
||||
|
||||
@Test
|
||||
public void testRebuild() {
|
||||
int counts = productSearchService.rebuild();
|
||||
int counts = searchProductManager.rebuild();
|
||||
System.out.println("重建数量:" + counts);
|
||||
|
||||
System.out.println(productRepository.count());
|
||||
System.out.println(esProductRepository.count());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 占位
|
||||
*/
|
||||
package cn.iocoder.mall.searchservice.service;
|
@ -0,0 +1,32 @@
|
||||
package cn.iocoder.mall.searchservice.service.product;
|
||||
|
||||
import cn.iocoder.mall.searchservice.service.product.bo.SearchProductConditionBO;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* {@link SearchProductService} 的测试类,目前是集成测试类
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
|
||||
public class SearchProductServiceTest {
|
||||
|
||||
static {
|
||||
System.setProperty("es.set.netty.runtime.available.processors", "false");
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private SearchProductService searchProductService;
|
||||
|
||||
@Test
|
||||
public void testGetSearchCondition() {
|
||||
SearchProductConditionBO conditionBO = searchProductService.getSearchProductCondition("商品", Collections.singletonList("category"));
|
||||
System.out.println(conditionBO);
|
||||
}
|
||||
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>search</artifactId>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>search-biz-api</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<!-- Mall 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>common-framework</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -1,110 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>search</artifactId>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>search-biz</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<!-- Mall 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>mall-spring-boot</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<artifactId>search-biz-api</artifactId>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>product-rpc-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<!-- DB 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-dubbo</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Registry 和 Config 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MQ 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-jdk8</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId> <!-- 引入该包,为了写单元测试用 -->
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 自动化配置 Spring Data Jest -->
|
||||
<dependency>
|
||||
<groupId>com.github.vanroy</groupId>
|
||||
<artifactId>spring-boot-starter-data-jest</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- 提供给 mapstruct 使用 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -1,20 +0,0 @@
|
||||
package cn.iocoder.mall.search.biz.service;
|
||||
|
||||
|
||||
public interface ProductSearchService {
|
||||
|
||||
Integer rebuild();
|
||||
|
||||
/**
|
||||
* 构建商品的搜索索引
|
||||
*
|
||||
* @param id 商品编号
|
||||
* @return 构建结果
|
||||
*/
|
||||
Boolean save(Integer id);
|
||||
//
|
||||
// ProductPageBO getSearchPage(ProductSearchPageDTO searchPageDTO);
|
||||
//
|
||||
// ProductConditionBO getSearchCondition(ProductConditionDTO conditionDTO);
|
||||
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package cn.iocoder.mall.search.biz.service;
|
||||
|
||||
import cn.iocoder.common.framework.util.CollectionUtil;
|
||||
import cn.iocoder.common.framework.vo.SortingField;
|
||||
import cn.iocoder.mall.search.biz.dao.ProductRepository;
|
||||
import cn.iocoder.mall.search.biz.dto.ProductSearchPageDTO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@org.apache.dubbo.config.annotation.Service(validation = "true", version = "${dubbo.provider.ProductSearchService.version}")
|
||||
public class ProductSearchServiceImpl implements ProductSearchService {
|
||||
|
||||
private static final Integer REBUILD_FETCH_PER_SIZE = 100;
|
||||
|
||||
@Autowired
|
||||
private ProductRepository productRepository;
|
||||
|
||||
|
||||
// @Reference(validation = "true", version = "${dubbo.consumer.ProductSpuService.version}")
|
||||
// private ProductSpuService productSpuService;
|
||||
// @Reference(validation = "true", version = "${dubbo.consumer.ProductCategoryService.version}")
|
||||
// private ProductCategoryService productCategoryService;
|
||||
// @Reference(validation = "true", version = "${dubbo.consumer.CartService.version}")
|
||||
// private CartService cartService;
|
||||
|
||||
// @Override
|
||||
// public Integer rebuild() {
|
||||
// // TODO 芋艿,因为目前商品比较少,所以写的很粗暴。等未来重构
|
||||
// Integer lastId = null;
|
||||
// int rebuildCounts = 0;
|
||||
// while (true) {
|
||||
// List<ProductSpuDetailBO> spus = productSpuService.getProductSpuDetailListForSync(lastId, REBUILD_FETCH_PER_SIZE);
|
||||
// rebuildCounts += spus.size();
|
||||
// // 存储到 ES 中
|
||||
// List<ESProductDO> products = spus.stream().map(this::convert).collect(Collectors.toList());
|
||||
// productRepository.saveAll(products);
|
||||
// // 设置新的 lastId ,或者结束
|
||||
// if (spus.size() < REBUILD_FETCH_PER_SIZE) {
|
||||
// break;
|
||||
// } else {
|
||||
// lastId = spus.get(spus.size() - 1).getId();
|
||||
// }
|
||||
// }
|
||||
// // 返回成功
|
||||
// return rebuildCounts;
|
||||
// }
|
||||
//
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
##################### 业务模块 #####################
|
||||
## OAuth2CodeService
|
||||
modules.oauth2-code-service.access-token-expire-time-millis = 2880000
|
||||
modules.oauth2-code-service.refresh-token-expire-time-millis = 43200000
|
||||
## OAuth2MobileCodeService
|
||||
modules.oauth2-mobile-code-service.code-expire-time-millis = 600000
|
||||
modules.oauth2-mobile-code-service.send-maximum-quantity-per-day = 10
|
||||
modules.oauth2-mobile-code-service.send-frequency = 60000
|
@ -1,7 +0,0 @@
|
||||
spring:
|
||||
data:
|
||||
# Jest 配置项
|
||||
jest:
|
||||
uri: http://127.0.0.1:9200
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
# 服务器的配置项
|
||||
server:
|
||||
port: 18099
|
||||
servlet:
|
||||
context-path: /search-api/
|
||||
|
||||
# Swagger 配置项
|
||||
swagger:
|
||||
title: 商品查询子系统
|
||||
description: 商品查询子系统
|
||||
version: 1.0.0
|
||||
base-package: cn.iocoder.mall.search.rest.controller
|
@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>search</artifactId>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>search-rpc</artifactId>
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>search-rpc-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>search-biz</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-dubbo</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Registry 和 Config 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 自动化配置 Spring Data Jest -->
|
||||
<dependency>
|
||||
<groupId>com.github.vanroy</groupId>
|
||||
<artifactId>spring-boot-starter-data-jest</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -1,35 +0,0 @@
|
||||
package cn.iocoder.mall.search.biz.convert;
|
||||
|
||||
import cn.iocoder.mall.search.biz.bo.ProductBO;
|
||||
import cn.iocoder.mall.search.biz.dataobject.ESProductDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ProductSearchConvert {
|
||||
|
||||
ProductSearchConvert INSTANCE = Mappers.getMapper(ProductSearchConvert.class);
|
||||
|
||||
// @Mappings({})
|
||||
// ESProductDO convert(ProductSpuDetailBO spu);
|
||||
|
||||
// @Mappings({})
|
||||
// default ESProductDO convert(ProductSpuDetailBO spu, CalcSkuPriceBO calcSkuPrice) {
|
||||
// // Spu 的基础数据
|
||||
// ESProductDO product = this.convert(spu);
|
||||
// product.setOriginalPrice(calcSkuPrice.getOriginalPrice()).setBuyPrice(calcSkuPrice.getBuyPrice());
|
||||
// // 设置促销活动相关字段
|
||||
// if (calcSkuPrice.getTimeLimitedDiscount() != null) {
|
||||
// PromotionActivityBO activity = calcSkuPrice.getTimeLimitedDiscount();
|
||||
// product.setPromotionActivityId(activity.getId()).setPromotionActivityTitle(activity.getTitle())
|
||||
// .setPromotionActivityType(activity.getActivityType());
|
||||
// }
|
||||
// // 返回
|
||||
// return product;
|
||||
// }
|
||||
|
||||
List<ProductBO> convert(List<ESProductDO> list);
|
||||
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package cn.iocoder.mall.search.biz.rpc.user;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.search.biz.api.user.ProductSearchRPC;
|
||||
import cn.iocoder.mall.search.biz.service.ProductSearchService;
|
||||
import org.apache.dubbo.config.annotation.Service;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
|
||||
@Service(validation = "true", version = "${dubbo.provider.ProductSearchRpc.version}")
|
||||
public class ProductSearchRPCImpl implements ProductSearchRPC {
|
||||
|
||||
@Autowired
|
||||
private ProductSearchService productSearchService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Integer> rebuild() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> save(Integer id){
|
||||
// ProductSpuDetailBO productSpuDetail = productSpuService.getProductSpuDetail(spuId);
|
||||
// return ProductSpuConvert.INSTANCE.convertDetail(productSpuDetail);
|
||||
return CommonResult.success(true);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
spring:
|
||||
# Spring Cloud 配置项
|
||||
cloud:
|
||||
nacos:
|
||||
# Spring Cloud Nacos Discovery 配置项
|
||||
discovery:
|
||||
server-addr: s1.iocoder.cn:8848 # Nacos 服务器地址
|
||||
namespace: local # Nacos 命名空间
|
||||
|
||||
# Dubbo 配置项
|
||||
dubbo:
|
||||
# Dubbo 注册中心
|
||||
registry:
|
||||
address: spring-cloud://s1.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址
|
@ -1,14 +0,0 @@
|
||||
spring:
|
||||
# Spring Cloud 配置项
|
||||
cloud:
|
||||
nacos:
|
||||
# Spring Cloud Nacos Discovery 配置项
|
||||
discovery:
|
||||
server-addr: s1.iocoder.cn:8848 # Nacos 服务器地址
|
||||
namespace: test # Nacos 命名空间
|
||||
|
||||
# Dubbo 配置项
|
||||
dubbo:
|
||||
# Dubbo 注册中心
|
||||
registry:
|
||||
address: spring-cloud://s1.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址
|
@ -1,22 +0,0 @@
|
||||
# Dubbo 配置项
|
||||
dubbo:
|
||||
# Spring Cloud Alibaba Dubbo 专属配置
|
||||
cloud:
|
||||
subscribed-services: 'search-application' # 设置订阅的应用列表,默认为 * 订阅所有应用
|
||||
# Dubbo 提供者的协议
|
||||
protocol:
|
||||
name: dubbo
|
||||
port: -1
|
||||
# Dubbo 提供服务的扫描基础包
|
||||
scan:
|
||||
base-packages: cn.iocoder.mall.search.rpc.rpc
|
||||
# Dubbo 服务提供者的配置
|
||||
provider:
|
||||
# filter: -exception
|
||||
# ProductSpuService:
|
||||
# version: 1.0.0
|
||||
|
||||
# Dubbo 服务消费者的配置
|
||||
consumer:
|
||||
# ProductSpuService:
|
||||
# version: 1.0.0
|
@ -1,16 +0,0 @@
|
||||
package cn.iocoder.mall.search.biz;
|
||||
|
||||
import cn.iocoder.mall.search.biz.bo.ProductConditionBO;
|
||||
import cn.iocoder.mall.search.biz.bo.ProductPageBO;
|
||||
import cn.iocoder.mall.search.biz.dto.ProductConditionDTO;
|
||||
import cn.iocoder.mall.search.biz.dto.ProductSearchPageDTO;
|
||||
|
||||
public interface ProductSearchService {
|
||||
|
||||
Integer rebuild();
|
||||
|
||||
ProductPageBO getSearchPage(ProductSearchPageDTO searchPageDTO);
|
||||
|
||||
ProductConditionBO getSearchCondition(ProductConditionDTO conditionDTO);
|
||||
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>search</artifactId>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>search-service-impl</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<!-- Mall 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>mall-spring-boot</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>search-service-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>product-service-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>order-service-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- DB 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-dubbo</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Registry 和 Config 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MQ 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId> <!-- 引入该包,为了写单元测试用 -->
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- 提供给 mapstruct 使用 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -1,39 +0,0 @@
|
||||
package cn.iocoder.mall.search.biz.convert;
|
||||
|
||||
import cn.iocoder.mall.order.api.bo.CalcSkuPriceBO;
|
||||
import cn.iocoder.mall.product.api.bo.ProductSpuDetailBO;
|
||||
import cn.iocoder.mall.promotion.api.bo.PromotionActivityBO;
|
||||
import cn.iocoder.mall.search.biz.bo.ProductBO;
|
||||
import cn.iocoder.mall.search.biz.dataobject.ESProductDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mappings;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ProductSearchConvert {
|
||||
|
||||
ProductSearchConvert INSTANCE = Mappers.getMapper(ProductSearchConvert.class);
|
||||
|
||||
@Mappings({})
|
||||
ESProductDO convert(ProductSpuDetailBO spu);
|
||||
|
||||
@Mappings({})
|
||||
default ESProductDO convert(ProductSpuDetailBO spu, CalcSkuPriceBO calcSkuPrice) {
|
||||
// Spu 的基础数据
|
||||
ESProductDO product = this.convert(spu);
|
||||
product.setOriginalPrice(calcSkuPrice.getOriginalPrice()).setBuyPrice(calcSkuPrice.getBuyPrice());
|
||||
// 设置促销活动相关字段
|
||||
if (calcSkuPrice.getTimeLimitedDiscount() != null) {
|
||||
PromotionActivityBO activity = calcSkuPrice.getTimeLimitedDiscount();
|
||||
product.setPromotionActivityId(activity.getId()).setPromotionActivityTitle(activity.getTitle())
|
||||
.setPromotionActivityType(activity.getActivityType());
|
||||
}
|
||||
// 返回
|
||||
return product;
|
||||
}
|
||||
|
||||
List<ProductBO> convert(List<ESProductDO> list);
|
||||
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
package cn.iocoder.mall.search.biz.api;
|
||||
|
||||
import cn.iocoder.common.framework.util.CollectionUtil;
|
||||
import cn.iocoder.common.framework.util.StringUtil;
|
||||
import cn.iocoder.common.framework.vo.SortingField;
|
||||
import cn.iocoder.mall.order.api.CartService;
|
||||
import cn.iocoder.mall.order.api.bo.CalcSkuPriceBO;
|
||||
import cn.iocoder.mall.product.api.ProductCategoryService;
|
||||
import cn.iocoder.mall.product.api.ProductSpuService;
|
||||
import cn.iocoder.mall.product.api.bo.ProductCategoryBO;
|
||||
import cn.iocoder.mall.product.api.bo.ProductSpuDetailBO;
|
||||
import cn.iocoder.mall.search.biz.ProductSearchService;
|
||||
import cn.iocoder.mall.search.biz.bo.ProductConditionBO;
|
||||
import cn.iocoder.mall.search.biz.bo.ProductPageBO;
|
||||
import cn.iocoder.mall.search.biz.dto.ProductConditionDTO;
|
||||
import cn.iocoder.mall.search.biz.dto.ProductSearchPageDTO;
|
||||
import cn.iocoder.mall.search.biz.convert.ProductSearchConvert;
|
||||
import cn.iocoder.mall.search.biz.dao.ProductRepository;
|
||||
import cn.iocoder.mall.search.biz.dataobject.ESProductDO;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.search.aggregations.Aggregation;
|
||||
import org.elasticsearch.search.aggregations.AggregationBuilders;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@org.apache.dubbo.config.annotation.Service(validation = "true", version = "${dubbo.provider.ProductSearchService.version}")
|
||||
public class ProductSearchServiceImpl implements ProductSearchService {
|
||||
|
||||
private static final Integer REBUILD_FETCH_PER_SIZE = 100;
|
||||
|
||||
@Autowired
|
||||
private ProductRepository productRepository;
|
||||
@Autowired
|
||||
private ElasticsearchTemplate elasticsearchTemplate; // 因为需要使用到聚合操作,只好引入 ElasticsearchTemplate 。
|
||||
|
||||
@Override
|
||||
public Integer rebuild() {
|
||||
// TODO 芋艿,因为目前商品比较少,所以写的很粗暴。等未来重构
|
||||
Integer lastId = null;
|
||||
int rebuildCounts = 0;
|
||||
while (true) {
|
||||
List<ProductSpuDetailBO> spus = productSpuService.getProductSpuDetailListForSync(lastId, REBUILD_FETCH_PER_SIZE);
|
||||
rebuildCounts += spus.size();
|
||||
// 存储到 ES 中
|
||||
List<ESProductDO> products = spus.stream().map(this::convert).collect(Collectors.toList());
|
||||
productRepository.saveAll(products);
|
||||
// 设置新的 lastId ,或者结束
|
||||
if (spus.size() < REBUILD_FETCH_PER_SIZE) {
|
||||
break;
|
||||
} else {
|
||||
lastId = spus.get(spus.size() - 1).getId();
|
||||
}
|
||||
}
|
||||
// 返回成功
|
||||
return rebuildCounts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProductConditionBO getSearchCondition(ProductConditionDTO conditionDTO) {
|
||||
// 创建 ES 搜索条件
|
||||
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
|
||||
// 筛选
|
||||
if (StringUtil.hasText(conditionDTO.getKeyword())) { // 如果有 keyword ,就去匹配
|
||||
nativeSearchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery(conditionDTO.getKeyword(),
|
||||
"name", "sellPoint", "categoryName"));
|
||||
} else {
|
||||
nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
|
||||
}
|
||||
// 聚合
|
||||
if (conditionDTO.getFields().contains(ProductConditionDTO.FIELD_CATEGORY)) { // 商品分类
|
||||
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("cids").field("cid"));
|
||||
}
|
||||
// 执行查询
|
||||
ProductConditionBO condition = elasticsearchTemplate.query(nativeSearchQueryBuilder.build(), response -> {
|
||||
ProductConditionBO result = new ProductConditionBO();
|
||||
// categoryIds 聚合
|
||||
Aggregation categoryIdsAggregation = response.getAggregations().get("cids");
|
||||
if (categoryIdsAggregation != null) {
|
||||
result.setCategories(new ArrayList<>());
|
||||
for (LongTerms.Bucket bucket : (((LongTerms) categoryIdsAggregation).getBuckets())) {
|
||||
result.getCategories().add(new ProductConditionBO.Category().setId(bucket.getKeyAsNumber().intValue()));
|
||||
}
|
||||
}
|
||||
// 返回结果
|
||||
return result;
|
||||
});
|
||||
// 聚合其它数据源
|
||||
if (!CollectionUtil.isEmpty(condition.getCategories())) {
|
||||
// 查询指定的 ProductCategoryBO 数组,并转换成 ProductCategoryBO Map
|
||||
Map<Integer, ProductCategoryBO> categoryMap = productCategoryService.getListByIds(
|
||||
condition.getCategories().stream().map(ProductConditionBO.Category::getId).collect(Collectors.toList()))
|
||||
.stream().collect(Collectors.toMap(ProductCategoryBO::getId, category -> category));
|
||||
// 设置分类名
|
||||
condition.getCategories().forEach(category -> category.setName(categoryMap.get(category.getId()).getName()));
|
||||
}
|
||||
// 返回结果
|
||||
return condition;
|
||||
}
|
||||
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
# es
|
||||
spring:
|
||||
data:
|
||||
elasticsearch:
|
||||
cluster-name: elasticsearch
|
||||
cluster-nodes: 192.168.88.14:9300
|
||||
repositories:
|
||||
enable: true
|
||||
|
||||
# rocketmq
|
||||
rocketmq:
|
||||
name-server: 192.168.88.14:9876
|
||||
producer:
|
||||
group: search-producer-group
|
@ -1,54 +0,0 @@
|
||||
# es
|
||||
spring:
|
||||
application:
|
||||
name: search-application
|
||||
data:
|
||||
elasticsearch:
|
||||
cluster-name: elasticsearch
|
||||
cluster-nodes: s1.iocoder.cn:9300
|
||||
repositories:
|
||||
enable: true
|
||||
elasticsearch:
|
||||
rest:
|
||||
uris: s1.iocoder.cn:9200
|
||||
|
||||
# Spring Cloud 配置项
|
||||
cloud:
|
||||
nacos:
|
||||
# Spring Cloud Nacos Discovery 配置项
|
||||
discovery:
|
||||
server-addr: s1.iocoder.cn:8848 # Nacos 服务器地址
|
||||
|
||||
# Dubbo 配置项
|
||||
dubbo:
|
||||
# Dubbo 注册中心
|
||||
registry:
|
||||
address: spring-cloud://s1.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址
|
||||
# Spring Cloud Alibaba Dubbo 专属配置
|
||||
cloud:
|
||||
subscribed-services: admin-application, order-application, product-application # 设置订阅的应用列表,默认为 * 订阅所有应用
|
||||
# Dubbo 提供者的协议
|
||||
protocol:
|
||||
name: dubbo
|
||||
port: -1
|
||||
# Dubbo 提供服务的扫描基础包
|
||||
scan:
|
||||
base-packages: cn.iocoder.mall.search.biz.service
|
||||
# Dubbo 服务提供者的配置
|
||||
provider:
|
||||
filter: -exception
|
||||
ProductSearchService:
|
||||
version: 1.0.0
|
||||
consumer:
|
||||
ProductSpuService:
|
||||
version: 1.0.0
|
||||
ProductCategoryService:
|
||||
version: 1.0.0
|
||||
CartService:
|
||||
version: 1.0.0
|
||||
|
||||
# rocketmq
|
||||
rocketmq:
|
||||
name-server: s1.iocoder.cn:9876
|
||||
producer:
|
||||
group: search-producer-group
|
@ -1,7 +0,0 @@
|
||||
package cn.iocoder.mall.search.biz;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.search"})
|
||||
public class Application {
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
package cn.iocoder.mall.search.biz.dao;
|
||||
|
||||
import cn.iocoder.mall.search.biz.dataobject.ESProductDO;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
|
||||
public class ProductRepositoryTest {
|
||||
|
||||
@Autowired
|
||||
private ProductRepository productRepository;
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testSave() {
|
||||
// productRepository.deleteById(1);
|
||||
ESProductDO product = new ESProductDO()
|
||||
.setId(1)
|
||||
.setName("你猜");
|
||||
productRepository.save(product);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testFindByName() {
|
||||
ESProductDO product = productRepository.findByName("锤子");
|
||||
System.out.println(product);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearch() {
|
||||
// Page<ESProductDO> page = productRepository.search(639, null, 1, 10);
|
||||
// console(page.getContent());
|
||||
|
||||
// Page<ESProductDO> page = productRepository.search(null, "数据库Oracle", 1, 10);
|
||||
// console(page.getContent());
|
||||
}
|
||||
|
||||
private void console(List<ESProductDO> list) {
|
||||
list.forEach(System.out::println);
|
||||
}
|
||||
|
||||
}
|
@ -12,4 +12,82 @@
|
||||
<artifactId>shop-web-app</artifactId>
|
||||
<description>商城,用于用户购物</description>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- onemall 基础 bom 文件 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>mall-dependencies</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>mall-spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>mall-spring-boot-starter-swagger</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>mall-spring-boot-starter-security-user</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>mall-spring-boot-starter-dubbo</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<!-- 用户服务 -->
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>user-service-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- 商品服务 -->
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>product-service-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- 系统服务 -->
|
||||
<groupId>cn.iocoder.mall</groupId>
|
||||
<artifactId>system-service-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Registry 和 Config 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-jdk8</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@ -0,0 +1,13 @@
|
||||
package cn.iocoder.mall.shopweb;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class ShopWebApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ShopWebApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.mall.userweb.controller.product;
|
||||
package cn.iocoder.mall.shopweb.controller.product;
|
||||
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.userweb.controller.product.vo.category.ProductCategoryRespVO;
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.mall.userweb.controller.product.vo.category;
|
||||
package cn.iocoder.mall.shopweb.controller.product.vo.category;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
@ -0,0 +1 @@
|
||||
package cn.iocoder.mall.shopweb.controller.product.vo;
|
14
shop-web-app/src/main/resources/application-dev.yml
Normal file
14
shop-web-app/src/main/resources/application-dev.yml
Normal file
@ -0,0 +1,14 @@
|
||||
spring:
|
||||
# Spring Cloud 配置项
|
||||
cloud:
|
||||
nacos:
|
||||
# Spring Cloud Nacos Discovery 配置项
|
||||
discovery:
|
||||
server-addr: 400-infra.server.iocoder.cn:8848 # Nacos 服务器地址
|
||||
namespace: dev # Nacos 命名空间
|
||||
|
||||
# Dubbo 配置项
|
||||
dubbo:
|
||||
# Dubbo 注册中心
|
||||
registry:
|
||||
address: spring-cloud://400-infra.server.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址
|
15
shop-web-app/src/main/resources/application-local.yml
Normal file
15
shop-web-app/src/main/resources/application-local.yml
Normal file
@ -0,0 +1,15 @@
|
||||
spring:
|
||||
# Spring Cloud 配置项
|
||||
cloud:
|
||||
nacos:
|
||||
# Spring Cloud Nacos Discovery 配置项
|
||||
discovery:
|
||||
server-addr: 400-infra.server.iocoder.cn:8848 # Nacos 服务器地址
|
||||
namespace: dev # Nacos 命名空间
|
||||
|
||||
# Dubbo 配置项
|
||||
dubbo:
|
||||
# Dubbo 注册中心
|
||||
registry:
|
||||
# address: spring-cloud://400-infra.server.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址
|
||||
address: nacos://400-infra.server.iocoder.cn:8848?namespace=dev # 指定 Dubbo 服务注册中心的地址
|
48
shop-web-app/src/main/resources/application.yml
Normal file
48
shop-web-app/src/main/resources/application.yml
Normal file
@ -0,0 +1,48 @@
|
||||
# 服务器的配置项
|
||||
server:
|
||||
port: 18083
|
||||
servlet:
|
||||
context-path: /user-api/
|
||||
|
||||
spring:
|
||||
# Application 的配置项
|
||||
application:
|
||||
name: shop-web
|
||||
# Profile 的配置项
|
||||
profiles:
|
||||
active: local
|
||||
# SpringMVC 配置项
|
||||
mvc:
|
||||
throw-exception-if-no-handler-found: true # 匹配不到路径时,抛出 NoHandlerFoundException 异常
|
||||
static-path-pattern: /doc.html # 静态资源的路径
|
||||
|
||||
# Dubbo 配置项
|
||||
dubbo:
|
||||
# Spring Cloud Alibaba Dubbo 专属配置
|
||||
cloud:
|
||||
subscribed-services: 'user-service,system-service' # 设置订阅的应用列表,默认为 * 订阅所有应用
|
||||
# Dubbo 服务消费者的配置
|
||||
consumer:
|
||||
timeout: 10000
|
||||
validation: true # 开启 Consumer 的参数校验
|
||||
UserSmsCodeRpc:
|
||||
version: 1.0.0
|
||||
UserRpc:
|
||||
version: 1.0.0
|
||||
OAuth2Rpc:
|
||||
version: 1.0.0
|
||||
SystemAccessLogRpc:
|
||||
version: 1.0.0
|
||||
SystemExceptionLogRpc:
|
||||
version: 1.0.0
|
||||
UserAddressRpc:
|
||||
version: 1.0.0
|
||||
ProductCategoryRpc:
|
||||
version: 1.0.0
|
||||
|
||||
# Swagger 配置项
|
||||
swagger:
|
||||
title: 商城中心
|
||||
description: 提供用户商城购物流程中的 API
|
||||
version: 1.0.0
|
||||
base-package: cn.iocoder.mall.shopweb.controller
|
@ -1 +0,0 @@
|
||||
package cn.iocoder.mall.userweb.controller.product.vo;
|
Loading…
Reference in New Issue
Block a user