创建实体类Content存储数据

  1. 7. @Data
  2. 8. @AllArgsConstructor
  3. 9. @NoArgsConstructor
  4. 10. public class Content {
  5. 11. private String title;
  6. 12. private String img;
  7. 13. private String price;
  8. 14. //可以自己添加数据
  9. 15. }

再创建一个工具类UtilOfKeyWord 并测试

  1. @Component
  2. public class HtmlParseUtil {
  3. public static List<Content> praseJD(String keywords) throws IOException {
  4. //获取请求 https://search.jd.com/Search?keyword=java
  5. //前提,需要联网,
  6. String url = "https://search.jd.com/Search?keyword="+keywords;
  7. //解析网页(jsoup返回的Document就是浏览器的Document对象)
  8. Document document = Jsoup.parse(new URL(url), 3000);
  9. //所有在js中的方法这里都可以使用
  10. Element element = document.getElementById("J_goodsList");
  11. // System.out.println(element.html());
  12. //获取所有的li元素
  13. Elements elements = element.getElementsByTag("li");
  14. ArrayList<Content> goodList = new ArrayList<>();
  15. //获取元素里面的内容
  16. for (Element el:elements){
  17. String img = el.getElementsByTag("img").eq(0).attr("data-lazy-img");
  18. String price = el.getElementsByClass("p-price").eq(0).text();
  19. String title = el.getElementsByClass("p-name").eq(0).text();
  20. Content content = new Content();
  21. content.setTitle(title);
  22. content.setPrice(price);
  23. content.setImg(img);
  24. goodList.add(content);
  25. }
  26. return goodList;
  27. }
  28. }

11.2.业务编写 - 图1

添加 配置文件 config/ElasticSearchConfig.java

  1. @Configuration
  2. public class ElasticSearchClientConfig {
  3. @Bean
  4. public RestHighLevelClient restHighLevelClient(){
  5. RestHighLevelClient client = new RestHighLevelClient(
  6. RestClient.builder(
  7. new HttpHost("localhost", 9200, "http")));
  8. return client;
  9. }
  10. }

编写业务类

将jd 查询数据存储es中

  1. //1.解析数据,放入es索引中
  2. public Boolean parseContent(String keywords) throws IOException {
  3. List<Content> contents = HtmlParseUtil.praseJD(keywords);
  4. //把查询到的数据放入es中
  5. BulkRequest bulkRequest = new BulkRequest();
  6. bulkRequest.timeout("2m");
  7. for (int i = 0 ;i < contents.size();i++){
  8. bulkRequest.add(
  9. new IndexRequest("kuang_index").id(""+(i+1))
  10. .source(JSON.toJSONString(contents.get(i)), XContentType.JSON));
  11. }
  12. BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
  13. return !bulk.hasFailures();
  14. }

编写ContentController

  1. /
  2. 7. @RestController
  3. 8. public class ContentController {
  4. 9.
  5. 10. @Autowired
  6. 11. private ContentService contentService;
  7. 12.
  8. 13. @GetMapping("/parse/{keyword}")
  9. 14. public Boolean parse(@PathVariable("keyword") String keyword) throws Exception{
  10. 15. return contentService.parseContent(keyword);
  11. 16. }
  12. 17. }

将京东数据存储es中
访问请求http://localhost:9090/parse/java
es 中显示内容
11.2.业务编写 - 图2

实现搜索功能(高亮)

