Guli Mall Notes + Stepping on the Pit (15) - Commodity Details Construction + Asynchronous Arrangement

Table of contents

1. Build the page environment

1.1. Configure Nginx and gateway

1.2. Static and dynamic resource allocation

1.3. Jump from the search page to the details page

2. Model class extraction and controller

2.1. Analyze the information that needs to be displayed on the homepage

2.2, home page model class vo

2.3. Sales attribute combination

2.4. Specification parameters

2.5. Create an ItemController to display the details of the current sku

3.0, business process, get homepage information according to sku_id

3.1. Obtain basic sku information

3.2. Get the picture information of sku

3.3. Obtain the sales attribute combination of spu

3.3.1,SkuInfoServiceImpl the

3.3.2,SkuSaleAttrValueServiceImpl

3.3.3,dao

3.3.4, sql, query all sales attributes id,name,value under the specified spu_id

3.3.5,mapper 

3.4. Get the introduction of spu

3.5. Obtain the specification parameter information of spu

4. Front-end, details page rendering

5. Switch between sku combinations, click on the sales attribute to jump to sku products

5.1, encapsulation Vo class

5.2, mapper, obtain sales attributes through sku_id

5.3. On the front end, modify the item.html file and re-render the sales attributes

6. Asynchronous orchestration optimization

6.1. Environment preparation

6.1.1. Add thread pool attribute class

6.1.2. Import dependencies, spring metadata processor

6.1.3, yml configuration thread pool

6.1.4, custom thread pool configuration class

6.2. Asynchronous orchestration optimization details page query business

1. Build the page environment

1.1. Configure Nginx and gateway

Configure Nginx and Gateway

Modify the local hosts file 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

Configure Nginx (forward requests under search to the gateway)
The mall business-retrieval service has already been configured, and there is no need to modify it here

If you are not sure, you can check it again:

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

configure gateway
Modify the application.yml under the path of gulimall-gateway service /src/main/resources

- id: gulimall_host
  uri: lb://gulimall-product
  predicates:
    - Host=gulimall.com,item.gulimall.com    #Settings can also be routed to the item module via "item.gulimall.com"

1.2. Static and dynamic resource allocation

Dynamic resources:

Copy shangpinxiangqing.html to the gulimall-product/src/main/resources/templates/ directory, and rename it to item.index.

Modify the static resource addresses of src and herf in the "item.index" file, and add "/static/item" to the prefix

Static resources:

Upload static resources to nginx

1.3. Jump from the search page to the details page

  1. Modify the list.html file in the gulimall-search service

    <p class="da">
      <a th:href="|http://item.gulimall.cn/${product.skuId}.html|" >
        <img th:src="${product.skuImg}" class="dim">
      </a>
    </p>
    
  2. Write Controller to realize page jump

  3. Add the "com.atguigu.gulimall.product.web.ItemController" class, the code is as follows:

    @Controller
    public class ItemController {
    
        /**
         * Display the details of the current sku
         * @param skuId
         * @return
         */
        @GetMapping("/{skuId}.html")
        public String skuItem(@PathVariable("skuId") Long skuId) {
    
            System.out.println("ready query:" + skuId + "details of");
    
            return "item.html";    //return to item.html
        }
    }
    
  4. Access test:
     

    After searching, click on the product to enter the details page:


     

2. Model class extraction and controller

2.1. Analyze the information that needs to be displayed on the homepage

According to the expected display information extraction on the home page:

Note: It is necessary to distinguish which information belongs to spu and which information belongs to sku.  

2.2, home page model class vo

package com.xx.gulimall.product.vo;

@ToString
@Data
public class SkuItemVo {

    //1. Acquisition of sku basic information pms_sku_info
    private SkuInfoEntity info;

    private boolean hasStock = true;

    //2. sku image information pms_sku_images
    private List<SkuImagesEntity> images;

    //3. Obtain the sales attribute combination of spu
    private List<SkuItemSaleAttrVo> saleAttr;

    //4. Obtain the introduction of spu
    private SpuInfoDescEntity desc;

    //5. Obtain the specification parameter information of spu
    private List<SpuItemAttrGroupVo> groupAttrs;

    //6. Preferential information for flash sale products
    private SeckillSkuVo seckillSkuVo;

}

2.3. Sales attribute combination

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

2.4. Specification parameters

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

    private Long attrId;
    private String attrName;
    private String attrValue;

}

