1.迁移product search 代码

2.先注释掉提示错误的代码,后续相关人员开发功能时自行解开
3.修改es连接方式为 rest,增加spring data jest
This commit is contained in:
lihailong 2020-05-20 18:44:33 +08:00
parent 1e8057b04e
commit ffd4fd82a8
53 changed files with 1605 additions and 186 deletions

View File

@ -13,8 +13,13 @@
<packaging>pom</packaging>
<modules>
<module>search-application</module>
<module>search-service-api</module>
<module>search-service-impl</module>
<module>search-biz</module>
<module>search-biz-api</module>
<!-- <module>search-service-api</module>-->
<!-- <module>search-service-impl</module>-->
<module>search-rpc</module>
<module>search-rest</module>
<module>search-rpc-api</module>
</modules>
<dependencyManagement>

View File

@ -15,92 +15,15 @@
<!-- Mall 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>common-framework</artifactId>
<artifactId>search-rest</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-spring-boot</artifactId>
<artifactId>search-rpc</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>user-sdk</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>search-service-impl</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>system-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
</dependency>
<!-- 服务保障相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 监控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<!-- 测试相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 提供给 mapstruct 使用 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<!-- 打包 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -2,13 +2,22 @@ package cn.iocoder.mall.search.application;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.config.ConfigFileApplicationListener;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.search"})
@EnableAsync(proxyTargetClass = true)
public class SearchApplication {
/**
* 设置需要读取的配置文件的名字
* 基于 {@link org.springframework.boot.context.config.ConfigFileApplicationListener#CONFIG_NAME_PROPERTY} 实现
*/
private static final String CONFIG_NAME_VALUE = "biz,rest,rpc,application";
public static void main(String[] args) {
// 设置环境变量
System.setProperty(ConfigFileApplicationListener.CONFIG_NAME_PROPERTY, CONFIG_NAME_VALUE);
// 解决 ES java.lang.IllegalStateException: availableProcessors is already
System.setProperty("es.set.netty.runtime.available.processors", "false");
SpringApplication.run(SearchApplication.class, args);

View File

@ -1,59 +0,0 @@
package cn.iocoder.mall.search.application.controller.users;
import cn.iocoder.common.framework.util.StringUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.common.framework.vo.SortingField;
import cn.iocoder.mall.search.api.ProductSearchService;
import cn.iocoder.mall.search.api.bo.ProductConditionBO;
import cn.iocoder.mall.search.api.bo.ProductPageBO;
import cn.iocoder.mall.search.api.dto.ProductConditionDTO;
import cn.iocoder.mall.search.api.dto.ProductSearchPageDTO;
import org.apache.dubbo.config.annotation.Reference;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import static cn.iocoder.common.framework.vo.CommonResult.success;
// TODO 芋艿搜索关键字的配置
// TODO 芋艿搜索日志
@RestController
@RequestMapping("users/product")
@Api("商品搜索")
public class UsersProductSearchController {
@Reference(validation = "true", version = "${dubbo.provider.ProductSearchService.version}")
private ProductSearchService productSearchService;
@GetMapping("/page") // TODO 芋艿后面把 BO 改成 VO
public CommonResult<ProductPageBO> page(@RequestParam(value = "cid", required = false) Integer cid,
@RequestParam(value = "keyword", required = false) String keyword,
@RequestParam(value = "pageNo", required = false) Integer pageNo,
@RequestParam(value = "pageSize", required = false) Integer pageSize,
@RequestParam(value = "sortField", required = false) String sortField,
@RequestParam(value = "sortOrder", required = false) String sortOrder) {
// 创建 ProductSearchPageDTO 对象
ProductSearchPageDTO productSearchPageDTO = new ProductSearchPageDTO().setCid(cid).setKeyword(keyword)
.setPageNo(pageNo).setPageSize(pageSize);
if (StringUtil.hasText(sortField) && StringUtil.hasText(sortOrder)) {
productSearchPageDTO.setSorts(Collections.singletonList(new SortingField(sortField, sortOrder)));
}
// 执行搜索
return success(productSearchService.getSearchPage(productSearchPageDTO));
}
@GetMapping("/condition") // TODO 芋艿后面把 BO 改成 VO
public CommonResult<ProductConditionBO> condition(@RequestParam(value = "keyword", required = false) String keyword) {
// 创建 ProductConditionDTO 对象
ProductConditionDTO productConditionDTO = new ProductConditionDTO().setKeyword(keyword)
.setFields(Collections.singleton(ProductConditionDTO.FIELD_CATEGORY));
// 执行搜索
return success(productSearchService.getSearchCondition(productConditionDTO));
}
}

View File

@ -1,29 +1,6 @@
spring:
application:
name: search-application
# Spring Cloud 配置项
cloud:
# Spring Cloud Sentinel 配置项
sentinel:
transport:
dashboard: s1.iocoder.cn:12088 # Sentinel Dashboard 服务地址
eager: true # 项目启动时,直接连接到 Sentinel
# server
server:
port: 18086
servlet:
context-path: /search-api/
swagger:
enable: false
management:
endpoints:
web:
exposure:
include: health,info,env,metrics,prometheus
metrics:
enabled: true
# Profile 的配置项
profiles:
active: local

View File

@ -0,0 +1,23 @@
<?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>

110
search/search-biz/pom.xml Normal file
View File

@ -0,0 +1,110 @@
<?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>

View File

@ -0,0 +1,86 @@
package cn.iocoder.mall.search.biz.bo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* 商品 ES BO
*/
@Data
@Accessors(chain = true)
public class ProductBO implements Serializable {
private Integer id;
// ========== 基本信息 =========
/**
* SPU 名字
*/
private String name;
/**
* 卖点
*/
private String sellPoint;
/**
* 描述
*/
private String description;
/**
* 分类编号
*/
private Integer cid;
/**
* 分类名
*/
private String categoryName;
/**
* 商品主图地数组
*/
private List<String> picUrls;
// ========== 其他信息 =========
/**
* 是否上架商品是否可见
*
* true 为已上架
* false 为已下架
*/
private Boolean visible;
/**
* 排序字段
*/
private Integer sort;
// ========== Sku 相关字段 =========
/**
* 原价格单位
*/
private Integer originalPrice;
/**
* 购买价格单位
*/
private Integer buyPrice;
/**
* 库存数量
*/
private Integer quantity;
// ========== 促销活动相关字段 =========
// 目前只促销单体商品促销目前仅限制折扣
/**
* 促销活动编号
*/
private Integer promotionActivityId;
/**
* 促销活动标题
*/
private String promotionActivityTitle;
/**
* 促销活动类型
*/
private Integer promotionActivityType;
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.mall.search.biz.bo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 商品搜索条件返回 BO
*/
@Data
@Accessors(chain = true)
public class ProductConditionBO {
/**
* 商品分类数组
*/
private List<Category> categories;
@Data
@Accessors(chain = true)
public static class Category {
/**
* 分类编号
*/
private Integer id;
/**
* 分类名称
*/
private String name;
}
}

View File

@ -0,0 +1,22 @@
package cn.iocoder.mall.search.biz.bo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
public class ProductPageBO implements Serializable {
/**
* 管理员数组
*/
private List<ProductBO> list;
/**
* 总量
*/
private Integer total;
}

View File

@ -0,0 +1,9 @@
package cn.iocoder.mall.search.biz.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
@Configuration
@EnableElasticsearchRepositories(basePackages = "cn.iocoder.mall.search.biz.dao")
public class JPAConfiguration {
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.mall.search.biz.constant;
/**
* ES 字段分析器的枚举类
*
* 关于 IK 分词文章 https://blog.csdn.net/xsdxs/article/details/72853288 不错
* 目前项目使用的 ES 版本是 6.7.1 可以在 https://www.elastic.co/cn/downloads/past-releases/elasticsearch-6-7-1 下载
* 如果不知道怎么安装 ES 可以看 https://blog.csdn.net/chengyuqiang/article/details/78837712 简单
*/
public class FieldAnalyzer {
/**
* IK 最大化分词
*
* 会将文本做最细粒度的拆分
*/
public static final String IK_MAX_WORD = "ik_max_word";
/**
* IK 智能分词
*
* 会做最粗粒度的拆分
*/
public static final String IK_SMART = "ik_smart";
}

View File

@ -0,0 +1,17 @@
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);
List<ProductBO> convert(List<ESProductDO> list);
}

View File

@ -0,0 +1,69 @@
package cn.iocoder.mall.search.biz.dao;
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.search.biz.dataobject.ESProductDO;
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
@Repository
public interface ProductRepository extends ElasticsearchRepository<ESProductDO, Integer> {
@Deprecated
ESProductDO findByName(String name);
default Page<ESProductDO> search(Integer cid, String keyword, Integer pageNo, Integer pageSize,
List<SortingField> sortFields) {
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
.withPageable(PageRequest.of(pageNo - 1, pageSize));
// 筛选条件 cid
if (cid != null) {
nativeSearchQueryBuilder.withFilter(QueryBuilders.termQuery("cid", cid));
}
// 筛选
if (StringUtil.hasText(keyword)) {
FunctionScoreQueryBuilder.FilterFunctionBuilder[] functions = { // TODO 芋艿分值随便打的
new FunctionScoreQueryBuilder.FilterFunctionBuilder(matchQuery("name", keyword),
ScoreFunctionBuilders.weightFactorFunction(10)),
new FunctionScoreQueryBuilder.FilterFunctionBuilder(matchQuery("sellPoint", keyword),
ScoreFunctionBuilders.weightFactorFunction(2)),
new FunctionScoreQueryBuilder.FilterFunctionBuilder(matchQuery("categoryName", keyword),
ScoreFunctionBuilders.weightFactorFunction(3)),
// new FunctionScoreQueryBuilder.FilterFunctionBuilder(matchQuery("description", keyword),
// ScoreFunctionBuilders.weightFactorFunction(2)), // TODO 芋艿目前这么做如果商品描述很长在按照价格降序会命中超级多的关键字
};
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(functions)
.scoreMode(FunctionScoreQuery.ScoreMode.SUM)
.setMinScore(2F); // TODO 芋艿需要考虑下 score
nativeSearchQueryBuilder.withQuery(functionScoreQueryBuilder);
} else {
nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
}
// 排序
if (!CollectionUtil.isEmpty(sortFields)) {
sortFields.forEach(sortField -> nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(sortField.getField())
.order(SortOrder.fromString(sortField.getOrder()))));
} else if (StringUtil.hasText(keyword)) {
nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
} else {
nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("sort").order(SortOrder.DESC));
}
// 执行查询
return search(nativeSearchQueryBuilder.build());
}
}

