一、添加模板页面 1 2 3 4 5 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-thymeleaf</artifactId > </dependency >
将资料中的前端页面放到 search 服务模块下的 resource/templates 下;
二、配置请求跳转 1、配置 Nginx 转发 配置 Windows hosts 文件:
1 192.168.56.10 search.gulimall.com
找到 Nginx 的配置文件,编辑 gulimall.conf,将所有 *.gulimall.com 的请求都经由 Nginx 转发给网关;
1 2 3 4 5 server { listen 80; server_name gulimall.com *.gulimall.com; ... }
然后重启 Nginx
2、配置网关服务转发到 search 服务 1 2 3 4 - id: gulimall-search uri: lb://gulimall-search predicates: - Host=search.gulimall.com
3、静态页面处理 把资料中的前端页面的 css、img、js 放到 nginx 的 static 目录下
修改 gulimall-search 项目中 index.html 中的资源路径 例如:
4、配置页面跳转 第一处: gulimall-search index.html
第二处 :gulimall-search index.html
配置 /list.html 请求转发到 list 模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @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_高清屏
四、DSL 分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 GET gulimall_product/_search { "query" : { "bool" : { "must" : [ { "match" : { "skuTitle" : "华为" } } ], "filter" : [ { "term" : { "catalogId" : "225" } }, { "terms" : { "brandId" : [ "2" ] } }, { "term" : { "hasStock" : "false" } }, { "range" : { "skuPrice" : { "gte" : 1000 , "lte" : 7000 } } }, { "nested" : { "path" : "attrs" , "query" : { "bool" : { "must" : [ { "term" : { "attrs.attrId" : { "value" : "6" } } } ] } } } } ] } }, "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 } } } }, "catalogAgg" :{ "terms" : { "field" : "catalogId" , "size" : 10 }, "aggs" : { "catalogNameAgg" : { "terms" : { "field" : "catalogName" , "size" : 10 } } } }, "attrs" :{ "nested" : { "path" : "attrs" }, "aggs" : { "attrIdAgg" : { "terms" : { "field" : "attrs.attrId" , "size" : 10 }, "aggs" : { "attrNameAgg" : { "terms" : { "field" : "attrs.attrName" , "size" : 10 } } } } } } } }
五、检索代码编写 1、请求参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Data public class SearchParam { private String keyword; private List<Long> brandId; private Long catalog3Id; private String sort; private Integer hasStock; private String skuPrice; private List<String> attrs; private Integer pageNum = 1 ; private String _queryString; }
2、返回结果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 @Data public class SearchResult { private List<SkuEsModel> product; private Integer pageNum; private Long total; private Integer totalPages; private List<Integer> pageNavs; private List<BrandVo> brands; private List<AttrVo> attrs; private List<CatalogVo> catalogs; private List<NavVo> navs; @Data public static class NavVo { private String navName; private String navValue; private String link; } @Data @AllArgsConstructor public static class BrandVo { private Long brandId; private String brandName; private String brandImg; } @Data @AllArgsConstructor public static class AttrVo { private Long attrId; private String attrName; private List<String> attrValue; } @Data @AllArgsConstructor public static class CatalogVo { private Long catalogId; private String catalogName; } }
六、检索功能 1、ES mall-product 映射 mapping 修改 注意:
这里由于之前设置的映射 设置一些字段的 doc_value 为 false,导致后面聚合查询时报错!修改完映射 mapping 要同步修改检索服务中的常量类中的 es 索引常量,二者要求对应。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 # 查看原来的映射规则 GET gulimall_product/_mapping # 修改为新的映射 并创建新的索引,下面进行数据迁移 PUT /mall_product { "mappings" : { "properties" : { "skuId" : { "type" : "long" } , "spuId" : { "type" : "long" } , "skuTitle" : { "type" : "text" , "analyzer" : "ik_smart" } , "skuPrice" : { "type" : "keyword" } , "skuImg" : { "type" : "keyword" } , "saleCount" : { "type" : "long" } , "hosStock" : { "type" : "boolean" } , "hotScore" : { "type" : "long" } , "brandId" : { "type" : "long" } , "catalogId" : { "type" : "long" } , "brandName" : { "type" : "keyword" } , "brandImg" : { "type" : "keyword" } , "catalogName" : { "type" : "keyword" } , "attrs" : { "type" : "nested" , "properties" : { "attrId" : { "type" : "long" } , "attrName" : { "type" : "keyword" } , "attrValue" : { "type" : "keyword" } } } } } } # 数据迁移 POST _reindex { "source" : { "index" : "gulimall_product" } , "dest" : { "index" : "mall_product" } }
2、ES 检索 DSL 语句分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 GET mall_product/_search { "query" : { "bool" : { "must" : [ { "match" : { # 检索出华为 "skuTitle" : "华为" } } ] , "filter" : [ #过滤 { "term" : { "catalogId" : "225" } } , { "terms" : { "brandId" : [ "2" ] } } , { "term" : { "hasStock" : "false" } } , { "range" : { "skuPrice" : { #价格1 k-7 k "gte" : 1000 , "lte" : 7000 } } } , { "nested" : { "path" : "attrs" , #聚合名字 "query" : { "bool" : { "must" : [ { "term" : { "attrs.attrId" : { "value" : "7" } } } ] } } } } ] } } , "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" : { # 每个商品id的品牌 "terms" : { "field" : "brandName" , "size" : 10 } } , "brandImgAgg" : { "terms" : { "field" : "brandImg" , "size" : 10 } } } } , "catalogAgg" : { "terms" : { "field" : "catalogId" , "size" : 10 } , "aggs" : { "catalogNameAgg" : { "terms" : { "field" : "catalogName" , "size" : 10 } } } } , "attrs" : { "nested" : { "path" : "attrs" } , "aggs" : { "attrIdAgg" : { "terms" : { "field" : "attrs.attrId" , "size" : 10 } , "aggs" : { "attrNameAgg" : { "terms" : { "field" : "attrs.attrName" , "size" : 10 } } } } } } } }
七、页面效果 详细代码具体请参考:https://gitee.com/oycodesite/gulimall.git
1、 基本数据渲染 将商品的基本属性渲染出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 <div class ="rig_tab" > <div th:each ="product : ${result.getProduct()}" > <div class ="ico" > <i class ="iconfont icon-weiguanzhu" > </i > <a href ="/static/search/#" > 关注</a > </div > <p class ="da" > <a th:href ="|http://item.gulimall.com/${product.skuId}.html|" > <img class ="dim" th:src ="${product.skuImg}" /> </a > </p > <ul class ="tab_im" > <li > <a href ="/static/search/#" title ="黑色" > <img th:src ="${product.skuImg}" /> </a > </li > </ul > <p class ="tab_R" > <span th:text ="'¥' + ${product.skuPrice}" > ¥5199.00</span > </p > <p class ="tab_JE" > <a href ="/static/search/#" th:utext ="${product.skuTitle}" > Apple iPhone 7 Plus (A1661) 32G 黑色 移动联通电信4G手机 </a > </p > <p class ="tab_PI" > 已有<span > 11万+</span > 热门评价 <a href ="/static/search/#" > 二手有售</a > </p > <p class ="tab_CP" > <a href ="/static/search/#" title ="谷粒商城Apple产品专营店" > 谷粒商城Apple产品...</a > <a href ="#" title ="联系供应商进行咨询" > <img src ="/static/search/img/xcxc.png" /> </a > </p > <div class ="tab_FO" > <div class ="FO_one" > <p > 自营 <span > 谷粒商城自营,品质保证</span > </p > <p > 满赠 <span > 该商品参加满赠活动</span > </p > </div > </div > </div > </div >
2、筛选条件渲染 将结果的品牌、分类、商品属性进行遍历显示,并且点击某个属性值时可以通过拼接 url 进行跳转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 <div class ="JD_nav_logo" > <div class ="JD_nav_wrap" > <div class ="sl_key" > <span > 品牌:</span > </div > <div class ="sl_value" > <div class ="sl_value_logo" > <ul > <li th:each ="brand: ${result.getBrands()}" > <a href ="#" th:href ="${'javascript:searchProducts(" brandId" ,'+brand.brandId+')'}" > <img src ="/static/search/img/598033b4nd6055897.jpg" alt ="" th:src ="${brand.brandImg}" /> <div th:text ="${brand.brandName}" > 华为(HUAWEI)</div > </a > </li > </ul > </div > </div > <div class ="sl_ext" > <a href ="#" > 更多 <i style ='background: url("image/search.ele.png")no-repeat 3px 7px' > </i > <b style ='background: url("image/search.ele.png")no-repeat 3px -44px' > </b > </a > <a href ="#" > 多选 <i > +</i > <span > +</span > </a > </div > </div > <div class ="JD_pre" th:each ="catalog: ${result.getCatalogs()}" > <div class ="sl_key" > <span > 分类:</span > </div > <div class ="sl_value" > <ul > <li > <a href ="#" th:text ="${catalog.getCatalogName()}" th:href ="${'javascript:searchProducts(" catalogId" ,'+catalog.catalogId+')'}" > 0-安卓(Android)</a > </li > </ul > </div > </div > <div class ="JD_pre" > <div class ="sl_key" > <span > 价格:</span > </div > <div class ="sl_value" > <ul > <li > <a href ="#" > 0-499</a > </li > <li > <a href ="#" > 500-999</a > </li > <li > <a href ="#" > 1000-1699</a > </li > <li > <a href ="#" > 1700-2799</a > </li > <li > <a href ="#" > 2800-4499</a > </li > <li > <a href ="#" > 4500-11999</a > </li > <li > <a href ="#" > 12000以上</a > </li > <li class ="sl_value_li" > <input type ="text" /> <p > -</p > <input type ="text" /> <a href ="#" > 确定</a > </li > </ul > </div > </div > <div class ="JD_pre" th:each ="attr: ${result.getAttrs()}" > <div class ="sl_key" > <span th:text ="${attr.getAttrName()}" > 系统:</span > </div > <div class ="sl_value" > <ul > <li th:each ="val: ${attr.getAttrValue()}" > <a href ="#" th:text ="${val}" th:href ="${'javascript:searchProducts(" attrs" ," '+attr.attrId+'_'+val+'" )'}" > 0-安卓(Android)</a > </li > </ul > </div > </div > </div >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 function searchProducts (name, value ) { location.href = replaceParamVal (location.href , name, value, true ); } function replaceParamVal (url, paramName, replaceVal, forceAdd ) { var oUrl = url.toString (); var nUrl; if (oUrl.indexOf (paramName) != -1 ) { if (forceAdd && oUrl.indexOf (paramName + "=" + replaceVal) == -1 ) { if (oUrl.indexOf ("?" ) != -1 ) { nUrl = oUrl + "&" + paramName + "=" + replaceVal; } else { nUrl = oUrl + "?" + paramName + "=" + replaceVal; } } else { var re = eval ("/(" + paramName + "=)([^&]*)/gi" ); nUrl = oUrl.replace (re, paramName + "=" + replaceVal); } } else { if (oUrl.indexOf ("?" ) != -1 ) { nUrl = oUrl + "&" + paramName + "=" + replaceVal; } else { nUrl = oUrl + "?" + paramName + "=" + replaceVal; } } return nUrl; }
3、 分页数据渲染 将页码绑定至属性 pn,当点击某页码时,通过获取 pn 值进行 url 拼接跳转页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <div class ="filter_page" > <div class ="page_wrap" > <span class ="page_span1" > <a class ="page_a" href ="#" th:if ="${result.pageNum>1}" th:attr ="pn=${result.getPageNum()-1}" > < 上一页 </a > <a href ="#" class ="page_a" th:each ="page: ${result.pageNavs}" th:text ="${page}" th:style ="${page==result.pageNum?'border: 0;color:#ee2222;background: #fff':''}" th:attr ="pn=${page}" > 1</a > <a href ="#" class ="page_a" th:if ="${result.pageNum<result.totalPages}" th:attr ="pn=${result.getPageNum()+1}" > 下一页 > </a > </span > <span class ="page_span2" > <em > 共<b th:text ="${result.totalPages}" > 169</b > 页 到第</em > <input type ="number" value ="1" class ="page_input" /> <em > 页</em > <a href ="#" > 确定</a > </span > </div > </div >
1 2 3 4 5 $(".page_a" ).click (function ( ) { var pn = $(this ).attr ("pn" ); location.href = replaceParamVal (location.href , "pageNum" , pn, false ); console .log (replaceParamVal (location.href , "pageNum" , pn, false )); });
4、 页面排序和价格区间
页面排序功能需要保证,点击某个按钮时,样式会变红,并且其他的样式保持最初的样子;
点击某个排序时首先按升序显示,再次点击再变为降序,并且还会显示上升或下降箭头
页面排序跳转的思路是通过点击某个按钮时会向其class
属性添加/去除desc
,并根据属性值进行 url 拼接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 <div class ="filter_top" > <div class ="filter_top_left" th:with ="p = ${param.sort}, priceRange = ${param.skuPrice}" > <a sort ="hotScore" th:class ="${(!#strings.isEmpty(p) && #strings.startsWith(p,'hotScore') && #strings.endsWith(p,'desc')) ? 'sort_a desc' : 'sort_a'}" th:attr ="style=${(#strings.isEmpty(p) || #strings.startsWith(p,'hotScore')) ? 'color: #fff; border-color: #e4393c; background: #e4393c;':'color: #333; border-color: #ccc; background: #fff;' }" > 综合排序[[${(!#strings.isEmpty(p) && #strings.startsWith(p,'hotScore') && #strings.endsWith(p,'desc')) ?'↓':'↑' }]]</a > <a sort ="saleCount" th:class ="${(!#strings.isEmpty(p) && #strings.startsWith(p,'saleCount') && #strings.endsWith(p,'desc')) ? 'sort_a desc' : 'sort_a'}" th:attr ="style=${(!#strings.isEmpty(p) && #strings.startsWith(p,'saleCount')) ? 'color: #fff; border-color: #e4393c; background: #e4393c;':'color: #333; border-color: #ccc; background: #fff;' }" > 销量[[${(!#strings.isEmpty(p) && #strings.startsWith(p,'saleCount') && #strings.endsWith(p,'desc'))?'↓':'↑' }]]</a > <a sort ="skuPrice" th:class ="${(!#strings.isEmpty(p) && #strings.startsWith(p,'skuPrice') && #strings.endsWith(p,'desc')) ? 'sort_a desc' : 'sort_a'}" th:attr ="style=${(!#strings.isEmpty(p) && #strings.startsWith(p,'skuPrice')) ? 'color: #fff; border-color: #e4393c; background: #e4393c;':'color: #333; border-color: #ccc; background: #fff;' }" > 价格[[${(!#strings.isEmpty(p) && #strings.startsWith(p,'skuPrice') && #strings.endsWith(p,'desc'))?'↓':'↑' }]]</a > <a sort ="hotScore" class ="sort_a" > 评论分</a > <a sort ="hotScore" class ="sort_a" > 上架时间</a > <input id ="skuPriceFrom" type ="number" th:value ="${#strings.isEmpty(priceRange)?'':#strings.substringBefore(priceRange,'_')}" style ="width: 100px; margin-left: 30px" /> - <input id ="skuPriceTo" type ="number" th:value ="${#strings.isEmpty(priceRange)?'':#strings.substringAfter(priceRange,'_')}" style ="width: 100px" /> <button id ="skuPriceSearchBtn" > 确定</button > </div > <div class ="filter_top_right" > <span class ="fp-text" > <b > 1</b > <em > /</em > <i > 169</i > </span > <a href ="#" class ="prev" > <</a > <a href ="#" class ="next" > > </a > </div > </div >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 $(".sort_a" ).click (function ( ) { changeStyle (this ); let sort = $(this ).attr ("sort" ); sort = $(this ).hasClass ("desc" ) ? sort + "_desc" : sort + "_asc" ; location.href = replaceParamVal (location.href , "sort" , sort, false ); return false ; }); function changeStyle (ele ) { $(".sort_a" ).css ({ color : "#333" , "border-color" : "#ccc" , background : "#fff" , }); $(".sort_a" ).each (function ( ) { let text = $(this ).text ().replace ("↓" , "" ).replace ("↑" , "" ); $(this ).text (text); }); $(ele).css ({ color : "#FFF" , "border-color" : "#e4393c" , background : "#e4393c" , }); $(ele).toggleClass ("desc" ); if ($(ele).hasClass ("desc" )) { let text = $(ele).text ().replace ("↓" , "" ).replace ("↑" , "" ); text = text + "↓" ; $(ele).text (text); } else { let text = $(ele).text ().replace ("↓" , "" ).replace ("↑" , "" ); text = text + "↑" ; $(ele).text (text); } }
价格区间搜索函数
1 2 3 4 5 6 7 8 9 10 $("#skuPriceSearchBtn" ).click (function ( ) { var skuPriceFrom = $("#skuPriceFrom" ).val (); var skuPriceTo = $("#skuPriceTo" ).val (); location.href = replaceParamVal ( location.href , "skuPrice" , skuPriceFrom + "_" + skuPriceTo, false ); });
5、面包屑导航 在封装结果时,将查询的属性值进行封装
1 2 3 4 5 6 @FeignClient("gulimall-product") public interface ProductFeignService { @GetMapping("/product/attr/info/{attrId}") public R info (@PathVariable("attrId") Long attrId) ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 List<String> attrs = searchParam.getAttrs(); if (attrs != null && attrs.size() > 0 ) { List<SearchResult.NavVo> navVos = attrs.stream().map(attr -> { String[] split = attr.split("_" ); SearchResult.NavVo navVo = new SearchResult .NavVo(); navVo.setNavValue(split[1 ]); try { R r = productFeignService.info(Long.parseLong(split[0 ])); if (r.getCode() == 0 ) { AttrResponseVo attrResponseVo = JSON.parseObject(JSON.toJSONString(r.get("attr" )), new TypeReference <AttrResponseVo>() { }); navVo.setNavName(attrResponseVo.getAttrName()); } } catch (Exception e) { log.error("远程调用商品服务查询属性失败" , e); } String queryString = searchParam.get_queryString(); String replace = queryString.replace("&attrs=" + attr, "" ).replace("attrs=" + attr+"&" , "" ).replace("attrs=" + attr, "" ); navVo.setLink("http://search.gulimall.com/search.html" + (replace.isEmpty()?"" :"?" +replace)); return navVo; }).collect(Collectors.toList()); result.setNavs(navVos); }
页面渲染
1 2 3 4 5 6 7 8 9 <div class ="JD_ipone_one c" > <a th:href ="${nav.link}" th:each ="nav:${result.navs}" > <span th:text ="${nav.navName}" > </span > :<span th:text ="${nav.navValue}" > </span > x</a > </div >
6、搜索框 1 2 3 4 5 6 7 8 9 <div class ="header_form" > <input id ="keyword_input" type ="text" placeholder ="手机" th:value ="${param.keyword}" /> <a href ="javascript:searchByKeyword()" > 搜索</a > </div >
1 2 3 function searchByKeyword ( ) { searchProducts ("keyword" , $("#keyword_input" ).val ()); }
自己修改
1 2 3 4 5 6 7 8 9 10 11 12 13 function searchProducts (name, value) { if (name === "keyword" ){ location.href = replaceParamVal(location.href,"keyword" ,value) return ; } location.href = replaceParamVal(location.href,name,value,true ) } function searchByKeyword () { searchProducts("keyword" , $("#keyword_input" ).val()); }
7、 条件筛选联动 SearchResult.java
1 2 3 4 private List<NavVo> navs = new ArrayList <>();private List<Long> attrIds = new ArrayList <>();
1 result.getAttrIds().add(Long.parseLong(s[0 ]));
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 if (param.getBrandId() != null && param.getBrandId().size() > 0 ){ List<SearchResult.NavVo> navs = result.getNavs(); SearchResult.NavVo navVo = new SearchResult .NavVo(); navVo.setNavName("品牌" ); R r = productFeignService.brandsInfo(param.getBrandId()); if (r.getCode() == 0 ){ List<BrandVo> brand = r.getData("brand" , new TypeReference <List<BrandVo>>() { }); StringBuffer buffer = new StringBuffer (); String 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); } private String replaceQueryString (SearchParam param, String value, String key) { String encode = null ; try { encode = URLEncoder.encode(value,"UTF-8" ); encode.replace("+" ,"%20" ); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return param.get_queryString().replace("&" +key+"=" + encode, "" ); }
Feign (ProductFeignService)
1 2 @GetMapping("/product/brand/infos") public R brandsInfo (@RequestParam("brandIds") List<Long> brandIds) ;
BrandServiceImpl.java
1 2 3 4 @Override public List<BrandEntity> getBrandsByIds (List<Long> brandIds) { return baseMapper.selectList(new QueryWrapper <BrandEntity>().in("brand_id" ,brandIds)); }
BrandController.java
1 2 3 4 5 6 @GetMapping("/infos") public R brandsInfo (@RequestParam("brandIds") List<Long> brandIds) { List<BrandEntity> brand = brandService.getBrandsByIds(brandIds); return R.ok().put("brand" ,brand); }
list.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <div class ="JD_nav_logo" th:with ="brandid= ${param.brandId}" > <div th:if ="${#strings.isEmpty(brandid)}" class ="JD_nav_wrap" > <div class ="sl_key" > <span > <b > 品牌:</b > </span > </div > ..... <div class ="JD_pre" th:each ="attr : ${result.attrs}" th:if ="${!#lists.contains(result.attrIds, attr.attrId)}" > <div class ="sl_key" > <span th:text ="${attr.attrName}" > 屏幕尺寸:</span > </div > </div > </div > </div >