一、配置对item.zidanmall.com的域名支持
1、首先配置DNS解析;
2、配置nginx的代理规则(这一条我们其实之前已经配置过了):
动静分离的路径 /static/ 配置也已经完成;
3、配置gateway网关路由规则:
- id: zidanmall_host_route uri: lb://zidanmall-product predicates: - Host=zidanmall.com, item.zidanmall.com
二、完成后端核心代码
1、核心返回实体类 SkuItemVo.java:
@Data public class SkuItemVo { //1.sku基本信息 pms_sku_info SkuInfoEntity info; //是否有货 Boolean hasStock=true; //2.sku 图片 pms_sku_images List<SkuImagesEntity> images; //3.spu 销售属性(sku所有组合) List<SkuItemSaleAttrVo> saleAttr; //4.spu介绍 SpuInfoDescEntity desp; //5.spu规格参数 List<SpuItemAttrGroupVo> groupAttrs; }
2、Controller类ItemController.java:
@Controller public class ItemController { @Autowired SkuInfoService skuInfoService; /** * 展示当前skuId对应的商品详情 * @param skuId * @return */ @GetMapping("/{skuId}.html") public String skuItem(@PathVariable("skuId") Long skuId, Model model){ SkuItemVo item = skuInfoService.item(skuId); System.out.println(item); model.addAttribute("item", item); return "item"; } }
3、业务类SkuInfoServiceImpl.java中的item()方法:
——注意这个方法后面会被做 ComplatableFuture 异步编排优化
/** * 查询skuId对应的页面需要的详情 * 1、sku基本信息获取 pms_sku_info * 2、sku图片信息 pms_sku_images * 3、获取spu的所有销售属性的组合 * 4、获取spu的介绍 * 5、获取spu的规格参数信息 * @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); //2、sku图片信息 pms_sku_images List<SkuImagesEntity> images = imagesService.getImagesBySkuId(skuId); skuItemVo.setImages(images); //3.spu 销售属性(sku所有组合) List<SkuItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrsBySpuId(info.getSpuId()); skuItemVo.setSaleAttr(saleAttrVos); //4.spu介绍 SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(info.getSpuId()); skuItemVo.setDesp(spuInfoDescEntity); //5.spu规格参数 List<SpuItemAttrGroupVo> groupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(info.getSpuId(), info.getCatalogId()); skuItemVo.setGroupAttrs(groupVos); return skuItemVo; }
三、前端渲染
前端渲染的其它地方都比较简单,比较复杂的是:多个销售属性自由组合,点击切换到不同的配对结果对应的skuId详情页的功能
1、html部分:
<div class="box-attr clear" th:each="attr:${item.saleAttr}"> <!--每个属性名遍历,选择‘颜色’、‘内存’等--> <dl> <dt>选择[[${attr.attrName}]]</dt> <dd th:each="val:${attr.attrValues}"> <a href="#" th:attr="skus=${val.skuIds}, class=${#lists.contains(#strings.listSplit(val.skuIds, ','), item.info.skuId.toString())}?'sku_attr_value checked':'sku_attr_value'"> [[${val.attrValue}]] </a> </dd> </dl> </div>
2、javascript部分:
<script type="text/javascript"> $(".sku_attr_value").click(function () { //1.点击的元素添加自定义属性。识别当前点击的 var skus = new Array(); $(this).addClass('clicked'); var cur = $(this).attr("skus").split(","); //当前被点击的所有skuId组合 skus.push(cur); //移除同一行的所有属性值的checked的class $(this).parent().parent().find(".sku_attr_value").removeClass("checked"); //找出当前的所有的被checked的属性值对应的skuId数组,放入skus中 $("a[class='sku_attr_value checked']").each(function () { skus.push($(this).attr("skus").split(",")); }) //2.取出交集 得到skuId var filterElm = skus[0]; //第一个0号位的肯定是刚刚被click的那个,因为实第一个被放入skus中的 for (var i = 1; i < skus.length; i++) { filterElm = $(filterElm).filter(skus[i]); } //3.跳转 location.href = "http://item.zidanmall.com/" + filterElm[0] + ".html"; }) //修改当前被“checked”的属性的颜色 $(function () { $(".sku_attr_value").parent().css({"border": "solid 1px #CCC"}) $("a[class='sku_attr_value checked']").parent().css({"border": "solid 1px red"}) }) </script>
到这里,整个前端sku商品详情页就做完了;
3、效果预览:
切换一组销售属性值看看效果:
Sku属性组合切换功能正常可用!
四、service层逻辑ComplatableFuture异步编排优化
1、我们先自定义一个线程池:
ThreadPoolConfigProperties.java:
@ConfigurationProperties(prefix = "zidanmall.thread") @Component @Data public class ThreadPoolConfigProperties { private Integer coreSize; private Integer maxSize; private Integer keepAliveTime; }
MyThreadConfig.java:
@Configuration public class MyThreadConfig { @Bean public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties properties){ System.out.println(properties); return new ThreadPoolExecutor(properties.getCoreSize(), properties.getMaxSize(), properties.getKeepAliveTime(), TimeUnit.SECONDS, new LinkedBlockingDeque<>(100000), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); } }
application.yml:
zidanmall: thread: core-size: 20 max-size: 200 keep-alive-time: 10
测试可用;
2、开始使用ComplatableFuture进行异步编排,提升性能:
/** * 查询skuId对应的页面需要的详情 * 1、sku基本信息获取 pms_sku_info * 2、sku图片信息 pms_sku_images * 3、获取spu的所有销售属性的组合 * 4、获取spu的介绍 * 5、获取spu的规格参数信息 * @param skuId * @return */ @Override public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException { SkuItemVo skuItemVo=new SkuItemVo(); CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(() -> { //1.sku基本信息 pms_sku_info SkuInfoEntity info = getById(skuId); skuItemVo.setInfo(info); return info; }, executor); CompletableFuture<Void> saleAttrFuture = infoFuture.thenAcceptAsync(res -> { //3.spu 销售属性(sku所有组合) List<SkuItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrsBySpuId(res.getSpuId()); skuItemVo.setSaleAttr(saleAttrVos); }, executor); CompletableFuture<Void> descFuture = infoFuture.thenAcceptAsync(res -> { //4.spu介绍 SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(res.getSpuId()); skuItemVo.setDesp(spuInfoDescEntity); }, executor); CompletableFuture<Void> baseAttrFuture = infoFuture.thenAcceptAsync(res -> { //5.spu规格参数 List<SpuItemAttrGroupVo> groupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(), res.getCatalogId()); skuItemVo.setGroupAttrs(groupVos); }, executor); CompletableFuture<Void> imgFuture = CompletableFuture.runAsync(() -> { //2、sku图片信息 pms_sku_images List<SkuImagesEntity> images = imagesService.getImagesBySkuId(skuId); skuItemVo.setImages(images); }, executor); //等待所有任务都完成 CompletableFuture.allOf(saleAttrFuture, descFuture, baseAttrFuture, imgFuture).get(); return skuItemVo; }
到这里,商品详情页的功能就全部完成了;