View File

@ -0,0 +1,96 @@
package cn.iocoder.mall.search.biz.dataobject;
import cn.iocoder.mall.search.biz.constant.FieldAnalyzer;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.util.List;
/**
* 商品 ES DO
*/
@Document(indexName = "product", type = "spu", shards = 1, replicas = 0)
@Data
@Accessors(chain = true)
public class ESProductDO {
@Id
private Integer id;
// ========== 基本信息 =========
/**
* SPU 名字
*/
@Field(analyzer = FieldAnalyzer.IK_MAX_WORD, type = FieldType.Text)
private String name;
/**
* 卖点
*/
@Field(analyzer = FieldAnalyzer.IK_MAX_WORD, type = FieldType.Text)
private String sellPoint;
/**
* 描述
*/
@Field(analyzer = FieldAnalyzer.IK_MAX_WORD, type = FieldType.Text)
private String description;
/**
* 分类编号
*/
private Integer cid;
/**
* 分类名
*/
@Field(analyzer = FieldAnalyzer.IK_MAX_WORD, type = FieldType.Text)
private String categoryName;
/**
* 商品主图地数组
*/
private List<String> picUrls;
// ========== 其他信息 =========
/**
* 是否上架商品是否可见
*
* true 为已上架
* false 为已下架
*/
private Boolean visible;
/**
* 排序字段
*/
private Integer sort;
// ========== Sku 相关字段 =========
/**
* 原价格单位
*/
private Integer originalPrice;
/**
* 购买价格单位
*/
private Integer buyPrice;
/**
* 库存数量
*/
private Integer quantity;
// ========== 促销活动相关字段 =========
// 目前只促销单体商品促销目前仅限制折扣
/**
* 促销活动编号
*/
private Integer promotionActivityId;
/**
* 促销活动标题
*/
private String promotionActivityTitle;
/**
* 促销活动类型
*/
private Integer promotionActivityType;
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.mall.search.biz.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Collection;
/**
* 获得商品检索条件 DTO
*/
@Data
@Accessors(chain = true)
public class ProductConditionDTO {
/**
* Field - 商品分类
*/
public static final String FIELD_CATEGORY = "category";
/**
* 关键字
*/
private String keyword;
/**
* 需要返回的搜索条件的 fields
*/
private Collection<String> fields;
}

View File

@ -0,0 +1,43 @@
package cn.iocoder.mall.search.biz.dto;
import cn.iocoder.common.framework.util.CollectionUtil;
import cn.iocoder.common.framework.vo.SortingField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
import java.util.Set;
/**
* 商品检索分页 DTO
*/
@Data
@Accessors(chain = true)
public class ProductSearchPageDTO {
public static final Set<String> SORT_FIELDS = CollectionUtil.asSet("buyPrice");
/**
* 分类编号
*/
private Integer cid;
/**
* 关键字
*/
private String keyword;
/**
* 页码
*/
private Integer pageNo;
/**
* 分页大小
*/
private Integer pageSize;
/**
* 排序字段数组
*/
private List<SortingField> sorts;
}

View File

@ -0,0 +1,20 @@
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);
}

