From 4063c8b06373a4d23b3a2ac6e2edf010871d9b46 Mon Sep 17 00:00:00 2001 From: paulGao Date: Tue, 7 Sep 2021 01:55:58 +0800 Subject: [PATCH] improve esGoods parameter selector buckets(not get category and brand from db, add EsGoodsIndex Field BrandName,BrandUrl,CategoryNamePath) --- .../lili/listener/GoodsMessageListener.java | 197 +++++++++++++++--- .../cn/lili/common/security/SecurityBean.java | 2 - .../BaseElasticsearchService.java | 30 +++ .../goods/service/CategoryService.java | 8 + .../goods/service/ParametersService.java | 10 + .../serviceimpl/CategoryServiceImpl.java | 48 ++--- .../serviceimpl/GoodsSkuServiceImpl.java | 16 +- .../serviceimpl/ParametersServiceImpl.java | 109 +++++++++- .../search/entity/dos/EsGoodsIndex.java | 34 ++- .../search/service/EsGoodsIndexService.java | 19 +- .../serviceimpl/EsGoodsIndexServiceImpl.java | 79 ++++--- .../serviceimpl/EsGoodsSearchServiceImpl.java | 103 +++++---- .../store/service/StoreGoodsLabelService.java | 8 + .../StoreGoodsLabelServiceImpl.java | 35 +++- .../cn/lili/rocketmq/tags/GoodsTagsEnum.java | 8 + .../goods/ParameterManagerController.java | 2 +- .../other/ElasticsearchController.java | 38 +++- .../cn/lili/test/elasticsearch/EsTest.java | 48 ++++- .../cn/lili/test/promotion/SeckillTest.java | 51 ++--- 19 files changed, 650 insertions(+), 195 deletions(-) diff --git a/consumer/src/main/java/cn/lili/listener/GoodsMessageListener.java b/consumer/src/main/java/cn/lili/listener/GoodsMessageListener.java index 9091ce03..ab36fce2 100644 --- a/consumer/src/main/java/cn/lili/listener/GoodsMessageListener.java +++ b/consumer/src/main/java/cn/lili/listener/GoodsMessageListener.java @@ -1,17 +1,23 @@ package cn.lili.listener; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.ArrayUtil; import cn.hutool.json.JSONUtil; import cn.lili.event.GoodsCommentCompleteEvent; import cn.lili.modules.distribution.entity.dos.DistributionGoods; import cn.lili.modules.distribution.entity.dos.DistributionSelectedGoods; import cn.lili.modules.distribution.service.DistributionGoodsService; import cn.lili.modules.distribution.service.DistributionSelectedGoodsService; +import cn.lili.modules.goods.entity.dos.Brand; +import cn.lili.modules.goods.entity.dos.Category; import cn.lili.modules.goods.entity.dos.Goods; import cn.lili.modules.goods.entity.dos.GoodsSku; import cn.lili.modules.goods.entity.dto.GoodsCompleteMessage; import cn.lili.modules.goods.entity.dto.GoodsParamsDTO; import cn.lili.modules.goods.entity.enums.GoodsAuthEnum; import cn.lili.modules.goods.entity.enums.GoodsStatusEnum; +import cn.lili.modules.goods.service.BrandService; +import cn.lili.modules.goods.service.CategoryService; import cn.lili.modules.goods.service.GoodsService; import cn.lili.modules.goods.service.GoodsSkuService; import cn.lili.modules.member.entity.dos.FootPrint; @@ -20,6 +26,8 @@ import cn.lili.modules.member.service.FootprintService; import cn.lili.modules.member.service.GoodsCollectionService; import cn.lili.modules.search.entity.dos.EsGoodsIndex; import cn.lili.modules.search.service.EsGoodsIndexService; +import cn.lili.modules.store.entity.dos.StoreGoodsLabel; +import cn.lili.modules.store.service.StoreGoodsLabelService; import cn.lili.modules.store.service.StoreService; import cn.lili.rocketmq.tags.GoodsTagsEnum; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -31,6 +39,8 @@ import org.apache.rocketmq.spring.core.RocketMQListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -89,6 +99,21 @@ public class GoodsMessageListener implements RocketMQListener { */ @Autowired private DistributionSelectedGoodsService distributionSelectedGoodsService; + /** + * 分类 + */ + @Autowired + private CategoryService categoryService; + /** + * 品牌 + */ + @Autowired + private BrandService brandService; + /** + * 店铺商品分类 + */ + @Autowired + private StoreGoodsLabelService storeGoodsLabelService; @Override public void onMessage(MessageExt messageExt) { @@ -101,37 +126,34 @@ public class GoodsMessageListener implements RocketMQListener { break; //生成索引 case GENERATOR_GOODS_INDEX: - String goodsJsonStr = new String(messageExt.getBody()); - Goods goods = JSONUtil.toBean(goodsJsonStr, Goods.class); - //如果商品通过审核&&并且已上架 - List goodsSkuList = this.goodsSkuService.list(new LambdaQueryWrapper().eq(GoodsSku::getGoodsId, goods.getId())); - if (goods.getIsAuth().equals(GoodsAuthEnum.PASS.name()) - && goods.getMarketEnable().equals(GoodsStatusEnum.UPPER.name()) - && Boolean.FALSE.equals(goods.getDeleteFlag())) { - for (GoodsSku goodsSku : goodsSkuList) { - EsGoodsIndex esGoodsOld = goodsIndexService.findById(goodsSku.getId()); - EsGoodsIndex goodsIndex = new EsGoodsIndex(goodsSku); - if (goods.getParams() != null && !goods.getParams().isEmpty()) { - List goodsParamDTOS = JSONUtil.toList(goods.getParams(), GoodsParamsDTO.class); - goodsIndex = new EsGoodsIndex(goodsSku, goodsParamDTOS); - } - //如果商品库存不为0,并且es中有数据 - if (goodsSku.getQuantity() > 0 && esGoodsOld == null) { - log.info("生成商品索引 {}", goodsIndex); - this.goodsIndexService.addIndex(goodsIndex); - } else if (goodsSku.getQuantity() > 0 && esGoodsOld != null) { - goodsIndexService.updateIndex(goodsIndex); - } - } + try { + String goodsJsonStr = new String(messageExt.getBody()); + Goods goods = JSONUtil.toBean(goodsJsonStr, Goods.class); + updateGoodsIndex(goods); + } catch (Exception e) { + log.error("生成商品索引事件执行异常,商品信息 {}", new String(messageExt.getBody())); } - //如果商品状态值不支持es搜索,那么将商品信息做下架处理 - else { - for (GoodsSku goodsSku : goodsSkuList) { - EsGoodsIndex esGoodsOld = goodsIndexService.findById(goodsSku.getId()); - if (esGoodsOld != null) { - goodsIndexService.deleteIndexById(goodsSku.getId()); - } + break; + case UPDATE_GOODS_INDEX: + try { + String goodsIdsJsonStr = new String(messageExt.getBody()); + List goodsList = new ArrayList<>(); + for (String goodsId : JSONUtil.toList(goodsIdsJsonStr, String.class)) { + Goods goods = goodsService.getById(goodsId); + goodsList.add(goods); } + this.updateGoodsIndex(goodsList); + } catch (Exception e) { + log.error("更新商品索引事件执行异常,商品信息 {}", new String(messageExt.getBody())); + } + break; + case RESET_GOODS_INDEX: + try { + String goodsIdsJsonStr = new String(messageExt.getBody()); + List goodsIndices = JSONUtil.toList(goodsIdsJsonStr, EsGoodsIndex.class); + goodsIndexService.updateBulkIndex(goodsIndices); + } catch (Exception e) { + log.error("重置商品索引事件执行异常,商品信息 {}", new String(messageExt.getBody())); } break; //审核商品 @@ -177,6 +199,117 @@ public class GoodsMessageListener implements RocketMQListener { } } + /** + * 更新商品索引 + * + * @param goodsList 商品列表消息 + */ + private void updateGoodsIndex(List goodsList) { + List goodsIndices = new ArrayList<>(); + for (Goods goods : goodsList) { + //如果商品通过审核&&并且已上架 + List goodsSkuList = this.goodsSkuService.list(new LambdaQueryWrapper().eq(GoodsSku::getGoodsId, goods.getId()).gt(GoodsSku::getQuantity, 0)); + if (goods.getIsAuth().equals(GoodsAuthEnum.PASS.name()) + && goods.getMarketEnable().equals(GoodsStatusEnum.UPPER.name()) + && Boolean.FALSE.equals(goods.getDeleteFlag())) { + goodsSkuList.forEach(goodsSku -> { + EsGoodsIndex goodsIndex = this.settingUpGoodsIndexData(goods, goodsSku); + goodsIndices.add(goodsIndex); + }); + } + //如果商品状态值不支持es搜索,那么将商品信息做下架处理 + else { + for (GoodsSku goodsSku : goodsSkuList) { + EsGoodsIndex esGoodsOld = goodsIndexService.findById(goodsSku.getId()); + if (esGoodsOld != null) { + goodsIndexService.deleteIndexById(goodsSku.getId()); + } + } + } + } + goodsIndexService.updateBulkIndex(goodsIndices); + } + + /** + * 更新商品索引 + * + * @param goods 商品消息 + */ + private void updateGoodsIndex(Goods goods) { + //如果商品通过审核&&并且已上架 + List goodsSkuList = this.goodsSkuService.list(new LambdaQueryWrapper().eq(GoodsSku::getGoodsId, goods.getId())); + if (goods.getIsAuth().equals(GoodsAuthEnum.PASS.name()) + && goods.getMarketEnable().equals(GoodsStatusEnum.UPPER.name()) + && Boolean.FALSE.equals(goods.getDeleteFlag())) { + this.generatorGoodsIndex(goods, goodsSkuList); + } + //如果商品状态值不支持es搜索,那么将商品信息做下架处理 + else { + for (GoodsSku goodsSku : goodsSkuList) { + EsGoodsIndex esGoodsOld = goodsIndexService.findById(goodsSku.getId()); + if (esGoodsOld != null) { + goodsIndexService.deleteIndexById(goodsSku.getId()); + } + } + } + } + + /** + * 生成商品索引 + * + * @param goods 商品信息 + * @param goodsSkuList 商品sku信息 + */ + private void generatorGoodsIndex(Goods goods, List goodsSkuList) { + for (GoodsSku goodsSku : goodsSkuList) { + EsGoodsIndex esGoodsOld = goodsIndexService.findById(goodsSku.getId()); + EsGoodsIndex goodsIndex = this.settingUpGoodsIndexData(goods, goodsSku); + //如果商品库存不为0,并且es中有数据 + if (goodsSku.getQuantity() > 0 && esGoodsOld == null) { + log.info("生成商品索引 {}", goodsIndex); + this.goodsIndexService.addIndex(goodsIndex); + } else if (goodsSku.getQuantity() > 0 && esGoodsOld != null) { + goodsIndexService.updateIndex(goodsIndex); + } + } + } + + private EsGoodsIndex settingUpGoodsIndexData(Goods goods, GoodsSku goodsSku) { + EsGoodsIndex goodsIndex = new EsGoodsIndex(goodsSku); + if (goods.getParams() != null && !goods.getParams().isEmpty()) { + List goodsParamDTOS = JSONUtil.toList(goods.getParams(), GoodsParamsDTO.class); + goodsIndex = new EsGoodsIndex(goodsSku, goodsParamDTOS); + } + goodsIndex.setIsAuth(goods.getIsAuth()); + goodsIndex.setMarketEnable(goods.getMarketEnable()); + this.settingUpGoodsIndexOtherParam(goodsIndex); + return goodsIndex; + } + + /** + * 设置商品索引的其他参数(非商品自带) + * + * @param goodsIndex 商品索引信息 + */ + private void settingUpGoodsIndexOtherParam(EsGoodsIndex goodsIndex) { + List categories = categoryService.listByIdsOrderByLevel(Arrays.asList(goodsIndex.getCategoryPath().split(","))); + if (!categories.isEmpty()) { + goodsIndex.setCategoryNamePath(ArrayUtil.join(categories.stream().map(Category::getName).toArray(), ",")); + } + Brand brand = brandService.getById(goodsIndex.getBrandId()); + if (brand != null) { + goodsIndex.setBrandName(brand.getName()); + goodsIndex.setBrandUrl(brand.getLogo()); + } + if (goodsIndex.getStoreCategoryPath() != null && CharSequenceUtil.isNotEmpty(goodsIndex.getStoreCategoryPath())) { + List storeGoodsLabels = storeGoodsLabelService.listByStoreIds(Arrays.asList(goodsIndex.getStoreCategoryPath().split(","))); + if (!storeGoodsLabels.isEmpty()) { + goodsIndex.setStoreCategoryNamePath(ArrayUtil.join(storeGoodsLabels.stream().map(StoreGoodsLabel::getLabelName).toArray(), ",")); + } + } + } + + /** * 删除商品 * 1.更新店铺的商品数量 @@ -203,7 +336,7 @@ public class GoodsMessageListener implements RocketMQListener { /** * 修改商品数量 * - * @param messageExt + * @param messageExt 信息体 */ private void updateGoodsNum(MessageExt messageExt) { @@ -224,7 +357,7 @@ public class GoodsMessageListener implements RocketMQListener { * 2.更新SKU购买数量 * 3.更新索引购买数量 * - * @param messageExt + * @param messageExt 信息体 */ private void goodsBuyComplete(MessageExt messageExt) { String goodsCompleteMessageStr = new String(messageExt.getBody()); @@ -252,7 +385,7 @@ public class GoodsMessageListener implements RocketMQListener { int buyCount = goodsSku.getBuyCount() + goodsCompleteMessage.getBuyNum(); goodsSku.setBuyCount(buyCount); goodsSkuService.update(goodsSku); - goodsIndexService.updateIndexBuyNum(goodsCompleteMessage.getSkuId(), buyCount); + goodsIndexService.updateIndex(goodsCompleteMessage.getSkuId(), new EsGoodsIndex().setBuyCount(buyCount)); } else { log.error("商品SkuId为[" + goodsCompleteMessage.getGoodsId() + "的商品不存在,更新商品失败!"); } diff --git a/framework/src/main/java/cn/lili/common/security/SecurityBean.java b/framework/src/main/java/cn/lili/common/security/SecurityBean.java index 7f660595..382426a0 100644 --- a/framework/src/main/java/cn/lili/common/security/SecurityBean.java +++ b/framework/src/main/java/cn/lili/common/security/SecurityBean.java @@ -7,7 +7,6 @@ import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import java.util.Arrays; import java.util.Collections; /** @@ -35,7 +34,6 @@ public class SecurityBean { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); -// config.addAllowedOrigin(CorsConfiguration.ALL); config.setAllowedOriginPatterns(Collections.singletonList(CorsConfiguration.ALL)); config.addAllowedHeader(CorsConfiguration.ALL); config.addAllowedMethod(CorsConfiguration.ALL); diff --git a/framework/src/main/java/cn/lili/elasticsearch/BaseElasticsearchService.java b/framework/src/main/java/cn/lili/elasticsearch/BaseElasticsearchService.java index a3b1f14d..ade3ebc7 100644 --- a/framework/src/main/java/cn/lili/elasticsearch/BaseElasticsearchService.java +++ b/framework/src/main/java/cn/lili/elasticsearch/BaseElasticsearchService.java @@ -140,6 +140,26 @@ public abstract class BaseElasticsearchService { " }\n" + " }\n" + " },\n" + + " \"brandName\": {\n" + + " \"type\": \"text\",\n" + + " \"fielddata\": true,\n" + + " \"fields\": {\n" + + " \"keyword\": {\n" + + " \"type\": \"keyword\",\n" + + " \"ignore_above\": 256\n" + + " }\n" + + " }\n" + + " },\n" + + " \"brandUrl\": {\n" + + " \"type\": \"text\",\n" + + " \"fielddata\": true,\n" + + " \"fields\": {\n" + + " \"keyword\": {\n" + + " \"type\": \"keyword\",\n" + + " \"ignore_above\": 256\n" + + " }\n" + + " }\n" + + " },\n" + " \"buyCount\": {\n" + " \"type\": \"long\"\n" + " },\n" + @@ -163,6 +183,16 @@ public abstract class BaseElasticsearchService { " }\n" + " }\n" + " },\n" + + " \"categoryNamePath\": {\n" + + " \"type\": \"text\",\n" + + " \"fielddata\": true,\n" + + " \"fields\": {\n" + + " \"keyword\": {\n" + + " \"type\": \"keyword\",\n" + + " \"ignore_above\": 256\n" + + " }\n" + + " }\n" + + " },\n" + " \"commentNum\": {\n" + " \"type\": \"long\"\n" + " },\n" + diff --git a/framework/src/main/java/cn/lili/modules/goods/service/CategoryService.java b/framework/src/main/java/cn/lili/modules/goods/service/CategoryService.java index 5914ef6b..4069d49d 100644 --- a/framework/src/main/java/cn/lili/modules/goods/service/CategoryService.java +++ b/framework/src/main/java/cn/lili/modules/goods/service/CategoryService.java @@ -25,6 +25,14 @@ public interface CategoryService extends IService { */ List dbList(String parentId); + /** + * 根据分类id集合获取所有分类根据层级排序 + * + * @param ids 分类ID集合 + * @return 商品分类列表 + */ + List listByIdsOrderByLevel(List ids); + /** * 获取分类树 * diff --git a/framework/src/main/java/cn/lili/modules/goods/service/ParametersService.java b/framework/src/main/java/cn/lili/modules/goods/service/ParametersService.java index 3a390f36..fa5fdf80 100644 --- a/framework/src/main/java/cn/lili/modules/goods/service/ParametersService.java +++ b/framework/src/main/java/cn/lili/modules/goods/service/ParametersService.java @@ -11,4 +11,14 @@ import com.baomidou.mybatisplus.extension.service.IService; */ public interface ParametersService extends IService { + + + /** + * 更新参数组信息 + * + * @param parameters 参数组信息 + * @return 是否更新成功 + */ + boolean updateParameter(Parameters parameters); + } \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/goods/serviceimpl/CategoryServiceImpl.java b/framework/src/main/java/cn/lili/modules/goods/serviceimpl/CategoryServiceImpl.java index 5ff92517..46c8ceb4 100644 --- a/framework/src/main/java/cn/lili/modules/goods/serviceimpl/CategoryServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/goods/serviceimpl/CategoryServiceImpl.java @@ -1,6 +1,6 @@ package cn.lili.modules.goods.serviceimpl; -import cn.hutool.core.util.StrUtil; +import cn.hutool.core.text.CharSequenceUtil; import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; import cn.lili.common.enums.ResultCode; @@ -48,6 +48,17 @@ public class CategoryServiceImpl extends ServiceImpl i return this.list(new LambdaQueryWrapper().eq(Category::getParentId, parentId)); } + /** + * 根据分类id集合获取所有分类根据层级排序 + * + * @param ids 分类ID集合 + * @return 商品分类列表 + */ + @Override + public List listByIdsOrderByLevel(List ids) { + return this.list(new LambdaQueryWrapper().in(Category::getId, ids).orderByAsc(Category::getLevel)); + } + @Override public List categoryTree() { List categoryVOList = (List) cache.get(CachePrefix.CATEGORY.getPrefix()); @@ -69,13 +80,8 @@ public class CategoryServiceImpl extends ServiceImpl i categoryVOList.add(categoryVO); } } - categoryVOList.sort(new Comparator() { - @Override - public int compare(CategoryVO o1, CategoryVO o2) { - return o1.getSortOrder().compareTo(o2.getSortOrder()); - } - }); - if (categoryVOList.size() != 0) { + categoryVOList.sort(Comparator.comparing(Category::getSortOrder)); + if (!categoryVOList.isEmpty()) { cache.put(CachePrefix.CATEGORY.getPrefix(), categoryVOList); cache.put(CachePrefix.CATEGORY_ARRAY.getPrefix(), list); } @@ -85,15 +91,13 @@ public class CategoryServiceImpl extends ServiceImpl i @Override public List getStoreCategory(String[] categories) { List arr = Arrays.asList(categories.clone()); - List categoryVOList = categoryTree().stream() + return categoryTree().stream() .filter(item -> arr.contains(item.getId())).collect(Collectors.toList()); - return categoryVOList; - } @Override public List firstCategory() { - QueryWrapper queryWrapper = Wrappers.query(); + QueryWrapper queryWrapper = Wrappers.query(); queryWrapper.eq("level", 0); return list(queryWrapper); } @@ -108,8 +112,9 @@ public class CategoryServiceImpl extends ServiceImpl i for (CategoryVO item : topCatList) { if (item.getId().equals(parentId)) { return item.getChildren(); + } else { + return getChildren(parentId, item.getChildren()); } - return getChildren(parentId, item.getChildren()); } return new ArrayList<>(); } @@ -129,12 +134,7 @@ public class CategoryServiceImpl extends ServiceImpl i categoryVOList.add(categoryVO); } } - categoryVOList.sort(new Comparator() { - @Override - public int compare(CategoryVO o1, CategoryVO o2) { - return o1.getSortOrder().compareTo(o2.getSortOrder()); - } - }); + categoryVOList.sort(Comparator.comparing(Category::getSortOrder)); return categoryVOList; } @@ -155,7 +155,7 @@ public class CategoryServiceImpl extends ServiceImpl i } //还为空的话,直接返回 if (categoryVOList == null) { - return null; + return new ArrayList<>(); } //循环顶级分类 for (Category category : categoryVOList) { @@ -174,7 +174,7 @@ public class CategoryServiceImpl extends ServiceImpl i public List findByAllBySortOrder(Category category) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq(category.getLevel() != null, "level", category.getLevel()) - .eq(StrUtil.isNotBlank(category.getName()), "name", category.getName()) + .eq(CharSequenceUtil.isNotBlank(category.getName()), "name", category.getName()) .eq(category.getParentId() != null, "parent_id", category.getParentId()) .ne(category.getId() != null, "id", category.getId()) .eq(DELETE_FLAG_COLUMN, false) @@ -329,7 +329,7 @@ public class CategoryServiceImpl extends ServiceImpl i /** * 递归自身,找到id等于parentId的对象,获取他的children 返回 * - * @param parentId 父ID + * @param parentId 父ID * @param categoryVOList 分类VO * @return 子分类列表VO */ @@ -338,11 +338,11 @@ public class CategoryServiceImpl extends ServiceImpl i if (item.getId().equals(parentId)) { return item.getChildren(); } - if (item.getChildren() != null && item.getChildren().size() > 0) { + if (item.getChildren() != null && !item.getChildren().isEmpty()) { return getChildren(parentId, categoryVOList); } } - return null; + return categoryVOList; } /** diff --git a/framework/src/main/java/cn/lili/modules/goods/serviceimpl/GoodsSkuServiceImpl.java b/framework/src/main/java/cn/lili/modules/goods/serviceimpl/GoodsSkuServiceImpl.java index 323b11b9..01ab7711 100644 --- a/framework/src/main/java/cn/lili/modules/goods/serviceimpl/GoodsSkuServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/goods/serviceimpl/GoodsSkuServiceImpl.java @@ -117,7 +117,7 @@ public class GoodsSkuServiceImpl extends ServiceImpl i } this.updateStock(newSkuList); - generateEsCheck(goods); + generateEs(goods); } @Override @@ -164,7 +164,7 @@ public class GoodsSkuServiceImpl extends ServiceImpl i this.updateBatchById(newSkuList); } this.updateStock(newSkuList); - generateEsCheck(goods); + generateEs(goods); } /** @@ -248,6 +248,10 @@ public class GoodsSkuServiceImpl extends ServiceImpl i EsGoodsIndex goodsIndex = goodsIndexService.findById(skuId); if (goodsIndex == null) { goodsIndex = goodsIndexService.resetEsGoodsIndex(goodsSku, goodsVO.getGoodsParamsDTOList()); + + //发送mq消息 + String destination = rocketmqCustomProperties.getGoodsTopic() + ":" + GoodsTagsEnum.RESET_GOODS_INDEX.name(); + rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(Collections.singletonList(goodsIndex)), RocketmqSendCallbackBuilder.commonCallback()); } //商品规格 @@ -300,7 +304,7 @@ public class GoodsSkuServiceImpl extends ServiceImpl i cache.remove(GoodsSkuService.getCacheKeys(sku.getId())); cache.put(GoodsSkuService.getCacheKeys(sku.getId()), sku); } - generateEsCheck(goods); + generateEs(goods); } } @@ -473,18 +477,18 @@ public class GoodsSkuServiceImpl extends ServiceImpl i //修改规格 this.update(goodsSku); //修改规格索引 - goodsIndexService.updateIndexCommentNum(goodsSku.getId(), goodsSku.getCommentNum(), highPraiseNum, grade); + goodsIndexService.updateIndex(goodsSku.getId(), new EsGoodsIndex().setCommentNum(goodsSku.getCommentNum()).setHighPraiseNum(highPraiseNum).setGrade(grade)); //修改商品的评价数量 goodsService.updateGoodsCommentNum(goodsSku.getGoodsId()); } /** - * 生成ES商品索引 + * 发送生成ES商品索引 * * @param goods 商品信息 */ - private void generateEsCheck(Goods goods) { + private void generateEs(Goods goods) { String destination = rocketmqCustomProperties.getGoodsTopic() + ":" + GoodsTagsEnum.GENERATOR_GOODS_INDEX.name(); //发送mq消息 rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(goods), RocketmqSendCallbackBuilder.commonCallback()); diff --git a/framework/src/main/java/cn/lili/modules/goods/serviceimpl/ParametersServiceImpl.java b/framework/src/main/java/cn/lili/modules/goods/serviceimpl/ParametersServiceImpl.java index c468b0a7..2d7e6c9f 100644 --- a/framework/src/main/java/cn/lili/modules/goods/serviceimpl/ParametersServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/goods/serviceimpl/ParametersServiceImpl.java @@ -1,13 +1,30 @@ package cn.lili.modules.goods.serviceimpl; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.json.JSONUtil; +import cn.lili.common.enums.ResultCode; +import cn.lili.common.exception.ServiceException; +import cn.lili.common.properties.RocketmqCustomProperties; +import cn.lili.modules.goods.entity.dos.Goods; import cn.lili.modules.goods.entity.dos.Parameters; +import cn.lili.modules.goods.entity.dto.GoodsParamsDTO; +import cn.lili.modules.goods.entity.dto.GoodsParamsItemDTO; import cn.lili.modules.goods.mapper.ParametersMapper; +import cn.lili.modules.goods.service.GoodsService; import cn.lili.modules.goods.service.ParametersService; +import cn.lili.rocketmq.RocketmqSendCallbackBuilder; +import cn.lili.rocketmq.tags.GoodsTagsEnum; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import lombok.RequiredArgsConstructor; +import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * 商品参数业务层实现 @@ -17,4 +34,92 @@ import org.springframework.transaction.annotation.Transactional; */ @Service public class ParametersServiceImpl extends ServiceImpl implements ParametersService { + + + @Autowired + private GoodsService goodsService; + + + @Autowired + private RocketmqCustomProperties rocketmqCustomProperties; + + @Autowired + private RocketMQTemplate rocketMQTemplate; + + /** + * 更新参数组信息 + * + * @param parameters 参数组信息 + * @return 是否更新成功 + */ + @Override + public boolean updateParameter(Parameters parameters) { + Parameters origin = this.getById(parameters.getId()); + if (origin == null) { + throw new ServiceException(ResultCode.CATEGORY_NOT_EXIST); + } + + List goodsIds = new ArrayList<>(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.select(Goods::getId, Goods::getParams); + queryWrapper.like(Goods::getParams, parameters.getGroupId()); + List> goodsList = this.goodsService.listMaps(queryWrapper); + + for (Map goods : goodsList) { + String params = (String) goods.get("params"); + List goodsParamsDTOS = JSONUtil.toList(params, GoodsParamsDTO.class); + List goodsParamsDTOList = goodsParamsDTOS.stream().filter(i -> i.getGroupId() != null && i.getGroupId().equals(parameters.getGroupId())).collect(Collectors.toList()); + this.setGoodsItemDTOList(goodsParamsDTOList, parameters); + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(Goods::getId, goods.get("id")); + updateWrapper.set(Goods::getParams, JSONUtil.toJsonStr(goodsParamsDTOS)); + this.goodsService.update(updateWrapper); + goodsIds.add(goods.get("id").toString()); + } + + + String destination = rocketmqCustomProperties.getGoodsTopic() + ":" + GoodsTagsEnum.UPDATE_GOODS_INDEX.name(); + //发送mq消息 + rocketMQTemplate.asyncSend(destination, JSONUtil.toJsonStr(goodsIds), RocketmqSendCallbackBuilder.commonCallback()); + return this.updateById(parameters); + } + + /** + * 更新商品参数信息 + * + * @param goodsParamsDTOList 商品参数项列表 + * @param parameters 参数信息 + */ + private void setGoodsItemDTOList(List goodsParamsDTOList, Parameters parameters) { + for (GoodsParamsDTO goodsParamsDTO : goodsParamsDTOList) { + List goodsParamsItemDTOList = goodsParamsDTO.getGoodsParamsItemDTOList().stream().filter(i -> i.getParamId() != null && i.getParamId().equals(parameters.getId())).collect(Collectors.toList()); + for (GoodsParamsItemDTO goodsParamsItemDTO : goodsParamsItemDTOList) { + this.setGoodsItemDTO(goodsParamsItemDTO, parameters); + } + } + } + + /** + * 更新商品参数详细信息 + * + * @param goodsParamsItemDTO 商品参数项信息 + * @param parameters 参数信息 + */ + private void setGoodsItemDTO(GoodsParamsItemDTO goodsParamsItemDTO, Parameters parameters) { + if (goodsParamsItemDTO.getParamId().equals(parameters.getId())) { + goodsParamsItemDTO.setParamId(parameters.getId()); + goodsParamsItemDTO.setParamName(parameters.getParamName()); + goodsParamsItemDTO.setRequired(parameters.getRequired()); + goodsParamsItemDTO.setIsIndex(parameters.getIsIndex()); + goodsParamsItemDTO.setSort(parameters.getSort()); + if (CharSequenceUtil.isNotEmpty(parameters.getOptions()) && !parameters.getOptions().contains(goodsParamsItemDTO.getParamValue())) { + if (parameters.getOptions().contains(",")) { + goodsParamsItemDTO.setParamValue(parameters.getOptions().substring(0, parameters.getOptions().indexOf(","))); + } else { + goodsParamsItemDTO.setParamValue(parameters.getOptions()); + } + } + } + } + } \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/search/entity/dos/EsGoodsIndex.java b/framework/src/main/java/cn/lili/modules/search/entity/dos/EsGoodsIndex.java index 7900d82d..9d0bd4d0 100644 --- a/framework/src/main/java/cn/lili/modules/search/entity/dos/EsGoodsIndex.java +++ b/framework/src/main/java/cn/lili/modules/search/entity/dos/EsGoodsIndex.java @@ -9,6 +9,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; +import lombok.experimental.Accessors; import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.DateFormat; import org.springframework.data.elasticsearch.annotations.Document; @@ -30,6 +31,7 @@ import java.util.Map; @Document(indexName = "#{@elasticsearchProperties.indexPrefix}_" + EsSuffix.GOODS_INDEX_NAME) @ToString @NoArgsConstructor +@Accessors(chain = true) public class EsGoodsIndex implements Serializable { private static final long serialVersionUID = -6856471777036048874L; @@ -99,6 +101,20 @@ public class EsGoodsIndex implements Serializable { @ApiModelProperty("品牌id") private String brandId; + /** + * 品牌名称 + */ + @Field(type = FieldType.Keyword, fielddata = true) + @ApiModelProperty("品牌名称") + private String brandName; + + /** + * 品牌图片地址 + */ + @Field(type = FieldType.Keyword, fielddata = true) + @ApiModelProperty("品牌图片地址") + private String brandUrl; + /** * 分类path */ @@ -106,6 +122,13 @@ public class EsGoodsIndex implements Serializable { @ApiModelProperty("分类path") private String categoryPath; + /** + * 分类名称path + */ + @Field(type = FieldType.Keyword) + @ApiModelProperty("分类名称path") + private String categoryNamePath; + /** * 店铺分类id */ @@ -113,6 +136,13 @@ public class EsGoodsIndex implements Serializable { @ApiModelProperty("店铺分类id") private String storeCategoryPath; + /** + * 店铺分类名称 + */ + @Field(type = FieldType.Keyword) + @ApiModelProperty("店铺分类名称") + private String storeCategoryNamePath; + /** * 商品价格 */ @@ -279,8 +309,8 @@ public class EsGoodsIndex implements Serializable { /** * 参数索引增加 * - * @param sku - * @param goodsParamDTOS + * @param sku 商品sku信息 + * @param goodsParamDTOS 商品参数信息 */ public EsGoodsIndex(GoodsSku sku, List goodsParamDTOS) { this(sku); diff --git a/framework/src/main/java/cn/lili/modules/search/service/EsGoodsIndexService.java b/framework/src/main/java/cn/lili/modules/search/service/EsGoodsIndexService.java index 466dad43..5172d66b 100644 --- a/framework/src/main/java/cn/lili/modules/search/service/EsGoodsIndexService.java +++ b/framework/src/main/java/cn/lili/modules/search/service/EsGoodsIndexService.java @@ -1,10 +1,10 @@ package cn.lili.modules.search.service; -import cn.lili.modules.goods.entity.dto.GoodsParamsDTO; +import cn.lili.common.enums.PromotionTypeEnum; import cn.lili.modules.goods.entity.dos.GoodsSku; +import cn.lili.modules.goods.entity.dto.GoodsParamsDTO; import cn.lili.modules.promotion.entity.dos.PromotionGoods; import cn.lili.modules.promotion.entity.dto.BasePromotion; -import cn.lili.common.enums.PromotionTypeEnum; import cn.lili.modules.search.entity.dos.EsGoodsIndex; import java.util.List; @@ -33,22 +33,19 @@ public interface EsGoodsIndexService { void updateIndex(EsGoodsIndex goods); /** - * 更新商品索引的购买数量 + * 更新商品索引的的部分属性(只填写更新的字段,不需要更新的字段不要填写) * * @param id 商品索引id - * @param buyCount 更新后的购买数量 + * @param goods 更新后的购买数量 */ - void updateIndexBuyNum(String id, Integer buyCount); + void updateIndex(String id, EsGoodsIndex goods); /** - * 更新商品索引的评论相关数据 + * 批量商品索引的的属性(ID 必填, 其他字段只填写更新的字段,不需要更新的字段不要填写。) * - * @param id 商品索引ID - * @param commentNum 评论数量 - * @param highPraiseNum 好评数量 - * @param grade 好评率 + * @param goodsIndices 商品索引列表 */ - void updateIndexCommentNum(String id, Integer commentNum, Integer highPraiseNum, Double grade); + void updateBulkIndex(List goodsIndices); /** * 删除索引 diff --git a/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsIndexServiceImpl.java b/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsIndexServiceImpl.java index 4a951c8d..a7af026f 100644 --- a/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsIndexServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsIndexServiceImpl.java @@ -2,8 +2,10 @@ package cn.lili.modules.search.serviceimpl; import cn.hutool.core.date.DateUtil; import cn.hutool.core.text.CharSequenceUtil; -import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.ReflectUtil; import cn.hutool.extra.pinyin.PinyinUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; import cn.lili.common.enums.PromotionTypeEnum; @@ -28,6 +30,8 @@ import cn.lili.modules.search.service.EsGoodsSearchService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.extern.slf4j.Slf4j; import org.assertj.core.util.IterableUtil; +import org.elasticsearch.action.bulk.BulkRequest; +import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.indices.AnalyzeRequest; import org.elasticsearch.client.indices.AnalyzeResponse; @@ -39,6 +43,7 @@ import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; import java.io.IOException; +import java.lang.reflect.Field; import java.util.*; import java.util.stream.Collectors; @@ -52,6 +57,10 @@ import java.util.stream.Collectors; @Service public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements EsGoodsIndexService { + private static final String IGNORE_FIELD = "serialVersionUID,promotionMap,id,goodsId"; + + private final Map fieldMap = ReflectUtil.getFieldMap(EsGoodsIndex.class); + @Autowired private ElasticsearchProperties elasticsearchProperties; @Autowired @@ -99,34 +108,49 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements } /** - * 更新商品索引的购买数量 + * 更新商品索引的的部分属性(只填写更新的字段,不需要更新的字段不要填写) * - * @param id 商品索引id - * @param buyCount 更新后的购买数量 + * @param id 商品索引id + * @param goods 更新后的购买数量 */ @Override - public void updateIndexBuyNum(String id, Integer buyCount) { + public void updateIndex(String id, EsGoodsIndex goods) { EsGoodsIndex goodsIndex = this.findById(id); - goodsIndex.setBuyCount(buyCount); - this.updateIndex(goodsIndex); + // 通过反射获取全部字段,在根据参数字段是否为空,设置要更新的字段 + for (Map.Entry entry : fieldMap.entrySet()) { + Object fieldValue = ReflectUtil.getFieldValue(goods, entry.getValue()); + if (fieldValue != null && !IGNORE_FIELD.contains(entry.getKey())) { + ReflectUtil.setFieldValue(goodsIndex, entry.getValue(), fieldValue); + } + } + goodsIndexRepository.save(goods); } /** - * 更新商品索引的评论相关数据 + * 批量商品索引的的属性(ID 必填, 其他字段只填写更新的字段,不需要更新的字段不要填写。) * - * @param id 商品索引ID - * @param commentNum 评论数量 - * @param highPraiseNum 好评数量 - * @param grade 好评率 + * @param goodsIndices 商品索引列表 */ @Override - public void updateIndexCommentNum(String id, Integer commentNum, Integer highPraiseNum, Double grade) { - EsGoodsIndex goodsIndex = this.findById(id); - //写入新的商品数据 - goodsIndex.setCommentNum(commentNum); - goodsIndex.setHighPraiseNum(highPraiseNum); - goodsIndex.setGrade(grade); - this.updateIndex(goodsIndex); + public void updateBulkIndex(List goodsIndices) { + try { + //索引名称拼接 + String indexName = elasticsearchProperties.getIndexPrefix() + "_" + EsSuffix.GOODS_INDEX_NAME; + + BulkRequest request = new BulkRequest(); + + for (EsGoodsIndex goodsIndex : goodsIndices) { + UpdateRequest updateRequest = new UpdateRequest(indexName, goodsIndex.getId()); + + JSONObject jsonObject = JSONUtil.parseObj(goodsIndex); + jsonObject.set("releaseTime", goodsIndex.getReleaseTime().getTime()); + updateRequest.doc(jsonObject); + request.add(updateRequest); + } + client.bulk(request, RequestOptions.DEFAULT); + } catch (IOException e) { + log.error("批量更新商品索引异常", e); + } } @Override @@ -208,7 +232,7 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements //更新索引 this.updateGoodsIndexPromotion(goodsIndex, key, promotion); } else { - log.error("更新索引商品促销信息失败!skuId 为 【{}】的索引不存在!", id); + log.error("更新索引商品促销信息失败!skuId 为 {} 的索引不存在!", id); } } @@ -402,7 +426,6 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements Map goodsCurrentPromotionMap = promotionService.getGoodsCurrentPromotionMap(index); //写入促销信息 index.setPromotionMap(goodsCurrentPromotionMap); - this.addIndex(index); return index; } @@ -473,7 +496,7 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements * @param words 商品关键字 */ private void wordsToDb(String words) { - if (StrUtil.isEmpty(words)) { + if (CharSequenceUtil.isEmpty(words)) { return; } try { @@ -493,16 +516,4 @@ public class EsGoodsIndexServiceImpl extends BaseElasticsearchService implements } } -// public List searchList(String index) { -// SearchResponse searchResponse = search(index); -// SearchHit[] hits = searchResponse.getHits().getHits(); -// List goodsIndices = new ArrayList<>(); -// Arrays.stream(hits).forEach(hit -> { -// Map sourceAsMap = hit.getSourceAsMap(); -// EsGoodsIndex person = BeanUtil.mapToBean(sourceAsMap, EsGoodsIndex.class, false, CopyOptions.create()); -// goodsIndices.add(person); -// }); -// return goodsIndices; -// } - } diff --git a/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java b/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java index deae01e1..326fb5cb 100644 --- a/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java @@ -2,22 +2,18 @@ package cn.lili.modules.search.serviceimpl; import cn.hutool.core.convert.Convert; import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.ArrayUtil; import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; import cn.lili.common.vo.PageVO; -import cn.lili.modules.goods.entity.dos.Brand; -import cn.lili.modules.goods.entity.dos.Category; import cn.lili.modules.goods.entity.enums.GoodsAuthEnum; import cn.lili.modules.goods.entity.enums.GoodsStatusEnum; -import cn.lili.modules.goods.service.BrandService; -import cn.lili.modules.goods.service.CategoryService; import cn.lili.modules.search.entity.dos.EsGoodsIndex; import cn.lili.modules.search.entity.dos.EsGoodsRelatedInfo; import cn.lili.modules.search.entity.dto.EsGoodsSearchDTO; import cn.lili.modules.search.entity.dto.HotWordsDTO; import cn.lili.modules.search.entity.dto.ParamOptions; import cn.lili.modules.search.entity.dto.SelectorOptions; -import cn.lili.modules.search.repository.EsGoodsIndexRepository; import cn.lili.modules.search.service.EsGoodsSearchService; import lombok.extern.slf4j.Slf4j; import org.apache.lucene.search.join.ScoreMode; @@ -61,21 +57,9 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { private static final String ATTR_VALUE = "attrList.value"; private static final String ATTR_NAME = "attrList.name"; private static final String ATTR_SORT = "attrList.sort"; + private static final String ATTR_BRAND_ID = "brandId"; private static final String ATTR_NAME_KEY = "nameList"; private static final String ATTR_VALUE_KEY = "valueList"; - - @Autowired - private EsGoodsIndexRepository goodsIndexRepository; - /** - * 商品分类 - */ - @Autowired - private CategoryService categoryService; - /** - * 品牌 - */ - @Autowired - private BrandService brandService; /** * ES */ @@ -123,9 +107,14 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { public EsGoodsRelatedInfo getSelector(EsGoodsSearchDTO goodsSearch, PageVO pageVo) { NativeSearchQueryBuilder builder = createSearchQueryBuilder(goodsSearch, null, true); //分类 - builder.addAggregation(AggregationBuilders.terms("categoryAgg").field("categoryPath")); + AggregationBuilder categoryNameBuilder = AggregationBuilders.terms("categoryNameAgg").field("categoryNamePath.keyword"); + builder.addAggregation(AggregationBuilders.terms("categoryAgg").field("categoryPath").subAggregation(categoryNameBuilder)); + //品牌 - builder.addAggregation(AggregationBuilders.terms("brandAgg").field("brandId").size(Integer.MAX_VALUE)); + AggregationBuilder brandNameBuilder = AggregationBuilders.terms("brandNameAgg").field("brandName.keyword"); + builder.addAggregation(AggregationBuilders.terms("brandIdNameAgg").field(ATTR_BRAND_ID).size(Integer.MAX_VALUE).subAggregation(brandNameBuilder)); + AggregationBuilder brandUrlBuilder = AggregationBuilders.terms("brandUrlAgg").field("brandUrl.keyword"); + builder.addAggregation(AggregationBuilders.terms("brandIdUrlAgg").field(ATTR_BRAND_ID).size(Integer.MAX_VALUE).subAggregation(brandUrlBuilder)); //参数 AggregationBuilder valuesBuilder = AggregationBuilders.terms("valueAgg").field(ATTR_VALUE); AggregationBuilder sortBuilder = AggregationBuilders.sum("sortAgg").field(ATTR_SORT); @@ -162,18 +151,22 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { if (categoryBuckets != null && !categoryBuckets.isEmpty()) { for (Terms.Bucket categoryBucket : categoryBuckets) { String categoryPath = categoryBucket.getKey().toString(); - String[] split = categoryPath.split(","); - for (String s : split) { - if (CharSequenceUtil.isNotEmpty(s)) { - Category category = categoryService.getById(s); - if (category != null) { - SelectorOptions so = new SelectorOptions(); - so.setName(category.getName()); - so.setValue(category.getId()); - if (!categoryOptions.contains(so)) { - categoryOptions.add(so); - } - } + ParsedStringTerms categoryNameAgg = categoryBucket.getAggregations().get("categoryNameAgg"); + List categoryNameBuckets = categoryNameAgg.getBuckets(); + + + String categoryNamePath = categoryPath; + if (!categoryBuckets.isEmpty()) { + categoryNamePath = categoryNameBuckets.get(0).getKey().toString(); + } + String[] split = ArrayUtil.distinct(categoryPath.split(",")); + String[] nameSplit = categoryNamePath.split(","); + for (int i = 0; i < split.length; i++) { + SelectorOptions so = new SelectorOptions(); + so.setName(nameSplit[i]); + so.setValue(split[i]); + if (!categoryOptions.contains(so)) { + categoryOptions.add(so); } } @@ -182,25 +175,47 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { esGoodsRelatedInfo.setCategories(categoryOptions); //品牌 - ParsedStringTerms brandTerms = (ParsedStringTerms) aggregationMap.get("brandAgg"); - List brandBuckets = brandTerms.getBuckets(); + ParsedStringTerms brandNameTerms = (ParsedStringTerms) aggregationMap.get("brandIdNameAgg"); + ParsedStringTerms brandUrlTerms = (ParsedStringTerms) aggregationMap.get("brandIdUrlAgg"); + List brandBuckets = brandNameTerms.getBuckets(); + List brandUrlBuckets = brandUrlTerms.getBuckets(); List brandOptions = new ArrayList<>(); if (brandBuckets != null && !brandBuckets.isEmpty()) { - for (Terms.Bucket brandBucket : brandBuckets) { + for (int i = 0; i < brandBuckets.size(); i++) { + String brandId = brandBuckets.get(i).getKey().toString(); if (CharSequenceUtil.isNotEmpty(goodsSearch.getBrandId())) { List brandList = Arrays.asList(goodsSearch.getBrandId().split("@")); - if (brandList.contains(brandBucket.getKey().toString())) { + if (brandList.contains(brandId)) { continue; } } - Brand brand = brandService.getById(brandBucket.getKey().toString()); - if (brand != null) { - SelectorOptions so = new SelectorOptions(); - so.setName(brand.getName()); - so.setValue(brand.getId()); - so.setUrl(brand.getLogo()); - brandOptions.add(so); + + String brandName = ""; + if (brandBuckets.get(i).getAggregations() != null && brandBuckets.get(i).getAggregations().get("brandNameAgg") != null) { + ParsedStringTerms brandNameAgg = brandBuckets.get(i).getAggregations().get("brandNameAgg"); + List categoryNameBuckets = brandNameAgg.getBuckets(); + if (categoryNameBuckets != null && !categoryNameBuckets.isEmpty()) { + brandName = categoryNameBuckets.get(0).getKey().toString(); + } } + + String brandUrl = ""; + if (brandUrlBuckets != null && !brandUrlBuckets.isEmpty() && + brandUrlBuckets.get(i).getAggregations() != null && + brandUrlBuckets.get(i).getAggregations().get("brandUrlAgg") != null) { + + ParsedStringTerms brandUrlAgg = brandUrlBuckets.get(i).getAggregations().get("brandUrlAgg"); + List categoryUrlBuckets = brandUrlAgg.getBuckets(); + if (categoryUrlBuckets != null && !categoryUrlBuckets.isEmpty()) { + brandUrl = categoryUrlBuckets.get(0).getKey().toString(); + } + + } + SelectorOptions so = new SelectorOptions(); + so.setName(brandName); + so.setValue(brandId); + so.setUrl(brandUrl); + brandOptions.add(so); } } esGoodsRelatedInfo.setBrands(brandOptions); @@ -339,7 +354,7 @@ public class EsGoodsSearchServiceImpl implements EsGoodsSearchService { //品牌判定 if (CharSequenceUtil.isNotEmpty(searchDTO.getBrandId())) { String[] brands = searchDTO.getBrandId().split("@"); - filterBuilder.must(QueryBuilders.termsQuery("brandId", brands)); + filterBuilder.must(QueryBuilders.termsQuery(ATTR_BRAND_ID, brands)); } if (searchDTO.getRecommend() != null) { filterBuilder.filter(QueryBuilders.termQuery("storeId", searchDTO.getRecommend())); diff --git a/framework/src/main/java/cn/lili/modules/store/service/StoreGoodsLabelService.java b/framework/src/main/java/cn/lili/modules/store/service/StoreGoodsLabelService.java index 6332fef0..dfd70af6 100644 --- a/framework/src/main/java/cn/lili/modules/store/service/StoreGoodsLabelService.java +++ b/framework/src/main/java/cn/lili/modules/store/service/StoreGoodsLabelService.java @@ -22,6 +22,14 @@ public interface StoreGoodsLabelService extends IService { */ List listByStoreId(String storeId); + /** + * 根据分类id集合获取所有店铺分类根据层级排序 + * + * @param ids 商家ID + * @return 店铺分类列表 + */ + List listByStoreIds(List ids); + /** * 添加商品分类 * diff --git a/framework/src/main/java/cn/lili/modules/store/serviceimpl/StoreGoodsLabelServiceImpl.java b/framework/src/main/java/cn/lili/modules/store/serviceimpl/StoreGoodsLabelServiceImpl.java index 5dbefa3c..39aa65af 100644 --- a/framework/src/main/java/cn/lili/modules/store/serviceimpl/StoreGoodsLabelServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/store/serviceimpl/StoreGoodsLabelServiceImpl.java @@ -1,7 +1,10 @@ package cn.lili.modules.store.serviceimpl; +import cn.hutool.core.text.CharSequenceUtil; import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; +import cn.lili.common.enums.ResultCode; +import cn.lili.common.exception.ServiceException; import cn.lili.common.security.AuthUser; import cn.lili.common.security.context.UserContext; import cn.lili.modules.store.entity.dos.StoreGoodsLabel; @@ -61,23 +64,32 @@ public class StoreGoodsLabelServiceImpl extends ServiceImpl() { - @Override - public int compare(StoreGoodsLabelVO o1, StoreGoodsLabelVO o2) { - return o1.getSortOrder().compareTo(o2.getSortOrder()); - } - }); + storeGoodsLabelVOList.sort(Comparator.comparing(StoreGoodsLabelVO::getSortOrder)); - if (storeGoodsLabelVOList.size() != 0) { + if (!storeGoodsLabelVOList.isEmpty()) { cache.put(CachePrefix.CATEGORY.getPrefix() + storeId + "tree", storeGoodsLabelVOList); } return storeGoodsLabelVOList; } + /** + * 根据分类id集合获取所有店铺分类根据层级排序 + * + * @param ids 商家ID + * @return 店铺分类列表 + */ + @Override + public List listByStoreIds(List ids) { + return this.list(new LambdaQueryWrapper().in(StoreGoodsLabel::getId, ids).orderByAsc(StoreGoodsLabel::getLevel)); + } + @Override public StoreGoodsLabel addStoreGoodsLabel(StoreGoodsLabel storeGoodsLabel) { //获取当前登录商家账号 AuthUser tokenUser = UserContext.getCurrentUser(); + if (tokenUser == null || CharSequenceUtil.isEmpty(tokenUser.getStoreId())) { + throw new ServiceException(ResultCode.USER_NOT_LOGIN); + } storeGoodsLabel.setStoreId(tokenUser.getStoreId()); //保存店铺分类 this.save(storeGoodsLabel); @@ -90,6 +102,9 @@ public class StoreGoodsLabelServiceImpl extends ServiceImpl lambdaUpdateWrapper = Wrappers.lambdaUpdate(); lambdaUpdateWrapper.eq(StoreGoodsLabel::getStoreId, tokenUser.getStoreId()); lambdaUpdateWrapper.eq(StoreGoodsLabel::getId, storeGoodsLabel.getId()); @@ -103,11 +118,15 @@ public class StoreGoodsLabelServiceImpl extends ServiceImpl update(@Valid Parameters parameters) { - if (parametersService.updateById(parameters)) { + if (parametersService.updateParameter(parameters)) { return ResultUtil.data(parameters); } throw new ServiceException(ResultCode.PARAMETER_UPDATE_ERROR); diff --git a/manager-api/src/main/java/cn/lili/controller/other/ElasticsearchController.java b/manager-api/src/main/java/cn/lili/controller/other/ElasticsearchController.java index 3455d199..6d5c31ca 100644 --- a/manager-api/src/main/java/cn/lili/controller/other/ElasticsearchController.java +++ b/manager-api/src/main/java/cn/lili/controller/other/ElasticsearchController.java @@ -1,32 +1,39 @@ package cn.lili.controller.other; +import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.thread.ThreadUtil; +import cn.hutool.core.util.ArrayUtil; import cn.hutool.json.JSONUtil; import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; -import cn.lili.common.enums.ResultCode; import cn.lili.common.enums.ResultUtil; import cn.lili.common.vo.ResultMessage; +import cn.lili.modules.goods.entity.dos.Brand; +import cn.lili.modules.goods.entity.dos.Category; import cn.lili.modules.goods.entity.dos.Goods; import cn.lili.modules.goods.entity.dos.GoodsSku; import cn.lili.modules.goods.entity.dto.GoodsParamsDTO; import cn.lili.modules.goods.entity.enums.GoodsAuthEnum; import cn.lili.modules.goods.entity.enums.GoodsStatusEnum; +import cn.lili.modules.goods.service.BrandService; +import cn.lili.modules.goods.service.CategoryService; import cn.lili.modules.goods.service.GoodsService; import cn.lili.modules.goods.service.GoodsSkuService; import cn.lili.modules.promotion.service.PromotionService; import cn.lili.modules.search.entity.dos.EsGoodsIndex; import cn.lili.modules.search.service.EsGoodsIndexService; +import cn.lili.modules.store.entity.dos.StoreGoodsLabel; +import cn.lili.modules.store.service.StoreGoodsLabelService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import io.swagger.annotations.Api; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.security.core.parameters.P; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -57,6 +64,15 @@ public class ElasticsearchController { @Autowired private PromotionService promotionService; + @Autowired + private CategoryService categoryService; + + @Autowired + private BrandService brandService; + + @Autowired + private StoreGoodsLabelService storeGoodsLabelService; + @Autowired private Cache cache; @@ -67,7 +83,6 @@ public class ElasticsearchController { if (Boolean.TRUE.equals(flag)) { return ResultUtil.error(100000, "当前有任务在执行"); } - cache.put(CachePrefix.INIT_INDEX_FLAG.getPrefix(), false); ThreadUtil.execAsync(() -> { //查询商品信息 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); @@ -84,6 +99,23 @@ public class ElasticsearchController { List goodsParamDTOS = JSONUtil.toList(goods.getParams(), GoodsParamsDTO.class); index = new EsGoodsIndex(goodsSku, goodsParamDTOS); } + if (goods.getCategoryPath() != null) { + List categories = categoryService.listByIdsOrderByLevel(Arrays.asList(goods.getCategoryPath().split(","))); + if (!categories.isEmpty()) { + index.setCategoryNamePath(ArrayUtil.join(categories.stream().map(Category::getName).toArray(), ",")); + } + } + Brand brand = brandService.getById(goods.getBrandId()); + if (brand != null) { + index.setBrandName(brand.getName()); + index.setBrandUrl(brand.getLogo()); + } + if (goods.getStoreCategoryPath() != null && CharSequenceUtil.isNotEmpty(goods.getStoreCategoryPath())) { + List storeGoodsLabels = storeGoodsLabelService.listByStoreIds(Arrays.asList(goods.getStoreCategoryPath().split(","))); + if (!storeGoodsLabels.isEmpty()) { + index.setStoreCategoryNamePath(ArrayUtil.join(storeGoodsLabels.stream().map(StoreGoodsLabel::getLabelName).toArray(), ",")); + } + } Map goodsCurrentPromotionMap = promotionService.getGoodsCurrentPromotionMap(index); index.setPromotionMap(goodsCurrentPromotionMap); esGoodsIndices.add(index); diff --git a/manager-api/src/test/java/cn/lili/test/elasticsearch/EsTest.java b/manager-api/src/test/java/cn/lili/test/elasticsearch/EsTest.java index e683f2ae..566a5772 100644 --- a/manager-api/src/test/java/cn/lili/test/elasticsearch/EsTest.java +++ b/manager-api/src/test/java/cn/lili/test/elasticsearch/EsTest.java @@ -1,5 +1,6 @@ package cn.lili.test.elasticsearch; +import cn.hutool.core.util.ReflectUtil; import cn.hutool.json.JSONUtil; import cn.lili.common.vo.PageVO; import cn.lili.modules.goods.entity.dos.GoodsSku; @@ -20,12 +21,13 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.domain.Page; import org.springframework.data.elasticsearch.core.SearchPage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.test.context.junit.jupiter.SpringExtension; +import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Map; @@ -56,6 +58,50 @@ class EsTest { private PromotionService promotionService; + public static void main(String[] args) { + EsGoodsIndex goodsIndex = new EsGoodsIndex(); + goodsIndex.setGoodsName("1111"); + goodsIndex.setBuyCount(99); + goodsIndex.setCommentNum(99); + goodsIndex.setGrade(100D); + goodsIndex.setHighPraiseNum(100); + goodsIndex.setIntro("I'd like a cup of tea, please"); + goodsIndex.setIsAuth("1"); + goodsIndex.setMarketEnable("1"); + goodsIndex.setMobileIntro("I want something cold to drink"); + goodsIndex.setPoint(0); + goodsIndex.setSelfOperated(true); + goodsIndex.setThumbnail("picture"); + goodsIndex.setStoreCategoryPath("1"); + + String ignoreField = "serialVersionUID,promotionMap,id,goodsId"; + + List goodsIndices = new ArrayList<>(); + Map fieldMap = ReflectUtil.getFieldMap(EsGoodsIndex.class); + for (int i = 0; i < 10; i++) { + EsGoodsIndex a = new EsGoodsIndex(); + for (Map.Entry entry : fieldMap.entrySet()) { + Object fieldValue = ReflectUtil.getFieldValue(goodsIndex, entry.getValue()); + if (fieldValue != null && !ignoreField.contains(entry.getKey())) { + ReflectUtil.setFieldValue(a, entry.getValue(), fieldValue); + } + } + goodsIndices.add(a); + } + + ; +// BeanUtil.copyProperties(goodsIndex, a); + System.out.println(cn.hutool.core.date.DateUtil.endOfDay(new Date())); +// ReflectUtil.getFieldValue(goodsIndex, ) +// for (Object o : ReflectUtil.getFieldsValue(goodsIndex)) { +// if (o != null) { +// System.out.println(o); +// } +// } + + + } + @Test void searchGoods() { EsGoodsSearchDTO goodsSearchDTO = new EsGoodsSearchDTO(); diff --git a/manager-api/src/test/java/cn/lili/test/promotion/SeckillTest.java b/manager-api/src/test/java/cn/lili/test/promotion/SeckillTest.java index 1c0fafc6..6c8492ce 100644 --- a/manager-api/src/test/java/cn/lili/test/promotion/SeckillTest.java +++ b/manager-api/src/test/java/cn/lili/test/promotion/SeckillTest.java @@ -35,18 +35,19 @@ class SeckillTest { @Test void add() { SeckillVO seckillVO = new SeckillVO(); - seckillVO.setId("123456"); + seckillVO.setId("10000"); seckillVO.setStoreIds("132"); seckillVO.setSeckillApplyStatus(SeckillApplyStatusEnum.NOT_APPLY.name()); seckillVO.setPromotionStatus(PromotionStatusEnum.NEW.name()); - seckillVO.setApplyEndTime(DateUtil.parse("2020-11-13 23:50:00")); - seckillVO.setStartTime(DateUtil.parse("2020-11-14 12:00:00")); - seckillVO.setEndTime(DateUtil.parse("2020-11-14 18:00:00")); - seckillVO.setHours("13,14,15,16,17"); + seckillVO.setApplyEndTime(DateUtil.parse("2021-09-06 14:20:00")); + seckillVO.setStartTime(DateUtil.parse("2021-09-06 14:22:00")); + seckillVO.setEndTime(DateUtil.parse("2021-09-06 23:59:00")); + seckillVO.setHours("15,17,19"); seckillVO.setPromotionName("Seckill" + seckillVO.getId()); seckillVO.setSeckillRule("rule" + seckillVO.getId()); - seckillVO.setStoreId("0"); + seckillVO.setStoreId("1376433565247471616"); seckillVO.setStoreName("platform"); + Assertions.assertTrue(seckillService.saveSeckill(seckillVO)); } @@ -54,32 +55,32 @@ class SeckillTest { void addApply() { List seckillApplyVOS = new ArrayList<>(); SeckillApplyVO seckillApplyVO = new SeckillApplyVO(); - seckillApplyVO.setGoodsName("Apple MacBook Pro 13.3 新款八核M1芯片 8G 256G SSD 深空灰 笔记本电脑 轻薄本 MYD82CH/A"); - seckillApplyVO.setSkuId("50111"); - seckillApplyVO.setOriginalPrice(20000D); - seckillApplyVO.setPrice(19000D); + seckillApplyVO.setGoodsName("Apple iPhone 12"); + seckillApplyVO.setSkuId("1387977574860193792"); + seckillApplyVO.setOriginalPrice(4000D); + seckillApplyVO.setPrice(3600D); seckillApplyVO.setPromotionApplyStatus(PromotionApplyStatusEnum.APPLY.name()); - seckillApplyVO.setQuantity(100); + seckillApplyVO.setQuantity(1); seckillApplyVO.setSalesNum(0); - seckillApplyVO.setSeckillId("123456"); - seckillApplyVO.setStoreId("501"); - seckillApplyVO.setStoreName("Apple产品自营旗舰店"); - seckillApplyVO.setTimeLine(17); + seckillApplyVO.setSeckillId("10000"); + seckillApplyVO.setStoreId("1376369067769724928"); + seckillApplyVO.setStoreName("Lilishop自营店"); + seckillApplyVO.setTimeLine(15); seckillApplyVOS.add(seckillApplyVO); seckillApplyVO = new SeckillApplyVO(); - seckillApplyVO.setGoodsName("RedmiBook 16 锐龙版 超轻薄全面屏(6核R5-4500U 16G 512G 100% sRGB高色域)灰 手提 笔记本电脑 小米 红米"); - seckillApplyVO.setSkuId("141"); - seckillApplyVO.setOriginalPrice(10000D); - seckillApplyVO.setPrice(9000D); + seckillApplyVO.setGoodsName("Apple iPhone 12"); + seckillApplyVO.setSkuId("1387977574864388096"); + seckillApplyVO.setOriginalPrice(4000D); + seckillApplyVO.setPrice(3600D); seckillApplyVO.setPromotionApplyStatus(PromotionApplyStatusEnum.APPLY.name()); - seckillApplyVO.setQuantity(100); + seckillApplyVO.setQuantity(1); seckillApplyVO.setSalesNum(0); - seckillApplyVO.setSeckillId("123456"); - seckillApplyVO.setStoreId("131"); - seckillApplyVO.setStoreName("小米自营旗舰店"); - seckillApplyVO.setTimeLine(16); + seckillApplyVO.setSeckillId("10000"); + seckillApplyVO.setStoreId("1376369067769724928"); + seckillApplyVO.setStoreName("Lilishop自营店"); + seckillApplyVO.setTimeLine(15); seckillApplyVOS.add(seckillApplyVO); - seckillApplyService.addSeckillApply("123456", "501", seckillApplyVOS); + seckillApplyService.addSeckillApply("10000", "1376369067769724928", seckillApplyVOS); Assertions.assertTrue(true); }