平板微信hd版seo網(wǎng)絡推廣是什么意思
一、product-es準備
P128
ES在內(nèi)存中,所以在檢索中優(yōu)于mysql。ES也支持集群,數(shù)據(jù)分片存儲。
需求:
- 上架的商品才可以在網(wǎng)站展示。
- 上架的商品需要可以被檢索。
分析sku在es中如何存儲
商品mapping
分析:商品上架在es中是存sku還是spu?
1)、檢索的時候輸入名字,是需要按照sku的title進行全文檢索的
2)、檢素使用商品規(guī)格,規(guī)格是spu的公共屬性,每個spu是一樣的
3)、按照分類id進去的都是直接列出spu的,還可以切換。
4〕、我們?nèi)绻麑ku的全量信息保存到es中(包括spu屬性〕就太多字段了
方案1:
{skuId:1spuId:11skyTitile:華為xxprice:999saleCount:99attr:[{尺寸:5},{CPU:高通945},{分辨率:全高清}]
缺點:如果每個sku都存儲規(guī)格參數(shù)(如尺寸),會有冗余存儲,因為每個sku對應的spu的規(guī)格參數(shù)都一樣
方案2:
sku索引
{spuId:1skuId:11
}
attr索引
{skuId:11attr:[{尺寸:5},{CPU:高通945},{分辨率:全高清}]
}
先找到4000個符合要求的spu,再根據(jù)4000個spu查詢對應的屬性,封裝了4000個id,long 8B*4000=32000B=32KB
1K個人檢索,就是32MB結(jié)論:如果將規(guī)格參數(shù)單獨建立索引,會出現(xiàn)檢索時出現(xiàn)大量數(shù)據(jù)傳輸?shù)膯栴},會引起網(wǎng)絡網(wǎng)絡
🚩 因此選用方案1,以空間換時間
建立product索引
最終選用的數(shù)據(jù)模型:
- { “type”: “keyword” }, # 保持數(shù)據(jù)精度問題,可以檢索,但不分詞
- “analyzer”: “ik_smart” # 中文分詞器
- “index”: false, # 不可被檢索,不生成index
- “doc_values”: false # 默認為true,不可被聚合,es就不會維護一些聚合的信息
PUT product
{"mappings":{"properties": {"skuId":{ "type": "long" },"spuId":{ "type": "keyword" }, # 不可分詞"skuTitle": {"type": "text","analyzer": "ik_smart" # 中文分詞器},"skuPrice": { "type": "keyword" }, # 保證精度問題"skuImg" : { "type": "keyword" }, # 視頻中有false"saleCount":{ "type":"long" },"hasStock": { "type": "boolean" },"hotScore": { "type": "long" },"brandId": { "type": "long" },"catalogId": { "type": "long" },"brandName": {"type": "keyword"}, # 視頻中有false"brandImg":{"type": "keyword","index": false, # 不可被檢索,不生成index,只用做頁面使用"doc_values": false # 不可被聚合,默認為true},"catalogName": {"type": "keyword" }, # 視頻里有false"attrs": {"type": "nested","properties": {"attrId": {"type": "long" },"attrName": {"type": "keyword","index": false,"doc_values": false},"attrValue": {"type": "keyword" }}}}}
}
如果檢索不到商品,自己用postman測試一下,可能有的字段需要更改,你也可以把沒必要的"keyword"去掉
冗余存儲的字段:不用來檢索,也不用來分析,節(jié)省空間
庫存是bool。
檢索品牌id,但是不檢索品牌名字、圖片
用skuTitle檢索
二、nested嵌入式對象
屬性是"type": “nested”,因為是內(nèi)部的屬性進行檢索
數(shù)組類型的對象會被扁平化處理(對象的每個屬性會分別存儲到一起)
user.name=["aaa","bbb"]
user.addr=["ccc","ddd"]這種存儲方式,可能會發(fā)生如下錯誤:
錯誤檢索到{aaa,ddd},這個組合是不存在的
數(shù)組的扁平化處理會使檢索能檢索到本身不存在的,為了解決這個問題,就采用了嵌入式屬性,數(shù)組里是對象時用嵌入式屬性(不是對象無需用嵌入式屬性)
三、商品上架(ES保存)
@Override // SpuInfoServiceImplpublic void up(Long spuId) {// 1 組裝數(shù)據(jù) 查出當前spuId對應的所有sku信息List<SkuInfoEntity> skus = skuInfoService.getSkusBySpuId(spuId);// 查詢這些sku是否有庫存List<Long> skuids = skus.stream().map(sku -> sku.getSkuId()).collect(Collectors.toList());// 2 封裝每個sku的信息// 3.查詢當前sku所有可以被用來檢索的規(guī)格屬性List<ProductAttrValueEntity> baseAttrs = attrValueService.baseAttrListForSpu(spuId);// 得到基本屬性idList<Long> attrIds = baseAttrs.stream().map(attr -> attr.getAttrId()).collect(Collectors.toList());// 過濾出可被檢索的基本屬性id,即search_type = 1 [數(shù)據(jù)庫中目前 4、5、6、11不可檢索]Set<Long> ids = new HashSet<>(attrService.selectSearchAttrIds(attrIds));// 可被檢索的屬性封裝到SkuEsModel.Attrs中List<SkuEsModel.Attrs> attrs = baseAttrs.stream().filter(item -> ids.contains(item.getAttrId())).map(item -> {SkuEsModel.Attrs attr = new SkuEsModel.Attrs();BeanUtils.copyProperties(item, attr);return attr;}).collect(Collectors.toList());// 每件skuId是否有庫存Map<Long, Boolean> stockMap = null;try {// 3.1 遠程調(diào)用庫存系統(tǒng) 查詢該sku是否有庫存R hasStock = wareFeignService.getSkuHasStock(skuids);// 構(gòu)造器受保護 所以寫成內(nèi)部類對象stockMap = hasStock.getData(new TypeReference<List<SkuHasStockVo>>() {}).stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, item -> item.getHasStock()));log.warn("服務調(diào)用成功" + hasStock);} catch (Exception e) {log.error("庫存服務調(diào)用失敗: 原因{}", e);}Map<Long, Boolean> finalStockMap = stockMap;//防止lambda中改變// 開始封裝esList<SkuEsModel> skuEsModels = skus.stream().map(sku -> {SkuEsModel esModel = new SkuEsModel();BeanUtils.copyProperties(sku, esModel);esModel.setSkuPrice(sku.getPrice());esModel.setSkuImg(sku.getSkuDefaultImg());// 4 設(shè)置庫存,只查是否有庫存,不查有多少if (finalStockMap == null) {esModel.setHasStock(true);} else {esModel.setHasStock(finalStockMap.get(sku.getSkuId()));}// TODO 1.熱度評分 剛上架是0esModel.setHotScore(0L);// 設(shè)置品牌信息BrandEntity brandEntity = brandService.getById(esModel.getBrandId());esModel.setBrandName(brandEntity.getName());esModel.setBrandImg(brandEntity.getLogo());// 查詢分類信息CategoryEntity categoryEntity = categoryService.getById(esModel.getCatalogId());esModel.setCatalogName(categoryEntity.getName());// 保存商品的屬性, 查詢當前sku的所有可以被用來檢索的規(guī)格屬性,同一spu都一樣,在外面查一遍即可esModel.setAttrs(attrs);return esModel;}).collect(Collectors.toList());// 5.發(fā)給ES進行保存 gulimall-searchR r = searchFeignService.productStatusUp(skuEsModels);if (r.getCode() == 0) {// 遠程調(diào)用成功baseMapper.updateSpuStatus(spuId, ProductConstant.StatusEnum.SPU_UP.getCode());} else {// 遠程調(diào)用失敗 TODO 接口冪等性 重試機制/*** Feign 的調(diào)用流程 Feign有自動重試機制* 1. 發(fā)送請求執(zhí)行* 2.*/}}
@Slf4j
@Service
public class ProductSaveServiceImpl implements ProductSaveService {@Resourceprivate RestHighLevelClient client;/*** 將數(shù)據(jù)保存到ES* 用bulk代替index,進行批量保存* BulkRequest bulkRequest, RequestOptions options*/@Override // ProductSaveServiceImplpublic boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException {// 1. 批量保存BulkRequest bulkRequest = new BulkRequest();// 2.構(gòu)造保存請求for (SkuEsModel esModel : skuEsModels) {// 設(shè)置es索引 gulimall_productIndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX);// 設(shè)置索引idindexRequest.id(esModel.getSkuId().toString());// json格式String jsonString = JSON.toJSONString(esModel);indexRequest.source(jsonString, XContentType.JSON);// 添加到文檔bulkRequest.add(indexRequest);}// bulk批量保存BulkResponse bulk = client.bulk(bulkRequest, GuliESConfig.COMMON_OPTIONS);// TODO 是否擁有錯誤boolean hasFailures = bulk.hasFailures();if(hasFailures){List<String> collect = Arrays.stream(bulk.getItems()).map(item -> item.getId()).collect(Collectors.toList());log.error("商品上架錯誤:{}",collect);}return hasFailures;}
}
PUT product
{"mappings": {"properties": {"skuId":{"type": "long"},"spuId":{"type": "keyword"},"skuTitle":{"type": "text","analyzer": "ik_smart"},"skuPrice":{"type": "keyword"},"skuImg":{"type": "keyword","index": false,"doc_values": false},"saleCount":{"type": "long"},"hasStock":{"type": "boolean"},"hotScore":{"type": "long"},"brandId":{"type": "long"},"catalogId":{"type": "long"},"brandName":{"type":"keyword","index": false,"doc_values": false},"brandImg":{"type": "keyword","index": false,"doc_values": false},"catalogName":{"type": "keyword","index": false,"doc_values": false},"attrs":{"type": "nested","properties": {"attrId":{"type":"long"},"attrName":{"type":"keyword","index":false,"doc_values": false},"attrValue":{"type":"keyword"}}}}}
}
四、檢索服務
package com.atguigu.gulimall.search.service.impl;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.to.es.SkuEsModel;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.search.config.GuliESConfig;
import com.atguigu.gulimall.search.constant.EsConstant;
import com.atguigu.gulimall.search.feign.ProductFeignService;
import com.atguigu.gulimall.search.service.SearchService;
import com.atguigu.gulimall.search.vo.AttrResponseVo;
import com.atguigu.gulimall.search.vo.BrandVo;
import com.atguigu.gulimall.search.vo.SearchParam;
import com.atguigu.gulimall.search.vo.SearchResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;import javax.annotation.Resource;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;/*** <p>Title: MallServiceImpl</p>* Description:* date:2020/6/12 23:06*/
@Slf4j
@Service
public class SearchServiceImpl implements SearchService {@Resourceprivate RestHighLevelClient restHighLevelClient;@Resourceprivate ProductFeignService productFeignService;@Overridepublic SearchResult search(SearchParam Param) {SearchResult result = null;// 1.準備檢索請求SearchRequest searchRequest = buildSearchRequest(Param);try {// 2.執(zhí)行檢索請求SearchResponse response = restHighLevelClient.search(searchRequest, GuliESConfig.COMMON_OPTIONS);// 3.分析響應數(shù)據(jù)result = buildSearchResult(response, Param);} catch (IOException e) {e.printStackTrace();}return result;}/*** 準備檢索請求 [構(gòu)建查詢語句]*/private SearchRequest buildSearchRequest(SearchParam Param) {// 幫我們構(gòu)建DSL語句的SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();// 1. 模糊匹配 過濾(按照屬性、分類、品牌、價格區(qū)間、庫存) 先構(gòu)建一個布爾Query// 1.1 mustBoolQueryBuilder boolQuery = QueryBuilders.boolQuery();if(!StringUtils.isEmpty(Param.getKeyword())){boolQuery.must(QueryBuilders.matchQuery("skuTitle",Param.getKeyword()));}// 1.2 bool - filter Catalog3Idif(StringUtils.isEmpty(Param.getCatalog3Id() != null)){boolQuery.filter(QueryBuilders.termQuery("catalogId", Param.getCatalog3Id()));}// 1.2 bool - brandId [集合]if(Param.getBrandId() != null && Param.getBrandId().size() > 0){boolQuery.filter(QueryBuilders.termsQuery("brandId", Param.getBrandId()));}// 屬性查詢if(Param.getAttrs() != null && Param.getAttrs().size() > 0){for (String attrStr : Param.getAttrs()) {BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();String[] s = attrStr.split("_");// 檢索的id 屬性檢索用的值String attrId = s[0];String[] attrValue = s[1].split(":");boolQueryBuilder.must(QueryBuilders.termQuery("attrs.attrId", attrId));boolQueryBuilder.must(QueryBuilders.termsQuery("attrs.attrValue", attrValue));// 構(gòu)建一個嵌入式Query 每一個必須都得生成嵌入的 nested 查詢NestedQueryBuilder attrsQuery = QueryBuilders.nestedQuery("attrs", boolQueryBuilder, ScoreMode.None);boolQuery.filter(attrsQuery);}}// 1.2 bool - filter [庫存]if(Param.getHasStock() != null){boolQuery.filter(QueryBuilders.termQuery("hasStock",Param.getHasStock() == 1));}// 1.2 bool - filter [價格區(qū)間]if(!StringUtils.isEmpty(Param.getSkuPrice())){RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice");String[] s = Param.getSkuPrice().split("_");if(s.length == 2){// 有三個值 就是區(qū)間rangeQuery.gte(s[0]).lte(s[1]);}else if(s.length == 1){// 單值情況if(Param.getSkuPrice().startsWith("_")){rangeQuery.lte(s[0]);}if(Param.getSkuPrice().endsWith("_")){rangeQuery.gte(s[0]);}}boolQuery.filter(rangeQuery);}// 把以前所有條件都拿來進行封裝sourceBuilder.query(boolQuery);// 1.排序if(!StringUtils.isEmpty(Param.getSort())){String sort = Param.getSort();// sort=hotScore_asc/descString[] s = sort.split("_");SortOrder order = s[1].equalsIgnoreCase("asc") ? SortOrder.ASC : SortOrder.DESC;sourceBuilder.sort(s[0], order);}// 2.分頁 pageSize : 5sourceBuilder.from((Param.getPageNum()-1) * EsConstant.PRODUCT_PASIZE);sourceBuilder.size(EsConstant.PRODUCT_PASIZE);// 3.高亮if(!StringUtils.isEmpty(Param.getKeyword())){HighlightBuilder builder = new HighlightBuilder();builder.field("skuTitle");builder.preTags("<b style='color:red'>");builder.postTags("</b>");sourceBuilder.highlighter(builder);}// 聚合分析// TODO 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));// 將品牌聚合加入 sourceBuildersourceBuilder.aggregation(brand_agg);// TODO 2.分類聚合TermsAggregationBuilder catalog_agg = AggregationBuilders.terms("catalog_agg").field("catalogId").size(20);catalog_agg.subAggregation(AggregationBuilders.terms("catalog_name_agg").field("catalogName").size(1));// 將分類聚合加入 sourceBuildersourceBuilder.aggregation(catalog_agg);// TODO 3.屬性聚合 attr_agg 構(gòu)建嵌入式聚合NestedAggregationBuilder attr_agg = AggregationBuilders.nested("attr_agg", "attrs");// 3.1 聚合出當前所有的attrIdTermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId");// 3.1.1 聚合分析出當前attrId對應的attrNameattrIdAgg.subAggregation(AggregationBuilders.terms("attr_name_agg").field("attrs.attrName").size(1));// 3.1.2 聚合分析出當前attrId對應的所有可能的屬性值attrValue 這里的屬性值可能會有很多 所以寫50attrIdAgg.subAggregation(AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue").size(50));// 3.2 將這個子聚合加入嵌入式聚合attr_agg.subAggregation(attrIdAgg);sourceBuilder.aggregation(attr_agg);log.info("\n構(gòu)建語句:->\n" + sourceBuilder.toString());SearchRequest searchRequest = new SearchRequest(new String[]{EsConstant.PRODUCT_INDEX}, sourceBuilder);return searchRequest;}/*** 構(gòu)建結(jié)果數(shù)據(jù) 指定catalogId 、brandId、attrs.attrId、嵌入式查詢、倒序、0-6000、每頁顯示兩個、高亮skuTitle、聚合分析*/private SearchResult buildSearchResult(SearchResponse response, SearchParam Param) {SearchResult result = new SearchResult();// 1.返回的所有查詢到的商品SearchHits hits = response.getHits();List<SkuEsModel> esModels = new ArrayList<>();if(hits.getHits() != null && hits.getHits().length > 0){for (SearchHit hit : hits.getHits()) {String sourceAsString = hit.getSourceAsString();// ES中檢索得到的對象SkuEsModel esModel = JSON.parseObject(sourceAsString, SkuEsModel.class);if(!StringUtils.isEmpty(Param.getKeyword())){// 1.1 獲取標題的高亮屬性HighlightField skuTitle = hit.getHighlightFields().get("skuTitle");String highlightFields = skuTitle.getFragments()[0].string();// 1.2 設(shè)置文本高亮esModel.setSkuTitle(highlightFields);}esModels.add(esModel);}}result.setProducts(esModels);// 2.當前所有商品涉及到的所有屬性信息ArrayList<SearchResult.AttrVo> attrVos = new ArrayList<>();ParsedNested attr_agg = response.getAggregations().get("attr_agg");ParsedLongTerms attr_id = attr_agg.getAggregations().get("attr_id_agg");for (Terms.Bucket bucket : attr_id.getBuckets()) {SearchResult.AttrVo attrVo = new SearchResult.AttrVo();// 2.1 得到屬性的idattrVo.setAttrId(bucket.getKeyAsNumber().longValue());// 2.2 得到屬性的名字String attr_name = ((ParsedStringTerms) bucket.getAggregations().get("attr_name_agg")).getBuckets().get(0).getKeyAsString();attrVo.setAttrName(attr_name);// 2.3 得到屬性的所有值List<String> attr_value = ((ParsedStringTerms) bucket.getAggregations().get("attr_value_agg")).getBuckets().stream().map(item -> item.getKeyAsString()).collect(Collectors.toList());attrVo.setAttrValue(attr_value);attrVos.add(attrVo);}result.setAttrs(attrVos);// 3.當前所有商品涉及到的所有品牌信息ArrayList<SearchResult.BrandVo> brandVos = new ArrayList<>();ParsedLongTerms brand_agg = response.getAggregations().get("brand_agg");for (Terms.Bucket bucket : brand_agg.getBuckets()) {SearchResult.BrandVo brandVo = new SearchResult.BrandVo();// 3.1 得到品牌的idlong brnadId = bucket.getKeyAsNumber().longValue();brandVo.setBrandId(brnadId);// 3.2 得到品牌的名String brand_name = ((ParsedStringTerms) bucket.getAggregations().get("brand_name_agg")).getBuckets().get(0).getKeyAsString();brandVo.setBrandName(brand_name);// 3.3 得到品牌的圖片String brand_img = ((ParsedStringTerms) (bucket.getAggregations().get("brand_img_agg"))).getBuckets().get(0).getKeyAsString();brandVo.setBrandImg(brand_img);brandVos.add(brandVo);}result.setBrands(brandVos);// 4.當前商品所有涉及到的分類信息ParsedLongTerms catalog_agg = response.getAggregations().get("catalog_agg");List<SearchResult.CatalogVo> catalogVos = new ArrayList<>();for (Terms.Bucket bucket : catalog_agg.getBuckets()) {// 設(shè)置分類idSearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();catalogVo.setCatalogId(Long.parseLong(bucket.getKeyAsString()));// 得到分類名ParsedStringTerms catalog_name_agg = bucket.getAggregations().get("catalog_name_agg");String catalog_name = catalog_name_agg.getBuckets().get(0).getKeyAsString();catalogVo.setCatalogName(catalog_name);catalogVos.add(catalogVo);}result.setCatalogs(catalogVos);// ================以上信息從聚合信息中獲取// 5.分頁信息-頁碼result.setPageNum(Param.getPageNum());// 總記錄數(shù)long total = hits.getTotalHits().value;result.setTotal(total);// 總頁碼:計算得到int totalPages = (int)(total / EsConstant.PRODUCT_PASIZE + 0.999999999999);result.setTotalPages(totalPages);// 設(shè)置導航頁ArrayList<Integer> pageNavs = new ArrayList<>();for (int i = 1;i <= totalPages; i++){pageNavs.add(i);}result.setPageNavs(pageNavs);// 6.構(gòu)建面包屑導航功能if(Param.getAttrs() != null){List<SearchResult.NavVo> navVos = Param.getAttrs().stream().map(attr -> {SearchResult.NavVo navVo = new SearchResult.NavVo();String[] s = attr.split("_");navVo.setNavValue(s[1]);R r = productFeignService.getAttrsInfo(Long.parseLong(s[0]));// 將已選擇的請求參數(shù)添加進去 前端頁面進行排除result.getAttrIds().add(Long.parseLong(s[0]));if(r.getCode() == 0){AttrResponseVo data = r.getData(new TypeReference<AttrResponseVo>(){});navVo.setName(data.getAttrName());}else{// 失敗了就拿id作為名字navVo.setName(s[0]);}// 拿到所有查詢條件 替換查詢條件String replace = replaceQueryString(Param, attr, "attrs");navVo.setLink("http://search.gulimall.com/list.html?" + replace);return navVo;}).collect(Collectors.toList());result.setNavs(navVos);}// 品牌、分類if(Param.getBrandId() != null && Param.getBrandId().size() > 0){List<SearchResult.NavVo> navs = result.getNavs();SearchResult.NavVo navVo = new SearchResult.NavVo();navVo.setName("品牌");// TODO 遠程查詢所有品牌R r = productFeignService.brandInfo(Param.getBrandId());if(r.getCode() == 0){List<BrandVo> brand = r.getData("data", new TypeReference<List<BrandVo>>() {});StringBuffer buffer = new StringBuffer();// 替換所有品牌IDString replace = "";for (BrandVo brandVo : brand) {buffer.append(brandVo.getBrandName() + ";");replace = replaceQueryString(Param, brandVo.getBrandId() + "", "brandId");}navVo.setNavValue(buffer.toString());navVo.setLink("http://search.gulimall.com/list.html?" + replace);}navs.add(navVo);}return result;}/*** 替換字符* key :需要替換的key*/private String replaceQueryString(SearchParam Param, String value, String key) {String encode = null;try {encode = URLEncoder.encode(value,"UTF-8");// 瀏覽器對空格的編碼和java的不一樣encode = encode.replace("+","%20");encode = encode.replace("%28", "(").replace("%29",")");} catch (UnsupportedEncodingException e) {e.printStackTrace();}return Param.get_queryString().replace("&" + key + "=" + encode, "");}
}