View File

@ -0,0 +1,147 @@
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;
@Autowired
private ElasticsearchTemplate elasticsearchTemplate; // 因为需要使用到聚合操作只好引入 ElasticsearchTemplate
// @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;
// }
//
// @Override
// public Boolean save(Integer id) {
// // 获得商品性情
// ProductSpuDetailBO result = productSpuService.getProductSpuDetail(id);
// // 存储到 ES
// ESProductDO product = convert(result);
// productRepository.save(product);
// // 返回成功
// return true;
// }
//
// @SuppressWarnings("OptionalGetWithoutIsPresent")
// private ESProductDO convert(ProductSpuDetailBO spu) {
// // 获得最小价格的 SKU 用于下面的价格计算
// ProductSpuDetailBO.Sku sku = spu.getSkus().stream().min(Comparator.comparing(ProductSpuDetailBO.Sku::getPrice)).get();
// // 价格计算
// CalcSkuPriceBO calSkuPriceResult = cartService.calcSkuPrice(sku.getId());
// // 拼装结果
// return ProductSearchConvert.INSTANCE.convert(spu, calSkuPriceResult);
// }
//
// @Override
// public ProductPageBO getSearchPage(ProductSearchPageDTO searchPageDTO) {
// checkSortFieldInvalid(searchPageDTO.getSorts());
// // 执行查询
// Page<ESProductDO> searchPage = productRepository.search(searchPageDTO.getCid(), searchPageDTO.getKeyword(),
// searchPageDTO.getPageNo(), searchPageDTO.getPageSize(), searchPageDTO.getSorts());
// // 转换结果
// return new ProductPageBO()
// .setList(ProductSearchConvert.INSTANCE.convert(searchPage.getContent()))
// .setTotal((int) searchPage.getTotalElements());
// }
private void checkSortFieldInvalid(List<SortingField> sorts) {
if (CollectionUtil.isEmpty(sorts)) {
return;
}
sorts.forEach(sortingField -> Assert.isTrue(ProductSearchPageDTO.SORT_FIELDS.contains(sortingField.getField()),
String.format("排序字段(%s) 不在允许范围内", sortingField.getField())));
}
@Override
public Integer rebuild() {
return null;
}
@Override
public Boolean save(Integer id) {
return null;
}
// @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;
// }
}

