• 6.6 Elasticsearch(六)京淘项目改造




    1.项目准备

    我们切换回到此前的京淘项目,对京淘项目使用Elasticsearch技术进行改造:
    在这里插入图片描述

    在这里插入图片描述

    此前我们在pd-web和pd-web-consumer中做了订单削峰,此次的改造,我们不涉及订单的相关业务,只需要对pd-web做改造,对商品完成搜索操作即可,首先运行pd-web模块,测试运行是否正常;

    正常启动后,需要设置其工作空间为pd-web文件夹目录:
    在这里插入图片描述

    在这里插入图片描述

    设置完成后重新启动,访问http://localhost/测试能否成功访问:
    在这里插入图片描述

    此次,我们就是要完成上方搜索功能的实现;

    2.基础配置

    2.1 添加pom.xml依赖

    在pd-web项目的pom.xml中添加Elasticsearch和lombok的依赖:

    		<dependency>
    			<groupId>org.springframework.bootgroupId>
    			<artifactId>spring-boot-starter-data-elasticsearchartifactId>
    		dependency>
    		<dependency>
    			<groupId>org.projectlombokgroupId>
    			<artifactId>lombokartifactId>
    		dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.2 yml配置es服务器地址列表

    在application.yml配置文件中添加es服务器地址列表:
    在这里插入图片描述

    3.具体实现

    3.1 item实体类封装

    package com.pd.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.data.annotation.Id;
    import org.springframework.data.elasticsearch.annotations.Document;
    import org.springframework.data.elasticsearch.annotations.Field;
    
    @Document(indexName = "pditems")
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Item {
        @Id
        private Long id;
        private String brand;
        private String title;
        @Field
        private String sellPoint;
        private String price;
        private String image;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    我们通过@Document(indexName = "pditems")注解来确定实体类的索引数据具体来自哪里,通过@Id注解来表明当前字段为ID;当实体类中的名字与索引中的字段不一致时,通过@Field("sell_point")注解来建立俩者间的联系;

    3.2 添加接口

    我们添加ItemRepository接口,定义商品搜索方法:

    package com.pd.es;
    
    import com.pd.pojo.Item;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.elasticsearch.annotations.Highlight;
    import org.springframework.data.elasticsearch.annotations.HighlightField;
    import org.springframework.data.elasticsearch.annotations.HighlightParameters;
    import org.springframework.data.elasticsearch.core.SearchHit;
    import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
    import java.util.List;
    
    public interface ItemRepository extends ElasticsearchRepository<Item,Long> {
    
        //在title和sellpoint俩个字段中搜索
        @Highlight(
                parameters = @HighlightParameters(preTags = "" ,postTags = ""),
                fields = {@HighlightField(name = "title")}
        )
        List<SearchHit<Item>> findByTitleOrSellPoint(String key1, String key2, Pageable pageable);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    接口中需要继承ElasticsearchRepository,并给定访问数据类型与ID的类型;

    然后再添加SearchService定义具体的搜索方法:

    package com.pd.service;
    
    import com.pd.pojo.Item;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.elasticsearch.core.SearchHit;
    import java.util.List;
    
    public interface SearchService {
        List<SearchHit<Item>> search(String key, Pageable pageable);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    以及其实现类SearchServiceImpl:

    package com.pd.service.impl;
    
    import com.pd.es.ItemRepository;
    import com.pd.pojo.Item;
    import com.pd.service.SearchService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.elasticsearch.core.SearchHit;
    import org.springframework.stereotype.Service;
    import java.util.List;
    @Service
    public class SearchServiceImpl implements SearchService {
        @Autowired
        private ItemRepository itemRepository;
        @Override
        public List<SearchHit<Item>> search(String key, Pageable pageable) {
            return itemRepository.findByTitleOrSellPoint(key, key, pageable);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    用户在搜索框中输入关键词进行搜索时,实际只输入了一个关键词,但是我们要将关键词发送俩次,使用俩个key来接收它,用户商品搜索中名字以及卖点的关键字:
    在这里插入图片描述

    3.3 SearchController

    package com.pd.controller;
    
    import com.pd.pojo.Item;
    import com.pd.service.SearchService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.elasticsearch.core.SearchHit;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import java.util.ArrayList;
    import java.util.List;
    
    @Controller
    public class SearchController {
        @Autowired
        private SearchService searchService;
    
        //?key=手机&page=0&size=20
        @GetMapping("/search/toSearch.html")
        public String search(Model model, String key, Pageable pageable) {
            // model对象用来向jsp传递数据的工具
            List<SearchHit<Item>> list = searchService.search(key, pageable);
            List<Item> items = zhuanHuan(list); //转换
            // items 集合传递到 jsp 进行显示
            // pageable 对象传递到 jsp 显示翻页
            model.addAttribute("items", items);
            model.addAttribute("p", pageable);
    
            return "/search.jsp";
        }
    
        private List<Item> zhuanHuan(List<SearchHit<Item>> list) {
            List<Item> items = new ArrayList<>();
            for (SearchHit<Item> sh : list) {
                Item item = sh.getContent(); //原始数据,没有高亮
                List<String> hlTitle = sh.getHighlightField("title"); //高亮title
                item.setTitle(pinJie(hlTitle));//高亮title替换原始的title数据
                items.add(item);
            }
            return items;
        }
        private String pinJie(List<String> hlTitle) {
            StringBuilder s = new StringBuilder();
            for (String s1 : hlTitle) {
                s.append(s1);
            }
            return s.toString();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    4.search.jsp界面

    我们这里的项目不是前后端分离的项目,这里我们直接使用在webapp目录下的search.jsp界面,上面SearchController 中也将数据直接返回给了search.jsp;

    4.1 搜索内容展示

    接下来我们调整jsp页面的相关代码:
    在这里插入图片描述

    此时搜索结果已可以正确显示:
    在这里插入图片描述

    4.2 高亮内容样式设置

    但是此时,我们设置的高亮显示的内容只是变为了斜体,并没有其他特殊样式,我们通过css样式设置来进行优化:,通过定位网页源代码我们可以看到,高亮显示的内容是在一个

    标签中,且通过class分类为describe,内部在

    标签中,且被标签包裹着:
    在这里插入图片描述

    我们通过