【业务功能篇84】微服务SpringCloud-ElasticSearch-Kibanan-电商实例应用

一、商品上架功能

ElasticSearch实现商城系统中全文检索的流程。

1.商品ES模型

商品的映射关系

json 复制代码
PUT product 
{
	"mappings": {
		"properties": {
			"skuId": {
				"type": "long"
			},
			"spuId": {
				"type": "keyword"
			},
			"skuTitle": {
				"type": "text",
				"analyzer": "ik_smart"
			},
			"skuPrice": {
				"type": "keyword"
			},
			"skuImg": {
				"type": "keyword",
				"index": "false",
				"doc_values": "false"
			},
			"saleCount": {
				"type": "long"
			},
			"hasStock": {
				"type": "boolean"
			},
			"hotScore": {
				"type": "long"
			},
			"brandId": {
				"type": "long"
			},
			"catalogId": {
				"type": "long"
			},
			"brandName": {
				"type": "keyword",
				"index": "false",
				"doc_values": "false"
			},
			"brandImg": {
				"type": "keyword",
				"index": "false",
				"doc_values": "false"
			},
			"catalogName": {
				"type": "keyword",
				"index": "false",
				"doc_values": "false"
			},
			"attrs": {
				"type": "nested",
				"properties": {
					"attrId": {
						"type": "long"
					},
					"attrName": {
						"type": "keyword",
						"index": "false",
						"doc_values": "false"
					},
					"attrValue": {
						"type": "keyword"
					}
				}
			}
		}
	}
}

2.netsted数据类型

如上的例子,netsted类型,避免了我们properties属性里的三个字段值同类型,他们的内容不会错乱匹配

参考官网地址:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/nested.html

3.实现上架功能

3.1 创建ESModel

点击上架功能传递spuId到后台,我们需要根据SpuID查询对应的信息,然后封装到自定义的Model对象中,然后将该对象传递给mall-search服务,所以我们需要先定义这样一个Model对象

java 复制代码
@Data
public class SkuESModel {
    private Long skuId;
    private Long spuId;
    private String subTitle;
    private BigDecimal skuPrice;
    private String skuImg;
    private Long saleCount;
    private Boolean hasStock;
    private Long hotScore;
    private Long brandId;
    private Long catalogId;
    private String brandName;
    private String brandImg;
    private String catalogName;
    private List<Attrs> attrs;
  
    @Data
    public static class Attrs{
       private Long attrId;
       private String attrName;
       private String attrValue;
    }

}

3.2 上架逻辑实现

controller层

java 复制代码
/**
 * spu信息
 *
 */
@RestController
@RequestMapping("product/spuinfo")
public class SpuInfoController {
    @Autowired
    private SpuInfoService spuInfoService;

    /**
     * app/product/spuinfo/6/up
     * 商品的上架功能
     * 传递过来一个spuID
     * 我们就需要根据SPUID查询出需要存储在ElasticSearch中的数据
     * 然后把数据存储到ELasticSearch中,并修改该SPU的状态为上架
     */
    @PostMapping("/{spuId}/up")
    public R spuUp(@PathVariable("spuId") Long spuId){
        spuInfoService.up(spuId);
        return R.ok();
    }
}

核心service层方法实现

调用了一些同moudle下的其他实现类方法忽略