View File

@ -0,0 +1,8 @@
##################### 业务模块 #####################
## 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

View File

@ -0,0 +1,7 @@
spring:
data:
# Jest 配置项
jest:
uri: http://127.0.0.1:9200

View File

@ -0,0 +1,42 @@
<?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-rest</artifactId>
<description>提供 商品搜索服务的 Rest 接口的实现,提供对外调用</description>
<dependencies>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>search-biz</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-spring-boot-starter-web</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-spring-boot-starter-security</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-spring-boot-starter-swagger</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,72 @@
package cn.iocoder.mall.search.rest.controller.user;
import cn.iocoder.common.framework.constant.MallConstants;
import cn.iocoder.common.framework.util.StringUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.common.framework.vo.SortingField;
import cn.iocoder.mall.search.biz.service.ProductSearchService;
import cn.iocoder.mall.search.rest.response.user.ProductPageResponse;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import cn.iocoder.mall.search.rest.request.user.ProductConditionRequest;
import cn.iocoder.mall.search.rest.request.user.ProductSearchPageRequest;
import cn.iocoder.mall.search.rest.response.user.ProductConditionResponse;
import java.util.Collections;
import static cn.iocoder.common.framework.vo.CommonResult.success;
/**
* Created with IDEA
*
* @author : lhl
* @version : 1.0
* @Time : 19:26
* @date : 2020/5/14
*/
@RestController
@RequestMapping(MallConstants.ROOT_PATH_ADMIN + "users/product")
@Api(tags = "商品查询 API")
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UsersProductSearchController {
private final ProductSearchService productSearchService;
@GetMapping("/page") // TODO 芋艿后面把 BO 改成 VO
public CommonResult<ProductPageResponse> page(@RequestParam(value = "cid", required = false) Integer cid,
@RequestParam(value = "keyword", required = false) String keyword,
@RequestParam(value = "pageNo", required = false) Integer pageNo,
@RequestParam(value = "pageSize", required = false) Integer pageSize,
@RequestParam(value = "sortField", required = false) String sortField,
@RequestParam(value = "sortOrder", required = false) String sortOrder) {
// 创建 ProductSearchPageDTO 对象
ProductSearchPageRequest productSearchPageDTO = new ProductSearchPageRequest().setCid(cid).setKeyword(keyword)
.setPageNo(pageNo).setPageSize(pageSize);
if (StringUtil.hasText(sortField) && StringUtil.hasText(sortOrder)) {
productSearchPageDTO.setSorts(Collections.singletonList(new SortingField(sortField, sortOrder)));
}
// 执行搜索
// return success(productSearchService.getSearchPage(productSearchPageDTO));
return success(null);
}
@GetMapping("/condition") // TODO 芋艿后面把 BO 改成 VO
public CommonResult<ProductConditionResponse> condition(@RequestParam(value = "keyword", required = false) String keyword) {
// 创建 ProductConditionDTO 对象
ProductConditionRequest productConditionDTO = new ProductConditionRequest().setKeyword(keyword)
.setFields(Collections.singleton(ProductConditionRequest.FIELD_CATEGORY));
// 执行搜索
// return success(productSearchService.getSearchCondition(productConditionDTO));
return success(null);
}
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.mall.search.rest.convert.user;
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 UsersProductSearchConvert {
cn.iocoder.mall.search.biz.convert.ProductSearchConvert INSTANCE = Mappers.getMapper(cn.iocoder.mall.search.biz.convert.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);
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.mall.search.rest.request.user;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Collection;
/**
* 获得商品检索条件 DTO
*/
@Data
@Accessors(chain = true)
public class UsersProductConditionRequest{
/**
* Field - 商品分类
*/
public static final String FIELD_CATEGORY = "category";
/**
* 关键字
*/
private String keyword;
/**
* 需要返回的搜索条件的 fields
*/
private Collection<String> fields;
}

View File

@ -0,0 +1,48 @@
package cn.iocoder.mall.search.rest.request.user;
import cn.iocoder.common.framework.util.CollectionUtil;
import cn.iocoder.common.framework.vo.SortingField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
import java.util.Set;
/**
* Created with IDEA
*
* @author : lhl
* @version : 1.0
* @Time : 19:09
* @date : 2020/5/14
*/
@Data
@Accessors(chain = true)
public class UsersProductSearchPageRequest {
public static final Set<String> SORT_FIELDS = CollectionUtil.asSet("buyPrice");
/**
* 分类编号
*/
private Integer cid;
/**
* 关键字
*/
private String keyword;
/**
* 页码
*/
private Integer pageNo;
/**
* 分页大小
*/
private Integer pageSize;
/**
* 排序字段数组
*/
private List<SortingField> sorts;
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.mall.search.rest.response.user;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 商品搜索条件返回 BO
*/
@Data
@Accessors(chain = true)
public class UsersProductConditionResponse {
/**
* 商品分类数组
*/
private List<Category> categories;
@Data
@Accessors(chain = true)
public static class Category {
/**
* 分类编号
*/
private Integer id;
/**
* 分类名称
*/
private String name;
}
}

View File

@ -0,0 +1,22 @@
package cn.iocoder.mall.search.rest.response.user;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
public class UsersProductPageResponse implements Serializable {
/**
* 管理员数组
*/
private List<ProductResponse> list;
/**
* 总量
*/
private Integer total;
}

View File

@ -0,0 +1,86 @@
package cn.iocoder.mall.search.rest.response.user;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* 商品 ES BO
*/
@Data
@Accessors(chain = true)
public class UsersProductResponse implements Serializable {
private Integer id;
// ========== 基本信息 =========
/**
* SPU 名字
*/
private String name;
/**
* 卖点
*/
private String sellPoint;
/**
* 描述
*/
private String description;
/**
* 分类编号
*/
private Integer cid;
/**
* 分类名
*/
private String categoryName;
/**
* 商品主图地数组
*/
private List<String> picUrls;
// ========== 其他信息 =========
/**
* 是否上架商品是否可见
*
* true 为已上架
* false 为已下架
*/
private Boolean visible;
/**
* 排序字段
*/
private Integer sort;
// ========== Sku 相关字段 =========
/**
* 原价格单位
*/
private Integer originalPrice;
/**
* 购买价格单位
*/
private Integer buyPrice;
/**
* 库存数量
*/
private Integer quantity;
// ========== 促销活动相关字段 =========
// 目前只促销单体商品促销目前仅限制折扣
/**
* 促销活动编号
*/
private Integer promotionActivityId;
/**
* 促销活动标题
*/
private String promotionActivityTitle;
/**
* 促销活动类型
*/
private Integer promotionActivityType;
}

View File

@ -0,0 +1,12 @@
# 服务器的配置项
server:
port: 18099
servlet:
context-path: /search-api/
# Swagger 配置项
swagger:
title: 商品查询子系统
description: 商品查询子系统
version: 1.0.0
base-package: cn.iocoder.mall.search.rest.controller

View File

@ -0,0 +1,33 @@
<?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-api</artifactId>
<dependencies>
<!--mall-->
<dependency>
<artifactId>search-biz-api</artifactId>
<groupId>cn.iocoder.mall</groupId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,21 @@
package cn.iocoder.mall.search.biz.api.user;
import cn.iocoder.common.framework.vo.CommonResult;
public interface ProductSearchRPC {
CommonResult<Integer> rebuild();
/**
* 构建商品的搜索索引
*
* @param id 商品编号
* @return 构建结果
*/
CommonResult<Boolean> save(Integer id);
// ProductPageBO getSearchPage(ProductSearchPageDTO searchPageDTO);
//
// ProductConditionBO getSearchCondition(ProductConditionDTO conditionDTO);
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.mall.search.biz.request.user;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Collection;
/**
* 获得商品检索条件 DTO
*/
@Data
@Accessors(chain = true)
public class ProductConditionRequest {
/**
* Field - 商品分类
*/
public static final String FIELD_CATEGORY = "category";
/**
* 关键字
*/
private String keyword;
/**
* 需要返回的搜索条件的 fields
*/
private Collection<String> fields;
}

View File

@ -0,0 +1,48 @@
package cn.iocoder.mall.search.biz.request.user;
import cn.iocoder.common.framework.util.CollectionUtil;
import cn.iocoder.common.framework.vo.SortingField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
import java.util.Set;
/**
* Created with IDEA
*
* @author : lhl
* @version : 1.0
* @Time : 19:09
* @date : 2020/5/14
*/
@Data
@Accessors(chain = true)
public class ProductSearchPageRequest {
public static final Set<String> SORT_FIELDS = CollectionUtil.asSet("buyPrice");
/**
* 分类编号
*/
private Integer cid;
/**
* 关键字
*/
private String keyword;
/**
* 页码
*/
private Integer pageNo;
/**
* 分页大小
*/
private Integer pageSize;
/**
* 排序字段数组
*/
private List<SortingField> sorts;
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.mall.search.biz.response.user;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 商品搜索条件返回 BO
*/
@Data
@Accessors(chain = true)
public class ProductConditionResponse {
/**
* 商品分类数组
*/
private List<Category> categories;
@Data
@Accessors(chain = true)
public static class Category {
/**
* 分类编号
*/
private Integer id;
/**
* 分类名称
*/
private String name;
}
}

View File

@ -0,0 +1,22 @@
package cn.iocoder.mall.search.biz.response.user;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
public class ProductPageResponse implements Serializable {
/**
* 管理员数组
*/
private List<ProductResponse> list;
/**
* 总量
*/
private Integer total;
}

View File

@ -0,0 +1,86 @@
package cn.iocoder.mall.search.biz.response.user;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* 商品 ES BO
*/
@Data
@Accessors(chain = true)
public class ProductResponse implements Serializable {
private Integer id;
// ========== 基本信息 =========
/**
* SPU 名字
*/
private String name;
/**
* 卖点
*/
private String sellPoint;
/**
* 描述
*/
private String description;
/**
* 分类编号
*/
private Integer cid;
/**
* 分类名
*/
private String categoryName;
/**
* 商品主图地数组
*/
private List<String> picUrls;
// ========== 其他信息 =========
/**
* 是否上架商品是否可见
*
* true 为已上架
* false 为已下架
*/
private Boolean visible;
/**
* 排序字段
*/
private Integer sort;
// ========== Sku 相关字段 =========
/**
* 原价格单位
*/
private Integer originalPrice;
/**
* 购买价格单位
*/
private Integer buyPrice;
/**
* 库存数量
*/
private Integer quantity;
// ========== 促销活动相关字段 =========
// 目前只促销单体商品促销目前仅限制折扣
/**
* 促销活动编号
*/
private Integer promotionActivityId;
/**
* 促销活动标题
*/
private String promotionActivityTitle;
/**
* 促销活动类型
*/
private Integer promotionActivityType;
}

48
search/search-rpc/pom.xml Normal file
View File

@ -0,0 +1,48 @@
<?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>

View File

@ -0,0 +1,35 @@
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);
}

View File

@ -0,0 +1,29 @@
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);
}
}

