前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >谷粒商城-高级篇(检索服务)

谷粒商城-高级篇(检索服务)

作者头像
OY
发布2022-03-20 13:46:48
发布2022-03-20 13:46:48
1.3K00
代码可运行
举报
文章被收录于专栏:OY_学习记录OY_学习记录
运行总次数:0
代码可运行

一、添加模板页面

代码语言:javascript
代码运行次数:0
复制
<!-- 模板引擎 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

将资料中的前端页面放到 search 服务模块下的 resource/templates 下;

二、配置请求跳转

1、配置 Nginx 转发

配置 Windows hosts 文件:

代码语言:javascript
代码运行次数:0
复制
192.168.56.10	search.gulimall.com

找到 Nginx 的配置文件,编辑 gulimall.conf,将所有 *.gulimall.com 的请求都经由 Nginx 转发给网关;

代码语言:javascript
代码运行次数:0
复制
server {
    listen       80;
    server_name  gulimall.com *.gulimall.com;
		...
 }

然后重启 Nginx

代码语言:javascript
代码运行次数:0
复制
docker restart nginx

2、配置网关服务转发到 search 服务

代码语言:javascript
代码运行次数:0
复制
- 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 模板

代码语言:javascript
代码运行次数:0
复制
/**
 * 自动将页面提交过来的所有请求参数封装成我们指定的对象
 *
 * @param param
 * @return
 */
@Controller
public class SearchController {

    @GetMapping("/list.html")
    public String listPage(){
        return "list";
    }
}

三、检索条件分析

  • 全文检索:skuTitle -> keyword
  • 排序:saleCount(销量)、hotScore(热度分)、skuPrice(价格)
  • 过滤:hasStock、skuPrice区间、brandId、catalog3Id、attrs
  • 聚合:attrs

完整查询参数 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分析

代码语言:javascript
代码运行次数:0
复制
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、请求参数

代码语言:javascript
代码运行次数:0
复制
@Data
public class SearchParam {
    // 页面传递过来的全文匹配关键字
    private String keyword;

    // 品牌id,可以多选
    private List<Long> brandId;

    // 三级分类
    private Long catalog3Id;

    // 排序条件: sort=price/salecount/hotscore_desc/asc
    private String sort;

    // 是否显示有货
    private Integer hasStock;

    // 价格区间查询
    private String skuPrice;

    // 按照属性进行筛选
    private List<String> attrs;

    // 页码
    private Integer pageNum = 1;

    // 原生的所有查询条件
    private String _queryString;
}

2、返回结果

代码语言:javascript
代码运行次数:0
复制
@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 索引常量,二者要求对应。

代码语言:javascript
代码运行次数:0
复制
# 查看原来的映射规则
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语句分析

