谷粒商城笔记+踩坑(15)——商品详情搭建+异步编排

简介: 查询 pms_spu_info_desc@Autowired// 4、获取 spu 的介绍 pms_spu_info_desc获取线程池的属性值这里直接调用与配置文件相对应的属性配置类@Bean。

 导航:

谷粒商城笔记+踩坑汇总篇

【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析

目录

1、搭建页面环境

1.1、配置 Nginx 和 网关

1.2、动静资源配置

1.3、搜索页到详情页跳转

2、模型类抽取和controller

2.1、分析首页需要展示的信息

2.2、首页模型类vo

2.3、销售属性组合

2.4、规格参数

2.5、创建ItemController,展示当前sku的详情

3、业务实现(不使用异步)

3.0、业务流程,根据sku_id获取首页信息

3.1、sku 基本信息获取

3.2、获取sku的图片信息

3.3、获取spu的销售属性组合

3.3.1、SkuInfoServiceImpl

3.3.2、SkuSaleAttrValueServiceImpl

3.3.3、dao

3.3.4、sql,查询指定spu_id下的所有销售属性id,name,value

3.3.5、mapper

3.4、获取 spu 的介绍

3.5、获取 spu 的规格参数信息

4、前端,详情页渲染

5、sku组合切换,点击销售属性跳转sku商品

5.1、封装Vo类

5.2、mapper,通过sku_id获取销售属性

5.3、 前端,修改item.html文件,重新渲染销售属性

6、异步编排优化

6.1、环境准备

6.1.1、添加线程池属性类

6.1.2、导入依赖,spring元数据处理器

6.1.3、yml配置线程池

6.1.4、自定义线程池配置类

6.2、异步编排优化详情页查询业务


1、搭建页面环境

1.1、配置 Nginx 和 网关

配置 Nginx 和 网关

修改本地的 hosts文件 vim /etc/hosts

# Gulimall Host Start
127.0.0.1 gulimall.cn
127.0.0.1 search.gulimall.cn
127.0.0.1 item.gulimall.cn
# Gulimall Host End

image.gif

配置Nginx(将search下的请求转给网关)

商城业务-检索服务的时候已经配置过了,这里不需要修改

不确定可以再查看一下:

vim /mydata/nginx/conf/conf.d/gulimall.conf
image.gif
server_name gulimall.com *.gulimall.com
image.gif

image.gif

配置网关

修改gulimall-gateway服务 /src/main/resources路径下的 application.yml

- id: gulimall_host
  uri: lb://gulimall-product
  predicates:
    - Host=gulimall.com,item.gulimall.com    #设置也可以通过“item.gulimall.com”路由到商品模块

image.gif

1.2、动静资源配置

动态资源:

复制shangpinxiangqing.html到gulimall-product/src/main/resources/templates/目录下,并改名为item.index。

image.gif

修改“item.index”文件里的srcherf的静态资源地址,前缀加“/static/item”

image.gif

静态资源:

将静态资源上传至nginx

image.gif

1.3、搜索页到详情页跳转

  1. 修改gulimall-search服务中 list.html 文件
<p class="da">
  <a th:href="|http://item.gulimall.cn/${product.skuId}.html|" >
    <img th:src="${product.skuImg}" class="dim">
  </a>
</p>
  1. image.gif
  2. 编写 Controller 实现页面跳转
  3. 添加“com.atguigu.gulimall.product.web.ItemController”类,代码如下:
@Controller
public class ItemController {
    /**
     * 展示当前sku的详情
     * @param skuId
     * @return
     */
    @GetMapping("/{skuId}.html")
    public String skuItem(@PathVariable("skuId") Long skuId) {
        System.out.println("准备查询:" + skuId + "的详情");
        return "item.html";    //返回到item.html
    }
}
  1. image.gif
  2. 访问测试:

    搜索后点击商品进入详情页:
    image.gif
    image.gif

2、模型类抽取和controller

2.1、分析首页需要展示的信息

根据首页预期展示信息抽取:

image.gif

注意:要分清哪些信息是spu的,哪些信息是sku的。

2.2、首页模型类vo