2.5. Create an ItemController to display the details of the current sku

package com.xxx.gulimall.product.web;
@Controller
public class ItemController {

    @Resource
    private SkuInfoService skuInfoService;

    /**
     * Display the details of the current sku
     */
    @GetMapping("/{skuId}.html")
    public String skuItem(@PathVariable("skuId") Long skuId, Model model) throws ExecutionException, InterruptedException {

        System.out.println("ready query" + skuId + "details");

        SkuItemVo vos = skuInfoService.item(skuId);
        
        model.addAttribute("item",vos);

        return "item";
    }
}

3. Business realization (do not use asynchrony)

3.0, business process, get homepage information according to sku_id

  • 1. Acquisition of sku basic information pms_sku_info
  • 2. sku image information pms_sku_images
  • 3. Obtain the sales attribute combination of spu
  • 4. Get the introduction of spu pms_spu_info_desc
  • 5. Obtain the specification parameter information of spu

3.1. Obtain basic sku information

Query pms_sku_info

com.xxx.gulimall.product.service.impl.SkuInfoServiceImpl
    @Override
    public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException{
        // 1. sku basic information pms_sku_info
        SkuInfoEntity info = getById(skuId);
        Long spuId=info.getSpuId();
        skuItemVo.setInfo(info);

    }

3.2. Get the picture information of sku

Table pms_sku_images

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

// 2. sku image information pms_sku_images
List<SkuImagesEntity> images = skuImagesService.getImagesBySkuId(skuId);
skuItemVo.setImages(images);

Inject SkuImagesService and call the getImagesBySkuId(skuId) method of the implementation class to obtain the image information of the spu

Write the SkuImagesServiceImpl implementation class under the com.atguigu.gulimall.product.service.impl path:

@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;
}

3.3. Obtain the sales attribute combination of spu

3.3.1,SkuInfoServiceImpl 

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

// 3. Obtain the sales attribute combination of spu
List<SkuItemSaleAttrsVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrsBySpuId(spuId);
skuItemVo.setSaleAttr(saleAttrVos);

3.3.2,SkuSaleAttrValueServiceImpl

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

3.3.3,dao

Use the getSaleAttrsBySpuId method of the SkuSaleAttrValueDao layer:

package com.atguigu.gulimall.product.dao;

@Mapper
public interface SkuSaleAttrValueDao extends BaseMapper<SkuSaleAttrValueEntity> {

    List<SkuItemSaleAttrsVo> getSaleAttrsBySpuId(@Param("spuId") Long spuId);

}

3.3.4, sql, query all sales attributes id,name,value under the specified spu_id

sku table pms_sku_info:

sku sales attribute table pms_sku_sale_attr_value:

Left outer join query:

SELECT    #Check the id,name, and value of the sales attribute
	ssav.attr_id attr_id,
	ssav.attr_name attr_name,
	GROUP_CONCAT( DISTINCT ssav.attr_value ) attr_values 
FROM    #sku table left outer join sku sales attribute table
	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;

search result:

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>

Analyze how many skus the current spu has, and the attribute combinations involved in all skus

  1. Query the pms_sku_info table through spu_id to get the sku_id corresponding to the current spu
  2. Query the pms_sku_sale_attr_value table through sku_id to obtain the sales attributes of all skus corresponding to the current spu
  3. Encapsulate it into what we want by summarizing functions

3.4. Get the introduction of spu

Query pms_spu_info_desc

@Autowired
SpuInfoDescService spuInfoDescService;

// 4. Get the introduction of spu pms_spu_info_desc
Long spuId = info.getSpuId();
SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(spuId);
skuItemVo.setDesp(spuInfoDescEntity);

3.5. Obtain the specification parameter information of spu

Query pms_spu_info_desc

@Autowired
AttrGroupService attrGroupService;

Long spuId = info.getSpuId();
Long catalogId = info.getCatalogId();
// 5. Obtain the specification parameter information of spu pms_spu_info_desc
List<SpuItemAttrGroupVo> attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(spuId,catalogId);
skuItemVo.setGroupAttrs(attrGroupVos);

Inject AttrGroupService and call the getAttrGroupWithAttrsBySpuId(spuId, catalogId) method of the implementation class

