一、配置对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;
}
到这里,商品详情页的功能就全部完成了;




