谷粒商城分布式高级(十一)—— 商城业务- 商品详情

 


一、商品详情

1、环境搭建

复制代码
请先参考文章 谷粒商城分布式高级(一)—— 环境搭建(高级篇补充)(ElasticSearch & nginx) 中的  “3、搭建域名访问环境(反向代理配置 & 负载均衡到网关)”
(1)html\详情页\shangpinxiangqing.html 放到gulimall-product下的templates文件夹,重命名为item.html,并且修改html命名空间 xmlns:th="http://www.thymeleaf.org"

  (2)上传文件到nginx,实现动静分离

  (a)虚拟机 /mydata/nginx/html/static 新建 item 文件夹

  (b)将以下静态资源上传到 /mydata/nginx/html/static/item 文件夹

(3)配置域名转发

  (a)修改 Windows 的 hosts文件,映射 item.gulimall.com 到 192.168.56.10(虚拟机地址)

  打开 SwitchHosts 操作即可

  (b)查看nginx配置是否如下

  nginx配置 /mydata/nginx/conf/conf.d/gulimall.conf

 (4)修改网关配置 实现 负载均衡到网关

   (a)配置gulimall-gateway(网关服务),新增配置:将域名为item.gulimall.com转发至product服务

   (b)新增文件 com.atguigu.gulimall.product.web.ItemController

package com.atguigu.gulimall.product.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Controller
public class ItemController {

/**
* 展示当前sku详情
* @param skuId
* @return
*/
@GetMapping("/{skuId}.html")
public String skuItem(@PathVariable("skuId") Long skuId){
System.out.println("准备查询"+skuId+"详情");
return "item";
}
}

(c)修改 gulimall-search 的templates/list.html

  (d)重启gulimall-gateway、gulimall-product、gulimall-search

复制代码

 

2、模型抽取/规格参数/销售属性组合

复制代码
1)新建文件 com.atguigu.gulimall.product.vo.SkuItemVo
package com.atguigu.gulimall.product.vo;

import com.atguigu.gulimall.product.entity.SkuImagesEntity;
import com.atguigu.gulimall.product.entity.SkuInfoEntity;
import com.atguigu.gulimall.product.entity.SpuInfoDescEntity;
import lombok.Data;

import java.util.List;

@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;
}
(2)新建文件 com.atguigu.gulimall.product.vo.SkuItemSaleAttrVo
package com.atguigu.gulimall.product.vo;

import lombok.Data;
import lombok.ToString;

import java.util.List;

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

(3)新建文件 com.atguigu.gulimall.product.vo.SpuItemAttrGroupVo
package com.atguigu.gulimall.product.vo;

import lombok.Data;
import lombok.ToString;

import java.util.List;

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

(4)修改文件 com.atguigu.gulimall.product.web.ItemController 的 skuItem 方法
/**
* 展示当前sku详情
* @param skuId
* @return
*/
@GetMapping("/{skuId}.html")
public String skuItem(@PathVariable("skuId") Long skuId, Model model){
System.out.println("准备查询"+skuId+"详情");
SkuItemVo vo = skuInfoService.item(skuId);
model.addAttribute("item", vo);
return "item";
}

(5)com.atguigu.gulimall.product.service.impl.SkuInfoServiceImpl 新增接口和实现类方法item
/**
* 查询商品详情
* @param skuId
* @return
*/
@Override
public SkuItemVo item(Long skuId) {
SkuItemVo skuItemVo = new SkuItemVo();
//1、获取sku基本信息 pms_sku_info
SkuInfoEntity info = getById(skuId);
skuItemVo.setInfo(info);
Long catalogId = info.getCatalogId();
Long spuId = info.getSpuId();

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

//3、获取spu的所有销售属性
List<SkuItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrBySpuId(spuId);
skuItemVo.setSaleAttr(saleAttrVos);

//4、获取spu的介绍
SpuInfoDescEntity spuInfoDescEntity = spuInfoService.getById(spuId);
skuItemVo.setDesc(spuInfoDescEntity);

//5、获取规格参数组及组下的规格参数
List<SpuItemAttrGroupVo> attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(spuId, catalogId);
skuItemVo.setGroupAttrs(attrGroupVos);

return skuItemVo;
}
(6)com.atguigu.gulimall.product.service.impl.SkuImagesServiceImpl 新增接口和实现类方法 getImagesBySkuId
@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;
}

