【第十五篇】商城系统-商品详情页功能实现

2022-10-04 18:37:55 浏览数 (1)

商品详情页

一、服务搭建

1.配置host文件

  我们的商品详情服务是一个独立的服务,我们需要在客户端的host中来配置映射

2.在Nginx中配置

  我们需要在Nginx中配置商品详情服务的反向代理和静态资源的管理,首先看反向代理的配置

  然后就是静态资源的管理,我们在es和商城首页的资源的同级目录下创建一个item目录,其中保存的就是商品详情页中的资源

3.网关服务路由

  当Nginx方向代理到了网关服务后,网关服务得跟进host路由到商品服务,我们得修改对应的配置信息

4.商品服务处理

  到请求到了商品服务中我们需要接收请求,并且跳转到商品详情页中。

代码语言:javascript复制
/**
 * 商品详情的控制器
 */
@Controller
public class ItemController {

    @GetMapping("/{skuId}.html")
    public String item(@PathVariable Long skuId){
        System.out.println(skuId);
        return "item";
    }
}

item.html页面中的内容在给大家的资源中有,拷贝进去即可,注意要修改相关的资源的路径

5.检索服务跳转

  商品详情服务搭建好了之后,我们需要通过商品的检索服务调整过来,那么我们需要修改跳转的地址信息

代码语言:javascript复制
                            <p class="da">
                                <a th:href="${'http://msb.item.com/' product.skuId '.html'}" >
                                    <img th:src="${product.getSkuImg()}" class="dim">
                                </a>
                            </p>

最终的商品详情页的展示效果

二、商品详情数据

1.响应VO封装

  根据SKUID查询对应的商品详情信息,我们需要把对应的信息封装到对应的VO中,我们需要自己来封装该对象。

代码语言:javascript复制
/**
 * 商品详情页的数据对象
 */
@Data
public class SpuItemVO {
    // 1.sku的基本信息 pms_sku_info
    SkuInfoEntity info;
    // 2.sku的图片信息pms_sku_images
    List<SkuImagesEntity> images;
    // 3.获取spu中的销售属性的组合
    List<SkuItemSaleAttrVo> saleAttrs;
    // 4.获取SPU的介绍
    SpuInfoDescEntity desc;

    // 5.获取SPU的规格参数
    List<SpuItemGroupAttrVo> baseAttrs;

}

销售属性的VO

代码语言:javascript复制
@ToString
@Data
public class SkuItemSaleAttrVo {
    private Long attrId;
    private String attrName;
    private String attrValue;
}

属性组相关的VO

代码语言:javascript复制
@ToString
@Data
public class SpuItemGroupAttrVo {
    private String groupName;
    private List<Attr> baseAttrs;
}

其中的Attr是之前就创建的VO对象

2.商品详细的数据查询

2.1 sku的基本信息

我们可以直接查询获取

代码语言:javascript复制
// 1.sku的基本信息 pms_sku_info
  SkuInfoEntity skuInfoEntity = getById(skuId);

2.2 sku的图片信息

图片信息也是直接获取

代码语言:javascript复制
List<SkuImagesEntity> images = skuImagesService.getImagesBySkuId(skuId);

2.3 销售属性

  销售属性的信息是根据SPU找到所有的SKU下的对应的属性信息,首先写出对应的SQL

代码语言:javascript复制
## 根据SPU编号找到所有的SKU编号 然后进而找到所有的销售属性信息
SELECT
  # psi.sku_id,
  pssav.attr_id,
  pssav.attr_name,
  GROUP_CONCAT( DISTINCT pssav.attr_value)
FROM `pms_sku_info` psi
LEFT JOIN `pms_sku_sale_attr_value` pssav 
	ON psi.sku_id = pssav.sku_id
WHERE psi.spu_id = 6
GROUP BY pssav.attr_id,pssav.attr_name

SQL对应的查询结果

对应的Mapper映射

