环境搭建

修改域名

21.商品详情_封装

 

 

 修改网关

让item也能跳到商品服务

21.商品详情_封装_02

 

 

 前端内容放入nginx

模型抽取

product模块里封装Vo,由于下面两个属性需要在mapper里映射结果集使用,所以不能写成静态内部类

@Data
public class SkuItemVo {
    private SkuInfoEntity info; //1.查询当前sku的基本信息 sku_info表
    private List<SkuImagesEntity> images; //2.sku的图片信息 pms_sku_image
    private List<SkuItemSaleAttrsVo> saleAttrsVos;  //3.获取spu的销售属性组合
    private SpuInfoDescEntity desp; //4.获取spu的介绍
    private List<SpuItemAttrGroup> groupAttrs;//5.获取spu的规格参数
    @ToString
    @Data
    public static class SkuItemSaleAttrsVo {
        private Long attrId;
        private String attrName;
        private List<String> attrValues;
    }
    @ToString
    @Data
    public class SpuItemAttrGroup{
        private String groupName;

        /** 两个属性attrName、attrValue */
        private List<SpuBaseAttrVo> attrs;
    }
    @ToString
    @Data
    public class  SpuBaseAttrVo{
        private String attrName;
        private String attrValue;
    }
}

规格参数--连表查询

想获取规格参数的sql,把需要用到的字段可以起上别名

SELECT pav.`spu_id`,ag.`attr_group_name` gorupName,ag.`attr_group_id`,aar.`attr_id`,attr.`attr_name` attrName,pav.`attr_value` attrValue
FROM `pms_attr_group` ag 
LEFT JOIN `pms_attr_attrgroup_relation` aar ON aar.`attr_group_id`=ag.`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=225 AND pav.`spu_id`=3

查询出来的结果

21.商品详情_线程池_03

 

 具体方法

21.商品详情_spring_04

<!--有嵌套属性的时候要封装自定义结果集-->
    <resultMap id="spuItemAttrGroupVo" type="com.wuyimin.gulimall.product.vo.SpuItemAttrGroup">
        <result property="groupName" column="groupName"></result>
        <collection property="attrs" ofType="com.wuyimin.gulimall.product.vo.SpuBaseAttrVo">
            <result property="attrName" column="attrName"></result>
            <result property="attrValue" column="attrValue"></result>
        </collection>
    </resultMap>
    <select id="getAttrGroupWithAttrsBySpuId"
            resultMap="spuItemAttrGroupVo">
    SELECT pav.`spu_id`,ag.`attr_group_name` groupName,ag.`attr_group_id`,aar.`attr_id`,attr.`attr_name` attrName,pav.`attr_value` attrValue
    FROM `pms_attr_group` ag
    LEFT JOIN `pms_attr_attrgroup_relation` aar ON aar.`attr_group_id`=ag.`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>

方法测试

    @Test
    void test(){
        List<SpuItemAttrGroup> attrGroupWithAttrsBySpuId = attrGroupDao.getAttrGroupWithAttrsBySpuId(3L, 225L);
        attrGroupWithAttrsBySpuId.forEach(System.out::println);
    }

测试结果

SpuItemAttrGroup(groupName=信息, attrs=[SpuBaseAttrVo(attrName=上市年份, attrValue=2020), SpuBaseAttrVo(attrName=颜色, attrValue=流光幻镜)])
SpuItemAttrGroup(groupName=基本信息, attrs=[SpuBaseAttrVo(attrName=入网参数, attrValue=5G), SpuBaseAttrVo(attrName=电池容量, attrValue=5000mAh), SpuBaseAttrVo(attrName=机身长度(mm), attrValue=168)])
SpuItemAttrGroup(groupName=芯片, attrs=[SpuBaseAttrVo(attrName=CPU型号, attrValue=麒麟990), SpuBaseAttrVo(attrName=CPU工艺, attrValue=5nm), SpuBaseAttrVo(attrName=CPU品牌, attrValue=海思(Hisilicon))])

 销售属性组合

测试的sql语句

##分析当前spu有多少个sku,所有sku涉及的属性组合
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 info.`spu_id`=3
GROUP BY ssav.`attr_id`,ssav.`attr_name`

21.商品详情_配置文件_05 

    <select id="getSaleAttrsBySpuId" resultType="com.wuyimin.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 info.`spu_id`=#{spuId}
        GROUP BY ssav.`attr_id`,ssav.`attr_name`
    </select>

方法测试

 @Test
    void test2(){
        List<SkuItemSaleAttrsVo> saleAttrsBySpuId = skuSaleAttrValueDao.getSaleAttrsBySpuId(3L);
        saleAttrsBySpuId.forEach(System.out::println);
    }

SkuItemSaleAttrsVo(attrId=4, attrName=颜色, attrValues=流光幻镜,钛空银,霓影紫)
SkuItemSaleAttrsVo(attrId=6, attrName=套餐, attrValues=套餐一,套餐三,套餐二)

整体方法

21.商品详情_结果集_06