3.1 编写搜索业务方法
ContentService层代码

  1. package cn.ither.esjd.service;
  2. import cn.ither.esjd.pojo.Content;
  3. import cn.ither.esjd.utils.HtmlParseUtil;
  4. import com.alibaba.fastjson.JSON;
  5. import org.elasticsearch.action.bulk.BulkRequest;
  6. import org.elasticsearch.action.bulk.BulkResponse;
  7. import org.elasticsearch.action.index.IndexRequest;
  8. import org.elasticsearch.action.search.SearchRequest;
  9. import org.elasticsearch.action.search.SearchResponse;
  10. import org.elasticsearch.client.RequestOptions;
  11. import org.elasticsearch.client.RestHighLevelClient;
  12. import org.elasticsearch.common.text.Text;
  13. import org.elasticsearch.common.unit.TimeValue;
  14. import org.elasticsearch.common.xcontent.XContentType;
  15. import org.elasticsearch.index.query.QueryBuilders;
  16. import org.elasticsearch.index.query.TermQueryBuilder;
  17. import org.elasticsearch.search.SearchHit;
  18. import org.elasticsearch.search.builder.SearchSourceBuilder;
  19. import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
  20. import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
  21. import org.springframework.beans.factory.annotation.Autowired;
  22. import org.springframework.stereotype.Service;
  23. import java.io.IOException;
  24. import java.util.ArrayList;
  25. import java.util.List;
  26. import java.util.Map;
  27. import java.util.concurrent.TimeUnit;
  28. /**
  29. * @Author: zhanghuan
  30. * @date: 2020/9/28 15:54
  31. * @description:
  32. */
  33. @Service
  34. public class ContentServiceImpl implements IContentService{
  35. @Autowired
  36. private RestHighLevelClient restHighLevelClient;
  37. //1.解析数据,放入es索引中
  38. public Boolean parseContent(String keywords) throws IOException {
  39. List<Content> contents = HtmlParseUtil.praseJD(keywords);
  40. //把查询到的数据放入es中
  41. BulkRequest bulkRequest = new BulkRequest();
  42. bulkRequest.timeout("2m");
  43. for (int i = 0 ;i < contents.size();i++){
  44. bulkRequest.add(
  45. new IndexRequest("kuang_index").id(""+(i+1))
  46. .source(JSON.toJSONString(contents.get(i)), XContentType.JSON));
  47. }
  48. BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
  49. return bulk.hasFailures();
  50. }
  51. //2.获取这些数据实现搜索功能(分页查询)
  52. public List<Map<String,Object>> searchPage(String keyword, int pageNo, int pageSize) throws IOException {
  53. if (pageNo <=0){
  54. pageNo = 1;
  55. }
  56. //条件搜索
  57. SearchRequest searchRequest = new SearchRequest("kuang_index");
  58. SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
  59. //分页
  60. searchSourceBuilder.from(pageNo);
  61. searchSourceBuilder.size(pageSize);
  62. //精准匹配
  63. //查询条件
  64. TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
  65. searchSourceBuilder.query(termQueryBuilder);
  66. // searchSourceBuilder.timeout(new TimeValue(60,TimeUnit.SECONDS));
  67. //执行搜索
  68. searchRequest.source(searchSourceBuilder);
  69. SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
  70. //解析结果
  71. ArrayList<Map<String,Object>> list = new ArrayList<>();
  72. for(SearchHit documentFields:searchResponse.getHits().getHits()){
  73. list.add( documentFields.getSourceAsMap());
  74. }
  75. return list;
  76. }
  77. //3.获取这些数据实现搜索功能(高亮)
  78. public List<Map<String,Object>> searchPageHighlightBuilder(String keyword, int pageNo, int pageSize) throws IOException {
  79. if (pageNo <=0){
  80. pageNo = 1;
  81. }
  82. //条件搜索
  83. SearchRequest searchRequest = new SearchRequest("kuang_index");
  84. SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
  85. //分页
  86. searchSourceBuilder.from(pageNo);
  87. searchSourceBuilder.size(pageSize);
  88. //精准匹配
  89. //查询条件
  90. TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
  91. searchSourceBuilder.query(termQueryBuilder);
  92. searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
  93. //高亮
  94. // 高亮
  95. HighlightBuilder highlightBuilder = new HighlightBuilder();
  96. highlightBuilder.field("title");//设置标题高亮
  97. highlightBuilder.requireFieldMatch(false);//关闭多个高亮显示
  98. highlightBuilder.preTags("<span style ='color:red;font-weight: bold'>"); //设置标签头
  99. highlightBuilder.postTags("</span>"); //设置标签尾
  100. searchSourceBuilder.highlighter(highlightBuilder);
  101. //执行搜索
  102. searchRequest.source(searchSourceBuilder);
  103. SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
  104. ArrayList<Map<String,Object>> list = new ArrayList<>();
  105. for (SearchHit documentFields: searchResponse.getHits().getHits()){
  106. Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
  107. HighlightField title = highlightFields.get("title");
  108. Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();//获取原来的结果
  109. //解析高亮的字段,将原来的字段换为高亮字段即可
  110. if(title != null){
  111. Text[] fragments = title.fragments();
  112. String n_title="";
  113. for (Text text: fragments) {//获取高亮的字段
  114. n_title+=text;
  115. }
  116. sourceAsMap.put("title",n_title);//高亮字段替换为原来内容即可
  117. }
  118. list.add(sourceAsMap);
  119. }
  120. return list;
  121. }
  122. }


ContentController层代码

  1. import cn.ither.esjd.service.IContentService;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.web.bind.annotation.GetMapping;
  4. import org.springframework.web.bind.annotation.PathVariable;
  5. import org.springframework.web.bind.annotation.RestController;
  6. import java.io.IOException;
  7. import java.util.List;
  8. import java.util.Map;
  9. /**
  10. * @Author: zhanghuan
  11. * @date: 2020/9/28 15:54
  12. * @description:
  13. */
  14. @RestController
  15. public class ContentController {
  16. @Autowired
  17. private IContentService contentService;
  18. @GetMapping("/parse/{keywords}")
  19. public Boolean parse(@PathVariable("keywords") String keywords) throws IOException {
  20. return contentService.parseContent(keywords);
  21. }
  22. @GetMapping("/search/{keywords}/{pageNo}/{pageSize}")
  23. public List<Map<String,Object>> search(@PathVariable("pageNo") int pageNo,
  24. @PathVariable("pageSize")int pageSize,
  25. @PathVariable("keywords") String keywords) throws IOException {
  26. return contentService.searchPage(keywords,pageNo,pageSize);
  27. }
  28. }

