Elasticsearch 4(项目实战:爬取京东的页面、用es做搜索)

1、写在前面

Elasticsearch 1 : https://blog.csdn.net/a__int__/article/details/111593162
Elasticsearch 2 : https://blog.csdn.net/a__int__/article/details/111604720
Elasticsearch 3 : https://blog.csdn.net/a__int__/article/details/111644611
Elasticsearch 4 :本文

2、项目实战

以京东商城为例,我们先爬取它的数据,然后再用es做数据搜索

2.1、准备项目

新建springboot项目,所选依赖如下
在这里插入图片描述
这里我springboot的版本:2.4.1,它对应的es版本:7.9.3
我把它手动改为7.10.1
在这里插入图片描述
导入之前写好的网页及静态资源文件

在这里下载静态资源:https://github.com/MrZhengliang/demo

在这里插入图片描述
写个controller试试能不能访问

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class IndexController {
    @GetMapping({"/","/index"})
    public String index(){
        return "index";
    }
}

在这里插入图片描述
启动项目,访问localhost:9090试试
在这里插入图片描述

2.2、爬取京东页面数据

添加jsoup依赖

        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.10.2</version>
        </dependency>

新建HtmlUtil.java
解析网页,拿到整个商品展示区的div
在这里插入图片描述
在这里插入图片描述
接下来获取div里所有li
在这里插入图片描述
在这里插入图片描述

2.2.1、获取图片

获取img
在这里插入图片描述
第一次未取到图片的url
通过观察我们发现,图片是通过source-data-lazy-img加载的
在这里插入图片描述
我们先打印我们获取到的div(图片加载前的)
在这里插入图片描述
我们发现data-lazy-img里面保存了图片路径
在这里插入图片描述

2.2.2、获取价格、标题

在这里插入图片描述

在这里插入图片描述

2.2.3、具体代码

新建一个实体类Content,存放imgurl、price、title

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Content {
    private String title;
    private String img;
    private String price;
}

新建工具类HtmlParseUtil,用来解析京东网页,获取imgurl、price、title

import com.beaninj.demo.pojo.Content;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

@Component
public class HtmlParseUtil {
    public List<Content> parseJD(String keywords) throws IOException {
        String url = "https://search.jd.com/Search?keyword="+keywords;
        Document html = Jsoup.parse(new URL(url), 30000);
        Element div = html.getElementById("J_goodsList");
        Elements lis = div.getElementsByTag("li");

        ArrayList<Content> goodsList = new ArrayList<>();
        for(Element li : lis){
            String imgURL = li.getElementsByTag("img").eq(0).attr("data-lazy-img");
            String price = li.getElementsByClass("p-price").eq(0).text();
            String title = li.getElementsByClass("p-name").eq(0).text();

            Content content = new Content();
            content.setImg(imgURL);
            content.setPrice(price);
            content.setTitle(title);
            goodsList.add(content);
        }
        return goodsList;
    }
}

如上类,用到了jsoup,记得导入这个依赖

在测试类里面试试能不能使用

import com.beaninj.demo.util.HtmlParseUtil;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;

@SpringBootTest
class DemoApplicationTests {
    @Autowired
    HtmlParseUtil htmlParseUtil;
    @Test
    void contextLoads() throws IOException {
        htmlParseUtil.parseJD("java").forEach(System.out::println);
    }

}

运行结果
在这里插入图片描述

2.3、将爬取的数据写入es

先看看接下来我们要创建的目录结构
在这里插入图片描述

导入es的配置类EsConfig

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class EsConfig {
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient rhc = new RestHighLevelClient(RestClient.builder(new HttpHost("127.0.0.1",9200,"http")));
        return rhc;
    }
}

写一个类,可以创建es的索引、也可以检查索引是否存在,CreatEsIndex.java

import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class CreatEsIndex {
    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient rhc;

	// 检查索引是否存在
    public boolean check(String name) throws IOException {
        GetIndexRequest t = new GetIndexRequest(name);
        return rhc.indices().exists(t, RequestOptions.DEFAULT);
    }
	// 创建索引
    public void creat(String name) throws IOException {
        // 创建索引请求
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(name);
        // 发起请求,获取响应内容
        CreateIndexResponse createIndexResponse = rhc.indices().create(createIndexRequest, RequestOptions.DEFAULT);

        System.out.println(createIndexResponse.index()+"索引创建成功");

    }

    /**
     * 检查索引是否存在,不存在就创建
     * @param name
     * @throws IOException
     */
    public void checkAndCreat(String name) throws IOException {
        if(!check(name)){
            creat(name);
        }else {
            System.out.println("已经存在该索引,无需创建");
        }
    }
}