View File

@ -0,0 +1,14 @@
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 服务注册中心的地址

View File

@ -0,0 +1,14 @@
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 服务注册中心的地址

View File

@ -0,0 +1,22 @@
# 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

View File

@ -1,9 +1,9 @@
package cn.iocoder.mall.search.api;
package cn.iocoder.mall.search.biz;
import cn.iocoder.mall.search.api.bo.ProductConditionBO;
import cn.iocoder.mall.search.api.bo.ProductPageBO;
import cn.iocoder.mall.search.api.dto.ProductConditionDTO;
import cn.iocoder.mall.search.api.dto.ProductSearchPageDTO;
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 {

View File

@ -1,4 +1,4 @@
package cn.iocoder.mall.search.api.bo;
package cn.iocoder.mall.search.biz.bo;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@ -1,4 +1,4 @@
package cn.iocoder.mall.search.api.bo;
package cn.iocoder.mall.search.biz.bo;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@ -1,4 +1,4 @@
package cn.iocoder.mall.search.api.bo;
package cn.iocoder.mall.search.biz.bo;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@ -1,4 +1,4 @@
package cn.iocoder.mall.search.api.dto;
package cn.iocoder.mall.search.biz.dto;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@ -1,4 +1,4 @@
package cn.iocoder.mall.search.api.dto;
package cn.iocoder.mall.search.biz.dto;
import cn.iocoder.common.framework.util.CollectionUtil;
import cn.iocoder.common.framework.vo.SortingField;

View File

@ -3,7 +3,7 @@ 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.api.bo.ProductBO;
import cn.iocoder.mall.search.biz.bo.ProductBO;
import cn.iocoder.mall.search.biz.dataobject.ESProductDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;

View File

@ -1,7 +1,7 @@
package cn.iocoder.mall.search.biz.mq;
import cn.iocoder.mall.product.api.message.ProductUpdateMessage;
import cn.iocoder.mall.search.api.ProductSearchService;
import cn.iocoder.mall.search.biz.ProductSearchService;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -1,4 +1,4 @@
package cn.iocoder.mall.search.biz.service;
package cn.iocoder.mall.search.biz.api;
import cn.iocoder.common.framework.util.CollectionUtil;
import cn.iocoder.common.framework.util.StringUtil;
@ -9,11 +9,11 @@ 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.api.ProductSearchService;
import cn.iocoder.mall.search.api.bo.ProductConditionBO;
import cn.iocoder.mall.search.api.bo.ProductPageBO;
import cn.iocoder.mall.search.api.dto.ProductConditionDTO;
import cn.iocoder.mall.search.api.dto.ProductSearchPageDTO;
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;

View File

@ -1,4 +1,4 @@
package cn.iocoder.mall.search.biz.service;
package cn.iocoder.mall.search.biz.api;
import cn.iocoder.mall.search.biz.dao.ProductRepository;
import org.junit.Test;