前后的交互

index.html代码

  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="utf-8"/>
  5. <title>Java-ES仿京东实战</title>
  6. <link rel="stylesheet" th:href="@{/css/style.css}"/>
  7. </head>
  8. <body class="pg">
  9. <div class="page" id="app">
  10. <div id="mallPage" class=" mallist tmall- page-not-market ">
  11. <!-- 头部搜索 -->
  12. <div id="header" class=" header-list-app">
  13. <div class="headerLayout">
  14. <div class="headerCon ">
  15. <!-- Logo-->
  16. <h1 id="mallLogo">
  17. <img th:src="@{/images/jdlogo.png}" alt="">
  18. </h1>
  19. <div class="header-extra">
  20. <!--搜索-->
  21. <div id="mallSearch" class="mall-search">
  22. <form name="searchTop" class="mallSearch-form clearfix">
  23. <fieldset>
  24. <legend>天猫搜索</legend>
  25. <div class="mallSearch-input clearfix">
  26. <div class="s-combobox" id="s-combobox-685">
  27. <div class="s-combobox-input-wrap">
  28. <input v-model="keyword" type="text" autocomplete="off" value="dd" id="mq"
  29. class="s-combobox-input" aria-haspopup="true">
  30. </div>
  31. </div>
  32. <button type="submit" @click.prevent="searchKey" id="searchbtn">搜索</button>
  33. </div>
  34. </fieldset>
  35. </form>
  36. <ul class="relKeyTop">
  37. <li><a>小莫Java</a></li>
  38. <li><a>小莫前端</a></li>
  39. <li><a>小莫Linux</a></li>
  40. <li><a>小莫大数据</a></li>
  41. <li><a>小莫聊理财</a></li>
  42. </ul>
  43. </div>
  44. </div>
  45. </div>
  46. </div>
  47. </div>
  48. <!-- 商品详情页面 -->
  49. <div id="content">
  50. <div class="main">
  51. <!-- 品牌分类 -->
  52. <form class="navAttrsForm">
  53. <div class="attrs j_NavAttrs" style="display:block">
  54. <div class="brandAttr j_nav_brand">
  55. <div class="j_Brand attr">
  56. <div class="attrKey">
  57. 品牌
  58. </div>
  59. <div class="attrValues">
  60. <ul class="av-collapse row-2">
  61. <li><a href="#"> 一起武林 </a></li>
  62. <li><a href="#"> Java </a></li>
  63. </ul>
  64. </div>
  65. </div>
  66. </div>
  67. </div>
  68. </form>
  69. <!-- 排序规则 -->
  70. <div class="filter clearfix">
  71. <a class="fSort fSort-cur">综合<i class="f-ico-arrow-d"></i></a>
  72. <a class="fSort">人气<i class="f-ico-arrow-d"></i></a>
  73. <a class="fSort">新品<i class="f-ico-arrow-d"></i></a>
  74. <a class="fSort">销量<i class="f-ico-arrow-d"></i></a>
  75. <a class="fSort">价格<i class="f-ico-triangle-mt"></i><i class="f-ico-triangle-mb"></i></a>
  76. </div>
  77. <!-- 商品详情 -->
  78. <div class="view grid-nosku">
  79. <div class="product" v-for="result in results">
  80. <div class="product-iWrap">
  81. <!--商品封面-->
  82. <div class="productImg-wrap">
  83. <a class="productImg">
  84. <img :src="result.img">
  85. </a>
  86. </div>
  87. <!--价格-->
  88. <p class="productPrice">
  89. <em>{{result.price}}</em>
  90. </p>
  91. <!--标题-->
  92. <p class="productTitle">
  93. <a v-html="result.title"></a>
  94. </p>
  95. <!-- 店铺名 -->
  96. <div class="productShop">
  97. <span>店铺: 小莫Java </span>
  98. </div>
  99. <!-- 成交信息 -->
  100. <p class="productStatus">
  101. <span>月成交<em>999笔</em></span>
  102. <span>评价 <a>3</a></span>
  103. </p>
  104. </div>
  105. </div>
  106. </div>
  107. </div>
  108. </div>
  109. </div>
  110. </div>
  111. <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  112. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  113. <script>
  114. new Vue({
  115. el:"#app",
  116. data :{
  117. keyword:"",//搜索关键字
  118. results:[] //搜索结果
  119. },
  120. methods: {
  121. searchKey() {
  122. var keyword = this.keyword;
  123. console.log(keyword);
  124. //对接后端的接口
  125. axios.get('search/'+keyword+"/1/10").then(response=>{
  126. console.log(response)
  127. this.results=response.data;
  128. })
  129. }
  130. }
  131. })
  132. </script>
  133. </body>
  134. </html>

页面展示效果
11.2.业务编写 - 图3

11.2.业务编写 - 图4

11.2.业务编写 - 图5