创建服务层ContentService.java,用来批量把从京东上拉取的信息插入es

import com.alibaba.fastjson.JSON;
import com.beaninj.demo.pojo.Content;
import com.beaninj.demo.util.CreatEsIndex;
import com.beaninj.demo.util.HtmlParseUtil;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;

@Service
public class ContentService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    @Autowired
    private HtmlParseUtil htmlParseUtil;
    @Autowired
    private CreatEsIndex creatEsIndex;

    /**
     *
     * @param keywords 查询的关键词
     * @return 返回是否插入数据成功
     * @throws IOException IO异常
     */
    public Boolean parseContent(String keywords) throws IOException {
        // 1、解析京东页面,返回imgurl、price、title
        List<Content> contents = htmlParseUtil.parseJD(keywords);
        // 2、创建索引
        creatEsIndex.checkAndCreat("jd_goods");
        // 3、imgurl、price、title批量插入到es中
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("2m");
        for (Content content : contents) {
            bulkRequest.add(new IndexRequest("jd_goods")
                    .source(JSON.toJSONString(content), XContentType.JSON));
        }
        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

        // 返回是否插入数据成功
        return !bulk.hasFailures();
    }
}

Controller层,ContentController.java

import com.beaninj.demo.service.ContentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

@RestController
public class ContentController  {
    @Autowired
    private ContentService contentService;

    @GetMapping("/insert/{keyword}")
    public Boolean insert(@PathVariable String keywords) throws IOException {
        return contentService.parseContent(keywords);
    }

}

运行项目,发起一个请求
在这里插入图片描述
查看es后台,看看数据是否插入成功
在这里插入图片描述

2.4、实现搜索功能

在ContentService类里面添加方法searchPage

public List<Map<String,Object>> searchPage(String keyword,int pageNo,int pageSize) throws IOException {
        if(pageNo<=1){ pageNo=1;}
        // 条件搜索
        SearchRequest jd_goods = new SearchRequest("jd_goods");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 分页
        searchSourceBuilder.from(pageNo);
        searchSourceBuilder.size(pageSize);
        // 精准匹配
        TermQueryBuilder title = QueryBuilders.termQuery("title", keyword);
        searchSourceBuilder.query(title);
        searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        // 执行搜素
        jd_goods.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(jd_goods, RequestOptions.DEFAULT);
        // 解析结果
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            list.add(hit.getSourceAsMap());
        }
        return list;
    }

ContentController类里添加search方法

    @GetMapping("/search/{keyword}/{pageNo}/{pageSize}")
    public List<Map<String,Object>> search(@PathVariable String keyword,
                                           @PathVariable int pageNo,
                                           @PathVariable int pageSize) throws IOException {
        return contentService.searchPage(keyword,pageNo,pageSize);
    }

启动、访问
在这里插入图片描述

2.5、和前端结合

安装vue
新建文件夹:jd-es,并在对应位置打开cmd
项目初始化:npm init -y
在这里插入图片描述
下载vue
在这里插入图片描述
下载axios
在这里插入图片描述
接下来将axios、vue导入我们的项目
在这里插入图片描述
在index.html里面使用vue
index.html完整内容

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="utf-8"/>
    <title>springboot+es</title>
    <link rel="stylesheet" th:href="@{/css/style.css}"/>
</head>