/**
 * Investigate and deal with all attribute grouping information corresponding to the current spuId and the values ​​corresponding to all attributes under the current grouping
 * @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;
}

Use the getAttrGroupWithAttrsBySpuId method of the AttrGroupDao layer:

package com.atguigu.gulimall.product.dao;
@Mapper
public interface AttrGroupDao extends BaseMapper<AttrGroupEntity> {

    List<SpuItemAttrGroupVo> getAttrGroupWithAttrsBySpuId(@Param("spuId") Long spuId, @Param("catalogId") Long catalogId);
}

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

<!--resultType Return the type of elements in the collection, as long as there are nested attributes, you need to customize the result set-->
<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>

Join table query is used here:

  1. Query the information of the corresponding attribute group in the pms_attr_group table through category_id attr_group_id, attr_group_name
  2. Query the attribute id in the pms_attr_attrgroup_relation table through the attr_group_id join table attr_id
  3. Query the corresponding attr_name and attr_id in the pms_attr table through the attr_id join table
  4. Query the corresponding attribute value in the pms_product_attr_value table through the attr_id join table attr_value


 

4. Front-end, details page rendering

1. Add the namespace of thymeleaf

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

2. Title name setting

<div class="box-name" th:text="${item.info.skuTitle}">
   Huawei HUAWEI Mate 10 6GB+128GB Bright black Mobile Unicom Telecom 4 G Mobile phone dual card dual standby
</div>
<div class="box-hide" th:text="${item.info.skuSubtitle}">Pre-order users are expected to ship around November 30! Kirin 970 chip! AI Smart camera!
   <a href="/static/item/"><u></u></a>
</div>

3. Big picture display

<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>

4. Price setting

<div class="box-summary clear">
  <ul>
    <li>Jingdong price</li>
    <li>
      <span>¥</span>
      <span th:text="${#numbers.formatDecimal(item.info.price,0,2)}">4499.00</span>
    </li>
    <li>
      Eligibility for reservation
    </li>
    <li>
      <a href="/static/item/">
        Appointment instructions
      </a>
    </li>
  </ul>
</div>

5. Is it in stock?

<li th:text="${item.hasStock?'In stock':'Sold Out'}">
   <span>Sold Out</span>, This item is temporarily sold out
</li>

6. Small picture display

<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>

7. Sales attribute

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

8. Product introduction

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

9. Specification packaging

<li class="baozhuang actives" id="li2">
   <div class="guiGebox" >
      <div class="guiGe" th:each="group:${item.groupAttrs}">
         <h3 th:text="${group.groupName}">main body</h3>
         <dl>
            <div th:each="attr:${group.attrs}">
               <dt th:text="${attr.attrName}">brand</dt>
               <dd th:text="${attr.attrValue}">Huawei(HUAWEI)</dd>
            </div>
         </dl>
      </div>
      <div class="package-list">
         <h3>packing list</h3>
         <p>Mobile phone (with built-in battery) X 1,5A High current Huawei SuperCharge charger X 1,5A USB data line X 1,Semi in-ear remote control headset X 1,quick guide X 1,Three Guarantees Certificate X 1,Pick up needle X 1,protective case X 1</p>
      </div>
   </div>
</li>


 

5. Switch between sku combinations, click on the sales attribute to jump to sku products

Requirement: Render sku products through different sales attributes

Obtain the sku corresponding to the sales attribute by selecting the sales attribute, and select the sku through the algorithm

5.1, encapsulation Vo class

  1. Create the AttrValueWithSkuIdVo class under the com.atguigu.gulimall.product.vo path

    @Data
    public class AttrValueWithSkuIdVo {
        private String attrValue;
        private String skuIds;
    }
    
  2. Modify the SkuItemSaleAttrsVo class

    @Data
    public class SkuItemSaleAttrsVo {
        private Long attrId;
        private String attrName;
        private List<AttrValueWithSkuIdVo> attrValues;
    }
    

5.2, mapper, obtain sales attributes through sku_id

Modify 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>

5.3. On the front end, modify the item.html file and re-render the sales attributes

<div class="box-attr-3">
   <div class="box-attr-2 clear" th:each="attr:${item.saleAttr}">
      <dl>
         <dt>choose[[${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>
<script>
   $(".sku_attr_value").click(function () {
      // 1. Add custom attributes to the clicked element. To recognize that we were just clicked
      var skus = new Array();
      $(this).addClass("ckicked");
      // Look for kicked in the class attribute in this column attribute
      var curr = $(this).attr("skus").split(",");
      // Put all the currently clicked sku combination arrays into it
      skus.push(curr);
      // Remove all checked in the same line
      $(this).parent().parent().find(".sku_attr_value").removeClass("checked");
      // Find that the class attribute in other attributes has checked
      $("a[class='sku_attr_value checked']").each(function () {
         skus.push($(this).attr("skus").split(","));
      });
      console.log(skus);

      // 2. Take out their intersection and get skuId
      var filterEle = skus[0];
      for (var i = 1; i<skus.length; i++) {
         filterEle = $(filterEle).filter(skus[i]);
      }
      console.log(filterEle[0]);

      // 3. Jump
      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>


 

6. Asynchronous orchestration optimization

6.1. Environment preparation

6.1.1. Add thread pool attribute class

Add a thread pool attribute configuration class and inject it into the container

package com.atguigu.gulimall.product.config;
//Binding to configuration files related to gulimall.thread
//This annotation sets the prefix of the yml configuration file, so that the yml data will be automatically injected into the Bean after configuration, no need to @Value
@ConfigurationProperties(prefix = "gulimall.thread")   
@Component
@Data
public class ThreadPoolConfigProperties {
    private Integer coreSize;
    private Integer maxSize;
    private Integer keepAliveTime;
}

6.1.2. Import dependencies, spring metadata processor

The function is to add prompts to the yml configuration, even without importing.

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

6.1.3, yml configuration thread pool

Add the following configuration to the gulimall-product service:

# Configure thread pool
gulimall:
  thread:
    core-size: 20
    max-size: 200
    keep-alive-time: 10

This is the custom configuration above, because the spring-boot-configuration-processor dependency is imported, so there is a hint when writing:

6.1.4, custom thread pool configuration class

Get the attribute value of the thread pool Here, directly call the attribute configuration class corresponding to the configuration file

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());
    }
}

6.2. Asynchronous orchestration optimization details page query business

Inject into the thread pool:

@Autowired
ThreadPoolExecutor executor;
  • infoFuture

    • saleAttrFuture
    • descFuture
    • baseAttrFuture (These three asynchronous tasks can only be executed after infoFuture is executed and its result is obtained)
  • imageFuture

Use supplyAsync instead of runAsync to get the results returned by the thread.

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

@Override
public SkuItemVo item(Long skuId) {
    SkuItemVo skuItemVo = new SkuItemVo();

    // 1. sku basic information pms_sku_info
//To create an asynchronous object, use supplyAsync instead of runAsync, so that the thread can return the result.
    CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(() -> {
        SkuInfoEntity info = getById(skuId);
        skuItemVo.setInfo(info);
        return info;
    }, executor);

    // 2. Obtain the sales attribute combination of spu
//Thread serialization uses thenAcceptAsync to receive the result of the first step, that is, the sku entity class, and no result is returned after executing it by itself
    CompletableFuture<Void> saleAttrFuture = infoFuture.thenAcceptAsync(res -> {
        List<SkuItemSaleAttrsVo> saleAttrVos = saleAttrValueService.getSaleAttrsBySpuId(res.getSpuId());
        skuItemVo.setSaleAttr(saleAttrVos);
    }, executor);

    // 3. Get the introduction of spu pms_spu_info_desc
//The sku entity class of the first step is also needed here, so the thenAcceptAsync of the future is still the first step
    CompletableFuture<Void> descFuture = infoFuture.thenAcceptAsync(res -> {
        SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(res.getSpuId());
        skuItemVo.setDesp(spuInfoDescEntity);
    }, executor);

    // 4. Obtain the specification parameter information of 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 image information pms_sku_images
//This task has nothing to do with the previous tasks.
//Create asynchronous objects here with runAsync instead of supplyAsync, because there is no need to get thread results
    CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> {
        List<SkuImagesEntity> images = imagesService.getImagesBySkuId(skuId);
        skuItemVo.setImages(images);
    }, executor);


    // Wait for all tasks to complete
//Multi-task combination, allOf waits for all tasks to complete. There is no need to add infoFuture here, because the saleAttrFuture that depends on its result has been completed, and it must have been completed.
    CompletableFuture.allOf(saleAttrFuture,descFuture,baseAttrFuture,imageFuture).get();

    return skuItemVo;
}

Tags: Nginx Spring Boot Spring Cloud

Posted by Thoughtless on Thu, 30 Mar 2023 20:48:58 +0530