赞
踩
目录
商城业务-检索服务-SearchRequest构建-排序、分页、高亮&测试
商城业务-检索服务-SearchRequest构建-分析&封装
Nginx动静分离,将搜索页中的静态资源上传至/static/search文件夹下,将index.html搜索首页存放在gulimall-search服务的templates下
- cd /mydata/nginx/html/static
- mkdir search
使用thymeleaf模板引擎:
①导入thymeleaf的依赖
- <!--导入thymeleaf依赖-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-thymeleaf</artifactId>
- </dependency>
② 导入thymeleaf的命名空间
xmlns:th="http://www.thymeleaf.org"
③ 修改静态资源的请求路径,使用CTRL+R进行全部替换
所有动态请求search.gulimall.com的请求由Nginx转发给网关
①配置域名转发
②配置Nginx配置文件
- cd /mydata/nginx/conf.d
- vi gulimall.conf
重启nginx服务
docker restart nginx
③配置网关
- - id: gulimall_host_route
- uri: lb://gulimall-product # lb:负载均衡
- predicates:
- - Host=gulimall.com # **.xxx 子域名
-
- - id: gulimall_search_route
- uri: lb://gulimall-search # lb:负载均衡
- predicates:
- - Host=search.gulimall.com # **.xxx 子域名
配置热部署
①导入依赖
- <!--导入热部署依赖-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-devtools</artifactId>
- <optional>true</optional>
- </dependency>
② 开发期间默认关闭缓存
点击这几处要跳转到检索首页
鼠标右击,点击检查
修改请求路径
CTRL+F9重新编译
出现错误:访问到80端口
出现问题的原因:nginx配置出错不能正确路由跳转
解决方案:修改nginx配置文件
- cd /mydata/nginx/conf/conf.d
- vi gulimall.conf
重启nginx
docker restart nginx
关闭Product服务的缓存,重启服务
首页,点击搜索按钮要来到搜索页
点击手机1111111要来到搜索页
请求路径为http://search.gmall.com/list.html?catalog3Id=225,这是一个错误请求路径,缺少了gulimall而不是gumall
①将index.html修改为list.html
②编写控制类
③首页搜索栏修改为
④ 修改js并上传nginx,重启nginx
结果:
①通过首页搜索栏进行检索,传递keyword
②通过分类进行检索。传递catalog3Id
③复杂查询
排序:①综合排序②销量③价格 ,例如:通过销量降序排序或者升序排序,sort=saleCount_desc/saleCount_asc
过滤:①库存,例如:有库存->hasStock=1,无库存 -> hasStock=0 ②价格区间 ,例如: 价格位于 400 -900 -> skuPrice=400_900,价格低于900 -> skuPrice= _900,价格高于900 -> skuPrice=900_ ③品牌: 可以按照多个品牌进行筛选
聚合:属性:多个属性以:分割,1号属性网络可以是4G也可以是5G -> attrs=1_4G:5G
分页:页码
创建Vo,用于封装查询条件
以京东为例,搜索小米
默认:查询所有商品信息
1.小米所属的品牌 2.小米所属的分类 3.小米所属的属性
编写返回结果的Vo
首先,这是一个复合查询即bool查询,将需要评分的检索条件写在must中,不需要评分的检索条件写在filter中。
①keyword的全文检索,例如:keyword=iphone
② 手机分类的检索,例如: catalogId=225 ,非文本字段检索用term
③ 品牌检索
④根据属性检索,属性未防止扁平化处理声明为nested,因此,需要使用nested查询
nested query文档地址:Nested query | Elasticsearch Guide [8.2] | Elastic
⑤是否有库存
⑥价格区间检索
⑦排序
⑧ 页码
⑨ 高亮,标题内容含有搜索内容则标题中含有的搜索内容标红
DSL语句:
- GET /product/_search
- {
- "query": {
- "bool": {
- "must": [
- {
- "match": {
- "skuTitle": "iphone"
- }
- }
- ],
- "filter": [
- {
- "term": {
- "catalogId": {
- "value": "225"
- }
- }
- },
- {
- "terms": {
- "brandId": [
- "8",
- "9"
- ]
- }
- },
- {
- "nested": {
- "path": "attrs",
- "query": {
- "bool": {
- "must": [
- {
- "term": {
- "attrs.attrId": {
- "value": "1"
- }
- }
- },
- {
- "terms": {
- "attrs.attrValue": [
- "5G",
- "4G"
- ]
- }
- }
- ]
- }
- }
- }
- },
- {
- "term": {
- "hasStock": {
- "value": "false"
- }
- }
- },
- {
- "range": {
- "skuPrice": {
- "gte": 4999,
- "lte": 5400
- }
- }
- }
- ]
- }
- },
- "sort": [
- {
- "skuPrice": {
- "order": "desc"
- }
- }
- ],
- "from": 0,
- "size": 10,
- "highlight": {
- "fields": {"skuTitle":{}},
- "pre_tags": "<b style='color:red'>",
- "post_tags": "</b>"
- }
- }
①product映射有些数据类型不允许索引,因此,创建新的映射,允许索引
- 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"
- }
- }
- }
- }
- }
- }
②数据迁移
③修改索引常量
④品牌聚合
⑤分类聚合
⑥属性聚合,应使用嵌入式聚合
nested aggregations文档地址:Nested Aggregations | Elasticsearch: The Definitive Guide [2.x] | Elastic
⑦完整DSL
- GET /gulimall_product/_search
- {
- "query": {
- "bool": {
- "must": [
- {
- "match": {
- "skuTitle": "iphone"
- }
- }
- ],
- "filter": [
- {
- "term": {
- "catalogId": {
- "value": "225"
- }
- }
- },
- {
- "terms": {
- "brandId": [
- "8",
- "9"
- ]
- }
- },
- {
- "nested": {
- "path": "attrs",
- "query": {
- "bool": {
- "must": [
- {
- "term": {
- "attrs.attrId": {
- "value": "1"
- }
- }
- },
- {
- "terms": {
- "attrs.attrValue": [
- "5G",
- "4G"
- ]
- }
- }
- ]
- }
- }
- }
- },
- {
- "term": {
- "hasStock": {
- "value": "false"
- }
- }
- },
- {
- "range": {
- "skuPrice": {
- "gte": 4999,
- "lte": 5400
- }
- }
- }
- ]
- }
- },
- "sort": [
- {
- "skuPrice": {
- "order": "desc"
- }
- }
- ],
- "from": 0,
- "size": 10,
- "highlight": {
- "fields": {"skuTitle":{}},
- "pre_tags": "<b style='color:red'>",
- "post_tags": "</b>"
- },
- "aggs": {
- "brand_agg": {
- "terms": {
- "field": "brandId",
- "size": 10
- },
- "aggs": {
- "brand_name_agg": {
- "terms": {
- "field": "brandName",
- "size": 10
- }
- },
- "brand_img-agg": {
- "terms": {
- "field": "brandImg",
- "size": 10
- }
- }
- }
- },
- "catalog_agg":{
- "terms": {
- "field": "catalogId",
- "size": 10
- },
- "aggs": {
- "catalog_name_agg": {
- "terms": {
- "field": "catelogName",
- "size": 10
- }
- }
- }
- },
- "attr_agg":{
- "nested": {
- "path": "attrs"
- },
- "aggs": {
- "attr_id_agg": {
- "terms": {
- "field": "attrs.attrId",
- "size": 10
- },
- "aggs": {
- "attr_name_agg": {
- "terms": {
- "field": "attrs.attrName",
- "size": 10
- }
- },
- "attr_value_agg":{
- "terms": {
- "field": "attrs.attrValue",
- "size": 10
- }
- }
- }
- }
- }
- }
- }
- }
⑧将gulimall_product映射和DSL进行保存
编写接口
导入ES客户端对象
整体逻辑:1.封装DSL 2.查询 3.封装响应结果
开始封装DSL
1.构建bool查询
2. 构建must查询
3. 构建filter中三级分类查询
4.构建filter中的品牌查询
5.构建filter中的库存查询
6.构建filter中的价格区间查询
7. 构建filter中的属性查询
1.构建排序
2. 构建分页
默认页码为1,页码大小为2方便测试
3.构建高亮
进行简单的测试,将打印的DSL复制到Kibana中看是否正确
1.品牌聚合
2.分类聚合
3.属性聚合
打上断点,根据返回的response封装响应结果
1对应于2
1. 封装所有记录
2. 封装品牌,聚合返回的类型可以从断点返回结果查看
3.封装分类
4.封装属性
5.封装页码
6.封装总记录数
7.封装总页数
高亮设置
由于有库存的商品非常少,因此,不设置库存的默认值,前端传进来的参数不为空时再拼装上查询条件
将分页大小设置为16
动态获取页面显示数据
①商品显示
注意细节:th:text 会进行转义 ,th:utext不会进行转义
如果使用th:text,带keyword高亮之后,则会出现下面的结果:
②品牌显示
③分类显示
④ 属性显示
1.按品牌条件筛选,"="
2.按分类条件筛选
3.按属性条件筛选
4. url拼接函数编写
1.搜索栏功能完成
为input创建id,方便后续拿到input中的输入;编写跳转方法
搜索框回显搜索内容,th:value 为属性设置值 ;param是指请求参数,param.keyword是指
请求参数中的keyword值
2.分页功能的完善
① 当前页码>第一页才能显示上一页,当前页码<总页码才能显示下一页
② 自定义属性用于保存当前页码,作用:用于替换请求参数中的pageNum值
③遍历显示页码
④ 当前页码显示特定的样式
⑤ 请求参数的替换
将a标签中href全部删除,添加a标签的class,为其绑定事件,并编写回调函数
$(this)指当前被点击的元素,return false作用:禁用默认行为,a标签可能会跳转
替换方法
- function replaceParamVal(url,paramName,replaceVal){
- var oUrl = url.toString();
- var re = eval('/('+paramName+'=)([^&]*)/gi');
- var nUrl = oUrl.replace(re,paramName+'='+replaceVal);
- return nUrl;
- }
为a标签定义class
为a标签绑定点击事件
为选中的元素设置样式
为选中的元素设置样式之前需要将所有元素的样式恢复成最初样式
使用toggleClass()为class加上desc,默认为降序排序
添加升降符号
$(this).text()获取当前点击元素的文本内容
添加升降符号之前需要清空元素的升降符号
将被选中元素的样式改变抽取成一个方法
- function changeStyle(ele){
- $(".sort_a").css({"color":"#333","border-color":"#CCC","background":"#FFF"})
- $(ele).css({"color":"#FFF","border-color":"#e4393c","background":"#e4393c"})
- $(ele).toggleClass("desc");
- $(".sort_a").each(function (){
- var text = $(this).text().replace("↓","").replace("↑","");
- $(this).text(text);
- });
- if ($(ele).hasClass("desc")){
- var text = $(ele).text().replace("↓","").replace("↑","");
- text = text+"↓";
- $(ele).text(text);
- }else {
- var text = $(ele).text().replace("↓","").replace("↑","");
- text = text+"↑";
- $(ele).text(text);
- }
- }
自定义属性赋值为某种排序
改写替换方法
- function replaceOrAddParamVal(url,paramName,replaceVal){
- var oUrl = url.toString();
- if (oUrl.indexOf(paramName)!=-1){
- var re = eval('/('+paramName+'=)([^&]*)/gi');
- var nUrl = oUrl.replace(re,paramName+'='+replaceVal);
- return nUrl;
- }else {
- if (oUrl.indexOf("?")!=-1){
- var nUrl = oUrl+"&"+paramName+"="+replaceVal;
- return nUrl;
- }else {
- var nUrl = oUrl+"?"+paramName+"="+replaceVal;
- return nUrl;
- }
- }
- }
跳转指定路径
出现问题: 通过toggleClass()为class添加desc,刷新或者跳转之后会丢失
页面跳转之后样式回显,th:with 用于声明变量,#strings即调用字符串工具类
根据URL动态添加class
动态的添加升降符号
编写价格区间搜索栏
为button按钮绑定单击事件
价格回显
①获取skuPirce的值
②价格区间回显
#strings.substringAfter(name,prefix):获取prifix之后的字符串
#strings.substringBefore(name,suffix):获取suffix之前的字符串
拼接是否有货查询条件
为单选框绑定改变事件
通过调用prop('check')获取是否被选中,选中为true否则false
回显选中状态
①编写面包屑导航栏Vo
② 封装面包屑导航栏数据
属性名的获取要通过远程服务调用product服务进行查询
①导入cloud的版本
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
② 导入cloud依赖管理
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-dependencies</artifactId>
- <version>${spring-cloud.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
③ 导入openfeign的依赖
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-openfeign</artifactId>
- </dependency>
④ 开启远程服务调用功能
⑤编写接口,配置调用的服务名
⑥编写调用服务的接口,注意:全路径
⑦编写自己传key和返回值类型获取自己想要的数据类型方法,之前的只能获取data的数据
⑧编写返回类型的Vo,Vo和AttrRespVo属性一致
⑨封装属性名
①封装原生的查询条件
HttpServletRequest的getQueryString()方法可以获取url的请求参数
②封装链接
出现问题:路径替换失败
出现问题的原因:浏览器会将中文进行一个编码,而查询出来的属性值是中文
解决方案:将中文进行编码
注意:有些符号,浏览器的编码与java编码不一致
例如:'(':浏览器不进行编码,java会编码成%28;')':浏览器不进行编码,java会编码成%29;空格浏览器会编码成%20,java会编码成'+'
- // 8.封装面包屑导航栏的数据
- if (param.getAttrs()!=null && param.getAttrs().size()>0){
- List<SearchResVo.NavVo> navVoList = param.getAttrs().stream().map(item -> {
- SearchResVo.NavVo navVo = new SearchResVo.NavVo();
- String[] s = item.split("_");
- // 封装属性值
- navVo.setAttrValue(s[1]);
-
- //封装属性名
- R r = productFeignService.info(Long.parseLong(s[0]));
- if (r.getCode() == 0){
- AttrResponseVo responseVo = r.getData("attr", new TypeReference<AttrResponseVo>() {});
- navVo.setAttrName(responseVo.getAttrName());
- }else {
- // 出现异常则封装id
- navVo.setAttrName(s[0]);
- }
-
- //封装链接即去掉当前属性的查询的url封装
- String encode=null;
- try {
- encode = URLEncoder.encode(item,"UTF-8");
- encode=encode.replace("%28","(").replace("%29",")").replace("+","%20");
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- String replace = param.get_queryString().replace("&attrs=" + encode, "");
- navVo.setLink("http://search.gulimall.com/list.html?"+replace);
- return navVo;
- }).collect(Collectors.toList());
- searchResVo.setNavs(navVoList);
- }
导航栏回显编写
①右击检测,找到元素
改写 replaceOrAddParamVal默认是对属性进行一个替换,forceAdd是否强制添加的标识
完善品牌面包屑导航栏功能,分类面包屑导航栏也类似,不同之处是不用剔除,设置url
①为面包屑vo设置一个默认值
② 远程调用product服务查询品牌名称
远程服务调用,查询很费时,可以将查询的结果保存进缓存中 ,例如:
value:分区名,key:用于标识第几号属性
③将封装替换url的方法抽取出来
④编写面包屑导航栏功能
品牌面包屑导航栏,品牌筛选剔除
⑤创建一个list用于封装已经筛选的属性id
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。