package com.xx.gulimall.product.vo;
@ToString
@Data
public class SkuItemVo {
    //1、sku基本信息的获取  pms_sku_info
    private SkuInfoEntity info;
    private boolean hasStock = true;
    //2、sku的图片信息    pms_sku_images
    private List<SkuImagesEntity> images;
    //3、获取spu的销售属性组合
    private List<SkuItemSaleAttrVo> saleAttr;
    //4、获取spu的介绍
    private SpuInfoDescEntity desc;
    //5、获取spu的规格参数信息
    private List<SpuItemAttrGroupVo> groupAttrs;
    //6、秒杀商品的优惠信息
    private SeckillSkuVo seckillSkuVo;
}

image.gif

2.3、销售属性组合

@Data
public class SkuItemSaleAttrsVo {
    private Long attrId;
    private String attrName;
    private String attrValues;
}

image.gif

2.4、规格参数

@ToString
@Data
public class SpuItemAttrGroupVo {
    private String groupName;
    private List<Attr> attrs;
}

image.gif

@Data
public class Attr {
    private Long attrId;
    private String attrName;
    private String attrValue;
}

image.gif

2.5、创建ItemController,展示当前sku的详情

package com.xxx.gulimall.product.web;
@Controller
public class ItemController {
    @Resource
    private SkuInfoService skuInfoService;
    /**
     * 展示当前sku的详情
     */
    @GetMapping("/{skuId}.html")
    public String skuItem(@PathVariable("skuId") Long skuId, Model model) throws ExecutionException, InterruptedException {
        System.out.println("准备查询" + skuId + "详情");
        SkuItemVo vos = skuInfoService.item(skuId);
        
        model.addAttribute("item",vos);
        return "item";
    }
}

image.gif

3、业务实现(不使用异步)

3.0、业务流程,根据sku_id获取首页信息

  • 1、sku基本信息的获取  pms_sku_info
  • 2、sku的图片信息    pms_sku_images
  • 3、获取spu的销售属性组合
  • 4、获取spu的介绍    pms_spu_info_desc
  • 5、获取spu的规格参数信息

3.1、sku 基本信息获取

查询 pms_sku_info

com.xxx.gulimall.product.service.impl.SkuInfoServiceImpl


@Override
    public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException{
        // 1、sku基本信息    pms_sku_info
        SkuInfoEntity info = getById(skuId);
        Long spuId=info.getSpuId();
        skuItemVo.setInfo(info);
    }

image.gif

3.2、获取sku的图片信息

表pms_sku_images 

com.xxx.gulimall.product.service.impl.SkuInfoServiceImpl

// 2、sku的图片信息   pms_sku_images
List<SkuImagesEntity> images = skuImagesService.getImagesBySkuId(skuId);
skuItemVo.setImages(images);

image.gif

注入 SkuImagesService,调用该实现类的 getImagesBySkuId(skuId) 方法获取spu的图片信息

com.atguigu.gulimall.product.service.impl 路径下的 SkuImagesServiceImpl 实现类编写:

@Override
public List<SkuImagesEntity> getImagesBySkuId(Long skuId) {
    SkuImagesDao imagesDao = this.baseMapper;
    List<SkuImagesEntity> imagesEntities = imagesDao.selectList(new QueryWrapper<SkuImagesEntity>().eq("sku_id", skuId));
    return imagesEntities;
}

image.gif

3.3、获取spu的销售属性组合

3.3.1、SkuInfoServiceImpl

com.xxx.gulimall.product.service.impl.SkuInfoServiceImpl

// 3、获取 spu 的销售属性组合
List<SkuItemSaleAttrsVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrsBySpuId(spuId);
skuItemVo.setSaleAttr(saleAttrVos);

image.gif

3.3.2、SkuSaleAttrValueServiceImpl

@Override
public List<SkuItemSaleAttrsVo> getSaleAttrsBySpuId(Long spuId) {
    SkuSaleAttrValueDao dao = this.baseMapper;
    List<SkuItemSaleAttrsVo> saleAttrVos = dao.getSaleAttrsBySpuId(spuId);
    return saleAttrVos;
}