java 复制代码
/**
     * 实现商品上架--》商品相关数据存储到ElasticSearch中
     * 1.根据SpuID查询出相关的信息
     *   封装到对应的对象中
     * 2.将封装的数据存储到ElasticSearch中--》调用mall-search的远程接口
     * 3.更新SpuID对应的状态--》上架
     *
     * @param spuId
     */
    @Override
    public void up(Long spuId) {
        // 1.根据spuId查询相关的信息 封装到SkuESModel对象中
        List<SkuESModel> skuEs = new ArrayList<>();
        // 根据spuID找到对应的SKU信息
        List<SkuInfoEntity> skus = skuInfoService.getSkusBySpuId(spuId);

        // 对应的规格参数  根据spuId来查询规格参数信息
        List<SkuESModel.Attrs> attrsModel = getAttrsModel(spuId);
        // 需要根据所有的skuId获取对应的库存信息---》远程调用
        List<Long> skuIds = skus.stream().map(sku -> {
            return sku.getSkuId();
        }).collect(Collectors.toList());
        Map<Long, Boolean> skusHasStockMap = getSkusHasStock(skuIds);
        // 2.远程调用mall-search的服务,将SukESModel中的数据存储到ES中
        List<SkuESModel> skuESModels = skus.stream().map(item -> {
            SkuESModel model = new SkuESModel();
            // 先实现属性的复制
            BeanUtils.copyProperties(item,model);
            model.setSubTitle(item.getSkuTitle());
            model.setSkuPrice(item.getPrice());

            // hasStock 是否有库存 --》 库存系统查询  一次远程调用获取所有的skuId对应的库存信息
            if(skusHasStockMap == null){
                model.setHasStock(true);
            }else{
                model.setHasStock(skusHasStockMap.get(item.getSkuId()));
            }
            // hotScore 热度分 --> 默认给0即可
            model.setHotScore(0l);
            // 品牌和类型的名称
            BrandEntity brand = brandService.getById(item.getBrandId());
            CategoryEntity category = categoryService.getById(item.getCatalogId());
            model.setBrandName(brand.getName());
            model.setBrandImg(brand.getLogo());
            model.setCatalogName(category.getName());
            // 需要存储的规格数据
            model.setAttrs(attrsModel);

            return model;
        }).collect(Collectors.toList());
        // 将SkuESModel中的数据存储到ES中
        R r = searchFeginService.productStatusUp(skuESModels);
        // 3.更新SPUID对应的状态
        // 根据对应的状态更新商品的状态
        log.info("----->ES操作完成:{}" ,r.getCode());
        System.out.println("-------------->"+r.getCode());
        if(r.getCode() == 0){
            // 远程调用成功  更新商品的状态为 上架
            baseMapper.updateSpuStatusUp(spuId, ProductConstant.StatusEnum.SPU_UP.getCode());
        }else{
            // 远程调用失败
        }
    }

Feign远程调用了其他微服务module

在当前需要调用远程微服务的模块中创建接口,通过注解@FeignClient("mall-search")找到对应被调用的微服务,接着将被调用微服务的controller层的所需方法名,形参路径等都全部复制过来,就能完成远程调用

java 复制代码
@FeignClient("mall-search")
public interface SearchFeginService {

    @PostMapping("/search/save/product")
    public R productStatusUp(@RequestBody List<SkuESModel> skuESModels);
}

被调用的微服务模块Controller层

java 复制代码
/**
 *
 * 存储商城数据到ElasticSearch的服务
 */
@Slf4j
@RequestMapping("/search/save")
@RestController
public class ElasticSearchSaveController {

    @Autowired
    private ElasticSearchSaveService service;

    /**
     * 存储商品上架信息到ElasticSearch服务的接口
     * @return
     */
    @PostMapping("/product")
    public R productStatusUp(@RequestBody List<SkuESModel> skuESModels){
        Boolean b = false;
        try {
            b = service.productStatusUp(skuESModels);
        } catch (IOException e) {
           // e.printStackTrace();
            log.error("ElasticSearch商品上架错误:{}",e);
            return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(), BizCodeEnume.PRODUCT_UP_EXCEPTION.getMsg());
        }
        if(b){
            return R.ok();
        }
        return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(), BizCodeEnume.PRODUCT_UP_EXCEPTION.getMsg());
    }
    
相关推荐
惜.己1 小时前
Docker启动失败 Failed to start Docker Application Container Engine.
spring cloud·docker·eureka
LQ深蹲不写BUG3 小时前
微服务的保护方式以及Sentinel详解
微服务·云原生·架构
鼠鼠我捏,要死了捏5 小时前
基于Apache Flink Stateful Functions的事件驱动微服务架构设计与实践指南
微服务·apache flink·实时处理
AAA修煤气灶刘哥7 小时前
ES 地理查询玩明白,产品要的 “附近的店” 再也难不倒我!(附 DSL+Java 实战)
java·后端·elasticsearch
chenrui3107 小时前
Spring Boot 和 Spring Cloud: 区别与联系
spring boot·后端·spring cloud
AAA修煤气灶刘哥11 小时前
ES 聚合爽到飞起!从分桶到 Java 实操,再也不用翻烂文档
后端·elasticsearch·面试
Elasticsearch12 小时前
Elastic Observability 中 Discover 的跟踪,用于深入的应用洞察
elasticsearch
勇往直前plus12 小时前
Sentinel微服务保护
java·spring boot·微服务·sentinel
Elasticsearch12 小时前
使用 cloud-native Elasticsearch 与 ECK 运行
elasticsearch
在未来等你16 小时前
Elasticsearch面试精讲 Day 9:复合查询与过滤器优化
大数据·分布式·elasticsearch·搜索引擎·面试