(7)com.atguigu.gulimall.product.service.impl.SkuSaleAttrValueServiceImpl 新增接口和实现类方法 getSaleAttrBySpuId
@Override
public List<SkuItemSaleAttrVo> getSaleAttrBySpuId(Long spuId) {
SkuSaleAttrValueDao dao = this.baseMapper;
List<SkuItemSaleAttrVo> skuItemSaleAttrVos = dao.getSaleAttrBySpuId(spuId);
return skuItemSaleAttrVos;
}

(8)SkuSaleAttrValueDao.xml 新增 xml 方法 getSaleAttrBySpuId
<select id="getSaleAttrBySpuId" resultType="com.atguigu.gulimall.product.vo.SkuItemSaleAttrVo" >
SELECT
ssav.attr_id attrId,
ssav.attr_name attrName,
GROUP_CONCAT(DISTINCT ssav.attr_value) attrValues
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>

(9)com.atguigu.gulimall.product.service.impl.AttrGroupServiceImpl 新增方法 getAttrGroupWithAttrsBySpuId
@Override
public List<SpuItemAttrGroupVo> getAttrGroupWithAttrsBySpuId(Long spuId, Long catalogId) {
//1、查出当前spu对应的所有属性的分组信息以及当前分组下的所有属性对应的值
List<SpuItemAttrGroupVo> vos = baseMapper.getAttrGroupWithAttrsBySpuId(spuId, catalogId);
return vos;
}

(10)AttrGroupDao.xml 新增 xml 方法 getAttrGroupWithAttrsBySpuId
<resultMap id="spuItemAttrGroupVo" type="com.atguigu.gulimall.product.vo.SpuItemAttrGroupVo">
<result property="groupName" column="attr_group_name"/>
<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 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>
复制代码

 

3、页面渲染和sku切换

4、异步编排优化

复制代码
1)gulimall-product 修改 pom.xml 引入配置提示依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

 (2)修改 application.properties 文件

 (3)新增配置文件类 com.atguigu.gulimall.product.config.ThreadPoolConfigProperties

package com.atguigu.gulimall.product.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@ConfigurationProperties(prefix = "gulimall.thread")
//@Component
@Data
public class ThreadPoolConfigProperties {

private Integer coreSize;

private Integer maxSize;

private Integer keepAliveTime;
}

(4)新增线程池配置文件 com.atguigu.gulimall.product.config.MyThreadConfig
package com.atguigu.gulimall.product.config;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@EnableConfigurationProperties(ThreadPoolConfigProperties.class)
@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());
}
}

(5)修改 com.atguigu.gulimall.product.service.impl.SkuInfoServiceImpl 的 item 方法
/**
* 查询商品详情
* @param skuId
* @return
*/
@Override
public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {
SkuItemVo skuItemVo = new SkuItemVo();

//1、获取sku基本信息 pms_sku_info
CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(() -> {
SkuInfoEntity info = getById(skuId);
skuItemVo.setInfo(info);
return info;
}, executor);

CompletableFuture<Void> saleAttrFuture = infoFuture.thenAcceptAsync((res) -> {
//3、获取spu的所有销售属性
List<SkuItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrBySpuId(res.getSpuId());
skuItemVo.setSaleAttr(saleAttrVos);
}, executor);

CompletableFuture<Void> descFuture = infoFuture.thenAcceptAsync((res) -> {
//4、获取spu的介绍
SpuInfoDescEntity spuInfoDescEntity = spuInfoService.getById(res.getSpuId());
skuItemVo.setDesc(spuInfoDescEntity);
}, executor);

CompletableFuture<Void> baseAttrFuture = infoFuture.thenAcceptAsync((res) -> {
//5、获取规格参数组及组下的规格参数
List<SpuItemAttrGroupVo> attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(), res.getCatalogId());
skuItemVo.setGroupAttrs(attrGroupVos);
}, executor);


//2、获取sku的图片信息 pms_sku_images
CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> {
List<SkuImagesEntity> imagesEntities = skuImagesService.getImagesBySkuId(skuId);
skuItemVo.setImages(imagesEntities);
}, executor);


//等待所有任务完成
CompletableFuture.allOf(saleAttrFuture, descFuture, baseAttrFuture, imageFuture).get();

return skuItemVo;
}
复制代码

 

  

 

posted @   沧海一粟hr  阅读(828)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
点击右上角即可分享
微信分享提示

目录导航