image.gif

3.3.3、dao

使用SkuSaleAttrValueDao 层 getSaleAttrsBySpuId 方法:

package com.atguigu.gulimall.product.dao;
@Mapper
public interface SkuSaleAttrValueDao extends BaseMapper<SkuSaleAttrValueEntity> {
    List<SkuItemSaleAttrsVo> getSaleAttrsBySpuId(@Param("spuId") Long spuId);
}

image.gif

3.3.4、sql,查询指定spu_id下的所有销售属性id,name,value

sku表pms_sku_info:

image.gif

sku销售属性表pms_sku_sale_attr_value:

image.gif

左外连接查询:

SELECT    #查销售属性的id,name,值
  ssav.attr_id attr_id,
  ssav.attr_name attr_name,
  GROUP_CONCAT( DISTINCT ssav.attr_value ) attr_values 
FROM    #sku表左外连接sku销售属性表
  pms_sku_info info
  LEFT JOIN pms_sku_sale_attr_value ssav ON ssav.sku_id = info.sku_id 
WHERE
  spu_id = #{spuId}
  
GROUP BY
  ssav.attr_id,
  ssav.attr_name;

image.gif

查询结果:

image.gif

3.3.5、mapper

gulimall-product/src/main/resources/mapper/product/SkuSaleAttrValueDao.xml

<select id="getSaleAttrsBySpuId" resultType="com.atguigu.gulimall.product.vo.SkuItemSaleAttrsVo">
    SELECT
        ssav.attr_id attr_id,
        ssav.attr_name attr_name,
        GROUP_CONCAT(DISTINCT ssav.attr_value) attr_values
    FROM pms_sku_info info
             LEFT JOIN pms_sku_sale_attr_value ssav ON ssav.sku_id = info.sku_id
    WHERE spu_id = #{spuId}
    GROUP BY ssav.attr_id,ssav.attr_name;
</select>

image.gif

分析当前spu有多少了sku,所有sku涉及到的属性组合

  1. 通过spu_id 查询 pms_sku_info 表,获得当前spu对应的 sku_id
  2. 通过sku_id 查询 pms_sku_sale_attr_value表,获取 当前spu 对应的所有的sku的销售属性
  3. 通过汇总函数封装成我们想要的样子

3.4、获取 spu 的介绍

查询 pms_spu_info_desc

@Autowired
SpuInfoDescService spuInfoDescService;
// 4、获取 spu 的介绍 pms_spu_info_desc
Long spuId = info.getSpuId();
SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(spuId);
skuItemVo.setDesp(spuInfoDescEntity);

image.gif

3.5、获取 spu 的规格参数信息

查询 pms_spu_info_desc

@Autowired
AttrGroupService attrGroupService;
Long spuId = info.getSpuId();
Long catalogId = info.getCatalogId();
// 5、获取 spu 的规格参数信息 pms_spu_info_desc
List<SpuItemAttrGroupVo> attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(spuId,catalogId);
skuItemVo.setGroupAttrs(attrGroupVos);

image.gif

注入 AttrGroupService,调用该实现类的 getAttrGroupWithAttrsBySpuId(spuId,catalogId) 方法

/**
 * 查处当前spuId对应的所有属性分组信息 以及 当前分组下的所有属性对应的值
 * @param spuId
 * @param catalogId
 * @return
 */
@Override
public List<SpuItemAttrGroupVo> getAttrGroupWithAttrsBySpuId(Long spuId, Long catalogId) {
    AttrGroupDao baseMapper = this.getBaseMapper();
    List<SpuItemAttrGroupVo> vos = baseMapper.getAttrGroupWithAttrsBySpuId(spuId,catalogId);
    return vos;
}

image.gif

使用AttrGroupDao 层 getAttrGroupWithAttrsBySpuId 方法:

package com.atguigu.gulimall.product.dao;
@Mapper
public interface AttrGroupDao extends BaseMapper<AttrGroupEntity> {
    List<SpuItemAttrGroupVo> getAttrGroupWithAttrsBySpuId(@Param("spuId") Long spuId, @Param("catalogId") Long catalogId);
}