@Override
    public SkuItemVo item(Long skuId) {
        SkuItemVo skuItemVo = new SkuItemVo();
        //1.查询当前sku的基本信息 sku_info表
        SkuInfoEntity skuInfoEntity = getById(skuId);
        Long spuId = skuInfoEntity.getSpuId();
        skuItemVo.setInfo(skuInfoEntity);
        //2.sku的图片信息 pms_sku_image
        List<SkuImagesEntity> skuImagesEntities = imagesService.list(new QueryWrapper<SkuImagesEntity>().eq("skuId", skuId));
        skuItemVo.setImages(skuImagesEntities);
        //3.获取spu的销售属性组合
        List<SkuItemSaleAttrsVo> skuItemSaleAttrsVos=skuSaleAttrValueService.getSaleAttrsBySpuId(spuId);
        skuItemVo.setSaleAttrsVos(skuItemSaleAttrsVos);
        //4.获取spu的介绍
        SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(spuId);
        skuItemVo.setDesp(spuInfoDescEntity);
        //5.获取spu的规格参数
        Long catalogId = skuInfoEntity.getCatalogId();
        List<SpuItemAttrGroup> spuItemAttrGroups=attrGroupService.getAttrGroupWithAttrsBySpuId(spuId,catalogId);
      skuItemVo.setGroupAttrs(spuItemAttrGroups);
return skuItemVo; }

21.商品详情_spring_07

    @GetMapping("/{skuId}.html")
    public String skuItem(@PathVariable("skuId") Long skuId, Model model){
        SkuItemVo skuItemVo=skuInfoService.item(skuId);
        model.addAttribute("item",skuItemVo);
        return "item";
    }

 修改之前抽取的模型来方便前端数据的修改

@Data
public class AttrValueWithSkuIdVo {
    private String attrValue;
    private String skuIds;
}

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

mapper相应的修改

21.商品详情_配置文件_05

 <resultMap id="SkuItemSaleAttrVo" type="com.wuyimin.gulimall.product.vo.SkuItemSaleAttrsVo">
        <result column="attr_id" property="attrId"></result>
        <result column="attr_name" property="attrName"></result>
        <collection property="attrValues" ofType="com.wuyimin.gulimall.product.vo.AttrValueWithSkuIdVo">
            <result column="attr_value" property="attrValue"></result>
            <result column="sku_ids" property="skuIds"></result>
        </collection>
    </resultMap>

    <select id="getSaleAttrsBySpuId" resultMap="SkuItemSaleAttrVo">
        SELECT ssav.`attr_id`,ssav.`attr_name`,ssav.`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>

测试结果:

SkuItemSaleAttrsVo(attrId=4, attrName=颜色, attrValues=[AttrValueWithSkuIdVo(attrValue=流光幻镜, skuIds=1,2,3), AttrValueWithSkuIdVo(attrValue=钛空银, skuIds=7,8,9), AttrValueWithSkuIdVo(attrValue=霓影紫, skuIds=4,5,6)])
SkuItemSaleAttrsVo(attrId=6, attrName=套餐, attrValues=[AttrValueWithSkuIdVo(attrValue=套餐一, skuIds=3,6,9), AttrValueWithSkuIdVo(attrValue=套餐三, skuIds=2,5,8), AttrValueWithSkuIdVo(attrValue=套餐二, skuIds=1,4,7)])

异步编排

配置线程池:实现更改配置文件就可以修改线程池的核心线程数,最大线程数,和存活时间

如果想实现配置文件的快捷提示,需要我们先导入一个依赖

<!--  配置文件,快捷提示-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

配置类

21.商品详情_结果集_09

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

修改类--》注意一定要加入到容器中

21.商品详情_线程池_10

@ConfigurationProperties(prefix = "gulimall.thread")
@Component
@Data
public class ThreadPoolConfigProperties {
    private Integer coreSize;
    private Integer maxSize;
    private Integer keepAliveTime;
}

这样就可以在yml文件里修改了

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

开始异步编排

21.商品详情_配置文件_11

    @Autowired
    ThreadPoolExecutor executor;

//运行的顺序 1 2同时 345要在1运行完之后运行
    @Override
    public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {
        SkuItemVo skuItemVo = new SkuItemVo();
        //第一个异步任务的结果别人还要用,所以就使用supply
        CompletableFuture<SkuInfoEntity> futureInfo = CompletableFuture.supplyAsync(() -> {
            //1.查询当前sku的基本信息 sku_info表
            SkuInfoEntity skuInfoEntity = getById(skuId);
            skuItemVo.setInfo(skuInfoEntity);
            return skuInfoEntity;
        }, executor);
        //需要接受结果
        CompletableFuture<Void> futureSaleAttrs = futureInfo.thenAcceptAsync(res -> {
            //3.获取spu的销售属性组合
            List<SkuItemSaleAttrsVo> skuItemSaleAttrsVos = skuSaleAttrValueService.getSaleAttrsBySpuId(res.getSpuId());
            skuItemVo.setSaleAttrsVos(skuItemSaleAttrsVos);
        }, executor);

        CompletableFuture<Void> futureInfoDesc = futureInfo.thenAcceptAsync(res -> {
            //4.获取spu的介绍
            SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(res.getSpuId());
            skuItemVo.setDesp(spuInfoDescEntity);
        }, executor);

        CompletableFuture<Void> futureItemAttrGroups = futureInfo.thenAcceptAsync(res -> {
            //5.获取spu的规格参数
            List<SpuItemAttrGroup> spuItemAttrGroups = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(), res.getCatalogId());
            skuItemVo.setGroupAttrs(spuItemAttrGroups);
        }, executor);
        //没有什么返回结果
        CompletableFuture<Void> futureImage = CompletableFuture.runAsync(() -> {
            //2.sku的图片信息 pms_sku_image
            List<SkuImagesEntity> skuImagesEntities = imagesService.list(new QueryWrapper<SkuImagesEntity>().eq("sku_Id", skuId));
            skuItemVo.setImages(skuImagesEntities);
        }, executor);
        //等到任务全部做完,可以不用写info,因为image完了info肯定完了
        CompletableFuture.allOf(futureImage,futureInfoDesc,futureItemAttrGroups,futureSaleAttrs).get();
        return skuItemVo;
    }