当前位置:网站首页>谷粒商城10——搜索、商品详情、异步编排
谷粒商城10——搜索、商品详情、异步编排
2022-08-02 03:33:00 【HotRabbit.】
文章目录
六、商城业务-搜索页面
1.页面跳转配置
[root@iZ2ze30iuo2wom5i3mm5qlZ /]# cd /mydata/nginx/conf/conf.d/
[root@iZ2ze30iuo2wom5i3mm5qlZ conf.d]# vi gulimall.conf
以gulimall.com结尾的访问路径 都转到网关去

网关配置:
- id: admin_host_route
uri: lb://gulimall-product
predicates:
- Host=gulimall.com
- id: admin_search_route
uri: lb://gulimall-search
predicates:
- Host=search.gulimall.com
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AV6IJ6eb-1659072942560)(C:\Users\10418\AppData\Roaming\Typora\typora-user-images\image-20220723110710007.png)]
配置search服务页面跳转
@Controller
public class SearchController {
@GetMapping("/list.html")
public String listPage(){
return "list";
}
}
2.封装、编写vo实体类
封装前端检索条件:
keyword=小米&sort=saleCount_desc/asc&hasStock=0/1&skuPrice=400_1900&brandId=1&catalog3Id=1&at trs=1_3G:4G:5G&attrs=2_骁龙845&attrs=4_高清屏
@Data
public class SearchParam {
/** * 页面传递过来的全文匹配关键字 */
private String keyword;
/** * 品牌id,可以多选 */
private List<Long> brandId;
/** * 三级分类id */
private Long catalog3Id;
/** * 排序条件:sort=price/salecount/hotscore_desc/asc */
private String sort;
/** * 是否显示有货 */
private Integer hasStock = 1;
/** * 价格区间查询 */
private String skuPrice;
/** * 按照属性进行筛选 */
private List<String> attrs;
/** * 页码 */
private Integer pageNum = 1;
/** * 原生的所有查询条件 */
private String _queryString;
}
封装返回数据:
@Data
public class SearchResponse {
/** * 所有商品信息 */
private List<SkuModel> products;
/** * 分页信息 */
private Integer pageNum;//当前页码
private Long total;//总记录数
private Long totalPage;//总页码
/** * 当前查询到的结果,所以涉及到的品牌 */
private List<BrandVo> brands;
/** *当前查询到的结果,所以涉及到的分类 */
private List<CatalogVo> catalogs;
/** * 当前查询到的结果,所以涉及到的属性 */
private List<AttrVo> attrs;
@Data
public static class BrandVo{
private Long brandId;
private String brandName;
private String brandImg;
}
@Data
public static class CatalogVo{
private Long catalogId;
private String catalogName;
}
@Data
public static class AttrVo{
private Long attrId;
private String attrName;
private List<String> attrValue;
}
}
3.ES 编写 DSL
//数据迁移
PUT gulimall_product
{
"mappings": {
"properties": {
"skuId": {
"type": "long"
},
"spuId": {
"type": "keyword"
},
"skuTitle": {
"type": "text",
"analyzer": "ik_smart"
},
"skuPrice": {
"type": "keyword"
},
"skuImg": {
"type": "keyword"
},
"saleCount": {
"type": "long"
},
"hasStock": {
"type": "boolean"
},
"hotScore": {
"type": "long"
},
"brandId": {
"type": "long"
},
"catelogId": {
"type": "long"
},
"brandName": {
"type": "keyword"
},
"brandImg": {
"type": "keyword"
},
"catelogName": {
"type": "keyword"
},
"attrs": {
"type": "nested",
"properties": {
"attrId": {
"type": "long"
},
"attrName": {
"type": "keyword"
},
"attrValue": {
"type": "keyword"
}
}
}
}
}
}
GET gulimall_product/_mapping
POST _reindex
{
"source": {
"index": "product"
},
"dest": {
"index":"gulimall_product"
}
}
//查询条件
GET gulimall_product/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"skuTitle": "华为"
}
}
],
"filter": [
{
"term": {
"catelogId": "225"
}
},
{
"terms": {
"brandId": [
"9"
]
}
},
{
"term": {
"hasStock": "true"
}
},
{
"range": {
"skuPrice": {
"gte": 1000,
"lte": 7000
}
}
},
{
"nested": {
"path": "attrs",
"query": {
"bool": {
"must": [
{
"term": {
"attrs.attrId": {
"value": "15"
}
}
}
]
}
}
}
}
]
}
},
"sort": [
{
"skuPrice": {
"order": "desc"
}
}
],
"from": 0,
"size": 5,
"highlight": {
"fields": {
"skuTitle": {
}
},
"pre_tags": "<b style='color:red'>",
"post_tags": "</b>"
},
"aggs": {
"brandAgg": {
"terms": {
"field": "brandId",
"size": 10
},
"aggs": {
"brandNameAgg": {
"terms": {
"field": "brandName",
"size": 10
}
},
"brandImgAgg": {
"terms": {
"field": "brandImg",
"size": 10
}
}
}
},
"catelogAgg": {
"terms": {
"field": "catelogId",
"size": 10
},
"aggs": {
"catelogNameAgg": {
"terms": {
"field": "catelogName",
"size": 10
}
}
}
},
"attrs": {
"nested": {
"path": "attrs"
},
"aggs": {
"attrIdAgg": {
"terms": {
"field": "attrs.attrId",
"size": 10
},
"aggs": {
"attrNameAgg": {
"terms": {
"field": "attrs.attrName",
"size": 10
}
}
}
}
}
}
}
}
4.业务代码
=================================SearchController.java==================================
@Controller
public class SearchController {
@Autowired
MallSearchService mallSearchService;
@GetMapping("/list.html")
public String listPage(SearchParam searchParam, Model model){
SearchResult searchResult = mallSearchService.search(searchParam);
model.addAttribute("result",searchResult);
return "list";
}
}
====================================MallSearchServiceImpl.java================================
//去es进行检索
@Override
public SearchResult search(SearchParam searchParam) {
//1.动态构建出要查询的DSL语句
SearchResult searchResult = null;
//1.准备检索请求
SearchRequest searchRequest = buildSearchRequest(searchParam);
try {
//2.执行检索请求
SearchResponse response = client.search(searchRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);
//3.分析响应数据,封装成想要的格式
searchResult = buildSearchResult(response);
} catch (IOException e) {
e.printStackTrace();
}
return searchResult;
}
/** * 1.准备检索请求 * @return * @param searchParam */
private SearchRequest buildSearchRequest(SearchParam searchParam) {
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();//构建DSL语句
/** * 查询:模糊匹配、过滤(按照属性、分类、品牌、价格区间、库存) */
//1.构建bool query
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//1.1 must -模糊匹配 keyword
if (!StringUtils.isEmpty(searchParam.getKeyword())){
//match
boolQuery.must(QueryBuilders.matchQuery("skuTitle",searchParam.getKeyword()));
}
//1.2 bool-filter catelogId
if (searchParam.getCatalog3Id() != null){
boolQuery.filter(QueryBuilders.termQuery("catelogId",searchParam.getCatalog3Id()));
}
//1.2 bool-filter brandId
if (searchParam.getBrandId() != null && searchParam.getBrandId().size() > 0){
boolQuery.filter(QueryBuilders.termsQuery("brandId",searchParam.getBrandId()));
}
//1.2 bool-filter hasStock
boolQuery.filter(QueryBuilders.termQuery("hasStock",searchParam.getHasStock() == 1));
//1.2 bool-filter skuPrice 1_500/_500/500_
if (!StringUtils.isEmpty(searchParam.getSkuPrice())){
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice");
String[] s = searchParam.getSkuPrice().split("_");
if (s.length == 2){
//rangeQuery.gte(s[0]).lte(s[1]);
//"_6000".split("_") = {"","6000"}
if (!s[0].isEmpty()){
rangeQuery.gte(s[0]);
}
rangeQuery.lte(s[1]);
}else if (s.length == 1){
if (searchParam.getSkuPrice().startsWith("_")){
rangeQuery.lte(s[0]);
}
if (searchParam.getSkuPrice().endsWith("_")){
rangeQuery.lte(s[0]);
}
}
boolQuery.filter(rangeQuery);
}
//1.2 bool-filter attrs {attrID,attrID,attrID...}
if (searchParam.getAttrs() != null && searchParam.getAttrs().size() > 0){
//attrs=1_5寸:8寸&attrs=2_16G:8G
for (String attr : searchParam.getAttrs()) {
BoolQueryBuilder nestedBoolQuery = QueryBuilders.boolQuery();
//attrs=1_5寸:8寸
String[] s = attr.split("_");//1 5寸:8寸
String attrId = s[0];//1
String[] attrValues = s[1].split(":");//5寸 8寸
nestedBoolQuery.must(QueryBuilders.termQuery("attrs.attrId",attrId));
nestedBoolQuery.must(QueryBuilders.termsQuery("attrs.attrValue",attrValues));
//attrs中的每一个attr 都对应一个 nestedQueryBuilder
NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery("attrs", nestedBoolQuery, ScoreMode.None);
boolQuery.filter(nestedQuery);
}
}
//封装所有的查询条件
sourceBuilder.query(boolQuery);
/** * 排序、分页、高亮 */
//2.1 排序 sort=hotScore_asc/desc
if (!StringUtils.isEmpty(searchParam.getSort())){
String[] s = searchParam.getSort().split("_");
sourceBuilder.sort(s[0], SortOrder.valueOf(s[1]));
}
//2.2 分页
sourceBuilder.from((searchParam.getPageNum()-1) * EsConstant.PRODUCT_PAGE_SIZE);
sourceBuilder.size(EsConstant.PRODUCT_PAGE_SIZE);
//2.3 高亮 根据关键字 匹配高亮
if (!StringUtils.isEmpty(searchParam.getKeyword())){
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("skuTitle");
highlightBuilder.preTags("<b style='color:red'>");
highlightBuilder.postTags("</b>");
sourceBuilder.highlighter(highlightBuilder);
}
/** * 聚合分析 */
//3.1 品牌聚合
TermsAggregationBuilder brand_agg = AggregationBuilders.terms("brand_agg");
brand_agg.field("brandId").size(50);
//品牌聚合的子聚合
brand_agg.subAggregation(AggregationBuilders.terms("brand_name_agg").field("brandName").size(1));
brand_agg.subAggregation(AggregationBuilders.terms("brand_img_agg").field("brandImg").size(1));
sourceBuilder.aggregation(brand_agg);
//3.2 分类聚合
TermsAggregationBuilder catelog_agg = AggregationBuilders.terms("catelog_agg");
catelog_agg.field("catelogId").size(2);
catelog_agg.subAggregation(AggregationBuilders.terms("catelog_name_agg").field("catelogName").size(1));
sourceBuilder.aggregation(catelog_agg);
//3.3 属性聚合
NestedAggregationBuilder attr_agg = AggregationBuilders.nested("attr_agg", "attrs");
//聚合出所有的 attr_id_agg
TermsAggregationBuilder attr_id_agg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId");
//聚合分析出当前 attr_id对应的名字
attr_id_agg.subAggregation(AggregationBuilders.terms("attr_name_agg").field("attrs.attrName").size(1));
//聚合分析出当前 attr_id对应的所有可能的属性值
attr_id_agg.subAggregation(AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue").size(50));
attr_agg.subAggregation(attr_id_agg);
sourceBuilder.aggregation(attr_agg);
String s = sourceBuilder.toString();
System.out.println(s);
//索引 、 DSL语句
SearchRequest searchRequest = new SearchRequest(new String[]{
EsConstant.PRODUCT_INDEX}, sourceBuilder);
return searchRequest;
}
/** * 3.分析响应数据,封装成想要的格式 * @param response * @return */
private SearchResult buildSearchResult(SearchResponse response,SearchParam searchParam) {
SearchResult searchResult = new SearchResult();
SearchHits hits = response.getHits();
//1.返回所以查询到的商品
List<SkuModel> esModels = new ArrayList<>();
if (hits.getHits() != null && hits.getHits().length > 0){
for (SearchHit hit : hits.getHits()) {
String sourceAsString = hit.getSourceAsString();
SkuModel esModel = JSON.parseObject(sourceAsString,SkuModel.class);
if (!StringUtils.isEmpty(searchParam.getKeyword())) {
HighlightField skuTitle = hit.getHighlightFields().get("skuTitle");
String highLightTitle = skuTitle.getFragments()[0].string();
esModel.setSkuTitle(highLightTitle);
}
esModels.add(esModel);
}
}
searchResult.setProducts(esModels);
//2.当前所有商品涉及到的属性信息
ParsedNested attr_agg = response.getAggregations().get("attr_agg");
List<SearchResult.AttrVo> attrVos = new ArrayList<>();
ParsedLongTerms attr_id_agg = attr_agg.getAggregations().get("attr_id_agg");
for (Terms.Bucket bucket : attr_id_agg.getBuckets()) {
SearchResult.AttrVo attrVo = new SearchResult.AttrVo();
//获取属性的id
Long attrId = bucket.getKeyAsNumber().longValue();
attrVo.setAttrId(attrId);
//获取属性的name
ParsedStringTerms attr_name_agg = bucket.getAggregations().get("attr_name_agg");
String attrName = attr_name_agg.getBuckets().get(0).getKeyAsString();
attrVo.setAttrName(attrName);
//获取属性的value
ParsedStringTerms attr_value_age = bucket.getAggregations().get("attr_value_agg");
List<String> attrValue = attr_value_age.getBuckets().stream().map(item -> {
String keyAsString = item.getKeyAsString();
return keyAsString;
}).collect(Collectors.toList());
attrVo.setAttrValue(attrValue);
attrVos.add(attrVo);
}
searchResult.setAttrs(attrVos);
//3.当前所有商品涉及到的品牌信息
ParsedLongTerms brand_agg = response.getAggregations().get("brand_agg");
List<SearchResult.BrandVo> brandVos = new ArrayList<>();
for (Terms.Bucket bucket : brand_agg.getBuckets()) {
SearchResult.BrandVo brandVo = new SearchResult.BrandVo();
//获取品牌id
String keyAsString = bucket.getKeyAsString();
brandVo.setBrandId(Long.parseLong(keyAsString));
//获取品牌名
ParsedStringTerms brand_name_agg = bucket.getAggregations().get("brand_name_agg");
String brand_name = brand_name_agg.getBuckets().get(0).getKeyAsString();
brandVo.setBrandName(brand_name);
//获取品牌图片
ParsedStringTerms brand_img_agg = bucket.getAggregations().get("brand_img_agg");
String brand_img = brand_img_agg.getBuckets().get(0).getKeyAsString();
brandVo.setBrandImg(brand_img);
brandVos.add(brandVo);
}
searchResult.setBrands(brandVos);
//4.当前所有商品涉及到的分类信息
ParsedLongTerms catelog_agg = response.getAggregations().get("catelog_agg");
List<SearchResult.CatalogVo> catalogVos = new ArrayList<>();
for (Terms.Bucket bucket : catelog_agg.getBuckets()) {
SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();
//得到分类id
String keyAsString = bucket.getKeyAsString();
catalogVo.setCatalogId(Long.parseLong(keyAsString));
//得到分类名
ParsedStringTerms catelog_name_agg = bucket.getAggregations().get("catelog_name_agg");
String catelog_name = catelog_name_agg.getBuckets().get(0).getKeyAsString();
catalogVo.setCatalogName(catelog_name);
catalogVos.add(catalogVo);
}
searchResult.setCatalogs(catalogVos);
//5.分页信息-页码
searchResult.setPageNum(searchParam.getPageNum());
//5.分页信息-总记录数
long total = hits.getTotalHits().value;
searchResult.setTotal(total);
//5.分页信息-总页码
int totoalPages = (int) total%EsConstant.PRODUCT_PAGE_SIZE == 0 ? (int) total/EsConstant.PRODUCT_PAGE_SIZE : (int) (total/EsConstant.PRODUCT_PAGE_SIZE + 1);
searchResult.setTotalPage(totoalPages);
return null;
}
七、CompletableFuture-异步编排
1.线程池回顾
参考博客:《Java并发编程的艺术》2 第九章 Java中的线程池_HotRabbit.的博客-CSDN博客
2.异步
- Future 是 Java 5 添加的类,用来描述一个异步计算的结果。你可以使用
isDone方法检查计 算是否完成,或者使用get阻塞住调用线程,直到计算完成返回结果,你也可以使用cancel方法停止任务的执行。 - 虽然
Future以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不 方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的 初衷相违背,轮询的方式又会耗费无谓的 CPU 资源,而且也不能及时地得到计算结果,为 什么不能用观察者设计模式当计算结果完成及时通知监听者呢? - 很多语言,比如 Node.js,采用回调的方式实现异步编程。Java 的一些框架,比如 Netty,自 己扩展了 Java 的
Future接口,提供了addListener等多个扩展方法;Google guava 也提供了 通用的扩展 Future;Scala 也提供了简单易用且功能强大的 Future/Promise 异步编程模式。 - 在 Java 8 中, 新增加了一个包含 50 个方法左右的类: CompletableFuture,提供了非常强大的 Future 的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以 通过回调的方式处理计算结果,并且提供了转换和组合 CompletableFuture 的方法。 CompletableFuture 类实现了 Future 接口,所以你还是可以像以前一样通过
get方法阻塞或 者轮询的方式获得结果,但是这种方式不推荐使用。 - CompletableFuture 和 FutureTask 同属于 Future 接口的实现类,都可以获取线程的执行结果。

3.创建异步对象
CompletableFuture 提供了四个静态方法来创建一个异步操作。


get方法会阻塞当前线程,直到提交的任务执行完

3.1 计算完成时回调方法

whenComplete 可以处理正常和异常的计算结果,exceptionally 处理异常情况。
whenComplete 和 whenCompleteAsync 的区别:
- whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。
- whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池 来进行执行
方法不以 Async 结尾,意味着 Action 使用相同的线程执行,而 Async 可能会使用其他线程 执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)