image.gif

gulimall-product/src/main/resources/mapper/product/AttrGroupDao.xml :

<!--resultType 返回集合里面元素的类型,只要有嵌套属性就要自定义结果集-->
<resultMap id="spuItemAttrGroupVo" type="com.atguigu.gulimall.product.vo.SpuItemAttrGroupVo">
    <result property="groupName" column="attr_group_name"></result>
    <collection property="attrs" ofType="com.atguigu.gulimall.product.vo.Attr">
        <result property="attrName" column="attr_name"></result>
        <result property="attrValue" column="attr_value"></result>
    </collection>
</resultMap>
<select id="getAttrGroupWithAttrsBySpuId" resultMap="spuItemAttrGroupVo">
    SELECT
        pav.spu_id,
        ag.attr_group_name,
        ag.attr_group_id,
        aar.attr_id,
        attr.attr_name,
        pav.attr_value
    FROM pms_attr_group ag LEFT JOIN pms_attr_attrgroup_relation aar ON ag.attr_group_id = aar.attr_group_id
                           LEFT JOIN pms_attr attr ON attr.attr_id = aar.attr_id
                           LEFT JOIN pms_product_attr_value pav on pav.attr_id = attr.attr_id
    WHERE ag.catelog_id=#{catalogId} AND pav.spu_id = #{spuId};
</select>

image.gif

这里使用了联表查询:

  1. 通过 catelog_id 查询 pms_attr_group 表中对应的 属性分组的信息 attr_group_idattr_group_name
  2. 通过 attr_group_id 联表查询 pms_attr_attrgroup_relation 表中的属性id attr_id
  3. 通过 attr_id 联表查询 pms_attr 表中对应的 attr_nameattr_id
  4. 通过 attr_id 联表查询 pms_product_attr_value 表中对应的 属性值 attr_value

 

4、前端,详情页渲染

1、添加thymeleaf的名称空间

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

image.gif

2、标题名设置

<div class="box-name" th:text="${item.info.skuTitle}">
   华为 HUAWEI Mate 10 6GB+128GB 亮黑色 移动联通电信4G手机 双卡双待
</div>
<div class="box-hide" th:text="${item.info.skuSubtitle}">预订用户预计11月30日左右陆续发货!麒麟970芯片!AI智能拍照!
   <a href="/static/item/"><u></u></a>
</div>

image.gif

3、大图显示

<div class="imgbox">
   <div class="probox">
      <img class="img1" alt="" th:src="${item.info.skuDefaultImg}">
      <div class="hoverbox"></div>
   </div>
   <div class="showbox">
      <img class="img1" alt="" th:src="${item.info.skuDefaultImg}">
   </div>
</div>

image.gif

4、价格设置

<div class="box-summary clear">
  <ul>
    <li>京东价</li>
    <li>
      <span>¥</span>
      <span th:text="${#numbers.formatDecimal(item.info.price,0,2)}">4499.00</span>
    </li>
    <li>
      预约享资格
    </li>
    <li>
      <a href="/static/item/">
        预约说明
      </a>
    </li>
  </ul>
</div>

image.gif

5、是否有货

<li th:text="${item.hasStock?'有货':'无货'}">
   <span>无货</span>, 此商品暂时售完
</li>

image.gif

6、小图显示

<div class="box-lh-one">
   <ul>
      <li th:each="img:${item.images}" th:if="${!#strings.isEmpty(img.imgUrl)}"><img th:src="${img.imgUrl}" /></li>
   </ul>
</div>

image.gif

7、销售属性

<div class="box-attr-3">
   <div class="box-attr-2 clear" th:each="attr:${item.saleAttr}">
      <dl>
         <dt>选择[[${attr.attrName}]]</dt>
         <dd th:each="val:${#strings.listSplit(attr.attrValues,',')}">
            [[${val}]]
         </dd>
      </dl>
   </div>
</div>

image.gif

8、商品介绍

<img class="xiaoguo" th:src="${desccp}" th:each="desccp:${#strings.listSplit(item.desp.decript,',')}" />

image.gif