<body class="pg">
<div class="page" id="app">
    <div id="mallPage" class=" mallist tmall- page-not-market ">

        <!-- 头部搜索 -->
        <div id="header" class=" header-list-app">
            <div class="headerLayout">
                <div class="headerCon ">
                    <!-- Logo-->
                    <h1 id="mallLogo">
                        <img th:src="@{/images/jdlogo.png}" alt="">
                    </h1>

                    <div class="header-extra">

                        <!--搜索-->
                        <div id="mallSearch" class="mall-search">
                            <form name="searchTop" class="mallSearch-form clearfix">
                                <fieldset>
                                    <legend>天猫搜索</legend>
                                    <div class="mallSearch-input clearfix">
                                        <div class="s-combobox" id="s-combobox-685">
                                            <div class="s-combobox-input-wrap">
                                                <input v-model="keyword" type="text" autocomplete="off" value="dd" id="mq"
                                                       class="s-combobox-input" aria-haspopup="true">
                                            </div>
                                        </div>
                                        <button @click.prevent="searchKey" type="submit" id="searchbtn">搜索</button>
                                    </div>
                                </fieldset>
                            </form>
                            <ul class="relKeyTop">
                                <li><a>Java</a></li>
                                <li><a>前端</a></li>
                                <li><a>Linux</a></li>
                                <li><a>大数据</a></li>
                                <li><a>人工智能</a></li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 商品详情页面 -->
        <div id="content">
            <div class="main">
                <!-- 品牌分类 -->
                <form class="navAttrsForm">
                    <div class="attrs j_NavAttrs" style="display:block">
                        <div class="brandAttr j_nav_brand">
                            <div class="j_Brand attr">
                                <div class="attrKey">
                                    品牌
                                </div>
                                <div class="attrValues">
                                    <ul class="av-collapse row-2">
                                        <li><a href="#"> python </a></li>
                                        <li><a href="#"> Java </a></li>
                                    </ul>
                                </div>
                            </div>
                        </div>
                    </div>
                </form>

                <!-- 排序规则 -->
                <div class="filter clearfix">
                    <a class="fSort fSort-cur">综合<i class="f-ico-arrow-d"></i></a>
                    <a class="fSort">人气<i class="f-ico-arrow-d"></i></a>
                    <a class="fSort">新品<i class="f-ico-arrow-d"></i></a>
                    <a class="fSort">销量<i class="f-ico-arrow-d"></i></a>
                    <a class="fSort">价格<i class="f-ico-triangle-mt"></i><i class="f-ico-triangle-mb"></i></a>
                </div>

                <!-- 商品详情 -->
                <div class="view grid-nosku">

                    <div class="product" v-for="result in results">
                        <div class="product-iWrap">
                            <!--商品封面-->
                            <div class="productImg-wrap">
                                <a class="productImg">
                                    <img :src="result.img">
                                </a>
                            </div>
                            <!--价格-->
                            <p class="productPrice">
                                <em><b>¥</b>{{result.price}}</em>
                            </p>
                            <!--标题-->
                            <p class="productTitle">
                                <a v-html="result.title"></a>
                            </p>
                            <!-- 店铺名 -->
                            <div class="productShop">
                                <span>店铺: springboot + es </span>
                            </div>
                            <!-- 成交信息 -->
                            <p class="productStatus">
                                <span>月成交<em>999笔</em></span>
                                <span>评价 <a>3</a></span>
                            </p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>


<script th:src="@{/js/axios.min.js}"></script>
<script th:src="@{/js/vue.min.js}"></script>

<script>
    new Vue({
        el: '#app',
        data: {
            keyword:'', // 搜索的关键字
            results:[]  // 搜索结果
        },
        methods:{
            searchKey(){
               var keyword = this.keyword;


               // 对接接口
                axios.get('search/' + keyword + "/1/10").then(response => {
                    console.log(response);
                    this.results = response.data; // 绑定数据
                })

            }
        }
    })
</script>

</body>
</html>

css/style.css完整内容