3.2 handle方法
和 complete 一样,可对结果做最后的处理(可处理异常),可改变返回值。

3.3 线程串行化方法

- thenApply 方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前 任务的返回值。
- thenAccept 方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。
- thenRun 方法:只要上面的任务执行完成,就开始执行 thenRun,只是处理完任务后,执行 thenRun 的后续操作
带有 Async 默认是异步执行的。同之前。
以上都要前置任务成功完成。 Function<? super T , ? extends U>
- T:上一个任务返回结果的类型
- U:当前任务的返回值类型
3.4 两任务组合-都要完成
两个任务必须都完成,触发该任务。
- thenCombine:组合前两个 future,获取前两个 future 的返回结果,并返回当前任务的返回值
- thenAcceptBoth:组合前两个 future,获取前两个 future 任务的返回结果,然后处理任务,没有 返回值。
- runAfterBoth:组合前两个 future,不需要获取 future 的结果,只需前两个 future 处理完任务后, 处理该任务。
3.5 两任务组合-一个完成
当两个任务中,任意一个 future 任务完成的时候,执行任务。
- applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。
- acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。
- runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返 回值
3.6 多任务组合
- allOf:等待所有任务完成
- anyOf:只要有一个任务完成
八、商品详情
配置详情页路由

1. 封装vo
封装一个详情页的skuvo
@ToString
@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;
//6、秒杀商品的优惠信息
//private SeckillSkuVo seckillSkuVo;
}
@Data
@ToString
public class SkuItemSaleAttrVo {
private Long attrId;
private String attrName;
private List<AttrValueWithSkuIdVo> attrValues;
//private String attrValue 属性值
//private String skuIds 该属性值对应的skuId的集合
}
@Data
@ToString
public class SpuItemAttrGroupVo {
private String groupName;
//attrId,attrName,attrValue
private List<Attr> attrs;
}
2.使用异步编排提高效率
@Override
public SkuItemVo item(Long skuId) {
SkuItemVo skuItemVo = new SkuItemVo();
CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(() -> {
//1、sku基本信息的获取 pms_sku_info
SkuInfoEntity skuInfoEntity = this.getById(skuId);
skuItemVo.setInfo(skuInfoEntity);
return skuInfoEntity;
}, executor);
//2、sku的图片信息 pms_sku_images
CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> {
List<SkuImagesEntity> skuImagesEntities = skuImagesService.list(new QueryWrapper<SkuImagesEntity>().eq("sku_id", skuId));
skuItemVo.setImages(skuImagesEntities);
}, executor);
//3、获取spu的销售属性组合-> 依赖1 获取spuId
CompletableFuture<Void> saleFuture = infoFuture.thenAcceptAsync((info) -> {
List<SkuItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.listSaleAttrs(info.getSpuId());
skuItemVo.setSaleAttr(saleAttrVos);
}, executor);
//4、获取spu的介绍-> 依赖1 获取spuId
CompletableFuture<Void> descFuture = infoFuture.thenAcceptAsync((info) -> {
SpuInfoDescEntity byId = spuInfoDescService.getById(info.getSpuId());
skuItemVo.setDesc(byId);
}, executor);
//5、获取spu的规格参数信息-> 依赖1 获取spuId catalogId
CompletableFuture<Void> attrFuture = infoFuture.thenAcceptAsync((info) -> {
List<SpuItemAttrGroupVo> spuItemAttrGroupVos=productAttrValueService.getProductGroupAttrsBySpuId(info.getSpuId(), info.getCatalogId());
skuItemVo.setGroupAttrs(spuItemAttrGroupVos);
}, executor);
// //6、秒杀商品的优惠信息
// CompletableFuture<Void> seckFuture = CompletableFuture.runAsync(() -> {
// R r = seckillFeignService.getSeckillSkuInfo(skuId);
// if (r.getCode() == 0) {
// SeckillSkuVo seckillSkuVo = r.getData(new TypeReference<SeckillSkuVo>() {
// });
// long current = System.currentTimeMillis();
// //如果返回结果不为空且活动未过期,设置秒杀信息
// if (seckillSkuVo != null&¤t<seckillSkuVo.getEndTime()) {
// skuItemVo.setSeckillSkuVo(seckillSkuVo);
// }
// }
// }, executor);
//等待所有任务执行完成
try {
CompletableFuture.allOf(imageFuture, saleFuture, descFuture, attrFuture).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return skuItemVo;
}
/** * 商品详情页 * * @param skuId * @return */
/* @Override public SkuItemVo item(Long skuId) { SkuItemVo skuItemVo = new SkuItemVo(); //1、sku基本信息的获取 pms_sku_info SkuInfoEntity skuInfoEntity = this.getById(skuId); skuItemVo.setInfo(skuInfoEntity); Long spuId = skuInfoEntity.getSpuId(); Long catalogId = skuInfoEntity.getCatalogId(); //2、sku的图片信息 pms_sku_images List<SkuImagesEntity> skuImagesEntities = skuImagesService.list(new QueryWrapper<SkuImagesEntity>().eq("sku_id", skuId)); skuItemVo.setImages(skuImagesEntities); //3、获取spu的销售属性组合-> 依赖1 获取spuId List<SkuItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.listSaleAttrs(spuId); skuItemVo.setSaleAttr(saleAttrVos); //4、获取spu的介绍-> 依赖1 获取spuId SpuInfoDescEntity byId = spuInfoDescService.getById(spuId); skuItemVo.setDesc(byId); //5、获取spu的规格参数信息-> 依赖1 获取spuId catalogId List<SpuItemAttrGroupVo> spuItemAttrGroupVos = productAttrValueService.getProductGroupAttrsBySpuId(spuId, catalogId); skuItemVo.setGroupAttrs(spuItemAttrGroupVos); //TODO 6、秒杀商品的优惠信息 return skuItemVo; } */