9、规格包装

<li class="baozhuang actives" id="li2">
   <div class="guiGebox" >
      <div class="guiGe" th:each="group:${item.groupAttrs}">
         <h3 th:text="${group.groupName}">主体</h3>
         <dl>
            <div th:each="attr:${group.attrs}">
               <dt th:text="${attr.attrName}">品牌</dt>
               <dd th:text="${attr.attrValue}">华为(HUAWEI)</dd>
            </div>
         </dl>
      </div>
      <div class="package-list">
         <h3>包装清单</h3>
         <p>手机(含内置电池) X 1、5A大电流华为SuperCharge充电器X 1、5A USB数据线 X 1、半入耳式线控耳机 X 1、快速指南X 1、三包凭证 X 1、取卡针 X 1、保护壳 X 1</p>
      </div>
   </div>
</li>

image.gif

image.gif

 

5、sku组合切换,点击销售属性跳转sku商品

需求:通过不同的销售属性渲染sku商品

通过选择销售属性获取该销售属性对应的sku,通过算法选中该sku

5.1、封装Vo类

  1. com.atguigu.gulimall.product.vo 路径下创建 AttrValueWithSkuIdVo 类
@Data
public class AttrValueWithSkuIdVo {
    private String attrValue;
    private String skuIds;
}
  1. image.gif
  2. 修改 SkuItemSaleAttrsVo 类
@Data
public class SkuItemSaleAttrsVo {
    private Long attrId;
    private String attrName;
    private List<AttrValueWithSkuIdVo> attrValues;
}
  1. image.gif

5.2、mapper,通过sku_id获取销售属性

修改gulimall-product/src/main/resources/mapper/product/SkuSaleAttrValueDao.xml

<resultMap id="skuItemSaleAttrsVo" type="com.atguigu.gulimall.product.vo.SkuItemSaleAttrsVo">
  <result property="attrId" column="attr_id"/>
  <result property="attrName" column="attr_name"/>
  <collection property="attrValues" ofType="com.atguigu.gulimall.product.vo.AttrValueWithSkuIdVo">
    <result property="attrValue" column="attr_value"/>
    <result property="skuIds" column="sku_ids"/>
  </collection>
</resultMap>
<select id="getSaleAttrsBySpuId" resultMap="skuItemSaleAttrsVo">
  SELECT
  ssav.attr_id attr_id,
  ssav.attr_name attr_name,
  ssav.attr_value attr_value,
  GROUP_CONCAT(DISTINCT info.sku_id) sku_ids
  FROM pms_sku_info info
  LEFT JOIN pms_sku_sale_attr_value ssav ON ssav.sku_id = info.sku_id
  WHERE info.spu_id = #{spuId}
  GROUP BY ssav.attr_id,ssav.attr_name,ssav.attr_value;
</select>

image.gif

5.3、 前端,修改item.html文件,重新渲染销售属性

