文章目录
- 1.项目准备
- 2.基础配置
- 2.1 添加pom.xml依赖
- 2.2 yml配置es服务器地址列表
- 3.具体实现
- 3.1 item实体类封装
- 3.2 添加接口
- 3.3 SearchController
- 4.search.jsp界面
- 4.1 搜索内容展示
- 4.2 高亮内容样式设置
- 4.3 搜索框内容回填
- 4.4 添加上下页按钮
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.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
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;
}
我们通过@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 = "<em>" ,postTags = "</em>"),
fields = {@HighlightField(name = "title")}
)
List<SearchHit<Item>> findByTitleOrSellPoint(String key1, String key2, Pageable pageable);
}
接口中需要继承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);
}
以及其实现类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);
}
}
用户在搜索框中输入关键词进行搜索时,实际只输入了一个关键词,但是我们要将关键词发送俩次,使用俩个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();
}
}
4.search.jsp界面
我们这里的项目不是前后端分离的项目,这里我们直接使用在webapp目录下的search.jsp界面,上面SearchController 中也将数据直接返回给了search.jsp;
4.1 搜索内容展示
接下来我们调整jsp页面的相关代码:
此时搜索结果已可以正确显示:
4.2 高亮内容样式设置
但是此时,我们设置的高亮显示的内容只是变为了斜体,并没有其他特殊样式,我们通过css样式设置来进行优化:,通过定位网页源代码我们可以看到,高亮显示的内容是在一个<div>
标签中,且通过class分类为describe,内部在<p>
标签中,且被<em>
标签包裹着:
我们通过<style>
标签并选择相关的标签内容进行颜色的css样式设置:
<style>
div.describe p em {
color: #f00;
}
</style>
通过在search.jsp文件中添加css样式代码 ,重启项目后我们可以发现,我们设置的高亮显示内容已可以成功展现:
4.3 搜索框内容回填
我们可以看到,搜索框中的内容是通过包含另外一个header.jsp
引入的:
通过一个判断语句,有关键词回填关键词,没有关键词回填提示语句:
我们将判断语句中的关键词匹配更改为正确的:
4.4 添加上下页按钮
我们通过判断当前页面在是否在第一页以后来添加上一页按钮;
通过判断当前页面数据大于等于20且页面数据不为0时添加下一页按钮;