将用户输入的关键字在标题中以红色的字体显示出来,就是搜索中常用的高亮显示.
修改工程(youlexuan_search_service)服务层代码 ItemSearchServiceImpl.java
创建私有方法,用于返回查询列表的结果(高亮)
//高亮显示
public Map searchList(Map searchMap){
Map<String, Object> map = new HashMap<>();
//1、创建一个支持高亮查询器对象
SimpleHighlightQuery query = new SimpleHighlightQuery();
//2、设定需要高亮处理字段
HighlightOptions options = new HighlightOptions();
options.addField("item_title");
//3、设置高亮前缀
options.setSimplePrefix("");
//4、设置高亮后缀
options.setSimplePostfix("");
//5、关联高亮选项到高亮查询器对象
query.setHighlightOptions(options);
//6、设定查询条件 根据关键字查询
//创建查询条件对象
Criteria criteria = new Criteria("item_keywords").is(searchMap.get("keywords"));
//关联查询条件到查询器对象
query.addCriteria(criteria);
//7、发出带高亮数据查询请求
HighlightPage<TbItem> highlightPage = solrTemplate.queryForHighlightPage(query, TbItem.class);
//8、获取查询结果记录集合
List<TbItem> list = highlightPage.getContent();
//9、循环集合对象
for (TbItem tbItem : list) {
//获取到针对对象TbItem高亮集合
List<HighlightEntry.Highlight> highlights = highlightPage.getHighlights(tbItem);
//获取第一个字段高亮对象
if(highlights != null && highlights.size() > 0){
List<String> snipplets = highlights.get(0).getSnipplets();
System.out.println("高亮:"+snipplets.get(0));
//使用高亮结果替换商品标题
tbItem.setTitle(snipplets.get(0));
}
}
map.put("rows",highlightPage.getContent());
return map;
}
注意:一定要判断高亮结果集合是否为空,因为搜索的是item_keywords,高亮处理的是item_title所以不是所有查询到的结果都一定有高亮,需要对高亮结果集合判断是否为空。
修改ItemSearchServiceImpl 的search方法,调用刚才编写的私有方法
@Override
public Map<String, Object> search(Map searchMap) {
Map<String, Object> map = new HashMap<>();
/*SimpleQuery query = new SimpleQuery();
// is:基于分词后的结果 和 传入的参数匹配
Criteria criteria = new Criteria("item_keywords").is(searchMap.get("keywords"));
// 添加查询条件
query.addCriteria(criteria);
ScoredPage tbItems = solrTemplate.queryForPage(query, TbItem.class);
List itemList = tbItems.getContent();
long total = tbItems.getTotalElements();
map.put("rows",itemList);
map.put("total",total);*/
//1.查询列表
map.putAll(searchList(searchMap));
return map;
}
开启 search_service,search_web
测试:http://localhost:9104/search.html
我们测试后发现高亮显示的html代码原样输出,这是angularJS为了防止html攻击采取的安全机制。我们如何在页面上显示html的结果呢?我们会用到$sce服务的trustAsHtml方法来实现转换。
因为这个功能具有一定通用性,我们可以通过angularJS的过滤器来简化开发,这样只写一次,调用的时候就非常方便了,看下面:
(1)修改 base.js
/*$sce服务写成过滤器,因为search.html中引入得是base.js所以就写到这里了*/
app.filter('trustHtml',['$sce',function($sce){
return function(data){
return $sce.trustAsHtml(data);
}
}]);
(2)使用过滤器
- ng-bind-html指令用于显示html内容
- 竖线 |用于调用过滤器
<div class="attr" ng-bind-html="item.title | trustHtml">
<em>{{item.title}}em>
div>
刷新页面还是不显示高亮:
检测:👇🏾👇🏾
解决:
刷新页面——> 清空缓存,则成功显示:
今天要完成的目标是在关键字搜索的基础上添加面板搜索功能。
面板上有商品分类、品牌、各种规格和价格区间等条件
业务规则:
(1)当用户输入关键字搜索后,除了显示列表结果外,还应该显示通过这个关键字搜索到的记录都有哪些商品分类。
(2)根据第一个商品分类查询对应的模板,根据模板查询出品牌列表
(3)根据第一个商品分类查询对应的模板,根据模板查询出规格列表
(4)当用户点击搜索面板的商品分类时,显示按照这个关键字查询结果的基础上,筛选此分类的结果。
(5)当用户点击搜索面板的品牌时,显示在以上结果的基础上,筛选此品牌的结果
(6)当用户点击搜索面板的规格时,显示在以上结果的基础上,筛选此规格的结果
(7)当用户点击价格区间时,显示在以上结果的基础上,按价格进行筛选的结果
(8)当用户点击搜索面板的相应条件时,隐藏已点击的条件。
(1)搜索面板的商品分类需要使用Spring Data Solr的分组查询来实现
(2)为了能够提高查询速度,我们需要把查询面板的品牌、规格数据提前放入redis
(3)查询条件的构建、面板的隐藏需要使用angularJS来实现
(4)后端的分类、品牌、规格、价格区间查询需要使用过滤查询来实现
根据搜索关键字查询商品分类名称列表
修改SearchItemServiceImpl.java创建方法
//商品分类
private List searchCategoryList(Map searchMap){
List<String> list = new ArrayList<>();
SimpleQuery query = new SimpleQuery();
//按照关键字查询
Criteria criteria= new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria);
//设置分组选项
GroupOptions groupOptions = new GroupOptions().addGroupByField("item_category");
query.setGroupOptions(groupOptions);
//得到分组页
GroupPage<TbItem> groupPage = solrTemplate.queryForGroupPage(query, TbItem.class);
//根据列得到分组结果集
GroupResult<TbItem> groupResult = groupPage.getGroupResult("item_category");
//得到分组结果入口页
Page<GroupEntry<TbItem>> groupEntries = groupResult.getGroupEntries();
//得到分组入口集合
List<GroupEntry<TbItem>> content = groupEntries.getContent();
for (GroupEntry<TbItem> itemGroupEntry : content) {
list.add(itemGroupEntry.getGroupValue());//将分组结果的名称封装到返回值中
}
return list;
}
search方法调用
@Override
public Map<String, Object> search(Map searchMap) {
Map<String, Object> map = new HashMap<>();
/*SimpleQuery query = new SimpleQuery();
// is:基于分词后的结果 和 传入的参数匹配
Criteria criteria = new Criteria("item_keywords").is(searchMap.get("keywords"));
// 添加查询条件
query.addCriteria(criteria);
ScoredPage tbItems = solrTemplate.queryForPage(query, TbItem.class);
List itemList = tbItems.getContent();
long total = tbItems.getTotalElements();
map.put("rows",itemList);
map.put("total",total);*/
//1.查询列表
map.putAll(searchList(searchMap));
//2.根据关键字查询商品分类
List categoryList = searchCategoryList(searchMap);
map.put("categoryList",categoryList);
return map;
}
修改search.html
<div class="clearfix selector" ng-if="resultMap.categoryList != null">
<div class="type-wrap">
<div class="fl key">商品分类div>
<div class="fl value" ng-repeat="category in resultMap.categoryList">
<a href="#">{{category}}a>
div>
<div class="fl ext">div>
div>
测试:http://localhost:9104/search.html
将商品分类数据、品牌数据、和规格数据都放入Redis存储。
- (1)当用户进入运营商后台的商品分类页面时,将商品分类数据放入缓存(Hash)。以分类名称作为key ,以模板ID作为值
当用户进入运营商后台的模板管理页面时,分别将品牌数据和规格数据放入缓存(Hash)。以模板ID作为key,以品牌列表和规格列表作为值。