代码语言:javascript复制
    <select id="getSkuSaleAttrValueBySpuId" resultType="com.msb.mall.product.vo.SkuItemSaleAttrVo">
        SELECT
            pssav.attr_id attr_id,
            pssav.attr_name attr_name,
            GROUP_CONCAT( DISTINCT pssav.attr_value) attr_value
        FROM `pms_sku_info` psi
                 LEFT JOIN `pms_sku_sale_attr_value` pssav
                           ON psi.sku_id = pssav.sku_id
        WHERE psi.spu_id = #{spuId}
        GROUP BY pssav.attr_id,pssav.attr_name
    </select>

然后对应的Dao接口

代码语言:javascript复制
@Mapper
public interface SkuSaleAttrValueDao extends BaseMapper<SkuSaleAttrValueEntity> {

    List<SkuItemSaleAttrVo> getSkuSaleAttrValueBySpuId(@Param("spuId") Long spuId);
}

销售属性中的Service接口及实现

代码语言:javascript复制
public interface SkuSaleAttrValueService extends IService<SkuSaleAttrValueEntity> {

    PageUtils queryPage(Map<String, Object> params);

    List<SkuItemSaleAttrVo> getSkuSaleAttrValueBySpuId(Long spuId);
}
代码语言:javascript复制
    @Override
    public List<SkuItemSaleAttrVo> getSkuSaleAttrValueBySpuId(Long spuId) {
        List<SkuItemSaleAttrVo>  attrsVo = skuSaleAttrValueDao.getSkuSaleAttrValueBySpuId(spuId);
        return attrsVo;
    }

然后就是对应的SkuService中的串联

代码语言:javascript复制
        // 3.获取spu中的销售属性的组合
        List<SkuItemSaleAttrVo> saleAttrs = skuSaleAttrValueService.getSkuSaleAttrValueBySpuId(spuId);

2.4 spu的详情

也是直接获取的

代码语言:javascript复制
        // 4.获取SPU的介绍
        SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(spuId);

2.5 Spu的规格参数

  Spu的规格参数,我们需要根据sku对应的商品分类和spu编号来查询,完整的SQL语句

代码语言:javascript复制
# `pms_attr_group`
# 根据 SPU编号和CatalogId类别编号 要查询出所有的属性组及其属性信息

SELECT t1.attr_group_id
	,t1.attr_group_name
	,t2.attr_id 
	,t3.attr_name
	,t4.attr_value
FROM `pms_attr_group` t1 
LEFT JOIN `pms_attr_attrgroup_relation` t2 ON t1.attr_group_id = t2.attr_group_id
LEFT JOIN `pms_attr` t3 ON t2.attr_id = t3.attr_id
LEFT JOIN `pms_product_attr_value` t4 ON t4.attr_id = t2.attr_id
WHERE t1.catelog_id = '225' AND t4.spu_id = 6

然后对应的查询效果

具体的实现,Dao层接口和映射文件

代码语言:javascript复制
@Mapper
public interface AttrGroupDao extends BaseMapper<AttrGroupEntity> {

    List<SpuItemGroupAttrVo> getAttrgroupWithSpuId(@Param("spuId") Long spuId, @Param("catalogId") Long catalogId);
}
代码语言:javascript复制
    <resultMap id="SpuItemGroupAttrVo" type="com.msb.mall.product.vo.SpuItemGroupAttrVo">
        <result column="attr_group_name" property="groupName"/>
        <collection property="baseAttrs" ofType="com.msb.mall.product.vo.Attr">
            <id column="attr_id" property="attrId" />
            <result column="attr_name" property="attrName"/>
            <result column="attr_value" property="attrValue" />
        </collection>
    </resultMap>

    <select id="getAttrgroupWithSpuId" resultMap="SpuItemGroupAttrVo">
        SELECT t1.attr_group_id
             ,t1.attr_group_name
             ,t2.attr_id
             ,t3.attr_name
             ,t4.attr_value
        FROM `pms_attr_group` t1
                 LEFT JOIN `pms_attr_attrgroup_relation` t2 ON t1.attr_group_id = t2.attr_group_id
                 LEFT JOIN `pms_attr` t3 ON t2.attr_id = t3.attr_id
                 LEFT JOIN `pms_product_attr_value` t4 ON t4.attr_id = t2.attr_id
        WHERE t1.catelog_id = #{catalogId} AND t4.spu_id = #{spuId}

    </select>

