迁移完成商品搜索的插入
parent
981b3d87e2
commit
0252bd0f0b
|
@ -36,8 +36,8 @@ public interface ProductSkuConvert {
|
||||||
List<ProductSkuRespDTO> convertList03(List<ProductSkuBO> list);
|
List<ProductSkuRespDTO> convertList03(List<ProductSkuBO> list);
|
||||||
|
|
||||||
@Named("translateAttrValueIdsFromString")
|
@Named("translateAttrValueIdsFromString")
|
||||||
default List<String> translateAttrValueIdsFromString(String attrValueIdsStar) {
|
default List<Integer> translateAttrValueIdsFromString(String attrValueIdsStar) {
|
||||||
return StringUtils.split(attrValueIdsStar, ",");
|
return StringUtils.splitToInt(attrValueIdsStar, ",");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Named("translateAttrValueIdsFromList")
|
@Named("translateAttrValueIdsFromList")
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package cn.iocoder.mall.productservice.service.sku.bo;
|
package cn.iocoder.mall.productservice.service.sku.bo;
|
||||||
|
|
||||||
import cn.iocoder.mall.productservice.dal.mysql.dataobject.attr.ProductAttrValueDO;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商品 SKU BO
|
* 商品 SKU BO
|
||||||
|
@ -33,11 +33,9 @@ public class ProductSkuBO {
|
||||||
*/
|
*/
|
||||||
private String picUrl;
|
private String picUrl;
|
||||||
/**
|
/**
|
||||||
* 规格值({@link ProductAttrValueDO})数组
|
* 规格值编号数组
|
||||||
*
|
|
||||||
* 数组,以逗号分隔
|
|
||||||
*/
|
*/
|
||||||
private String attrs;
|
private List<Integer> attrValueIds;
|
||||||
/**
|
/**
|
||||||
* 价格,单位:分
|
* 价格,单位:分
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -32,19 +32,6 @@ public class AdminsProductAttrController {
|
||||||
@Reference(validation = "true", version = "${dubbo.provider.ProductAttrService.version}")
|
@Reference(validation = "true", version = "${dubbo.provider.ProductAttrService.version}")
|
||||||
private ProductAttrService productAttrService;
|
private ProductAttrService productAttrService;
|
||||||
|
|
||||||
@GetMapping("/attr/page")
|
|
||||||
@ApiOperation("获得规格分页")
|
|
||||||
public CommonResult<AdminsProductAttrPageVO> attrPage(@RequestParam(value = "name", required = false) String name,
|
|
||||||
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
|
|
||||||
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
|
|
||||||
// 创建 ProductAttrPageDTO 对象
|
|
||||||
ProductAttrPageDTO productAttrPageDTO = new ProductAttrPageDTO().setName(name).setPageNo(pageNo).setPageSize(pageSize);
|
|
||||||
// 查询分页
|
|
||||||
ProductAttrPageBO result = productAttrService.getProductAttrPage(productAttrPageDTO);
|
|
||||||
// 返回结果
|
|
||||||
return success(ProductAttrConvert.INSTANCE.convert2(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/attr/tree")
|
@GetMapping("/attr/tree")
|
||||||
@ApiOperation(value = "获得规格树结构", notes = "该接口返回的信息更为精简。一般用于前端缓存数据字典到本地。")
|
@ApiOperation(value = "获得规格树结构", notes = "该接口返回的信息更为精简。一般用于前端缓存数据字典到本地。")
|
||||||
public CommonResult<List<AdminsProductAttrSimpleVO>> tree() {
|
public CommonResult<List<AdminsProductAttrSimpleVO>> tree() {
|
||||||
|
@ -54,87 +41,4 @@ public class AdminsProductAttrController {
|
||||||
return success(ProductAttrConvert.INSTANCE.convert(result));
|
return success(ProductAttrConvert.INSTANCE.convert(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/attr/add")
|
|
||||||
@ApiOperation(value = "创建商品规格")
|
|
||||||
@ApiImplicitParams({
|
|
||||||
@ApiImplicitParam(name = "name", value = "规格名", required = true, example = "颜色")
|
|
||||||
})
|
|
||||||
public CommonResult<AdminsProductAttrVO> addAttr(@RequestParam("name") String name) {
|
|
||||||
// 创建 ProductAttrAddDTO 对象
|
|
||||||
ProductAttrAddDTO productAttrAddDTO = new ProductAttrAddDTO().setName(name);
|
|
||||||
// 添加
|
|
||||||
ProductAttrBO result = productAttrService.addProductAttr(AdminSecurityContextHolder.getContext().getAdminId(), productAttrAddDTO);
|
|
||||||
// 返回结果
|
|
||||||
return success(ProductAttrConvert.INSTANCE.convert3(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/attr/update")
|
|
||||||
@ApiOperation(value = "修改商品规格")
|
|
||||||
@ApiImplicitParams({
|
|
||||||
@ApiImplicitParam(name = "id", value = "规格编号", required = true, example = "1"),
|
|
||||||
@ApiImplicitParam(name = "name", value = "规格名", required = true, example = "颜色")
|
|
||||||
})
|
|
||||||
public CommonResult<Boolean> updateAttr(@RequestParam("id") Integer id,
|
|
||||||
@RequestParam("name") String name) {
|
|
||||||
// 创建 ProductAttrUpdateDTO 对象
|
|
||||||
ProductAttrUpdateDTO productAttrUpdateDTO = new ProductAttrUpdateDTO().setId(id).setName(name);
|
|
||||||
// 更新
|
|
||||||
return success(productAttrService.updateProductAttr(AdminSecurityContextHolder.getContext().getAdminId(), productAttrUpdateDTO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/attr/update_status")
|
|
||||||
@ApiOperation(value = "修改商品规格状态")
|
|
||||||
@ApiImplicitParams({
|
|
||||||
@ApiImplicitParam(name = "id", value = "规格编号", required = true, example = "100"),
|
|
||||||
@ApiImplicitParam(name = "status", value = "状态", required = true, example = "1")
|
|
||||||
})
|
|
||||||
public CommonResult<Boolean> updateAttrStatus(@RequestParam("id") Integer id,
|
|
||||||
@RequestParam("status") Integer status) {
|
|
||||||
return success(productAttrService.updateProductAttrStatus(AdminSecurityContextHolder.getContext().getAdminId(), id, status));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO 芋艿 暂时不考虑 delete Attr 。因为关联逻辑比较多
|
|
||||||
|
|
||||||
@PostMapping("/attr_value/add")
|
|
||||||
@ApiOperation(value = "创建商品规格值")
|
|
||||||
@ApiImplicitParams({
|
|
||||||
@ApiImplicitParam(name = "attrId", value = "规格编号", required = true, example = "100"),
|
|
||||||
@ApiImplicitParam(name = "name", value = "规格值", required = true, example = "蓝色")
|
|
||||||
})
|
|
||||||
public CommonResult<AdminsProductAttrValueVO> addAttrValue(@RequestParam("attrId") Integer attrId,
|
|
||||||
@RequestParam("name") String name) {
|
|
||||||
// 创建 ProductAttrValueAddDTO 对象
|
|
||||||
ProductAttrValueAddDTO productAttrValueAddDTO = new ProductAttrValueAddDTO().setAttrId(attrId).setName(name);
|
|
||||||
// 添加
|
|
||||||
ProductAttrValueBO result = productAttrService.addProductAttrValue(AdminSecurityContextHolder.getContext().getAdminId(), productAttrValueAddDTO);
|
|
||||||
// 返回结果
|
|
||||||
return success(ProductAttrConvert.INSTANCE.convert4(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/attr_value/update")
|
|
||||||
@ApiOperation(value = "修改商品规格值")
|
|
||||||
@ApiImplicitParams({
|
|
||||||
@ApiImplicitParam(name = "id", value = "规格值编号", required = true, example = "100"),
|
|
||||||
@ApiImplicitParam(name = "name", value = "规格值", required = true, example = "蓝色")
|
|
||||||
})
|
|
||||||
public CommonResult<Boolean> updateAttrValue(@RequestParam("id") Integer id,
|
|
||||||
@RequestParam("name") String name) {
|
|
||||||
// 创建 ProductAttrValueUpdateDTO 对象
|
|
||||||
ProductAttrValueUpdateDTO productAttrValueUpdateDTO = new ProductAttrValueUpdateDTO().setId(id).setName(name);
|
|
||||||
// 更新
|
|
||||||
return success(productAttrService.updateProductAttrValue(AdminSecurityContextHolder.getContext().getAdminId(), productAttrValueUpdateDTO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/attr_value/update_status")
|
|
||||||
@ApiImplicitParams({
|
|
||||||
@ApiImplicitParam(name = "id", value = "规格编号", required = true, example = "100"),
|
|
||||||
@ApiImplicitParam(name = "status", value = "状态", required = true, example = "1")
|
|
||||||
})
|
|
||||||
public CommonResult<Boolean> updateAttrValueStatus(@RequestParam("id") Integer id,
|
|
||||||
@RequestParam("status") Integer status) {
|
|
||||||
return success(productAttrService.updateProductAttrValueStatus(AdminSecurityContextHolder.getContext().getAdminId(), id, status));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO 芋艿 暂时不考虑 delete Attr Value 。因为关联逻辑比较多
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
package cn.iocoder.mall.searchservice.rpc;
|
|
@ -0,0 +1,7 @@
|
||||||
|
package cn.iocoder.mall.searchservice.rpc.product;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品搜索 RPC 接口
|
||||||
|
*/
|
||||||
|
public interface SearchProductRpc {
|
||||||
|
}
|
|
@ -32,6 +32,13 @@
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<!-- 搜索服务 -->
|
||||||
|
<groupId>cn.iocoder.mall</groupId>
|
||||||
|
<artifactId>search-service-api</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- MQ 相关 -->
|
<!-- MQ 相关 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.mall</groupId>
|
<groupId>cn.iocoder.mall</groupId>
|
||||||
|
|
|
@ -1,4 +1,15 @@
|
||||||
package cn.iocoder.mall.searchservice;
|
package cn.iocoder.mall.searchservice;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
public class SearchServiceApplication {
|
public class SearchServiceApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// 解决 ES java.lang.IllegalStateException: availableProcessors is already
|
||||||
|
System.setProperty("es.set.netty.runtime.available.processors", "false");
|
||||||
|
SpringApplication.run(SearchServiceApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
package cn.iocoder.mall.searchservice.convert;
|
|
@ -0,0 +1,30 @@
|
||||||
|
package cn.iocoder.mall.searchservice.convert.product;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.productservice.rpc.category.dto.ProductCategoryRespDTO;
|
||||||
|
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO;
|
||||||
|
import cn.iocoder.mall.searchservice.dal.es.dataobject.ESProductDO;
|
||||||
|
import cn.iocoder.mall.searchservice.service.product.bo.SearchProductCreateBO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface SearchProductConvert {
|
||||||
|
|
||||||
|
SearchProductConvert INSTANCE = Mappers.getMapper(SearchProductConvert.class);
|
||||||
|
|
||||||
|
|
||||||
|
@Mapping(source = "spu.id", target = "id")
|
||||||
|
@Mapping(source = "spu.name", target = "name")
|
||||||
|
@Mapping(source = "spu.sellPoint", target = "sellPoint")
|
||||||
|
@Mapping(source = "spu.description", target = "description")
|
||||||
|
@Mapping(source = "spu.cid", target = "cid")
|
||||||
|
@Mapping(source = "category.name", target = "categoryName")
|
||||||
|
@Mapping(source = "spu.picUrls", target = "picUrls")
|
||||||
|
@Mapping(source = "spu.visible", target = "visible")
|
||||||
|
@Mapping(source = "spu.sort", target = "sort")
|
||||||
|
SearchProductCreateBO convert(ProductSpuRespDTO spu, ProductCategoryRespDTO category);
|
||||||
|
|
||||||
|
ESProductDO convert(SearchProductCreateBO bean);
|
||||||
|
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ import java.util.List;
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface ProductRepository extends ElasticsearchRepository<ESProductDO, Integer> {
|
public interface ESProductRepository extends ElasticsearchRepository<ESProductDO, Integer> {
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ESProductDO findByName(String name);
|
ESProductDO findByName(String name);
|
|
@ -1,40 +0,0 @@
|
||||||
package cn.iocoder.mall.searchservice.manager.product;
|
|
||||||
|
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
|
||||||
import cn.iocoder.mall.productservice.rpc.category.ProductCategoryRpc;
|
|
||||||
import cn.iocoder.mall.productservice.rpc.sku.ProductSkuRpc;
|
|
||||||
import cn.iocoder.mall.productservice.rpc.sku.dto.ProductSkuListQueryReqDTO;
|
|
||||||
import cn.iocoder.mall.productservice.rpc.sku.dto.ProductSkuRespDTO;
|
|
||||||
import cn.iocoder.mall.productservice.rpc.spu.ProductSpuRpc;
|
|
||||||
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO;
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class ProductSearchManager {
|
|
||||||
|
|
||||||
@DubboReference(version = "${dubbo.consumer.ProductSpuRpc.version}")
|
|
||||||
private ProductSpuRpc productSpuRpc;
|
|
||||||
@DubboReference(version = "${dubbo.consumer.ProductSkuRpc.version}")
|
|
||||||
private ProductSkuRpc productSkuRpc;
|
|
||||||
@DubboReference(version = "${dubbo.consumer.ProductCategoryRpc.version}")
|
|
||||||
private ProductCategoryRpc productCategoryRpc;
|
|
||||||
|
|
||||||
// @DubboReference( version = "${dubbo.consumer.CartService.version}")
|
|
||||||
// private CartService cartService;
|
|
||||||
|
|
||||||
public Boolean saveProduct(Integer id) {
|
|
||||||
// 获得商品 SPU
|
|
||||||
CommonResult<ProductSpuRespDTO> productSpuResult = productSpuRpc.getProductSpu(id);
|
|
||||||
productSpuResult.checkError();
|
|
||||||
// 获得商品 SKU
|
|
||||||
CommonResult<List<ProductSkuRespDTO>> listProductSkusResult =
|
|
||||||
productSkuRpc.listProductSkus(new ProductSkuListQueryReqDTO().setProductSpuId(id));
|
|
||||||
listProductSkusResult.checkError();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
package cn.iocoder.mall.searchservice.manager.product;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.util.CollectionUtils;
|
||||||
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
|
import cn.iocoder.mall.productservice.rpc.category.ProductCategoryRpc;
|
||||||
|
import cn.iocoder.mall.productservice.rpc.category.dto.ProductCategoryRespDTO;
|
||||||
|
import cn.iocoder.mall.productservice.rpc.sku.ProductSkuRpc;
|
||||||
|
import cn.iocoder.mall.productservice.rpc.sku.dto.ProductSkuListQueryReqDTO;
|
||||||
|
import cn.iocoder.mall.productservice.rpc.sku.dto.ProductSkuRespDTO;
|
||||||
|
import cn.iocoder.mall.productservice.rpc.spu.ProductSpuRpc;
|
||||||
|
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO;
|
||||||
|
import cn.iocoder.mall.searchservice.convert.product.SearchProductConvert;
|
||||||
|
import cn.iocoder.mall.searchservice.service.product.SearchProductService;
|
||||||
|
import cn.iocoder.mall.searchservice.service.product.bo.SearchProductCreateBO;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.dubbo.config.annotation.DubboReference;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class SearchProductManager {
|
||||||
|
|
||||||
|
@DubboReference(version = "${dubbo.consumer.ProductSpuRpc.version}")
|
||||||
|
private ProductSpuRpc productSpuRpc;
|
||||||
|
@DubboReference(version = "${dubbo.consumer.ProductSkuRpc.version}")
|
||||||
|
private ProductSkuRpc productSkuRpc;
|
||||||
|
@DubboReference(version = "${dubbo.consumer.ProductCategoryRpc.version}")
|
||||||
|
private ProductCategoryRpc productCategoryRpc;
|
||||||
|
|
||||||
|
// @DubboReference( version = "${dubbo.consumer.CartService.version}")
|
||||||
|
// private CartService cartService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SearchProductService searchProductService;
|
||||||
|
|
||||||
|
public Boolean saveProduct(Integer id) {
|
||||||
|
// 获得商品 SPU
|
||||||
|
CommonResult<ProductSpuRespDTO> productSpuResult = productSpuRpc.getProductSpu(id);
|
||||||
|
productSpuResult.checkError();
|
||||||
|
if (productSpuResult.getData() == null) {
|
||||||
|
log.error("[saveProduct][商品 SPU({}) 不存在]", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 获得商品 SKU
|
||||||
|
CommonResult<List<ProductSkuRespDTO>> listProductSkusResult =
|
||||||
|
productSkuRpc.listProductSkus(new ProductSkuListQueryReqDTO().setProductSpuId(id));
|
||||||
|
listProductSkusResult.checkError();
|
||||||
|
if (CollectionUtils.isEmpty(listProductSkusResult.getData())) {
|
||||||
|
log.error("[saveProduct][商品 SPU({}) 的 SKU 不存在]", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 获得商品分类
|
||||||
|
CommonResult<ProductCategoryRespDTO> getProductCategoryResult =
|
||||||
|
productCategoryRpc.getProductCategory(productSpuResult.getData().getCid());
|
||||||
|
getProductCategoryResult.checkError();
|
||||||
|
if (getProductCategoryResult.getData() == null) {
|
||||||
|
log.error("[saveProduct][商品 SPU({}) 的分类({}) 不存在]", id, productSpuResult.getData().getCid());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 保存商品到 ES 中
|
||||||
|
SearchProductCreateBO searchProductCreateBO = SearchProductConvert.INSTANCE.convert(
|
||||||
|
productSpuResult.getData(), getProductCategoryResult.getData());
|
||||||
|
ProductSkuRespDTO productSku = listProductSkusResult.getData().stream()
|
||||||
|
.min(Comparator.comparing(ProductSkuRespDTO::getPrice)).orElse(null);
|
||||||
|
assert productSku != null;
|
||||||
|
// // 价格计算 TODO 芋艿:需要补充,暂时使用这个逻辑
|
||||||
|
// CalcSkuPriceBO calSkuPriceResult = cartService.calcSkuPrice(sku.getId());
|
||||||
|
searchProductCreateBO.setOriginalPrice(productSku.getPrice());
|
||||||
|
searchProductCreateBO.setBuyPrice(productSku.getPrice());
|
||||||
|
searchProductCreateBO.setQuantity(productSku.getQuantity());
|
||||||
|
searchProductService.createSearchProduct(searchProductCreateBO);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package cn.iocoder.mall.searchservice.mq.consumer;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.searchservice.manager.product.SearchProductManager;
|
||||||
|
import cn.iocoder.mall.searchservice.mq.consumer.message.ProductUpdateMessage;
|
||||||
|
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||||
|
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RocketMQMessageListener(
|
||||||
|
topic = ProductUpdateMessage.TOPIC,
|
||||||
|
consumerGroup = "${spring.application.name}-consumer-group-" + ProductUpdateMessage.TOPIC
|
||||||
|
)
|
||||||
|
public class PayTransactionPaySuccessConsumer implements RocketMQListener<ProductUpdateMessage> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SearchProductManager productSearchManager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(ProductUpdateMessage message) {
|
||||||
|
Boolean result = productSearchManager.saveProduct(message.getId());
|
||||||
|
Assert.isTrue(result, String.format("重构商品(%d)的 ES 索引,必然成功。实际结果是 %s", message.getId(), result));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package cn.iocoder.mall.searchservice.mq.consumer.message;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品更新(包括创建)消息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class ProductUpdateMessage {
|
||||||
|
|
||||||
|
public static final String TOPIC = "ProductUpdate";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品编号
|
||||||
|
*/
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
package cn.iocoder.mall.searchservice.rpc;
|
|
@ -0,0 +1,7 @@
|
||||||
|
package cn.iocoder.mall.searchservice.rpc.product;
|
||||||
|
|
||||||
|
import org.apache.dubbo.config.annotation.DubboService;
|
||||||
|
|
||||||
|
@DubboService
|
||||||
|
public class SearchProductRpcImpl implements SearchProductRpc {
|
||||||
|
}
|
|
@ -1,7 +0,0 @@
|
||||||
package cn.iocoder.mall.searchservice.service.product;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class ProductSearchService {
|
|
||||||
}
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package cn.iocoder.mall.searchservice.service.product;
|
||||||
|
|
||||||
|
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.service.product.bo.SearchProductCreateBO;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SearchProductService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ESProductRepository productRepository;
|
||||||
|
|
||||||
|
public void createSearchProduct(SearchProductCreateBO createBO) {
|
||||||
|
ESProductDO productDO = SearchProductConvert.INSTANCE.convert(createBO);
|
||||||
|
productRepository.save(productDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package cn.iocoder.mall.searchservice.service.product.bo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索商品创建 BO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors
|
||||||
|
public class SearchProductCreateBO {
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
|
@ -5,6 +5,16 @@ spring:
|
||||||
# Profile 的配置项
|
# Profile 的配置项
|
||||||
profiles:
|
profiles:
|
||||||
active: local
|
active: local
|
||||||
|
# Elasticsearch 配置项
|
||||||
|
data:
|
||||||
|
elasticsearch:
|
||||||
|
cluster-name: elasticsearch
|
||||||
|
cluster-nodes: 400-infra.server.iocoder.cn:9300
|
||||||
|
repositories:
|
||||||
|
enable: true
|
||||||
|
elasticsearch:
|
||||||
|
rest:
|
||||||
|
uris: 400-infra.server.iocoder.cn:9200
|
||||||
|
|
||||||
# Dubbo 配置项
|
# Dubbo 配置项
|
||||||
dubbo:
|
dubbo:
|
||||||
|
@ -17,7 +27,7 @@ dubbo:
|
||||||
port: -1
|
port: -1
|
||||||
# Dubbo 提供服务的扫描基础包
|
# Dubbo 提供服务的扫描基础包
|
||||||
scan:
|
scan:
|
||||||
base-packages: cn.iocoder.mall.searrchservice.rpc
|
base-packages: cn.iocoder.mall.searchservice.rpc
|
||||||
# Dubbo 服务提供者的配置
|
# Dubbo 服务提供者的配置
|
||||||
provider:
|
provider:
|
||||||
filter: -exception
|
filter: -exception
|
||||||
|
@ -31,16 +41,16 @@ dubbo:
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
ProductSpuRpc:
|
ProductSpuRpc:
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
|
ProductSkuRpc:
|
||||||
|
version: 1.0.0
|
||||||
|
|
||||||
# RocketMQ 配置项
|
# RocketMQ 配置项
|
||||||
rocketmq:
|
rocketmq:
|
||||||
name-server: 400-infra.server.iocoder.cn:9876
|
name-server: 400-infra.server.iocoder.cn:9876
|
||||||
producer:
|
|
||||||
group: ${spring.application.name}-producer-group
|
|
||||||
|
|
||||||
# Mall 配置项
|
# Mall 配置项
|
||||||
mall:
|
mall:
|
||||||
# 错误码配置项对应 ErrorCodeProperties 配置类
|
# 错误码配置项对应 ErrorCodeProperties 配置类
|
||||||
error-code:
|
error-code:
|
||||||
group: ${spring.application.name}
|
group: ${spring.application.name}
|
||||||
constants-class: cn.iocoder.mall.searrchservice.enums.ProductErrorCodeConstants
|
constants-class: cn.iocoder.mall.searchservice.enums.ProductErrorCodeConstants
|
||||||
|
|
|
@ -1,29 +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-application</artifactId>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<!-- Mall 相关 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.mall</groupId>
|
|
||||||
<artifactId>search-rest</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.mall</groupId>
|
|
||||||
<artifactId>search-rpc</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
|
@ -1,26 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
swagger:
|
|
||||||
enable: true
|
|
||||||
title: 搜索子系统
|
|
||||||
description: 搜索子系统
|
|
||||||
version: 1.0.0
|
|
||||||
base-package: cn.iocoder.mall.search.application.controller
|
|
|
@ -1,6 +0,0 @@
|
||||||
spring:
|
|
||||||
application:
|
|
||||||
name: search-application
|
|
||||||
# Profile 的配置项
|
|
||||||
profiles:
|
|
||||||
active: local
|
|
|
@ -1,27 +0,0 @@
|
||||||
package cn.iocoder.mall.search.biz.mq;
|
|
||||||
|
|
||||||
import cn.iocoder.mall.product.api.message.ProductUpdateMessage;
|
|
||||||
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;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@RocketMQMessageListener(
|
|
||||||
topic = ProductUpdateMessage.TOPIC,
|
|
||||||
consumerGroup = "search-consumer-group-" + ProductUpdateMessage.TOPIC
|
|
||||||
)
|
|
||||||
public class PayTransactionPaySuccessConsumer implements RocketMQListener<ProductUpdateMessage> {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ProductSearchService productSearchService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMessage(ProductUpdateMessage message) {
|
|
||||||
Boolean result = productSearchService.save(message.getId());
|
|
||||||
Assert.isTrue(result, String.format("重构商品 ES 索引,必然成功。实际结果是 %s", result));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -68,27 +68,6 @@ public class ProductSearchServiceImpl implements ProductSearchService {
|
||||||
return rebuildCounts;
|
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
|
@Override
|
||||||
public ProductPageBO getSearchPage(ProductSearchPageDTO searchPageDTO) {
|
public ProductPageBO getSearchPage(ProductSearchPageDTO searchPageDTO) {
|
||||||
checkSortFieldInvalid(searchPageDTO.getSorts());
|
checkSortFieldInvalid(searchPageDTO.getSorts());
|
||||||
|
|
Loading…
Reference in New Issue