边栏推荐
- 分割回文串 DP+回溯 (LeetCode-131)
- TC358860XBG BGA65 东芝桥接芯片 HDMI转MIPI
- Modify hosts file using batch script
- Case | industrial iot solutions, steel mills high-performance security for wisdom
- 408-Binary tree-preorder inorder postorder level traversal
- [Arduino connects the clock module to display the time on LCD1602]
- USB2.0一致性测试方法_高速示波器
- path 修补文件命令
- 实现动态库(DLL)之间内存统一管理
- Host your own website with Vercel
猜你喜欢

bluez5.50蓝牙文件传输

【LeetCode】链表相加 进位

判断子序列 —— LeetCode-392

Typora use

基础IO(上):文件管理和描述符

Modify hosts file using batch script

MIPI解决方案 ICN6202:MIPI DSI转LVDS转换芯片

【Connect the heart rate sensor to Arduino to read the heart rate data】

【TCS3200 color sensor and Arduino realize color recognition】

Cadence allegro导出Gerber文件(制板文件)图文操作
随机推荐
Laptop charging problems
【操作系统】线程安全保护机制
MIPI解决方案 ICN6202:MIPI DSI转LVDS转换芯片
proteus数字电路仿真——入门实例
联阳(ITE)IT66021FN:HDMI转RGB芯片 3D 资料
408-Binary tree-preorder inorder postorder level traversal
GM7150 CVBS转BT656视频解码芯片详细内容及设计要求
Chrome 里的小恐龙游戏是怎么做出来的?
【plang 1.4.6】Plang高级编程语言(发布)
GM7150,振芯科技,视频解码器,CVBS转BT656/601,QFN32,替换TVP5150/CJC5150
MAC安装Mysql超详细完整教程
[Arduino connects the clock module to display the time on LCD1602]
判断子序列 —— LeetCode-392
install 命令
将ORCAD原理图导入allegro中进行PCB设计
[Arduino connected to GPS module (NEO-6M) to read positioning data]
机械臂运动学解析
Modify hosts file using batch script
引擎开发日志:场景编辑器开发难点
Arduino lights up nixie tubes