对应的AttrGroupService中的定义和实现

代码语言:javascript复制
    List<SpuItemGroupAttrVo> getAttrgroupWithSpuId(Long spuId
            , Long catalogId);
代码语言:javascript复制
    /**
     * 跟进SpuId和CatalogId查询出对应的 属性组及其属性信息
     * @param spuId
     * @param catalogId
     * @return
     */
    @Override
    public List<SpuItemGroupAttrVo> getAttrgroupWithSpuId(Long spuId, Long catalogId) {
        //
        List<SpuItemGroupAttrVo> groupAttrVo = attrGroupDao.getAttrgroupWithSpuId(spuId,catalogId);
        return groupAttrVo;
    }

然后就是对应的SkuInfoServiceImpl中的处理

代码语言:javascript复制
        // 5.获取SPU的规格参数
        List<SpuItemGroupAttrVo> groupAttrVo = attrGroupService.getAttrgroupWithSpuId(spuId,catalogId);

2.6 完成的处理

  在SkuInfoServiceImpl中的完整的处理

代码语言:javascript复制
    @Override
    public SpuItemVO item(Long skuId) {
        SpuItemVO vo = new SpuItemVO();
        // 1.sku的基本信息 pms_sku_info
        SkuInfoEntity skuInfoEntity = getById(skuId);
        vo.setInfo(skuInfoEntity);
        // 获取对应的SPUID
        Long spuId = skuInfoEntity.getSpuId();
        // 获取对应的CatalogId 类别编号
        Long catalogId = skuInfoEntity.getCatalogId();
        // 2.sku的图片信息pms_sku_images
        List<SkuImagesEntity> images = skuImagesService.getImagesBySkuId(skuId);
        vo.setImages(images);
        // 3.获取spu中的销售属性的组合
        List<SkuItemSaleAttrVo> saleAttrs = skuSaleAttrValueService.getSkuSaleAttrValueBySpuId(spuId);
        vo.setSaleAttrs(saleAttrs);
        // 4.获取SPU的介绍
        SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(spuId);
        vo.setDesc(spuInfoDescEntity);

        // 5.获取SPU的规格参数
        List<SpuItemGroupAttrVo> groupAttrVo = attrGroupService.getAttrgroupWithSpuId(spuId,catalogId);
        vo.setBaseAttrs(groupAttrVo);
        return vo;
    }

然后Controller中完成商品详情的数据查询,绑定数据后调整到商品详情页。之后做页面的渲染操作

代码语言:javascript复制
    /**
     * 根据前端传递的SkuId我们需要查询出对有的商品信息
     * @param skuId
     * @return
     */
    @GetMapping("/{skuId}.html")
    public String item(@PathVariable Long skuId, Model model){
        SpuItemVO itemVO = skuInfoService.item(skuId);
        model.addAttribute("item",itemVO);
        return "item";
    }

3.商品详情页渲染

3.1 SKU标题

3.2 图片展示

3.3 价格和有货

3.4 销售属性

  销售属性是当前SKU对应的SPU下所有的销售属性的组合。

3.5 SPU详情

3.6 规格参数

4.异步处理

  然后我们就可以在商品详细信息查询的位置实现CompletableFuture的异步编排处理。

先定义线程池

代码语言:javascript复制
@Configuration
public class MyThreadPoolConfig {

    @Bean
    public ThreadPoolExecutor threadPoolExecutor()
    {
        return new ThreadPoolExecutor(20
                ,200
                ,10
                , TimeUnit.SECONDS
                ,new LinkedBlockingQueue(10000)
                , Executors.defaultThreadFactory()
                ,new ThreadPoolExecutor.AbortPolicy()
        );
    }
}

具体的编排处理

0 人点赞