21.商品详情
环境搭建
修改域名
修改网关
让item也能跳到商品服务
前端内容放入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
查询出来的结果
具体方法
<!--有嵌套属性的时候要封装自定义结果集--> <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`
<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=套餐一,套餐三,套餐二)
整体方法
@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; }
@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相应的修改
<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>
配置类
@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()); } }
修改类--》注意一定要加入到容器中
@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
开始异步编排
@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; }