<div class="box-attr-3">
   <div class="box-attr-2 clear" th:each="attr:${item.saleAttr}">
      <dl>
         <dt>选择[[${attr.attrName}]]</dt>
         <dd th:each="vals:${attr.attrValues}">
            <a
               th:attr="
               class=${#lists.contains(#strings.listSplit(vals.skuIds,','),item.info.skuId.toString())}?'sku_attr_value checked':'sku_attr_value',
               skus=${vals.skuIds}">
               [[${vals.attrValue}]]
            </a>
         </dd>
      </dl>
   </div>
</div>

image.gif

<script>
   $(".sku_attr_value").click(function () {
      // 1、点击的元素添加自定义的属性。为了识别我们是刚才被点击
      var skus = new Array();
      $(this).addClass("ckicked");
      // 寻找本列属性中class属性中有 ckicked
      var curr = $(this).attr("skus").split(",");
      // 将当前被点击的所有sku组合数组放进去
      skus.push(curr);
      // 去掉同一行中所有的 checked
      $(this).parent().parent().find(".sku_attr_value").removeClass("checked");
      // 寻找其他属性中class属性有 checked
      $("a[class='sku_attr_value checked']").each(function () {
         skus.push($(this).attr("skus").split(","));
      });
      console.log(skus);
      // 2、取出他们的交集,得到skuId
      var filterEle = skus[0];
      for (var i = 1; i<skus.length; i++) {
         filterEle = $(filterEle).filter(skus[i]);
      }
      console.log(filterEle[0]);
      // 3、跳转
      location.href = "http://item.gulimall.cn/"+ filterEle[0] +".html";
   });
   $(function () {
      $(".sku_attr_value").parent().css({"border":"solid 1px #CCC"});
      $("a[class='sku_attr_value checked']").parent().css({"border":"solid 1px red"});
   })
</script>

image.gif

 

6、异步编排优化

6.1、环境准备

6.1.1、添加线程池属性类

添加线程池属性配置类,并注入到容器中

package com.atguigu.gulimall.product.config;
//跟gulimall.thread相关的配置文件绑定
//这个注解设置yml配置文件前缀,这样配置后yml数据就会自动注入到 Bean 中,不用再@Value
@ConfigurationProperties(prefix = "gulimall.thread")   
@Component
@Data
public class ThreadPoolConfigProperties {
    private Integer coreSize;
    private Integer maxSize;
    private Integer keepAliveTime;
}

image.gif

6.1.2、导入依赖,spring元数据处理器

作用是给yml配置加提示,不导入也行。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

image.gif

6.1.3、yml配置线程池

在gulimall-product服务中加入以下配置:

# 配置线程池
gulimall:
  thread:
    core-size: 20
    max-size: 200
    keep-alive-time: 10

image.gif

这是上面自定义的配置,因为导入了spring-boot-configuration-processor依赖,所以编写时有提示:

image.gif

6.1.4、自定义线程池配置类

获取线程池的属性值这里直接调用与配置文件相对应的属性配置类

package com.atguigu.gulimall.product.config;
@Configuration
public class MyThreadConfig {
    @Bean
    public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool) {
        return new ThreadPoolExecutor(pool.getCoreSize(),
                pool.getMaxSize(),
                pool.getKeepAliveTime(),
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
    }
}

image.gif

6.2、异步编排优化详情页查询业务

注入线程池:

@Autowired
ThreadPoolExecutor executor;

image.gif

  • infoFuture
  • saleAttrFuture
  • descFuture
  • baseAttrFuture (这三个异步任务需要 infoFuture 执行完得到其结果才能执行)
  • imageFuture

supplyAsync而不是runAsync ,以便于获取线程返回结果

com.xxx.gulimall.product.service.impl.SkuInfoServiceImpl

@Override
public SkuItemVo item(Long skuId) {
    SkuItemVo skuItemVo = new SkuItemVo();
    // 1、sku基本信息    pms_sku_info
//创建异步对象用supplyAsync而不是runAsync ,以便于获取线程返回结果。
    CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(() -> {
        SkuInfoEntity info = getById(skuId);
        skuItemVo.setInfo(info);
        return info;
    }, executor);
    // 2、获取 spu 的销售属性组合
//线程串行化用thenAcceptAsync接收第一步的结果即sku实体类,自己执行完没有返回结果
    CompletableFuture<Void> saleAttrFuture = infoFuture.thenAcceptAsync(res -> {
        List<SkuItemSaleAttrsVo> saleAttrVos = saleAttrValueService.getSaleAttrsBySpuId(res.getSpuId());
        skuItemVo.setSaleAttr(saleAttrVos);
    }, executor);
    // 3、获取 spu 的介绍 pms_spu_info_desc
//这里也需要第一步的sku实体类,所以还是第一步future的thenAcceptAsync
    CompletableFuture<Void> descFuture = infoFuture.thenAcceptAsync(res -> {
        SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(res.getSpuId());
        skuItemVo.setDesp(spuInfoDescEntity);
    }, executor);
    // 4、获取 spu 的规格参数信息 pms_spu_info_desc
    CompletableFuture<Void> baseAttrFuture = infoFuture.thenAcceptAsync(res -> {
        List<SpuItemAttrGroupVo> attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(), res.getCatalogId());
        skuItemVo.setGroupAttrs(attrGroupVos);
    }, executor);
    // 5、sku的图片信息   pms_sku_images
//这个任务跟前面几个任务都没关系
//这里创建异步对象用runAsync 而不是supplyAsync,因为不需要获取线程结果
    CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> {
        List<SkuImagesEntity> images = imagesService.getImagesBySkuId(skuId);
        skuItemVo.setImages(images);
    }, executor);
    // 等待所有任务都完成