/*** uncss> filename: http://localhost:9090/css/global.css ***/body,button,fieldset,form,h1,input,legend,li,p,ul{margin:0;padding:0}body,button,input{font:12px/1.5 tahoma,arial,"\5b8b\4f53";-ms-overflow-style:scrollbar}button,h1,input{font-size:100%}em{font-style:normal}ul{list-style:none}a{text-decoration:none}a:hover{text-decoration:underline}legend{color:#000}fieldset,img{border:0}#content,#header{margin-left:auto;margin-right:auto}html{zoom:expression(function(ele){ ele.style.zoom = "1"; document.execCommand("BackgroundImageCache", false, true); }(this))}@font-face{font-family:mui-global-iconfont;src:url(//at.alicdn.com/t/font_1401963178_8135476.eot);src:url(//at.alicdn.com/t/font_1401963178_8135476.eot?#iefix) format('embedded-opentype'),url(//at.alicdn.com/t/font_1401963178_8135476.woff) format('woff'),url(//at.alicdn.com/t/font_1401963178_8135476.ttf) format('truetype'),url(//at.alicdn.com/t/font_1401963178_8135476.svg#iconfont) format('svg')}#mallPage{width:auto;min-width:990px;background-color:transparent}#content{width:990px;margin:auto}#mallLogo{float:left;z-index:9;padding-top:28px;width:280px;height:64px;line-height:64px;position:relative}.page-not-market #mallLogo{width:400px}.clearfix:after,.clearfix:before,.headerCon:after,.headerCon:before{display:table;content:"";overflow:hidden}#mallSearch legend{display:none}.clearfix:after,.headerCon:after{clear:both}.clearfix,.headerCon{zoom:1}#mallPage #header{margin-top:-30px;width:auto;margin-bottom:0;min-width:990px;background:#fff}#header{height:122px;margin-top:-26px!important;background:#fff;min-width:990px;width:auto!important;position:relative;z-index:1000}#mallSearch #mq,#mallSearch fieldset,.mallSearch-input{position:relative}.headerLayout{width:990px;padding-top:26px;margin:0 auto}.header-extra{overflow:hidden}#mallSearch{float:right;padding-top:25px;width:390px;overflow:hidden}.mallSearch-form{border:solid #FF0036;border-width:3px 0 3px 3px}.mallSearch-input{background:#fff;height:30px}#mallSearch #mq{color:#000;margin:0;z-index:2;width:289px;height:20px;line-height:20px;padding:5px 3px 5px 5px;outline:0;border:none;font-weight:900;background:url(data:image/gif;base64,R0lGODlhAQADAJEAAObm5t3d3ff39wAAACH5BAAAAAAALAAAAAABAAMAAAICDFQAOw==) repeat-x;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}#mallSearch button{position:absolute;right:0;top:0;width:90px;border:0;font-size:16px;letter-spacing:4px;cursor:pointer;color:#fff;background-color:#FF0036;height:30px;overflow:hidden;font-family:'\5FAE\8F6F\96C5\9ED1',arial,"\5b8b\4f53"}#mallSearch .s-combobox{height:30px}#mallSearch .s-combobox .s-combobox-input:focus{outline:0}button::-moz-focus-inner{border:0;padding:0;margin:0}.page-not-market #mallSearch{width:540px!important}.page-not-market #mq{width:439px!important} 
/*** uncss> filename: http://localhost:9090/css/test.css ***/#mallSearch{float:none}.page-not-market #mallLogo{width:280px}.header-list-app #mallSearch{width:448px!important}.header-list-app #mq{width:347px!important}@media (min-width:1210px){#header .headerCon,#header .headerLayout,.main{width:1190px!important}.header-list-app #mallSearch{width:597px!important}.header-list-app #mq{width:496px!important}}@media (min-width:600px) and (max-width:800px) and (orientation:portrait){.pg .page{min-width:inherit!important}.pg #mallPage,.pg #mallPage #header{min-width:740px!important}.pg #header .headerCon,.pg #header .headerLayout,.pg .main{width:740px!important}.pg #mallPage #mallLogo{width:260px}.pg #header{min-width:inherit}.pg #mallSearch .mallSearch-input{padding-right:95px}.pg #mallSearch .s-combobox{width:100%!important}.pg #mallPage .header-list-app #mallSearch{width:auto!important}.pg #mallPage .header-list-app #mallSearch #mq{width:100%!important;padding:5px 0 5px 5px}}i{font-style:normal}.main,.page{position:relative}.page{overflow:hidden}@font-face{font-family:tm-list-font;src:url(//at.alicdn.com/t/font_1442456441_338337.eot);src:url(//at.alicdn.com/t/font_1442456441_338337.eot?#iefix) format('embedded-opentype'),url(//at.alicdn.com/t/font_1442456441_338337.woff) format('woff'),url(//at.alicdn.com/t/font_1442456441_338337.ttf) format('truetype'),url(//at.alicdn.com/t/font_1442456441_338337.svg#iconfont) format('svg')}::selection{background:rgba(0,0,0,.1)}*{-webkit-tap-highlight-color:rgba(0,0,0,.3)}b{font-weight:400}.page{background:#fff;min-width:990px}#content{margin:0!important;width:100%!important}.main{margin:auto;width:990px}.main img{-ms-interpolation-mode:bicubic}.fSort i{background:url(//img.alicdn.com/tfs/TB1XClLeAY2gK0jSZFgXXc5OFXa-165-206.png) 9999px 9999px no-repeat}#mallSearch .s-combobox{width:auto}::-ms-clear,::-ms-reveal{display:none}.attrKey{white-space:nowrap;text-overflow:ellipsis}.attrs{border-top:1px solid #E6E2E1}.attrs a{outline:0}.attr{background-color:#F7F5F5;border-color:#E6E2E1 #E6E2E1 #D1CCC7;border-style:solid solid dotted;border-width:0 1px 1px}.attr ul:after,.attr:after{display:block;clear:both;height:0;content:' '}.attrKey{float:left;padding:7px 0 0;width:10%;color:#B0A59F;text-indent:13px}.attrKey{display:block;height:16px;line-height:16px;overflow:hidden}.attrValues{position:relative;float:left;background-color:#FFF;width:90%;padding:4px 0 0;overflow:hidden}.attrValues ul{position:relative;margin-right:105px;margin-left:25px}.attrValues ul.av-collapse{overflow:hidden}.attrValues li{float:left;height:22px;line-height:22px}.attrValues li a{position:relative;color:#806F66;display:inline-block;padding:1px 20px 1px 4px;line-height:20px;height:20px;white-space:nowrap}.attrValues li a:hover{color:#ff0036;text-decoration:none}.brandAttr .attr{border:2px solid #D1CCC7;margin-top:-1px}.brandAttr .attrKey{padding-top:9px}.brandAttr .attrValues{padding-top:6px}.brandAttr .av-collapse{overflow:hidden;max-height:60px}.brandAttr li{margin:0 8px 8px 0}.brandAttr li a{text-overflow:ellipsis;overflow:hidden}.navAttrsForm{position:relative}.relKeyTop{padding:4px 0 0;margin-left:-13px;height:16px;overflow:hidden;width:100%}.relKeyTop li{display:inline-block;border-left:1px solid #ccc;line-height:1.1;padding:0 12px}.relKeyTop li a{color:#999}.relKeyTop li a:hover{color:#ff0036;text-decoration:none}.filter i{display:inline-block;overflow:hidden}.filter{margin:10px 0;padding:5px;position:relative;z-index:10;background:#faf9f9;color:#806f66}.filter i{position:absolute}.filter a{color:#806f66;cursor:pointer}.filter a:hover{color:#ff0036;text-decoration:none}.fSort{float:left;height:22px;line-height:20px;line-height:24px\9;border:1px solid #ccc;background-color:#fff;z-index:10}.fSort{position:relative}.fSort{display:inline-block;margin-left:-1px;overflow:hidden;padding:0 15px 0 5px}.fSort:hover,a.fSort-cur{color:#ff0036;background:#F1EDEC}.fSort i{top:6px;right:5px;width:7px;height:10px;line-height:10px}.fSort .f-ico-arrow-d{background-position:-22px -23px}.fSort-cur .f-ico-arrow-d,.fSort:hover .f-ico-arrow-d{background-position:-30px -23px}i.f-ico-triangle-mb,i.f-ico-triangle-mt{border:4px solid transparent;height:0;width:0}i.f-ico-triangle-mt{border-bottom:4px solid #806F66;top:2px}i.f-ico-triangle-mb{border-top:4px solid #806F66;border-width:3px\9;right:6px\9;top:12px}:root i.f-ico-triangle-mb{border-width:4px\9;right:5px\9}i.f-ico-triangle-mb,i.f-ico-triangle-mt{border:4px solid transparent;height:0;width:0}i.f-ico-triangle-mt{border-bottom:4px solid #806F66;top:2px}i.f-ico-triangle-mb{border-top:4px solid #806F66;border-width:3px\9;right:6px\9;top:12px}:root i.f-ico-triangle-mb{border-width:4px\9;right:5px\9}.view:after{clear:both;content:' '}.productImg,.productPrice em b{vertical-align:middle}.product{position:relative;float:left;padding:0;margin:0 0 20px;line-height:1.5;overflow:visible;z-index:1}.product:hover{overflow:visible;z-index:3;background:#fff}.product-iWrap{position:absolute;background-color:#fff;margin:0;padding:4px 4px 0;font-size:0;border:1px solid #f5f5f5;border-radius:3px}.product-iWrap *{font-size:12px}.product:hover .product-iWrap{height:auto;margin:-3px;border:4px solid #ff0036;border-radius:0;-webkit-transition:border-color .2s ease-in;-moz-transition:border-color .2s ease-in;-ms-transition:border-color .2s ease-in;-o-transition:border-color .2s ease-in;transition:border-color .2s ease-in}.productPrice,.productShop,.productStatus,.productTitle{display:block;overflow:hidden;margin-bottom:3px}.view:after{display:block}.view{margin-top:10px}.view:after{height:0}.productImg-wrap{display:table;table-layout:fixed;height:210px;width:100%;padding:0;margin:0 0 5px}.productImg-wrap a,.productImg-wrap img{max-width:100%;max-height:210px}.productImg{display:table-cell;width:100%;text-align:center}.productImg img{display:block;margin:0 auto}.productPrice{font-family:arial,verdana,sans-serif!important;color:#ff0036;font-size:14px;height:30px;line-height:30px;margin:0 0 5px;letter-spacing:normal;overflow:inherit!important;white-space:nowrap}.productPrice *{height:30px}.productPrice em{float:left;font-family:arial;font-weight:400;font-size:20px;color:#ff0036}.productPrice em b{margin-right:2px;font-weight:700;font-size:14px}.productTitle{display:block;color:#666;height:14px;line-height:12px;margin-bottom:3px;word-break:break-all;font-size:0;position:relative}.productTitle *{font-size:12px;font-family:\5FAE\8F6F\96C5\9ED1;line-height:14px}.productTitle a{color:#333}.productTitle a:hover{color:#ff0036!important}.productTitle a:visited{color:#551A8B!important}.product:hover .productTitle{height:14px}.productShop{position:relative;height:22px;line-height:20px;margin-bottom:5px;color:#999;white-space:nowrap;overflow:visible}.productStatus{position:relative;height:32px;border:none;border-top:1px solid #eee;margin-bottom:0;color:#999}.productStatus span{float:left;display:inline-block;border-right:1px solid #eee;width:39%;padding:10px 1px;margin-right:6px;line-height:12px;text-align:left;white-space:nowrap}.productStatus a,.productStatus em{margin-top:-8px;font-family:arial;font-size:12px;font-weight:700}.productStatus em{color:#b57c5b}.productStatus a{color:#38b}.productImg-wrap{position:relative}.product-iWrap{min-height:98%;width:210px}.view{padding-left:5px;padding-right:5px}.view{width:1023px}.view .product{width:220px;margin-right:33px}@media (min-width:1210px){.view{width:1210px;padding-left:5px;padding-right:5px}.view .product{width:220px;margin-right:20px}}@media (min-width:600px) and (max-width:800px) and (orientation:portrait){.view{width:775px;padding-left:5px;padding-right:5px}.view .product{width:220px;margin-right:35px}}.product{height:372px}.grid-nosku .product{height:333px}

京东logo
在这里插入图片描述
页面展示
在这里插入图片描述

2.6、index.html里的vue代码解析

在这里插入图片描述
使用方法searchKey()
在这里插入图片描述
在这里插入图片描述

2.6、实现高亮搜索

在ContentService类新建方法searchPageHigh

public List<Map<String,Object>> searchPageHigh(String keyword,int pageNo,int pageSize) throws IOException {
        if(pageNo<=1){ pageNo=1;}
        // 条件搜索
        SearchRequest jd_goods = new SearchRequest("jd_goods");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 分页
        searchSourceBuilder.from(pageNo);
        searchSourceBuilder.size(pageSize);
        // 精准匹配
        TermQueryBuilder title = QueryBuilders.termQuery("title", keyword);
        searchSourceBuilder.query(title);
        searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        // 查询时将高亮加入
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.requireFieldMatch(false);   //关闭多个高亮显示
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        searchSourceBuilder.highlighter(highlightBuilder);

        // 执行搜素
        jd_goods.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(jd_goods, RequestOptions.DEFAULT);
        // 解析结果
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            // 解析高亮字段
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField title1 = highlightFields.get("title");
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();    //这儿得到的是原来的结果
            // 将原来的字段替换为高亮字段
            if(title1!=null){
                Text[] fragments = title1.fragments();
                String new_title1="";
                for(Text f:fragments){
                    new_title1 += f;
                }
                sourceAsMap.put("title",new_title1);  // 替换
            }
            list.add(hit.getSourceAsMap());
        }
        return list;
    }

和之前的searchPage方法比起来多了两处
在这里插入图片描述

然后再contrallor里换成这个方法

在这里插入图片描述
重启试一下
在这里插入图片描述
注意,前端是v-html才能解析标签

在这里插入图片描述

下面是项目整体目录截图
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值