赞
踩
用到的技术:Springboot+Vue+Thymeleaf+Elasticsearch
效果如下
接下来上代码(不分前后顺序)
页面跳转controller
package com.wyh.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; /** * @program: SpringBoot_ElasticSearch * @description: index页面跳转controller * @author: 魏一鹤 * @createDate: 2022-04-19 23:09 **/ @Controller public class IndexController { @GetMapping({"/","/index"}) public String index() { return "index"; } }
接口数据请求controller
package com.wyh.controller; import com.wyh.service.JDContentService; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.io.IOException; import java.util.List; import java.util.Map; /** * @program: SpringBoot_ElasticSearch_JD * @description: 京东商品控制器 * @author: 魏一鹤 * @createDate: 2022-04-20 00:48 **/ //前端请求编写 @RestController public class JDContentController { @Autowired private JDContentService jdContentService; //测试es批量添加京东数据 restful风格 @GetMapping("/parse/{keyword}") public boolean parse(@PathVariable("keyword") String keyword) throws IOException { return jdContentService.parseContent(keyword); } //测试查询 @GetMapping("/search/{keyword}/{pageNo}/{pageSize}") public List<Map<String,Object>> search(@PathVariable("keyword") String keyword, @PathVariable("pageNo") int pageNo, @PathVariable("pageSize")int pageSize) throws IOException { return jdContentService.searchPageHighLight(keyword,pageNo,pageSize); } }
京东商品实体
package com.wyh.entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.stereotype.Component; /** * @program: SpringBoot_ElasticSearch_JD * @description: JD内容实体 * @author: 魏一鹤 * @createDate: 2022-04-20 00:37 **/ @Data @AllArgsConstructor @NoArgsConstructor @Component public class JDContent { private String title; private String img; private String price; //可以自定义继续加属性 }
京东商品service
package com.wyh.service; import com.alibaba.fastjson.JSON; import com.wyh.entity.JDContent; import com.wyh.utils.HtmlParseUtil; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.TermQueryBuilder; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; /** * @program: SpringBoot_ElasticSearch_JD * @description: 京东商品服务接口 * @author: 魏一鹤 * @createDate: 2022-04-20 00:47 **/ //业务编写 @Service public class JDContentService { //注入bean @Resource private RestHighLevelClient client; //1 解析数据 放入es索引库 public boolean parseContent(String keywords) throws IOException { ArrayList<JDContent> jdContents = new HtmlParseUtil().parseJD(keywords); //把查询并且解析好的数据批量插入到es库 BulkRequest bulkRequest = new BulkRequest(); //过期时间2分钟 bulkRequest.timeout("2m"); //批量插入数据 for (int i = 0; i < jdContents.size(); i++) { bulkRequest.add(new IndexRequest("jd_goods") //这里就不给id赋值了 随时生成 .source(JSON.toJSONString(jdContents.get(i)),XContentType.JSON) ); } //执行批量插入请求 BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT); //没有返回失败就是成功 return !bulk.isFragment(); } //2 获取这些数据 实现搜索功能 public List<Map<String,Object>> searchPage(String keyword,int pageNo,int pageSize) throws IOException { //当前页数第一条 if(pageNo<=1){ pageNo=1; } //条件搜索 SearchRequest searchRequest = new SearchRequest("jd_goods"); //构建查询 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); //查询条件 TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword); //分页 searchSourceBuilder.from(pageNo); searchSourceBuilder.size(pageSize); //精准匹配关键字 SearchSourceBuilder query = searchSourceBuilder.query(termQueryBuilder); //超时时间 searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); //执行搜索 searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); //创建map 用于返回 ArrayList<Map<String,Object>> arrayList = new ArrayList(); //解析结果 for (SearchHit document : searchResponse.getHits().getHits()) { arrayList.add(document.getSourceAsMap()); } return arrayList; } //3 实现搜索高亮的功能 public List<Map<String,Object>> searchPageHighLight(String keyword,int pageNo,int pageSize) throws IOException { //当前页数第一条 if(pageNo<=1){ pageNo=1; } //条件搜索 SearchRequest searchRequest = new SearchRequest("jd_goods"); //构建查询 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); //查询条件 TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword); //分页 searchSourceBuilder.from(pageNo); searchSourceBuilder.size(pageSize); //精准匹配关键字 SearchSourceBuilder query = searchSourceBuilder.query(termQueryBuilder); //超时时间 searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); //高亮显示 HighlightBuilder highlightBuilder = new HighlightBuilder(); //让标题高亮 highlightBuilder.field("title"); //高亮的前缀 highlightBuilder.preTags("<span style='color:red'>"); //高亮的后缀 highlightBuilder.postTags("</span>"); //关闭多个高亮 highlightBuilder.requireFieldMatch(false); searchSourceBuilder.highlighter(highlightBuilder); //执行搜索 searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); //创建map 用于返回 ArrayList<Map<String,Object>> arrayList = new ArrayList(); //解析结果 for (SearchHit document : searchResponse.getHits().getHits()) { //获取高亮的字段 Map<String, HighlightField> highlightFields = document.getHighlightFields(); HighlightField title = highlightFields.get("title"); //原来的结果 Map<String, Object> sourceAsMap = document.getSourceAsMap(); //解析高亮的字段,将原来的字段换成高亮的字段即可 //如果高亮字段存在 if(title!=null){ Text[] fragments = title.fragments(); //新标题 String newTitle=""; for (Text fragment : fragments) { newTitle+=fragment; } //高亮字段替换原来的字段内容即可 sourceAsMap.put("title",newTitle); } arrayList.add(sourceAsMap); } return arrayList; } }
解析页面工具包
package com.wyh.utils; import com.wyh.entity.JDContent; 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.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; /** * @program: SpringBoot_ElasticSearch_JD * @description: jsoup解析网页 * @author: 魏一鹤 * @createDate: 2022-04-19 23:53 **/ @Component public class HtmlParseUtil { //public static void main(String[] args) throws IOException { // //ArrayList<JDContent> jdContents = parseJD("你好"); // //for (JDContent jdContent : jdContents) { // // System.out.println(jdContent); // //} // 获取请求 前提需要联网 // //String url="https://search.jd.com/Search?keyword=java"; // 解析网页 jsoup返回的document对象就是浏览器document对象 // 所有在js中可以使用的方法,这里都能使用 比如document.getElementById() // //Document document = Jsoup.parse(new URL(url), 30000); // 获取我们想要的数据 // //Element element = document.getElementById("J_goodsList"); // //System.out.println(element.html()); // 获取全部的li元素 // //Elements elements = element.getElementsByTag("li"); // //System.out.println(elements); // 获取元素中的内容 // //for (Element el : elements) { // // //图片 // // //为什么明明可以看到图片的src但是就是获取不到呢 // // //这里面用到一个懒加载机制 真正的图片是放在source-data-lazy-img(data-lazy-img)中的 // // String img = el.getElementsByTag("img").eq(0).attr("data-lazy-img"); // // //价格 // // String price = el.getElementsByClass("p-price").eq(0).text(); // // //标题 // // String title = el.getElementsByClass("p-name").eq(0).text(); // // System.out.println("-------------------------------"); // // System.out.println(img); // // System.out.println(price); // // System.out.println(title); // // // //} //} //解析京东请求 public ArrayList<JDContent> parseJD(String keywords) throws IOException { //获取请求 前提需要联网 String url="https://search.jd.com/Search?keyword="+keywords; //解析网页 jsoup返回的document对象就是浏览器document对象 //所有在js中可以使用的方法,这里都能使用 比如document.getElementById() Document document = Jsoup.parse(new URL(url), 30000); //获取我们想要的数据 Element element = document.getElementById("J_goodsList"); System.out.println(element.html()); //获取全部的li元素 Elements elements = element.getElementsByTag("li"); //京东实体对象集合 ArrayList<JDContent> jdContents = new ArrayList<>(); //获取元素中的内容 for (Element el : elements) { //图片 //为什么明明可以看到图片的src但是就是获取不到呢 //这里面用到一个懒加载机制 真正的图片是放在source-data-lazy-img(data-lazy-img)中的 String img = el.getElementsByTag("img").eq(0).attr("data-lazy-img"); //价格 String price = el.getElementsByClass("p-price").eq(0).text(); //标题 String title = el.getElementsByClass("p-name").eq(0).text(); System.out.println("-------------------------------"); System.out.println(img); System.out.println(price); System.out.println(title); //创建京东实体对象 JDContent jdContent = new JDContent(); jdContent.setImg(img); jdContent.setTitle(title); jdContent.setPrice(price); //把全部属性放进集合里面 jdContents.add(jdContent); } return jdContents; } }
es配置
package com.wyh.config; 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; /** * @program: SpringBoot_ElasticSearch * @description: ElasticSearch相关配置 * @author: 魏一鹤 * @createDate: 2022-04-18 22:04 **/ //表面这是一个配置文件 @Configuration public class ElasticSearchClientConfig { //配置bean 注册 rest高级客户端 @Bean public RestHighLevelClient restHighLevelClient(){ RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( //ip 端口 协议 //一定要保证es服务是开启的 new HttpHost("127.0.0.1",9200,"http"))); return client; } }
新建一个索引库 用来存放京东数据
springboot application配置
#端口
server.port=8080
#关闭thymeleaf缓存
spring.thymeleaf.cache=false
页面
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"/> <title>仿京东高亮搜索</title> <link rel="stylesheet" th:href="@{/css/style.css}"/> <script th:src="@{/js/jquery.min.js}"></script> </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 type="text" v-model="keyword" autocomplete="off" value="dd" id="mq" class="s-combobox-input" aria-haspopup="true"> </div> </div> <button type="submit" @click.prevent="searchKey" id="searchbtn">搜索</button> </div> </fieldset> </form> <ul class="relKeyTop"> <li><a>学习</a></li> <li><a>摸鱼</a></li> <li><a>睡觉</a></li> <li><a>LOL</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="#"> 魏一鹤 </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>店铺:魏一鹤的小店 </span> </div> <!-- 成交信息 --> <p class="productStatus"> <span>月成交<em>999笔</em></span> <span>评价 <a>3</a></span> </p> </div> </div> </div> </div> </div> </div> </div> <!--前端使用vue实现前后端分离 导入依赖--> <script th:src="@{/js/jquery.min.js}"></script> <script th:src="@{/js/axios.min.js}"></script> <script th:src="@{/js/vue.min.js}"></script> <script> //创建VUE对象 new Vue({ el:'#app', //div的id data:{ keyword:'', //搜索的关键字 results:[] //搜索的结果 }, //搜索事件 methods:{ searchKey(){ var keyword=this.keyword; //对接后端的接口 axios.get('search/'+keyword+"/1/20").then(response=>{ console.log(response.data); //绑定数据 this.results=response.data }) } } }) </script> </body> </html>
pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.6</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com</groupId> <artifactId>wyh</artifactId> <version>0.0.1-SNAPSHOT</version> <name>wyh</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <!--自定义版本ES依赖 保证和本地版本一致--> <elasticsearch.version>7.6.1</elasticsearch.version> </properties> <dependencies> <!--jsonp解析网页--> <!-- 解析网页 爬视频可 研究tiko --> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.10.2</version> </dependency> <!-- thymeleaf --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--ES依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> <!--spring web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> </dependency> <!--fastjson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.70</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
测试接口
测试批量插入数据 java
成功插入到数据库
再插入点vue数据
测试查询接口
引入vue.js和axios.js
项目目录
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。