//多任务组合,allOf等待所有任务完成。这里就不需要加infoFuture,因为依赖于它结果的saleAttrFuture等都完成了,它肯定也完成了。
    CompletableFuture.allOf(saleAttrFuture,descFuture,baseAttrFuture,imageFuture).get();
    return skuItemVo;
}

image.gif


相关文章
|
11月前
|
SQL 小程序 前端开发
【易售小程序项目】商品详情展示+评论、评论展示、评论点赞+商品收藏【后端基于若依管理系统开发】
【易售小程序项目】商品详情展示+评论、评论展示、评论点赞+商品收藏【后端基于若依管理系统开发】
105 0
|
5天前
|
存储 设计模式 JSON
|
5天前
|
设计模式 SQL JSON
谷粒商城笔记+踩坑(8)——仓库管理
采购单维护-采购需求、 采购单维护-采购单、 仓库维护、商品库存:
谷粒商城笔记+踩坑(8)——仓库管理
|
5天前
|
存储 前端开发 Java
谷粒商城笔记+踩坑(19)——订单模块构建、登录拦截器
首先搭建页面环境,然后介绍整合Spring Session的相关内容,并将用户信息放到session里,多线程优化,完成订单模块的功能、登录拦截等功能的实现
谷粒商城笔记+踩坑(19)——订单模块构建、登录拦截器
|
1月前
|
前端开发 JavaScript NoSQL
构建苏宁商品详情页:从前端展示到后端服务的实战指南
苏宁商品详情页集成前端展示与后端服务,前端利用HTML/CSS/JavaScript呈现信息,后端采用Node.js/Java/Python等技术处理请求并从MySQL/MongoDB等数据库获取数据。示例中,Node.js通过Express框架搭建API,模拟商品查询逻辑。实际应用更为复杂,涵盖用户评价、推荐等功能,并需考虑分布式架构、安全防护及性能优化等方面。
构建苏宁商品详情页:从前端展示到后端服务的实战指南
|
5天前
|
消息中间件 NoSQL Java
谷粒商城笔记+踩坑(23)——定时关闭订单
使用MQ延迟队列,实现项目订单的定时关闭,并阐述消息丢失、重复、积压等问题的解决方案
|
2月前
|
XML JSON API
开发者必备:淘宝商品列表接口集成全攻略
淘宝开放平台提供的商品列表数据接口让开发者编程获取商品列表数据。接口支持按关键词、类目等查询条件获取商品详情,包括标题、价格等信息。具备灵活性高、数据丰富及操作便捷等特点。使用流程包括注册账号、构建并发送HTTP请求及处理响应数据。可用于电商数据分析、商品推荐等场景。开发者需遵守规定确保数据安全合法。[体验API](c0b.cc/R4rbK2)
|
3月前
|
JSON 安全 API
电商开发者必读:微店商品详情API接口全解析
微店商品详情API让开发者能通过商品ID获取包括名称、价格、库存、描述和图片在内的详细信息。开发者需注册账号、获取API密钥和访问权限,并熟悉HTTP请求。请求示例为GET方法,响应数据以JSON格式返回。注意错误处理、保密性、频率限制和数据验证,以确保安全和高效使用。
|
4月前
|
JSON JavaScript 前端开发
使用API接口获取商品数据:从入门到实践
随着电子商务的飞速发展,许多电商平台提供了API接口,允许开发者获取商品数据,以创建各种创新的应用。本文将详细介绍如何使用API接口获取商品数据,并通过代码示例进行演示。
|
4月前
|
小程序 JavaScript 前端开发
点餐小程序实战教程08-购物车功能开发
点餐小程序实战教程08-购物车功能开发