代码语言:javascript
代码运行次数:0
复制
GET mall_product/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": { # 检索出华为
            "skuTitle": "华为"
          }
        }
      ],
      "filter": [ #过滤
        {
          "term": {
            "catalogId": "225"
          }
        },
        {
          "terms": {
            "brandId": [
              "2"
            ]
          }
        },
        {
          "term": {
            "hasStock": "false"
          }
        },
        {
          "range": {
            "skuPrice": { #价格1k-7k
              "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、 基本数据渲染

将商品的基本属性渲染出来

代码语言:javascript
代码运行次数:0
复制
<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">
            <!-- 标题 -->
            <!-- 使用utext标签,使检索时高亮不会被转义-->
            <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进行跳转

代码语言:javascript
代码运行次数:0
复制
<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()}">
                        <!--替换url-->
                        <a href="#"  th:href="${'javascript:searchProducts(&quot;brandId&quot;,'+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(&quot;catalogId&quot;,'+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(&quot;attrs&quot;,&quot;'+attr.attrId+'_'+val+'&quot;)'}">0-安卓(Android)</a></li>
            </ul>
        </div>
    </div>
</div>
代码语言:javascript
代码运行次数:0
复制
function searchProducts(name, value) {
    //原來的页面
    location.href = replaceParamVal(location.href,name,value,true)
};

   /**
     * @param url 目前的url
     * @param paramName 需要替换的参数属性名
     * @param replaceVal 需要替换的参数的新属性值
     * @param forceAdd 该参数是否可以重复查询(attrs=1_3G:4G:5G&attrs=2_骁龙845&attrs=4_高清屏)
     * @returns {string} 替换或添加后的url
     */
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拼接跳转页面

代码语言:javascript
代码运行次数:0
复制
<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>
             <!-- 将各个页码遍历显示,并将当前页码绑定至属性pn -->
            <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>页&nbsp;&nbsp;到第</em>
            <input type="number" value="1" class="page_input">
            <em>页</em>
            <a href="#">确定</a>
        </span>
    </div>
</div>
代码语言:javascript
代码运行次数:0
复制
$(".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拼接

代码语言:javascript
代码运行次数:0
复制
<div class="filter_top">
    <div class="filter_top_left" th:with="p = ${param.sort}, priceRange = ${param.skuPrice}">
        <!-- 通过判断当前class是否有desc来进行样式的渲染和箭头的显示-->
        <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>
代码语言:javascript
代码运行次数:0
复制
$(".sort_a").click(function () {
    	changeStyle(this);
    	//添加、剔除desc
        //$(this).toggleClass("desc");
    	//获取sort属性值并进行url跳转
        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){
    // location.href = replaceParamVal(href, "pageNum", pn,flase);
    // color: #333; border-color: #ccc; background: #fff
    // color: #fff; border-color: #e4393c; background: #e4393c
    $(".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);
    }
}

价格区间搜索函数

代码语言:javascript
代码运行次数:0
复制
$("#skuPriceSearchBtn").click(function () {
    var skuPriceFrom = $("#skuPriceFrom").val();
    var skuPriceTo = $("#skuPriceTo").val();
    location.href = replaceParamVal(location.href, "skuPrice", skuPriceFrom + "_" + skuPriceTo, false);
})

5、面包屑导航

在封装结果时,将查询的属性值进行封装

代码语言:javascript
代码运行次数:0
复制
@FeignClient("gulimall-product")
public interface ProductFeignService {

    @GetMapping("/product/attr/info/{attrId}")
    public R info(@PathVariable("attrId") Long attrId);
}
代码语言:javascript
代码运行次数:0
复制
// 6. 构建面包屑导航
     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();
             //6.1 设置属性值
             navVo.setNavValue(split[1]);
             //6.2 查询并设置属性名
             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);
             }
             //6.3 设置面包屑跳转链接(当点击该链接时剔除点击属性)
             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);
     }

页面渲染

代码语言:javascript
代码运行次数:0
复制
<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、搜索框

代码语言:javascript
代码运行次数:0
复制
<div class="header_form">
    <input id="keyword_input" type="text" placeholder="手机" th:value="${param.keyword}"/>
    <a href="javascript:searchByKeyword()">搜索</a>
</div>
代码语言:javascript
代码运行次数:0
复制
function searchByKeyword() {
    searchProducts("keyword", $("#keyword_input").val());
}

自己修改

代码语言:javascript
代码运行次数:0
复制
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

代码语言:javascript
代码运行次数:0
复制
//    面包屑导航数据
private List<NavVo> navs = new ArrayList<>();

private List<Long> attrIds = new ArrayList<>();
代码语言:javascript
代码运行次数:0
复制
result.getAttrIds().add(Long.parseLong(s[0]));
代码语言:javascript
代码运行次数:0
复制
// 品牌,分类
if(param.getBrandId() != null && param.getBrandId().size() > 0){
    List<SearchResult.NavVo> navs = result.getNavs();
    SearchResult.NavVo navVo = new SearchResult.NavVo();

    navVo.setNavName("品牌");
    // TODO 远程查询所有品牌
    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");  //浏览器对空格的编码和Java不一样,差异化处理
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return param.get_queryString().replace("&"+key+"=" + encode, "");
}

Feign (ProductFeignService)

代码语言:javascript
代码运行次数:0
复制
@GetMapping("/product/brand/infos")
public R brandsInfo(@RequestParam("brandIds") List<Long> brandIds);

BrandServiceImpl.java

代码语言:javascript
代码运行次数:0
复制
@Override
public List<BrandEntity> getBrandsByIds(List<Long> brandIds) {
    return baseMapper.selectList(new QueryWrapper<BrandEntity>().in("brand_id",brandIds));
}

BrandController.java

代码语言:javascript
代码运行次数:0
复制
@GetMapping("/infos")
public R brandsInfo(@RequestParam("brandIds") List<Long> brandIds){
    List<BrandEntity> brand  = brandService.getBrandsByIds(brandIds);

    return R.ok().put("brand",brand);
}

list.html

代码语言:javascript
代码运行次数:0
复制
<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>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-10-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、添加模板页面
  • 二、配置请求跳转
    • 1、配置 Nginx 转发
    • 2、配置网关服务转发到 search 服务
    • 3、静态页面处理
    • 4、配置页面跳转
  • 三、检索条件分析
  • 四、DSL分析
  • 五、检索代码编写
    • 1、请求参数
    • 2、返回结果
  • 六、检索功能
    • 1、ES mall-product 映射 mapping修改
    • 2、ES 检索 DSL语句分析
  • 七、页面效果
    • 1、 基本数据渲染
    • 2、筛选条件渲染
    • 3、 分页数据渲染
    • 4、 页面排序和价格区间
    • 5、面包屑导航
    • 6、搜索框
    • 7、 条件筛选联动
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档