[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";
}
}
封装前端检索条件:
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;
}
}
//数据迁移
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": "",
"post_tags": ""
},
"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
}
}
}
}
}
}
}
}
=================================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("");
highlightBuilder.postTags("");
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;
}
参考博客:《Java并发编程的艺术》2 第九章 Java中的线程池_HotRabbit.的博客-CSDN博客
isDone
方法检查计 算是否完成,或者使用get
阻塞住调用线程,直到计算完成返回结果,你也可以使用cancel
方法停止任务的执行。Future
以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不 方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的 初衷相违背,轮询的方式又会耗费无谓的 CPU 资源,而且也不能及时地得到计算结果,为 什么不能用观察者设计模式当计算结果完成及时通知监听者呢?Future
接口,提供了addListener
等多个扩展方法;Google guava 也提供了 通用的扩展 Future;Scala 也提供了简单易用且功能强大的 Future/Promise 异步编程模式。get
方法阻塞或 者轮询的方式获得结果,但是这种方式不推荐使用。CompletableFuture 提供了四个静态方法来创建一个异步操作。
get方法会阻塞当前线程,直到提交的任务执行完
whenComplete 可以处理正常和异常的计算结果,exceptionally 处理异常情况。
whenComplete 和 whenCompleteAsync 的区别:
方法不以 Async 结尾,意味着 Action 使用相同的线程执行,而 Async 可能会使用其他线程 执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)
和 complete 一样,可对结果做最后的处理(可处理异常),可改变返回值。
带有 Async 默认是异步执行的。同之前。
以上都要前置任务成功完成。 Function super T , ? extends U>
两个任务必须都完成,触发该任务。
当两个任务中,任意一个 future 任务完成的时候,执行任务。
配置详情页路由
封装一个详情页的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;
}
@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 seckFuture = CompletableFuture.runAsync(() -> {
// R r = seckillFeignService.getSeckillSkuInfo(skuId);
// if (r.getCode() == 0) {
// SeckillSkuVo seckillSkuVo = r.getData(new TypeReference() {
// });
// long current = System.currentTimeMillis();
// //如果返回结果不为空且活动未过期,设置秒杀信息
// if (seckillSkuVo != null&¤t
// 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 skuImagesEntities = skuImagesService.list(new QueryWrapper().eq("sku_id", skuId));
skuItemVo.setImages(skuImagesEntities);
//3、获取spu的销售属性组合-> 依赖1 获取spuId
List 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 spuItemAttrGroupVos = productAttrValueService.getProductGroupAttrsBySpuId(spuId, catalogId);
skuItemVo.setGroupAttrs(spuItemAttrGroupVos);
//TODO 6、秒杀商品的优惠信息
return skuItemVo;
}
*/