目录
前言
找了一套SSM的电商系统开发,记录一下开发的流程。
因为是根据大佬的项目点滴做起,如果看到此博客侵犯利益,请告知立即删除。
第九章 网站前台-搜索页面-搜索解决方案-Solr【1】
1.Solr安装与配置
1.1什么是Solr
大多数搜索引擎应用都必须具有某种搜索功能,问题是搜索功能往往是巨大的资源消耗并且它们由于沉重的数据库加载而拖垮你的应用的性能。
这就是为什么转移负载到一个外部的搜索服务器是一个不错的主意,Apache Solr是一个流行的开源搜索服务器,它通过使用类似REST的HTTP API,这就确保你能从几乎任何编程语言来使用solr。
Solr是一个开源搜索平台,用于构建搜索应用程序。 它建立在Lucene(全文搜索引擎)之上。 Solr是企业级的,快速的和高度可扩展的。 使用Solr构建的应用程序非常复杂,可提供高性能。
为了在CNET网络的公司网站上添加搜索功能,Yonik Seely于2004年创建了Solr。并在2006年1月,它成为Apache软件基金会下的一个开源项目。并于2016年发布最新版本Solr 6.0,支持并行SQL查询的执行。
Solr可以和Hadoop一起使用。由于Hadoop处理大量数据,Solr帮助我们从这么大的源中找到所需的信息。不仅限于搜索,Solr也可以用于存储目的。像其他NoSQL数据库一样,它是一种非关系数据存储和处理技术。
总之,Solr是一个可扩展的,可部署,搜索/存储引擎,优化搜索大量以文本为中心的数据。
1.2 Solr安装
1:安装 Tomcat,解压缩即可。
2:解压 solr。
3:把 solr 下的dist目录solr-4.10.3.war部署到 Tomcat\webapps下(去掉版本号)。
4:启动 Tomcat解压缩 war 包
5:把solr下example/lib/ext 目录下的所有的 jar 包,添加到 solr 的工程中(\WEB-INF\lib目录下)。
6:创建一个 solrhome 。solr 下的/example/solr 目录就是一个 solrhome。复制此目录到D盘改名为solrhome
7:关联 solr 及 solrhome。需要修改 solr 工程的 web.xml 文件。
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>d:\solrhome</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
8:启动 Tomcat
http://IP:8080/solr/
1.3中文分析器IK Analyzer
1.3.1 IK Analyzer简介
IK Analyzer 是一个开源的,基亍 java 语言开发的轻量级的中文分词工具包。从 2006年 12 月推出 1.0 版开始, IKAnalyzer 已经推出了 4 个大版本。最初,它是以开源项目Luence 为应用主体的,结合词典分词和文法分析算法的中文分词组件。从 3.0 版本开始,IK 发展为面向 Java 的公用分词组件,独立亍 Lucene 项目,同时提供了对 Lucene 的默认优化实现。在 2012 版本中,IK 实现了简单的分词歧义排除算法,标志着 IK 分词器从单纯的词典分词向模拟语义分词衍化。
1.3.2 IK Analyzer配置
步骤:
1、把IKAnalyzer2012FF_u1.jar 添加到 solr 工程的 lib 目录下
2、创建WEB-INF/classes文件夹 把扩展词典、停用词词典、配置文件放到 solr 工程的 WEB-INF/classes 目录下。
3、修改 Solrhome 的 schema.xml 文件,配置一个 FieldType,使用 IKAnalyzer
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
1.4配置域
域相当于数据库的表字段,用户存放数据,因此用户根据业务需要去定义相关的Field(域),一般来说,每一种对应着一种数据,用户对同一种数据进行相同的操作。
域的常用属性:
name:指定域的名称
type:指定域的类型
indexed:是否索引
stored:是否存储
required:是否必须
multiValued:是否多值
1.4.1域
修改solrhome的schema.xml 文件 设置业务系统 Field
<field name="item_goodsid" type="long" indexed="true" stored="true"/>
<field name="item_title" type="text_ik" indexed="true" stored="true"/>
<field name="item_price" type="double" indexed="true" stored="true"/>
<field name="item_image" type="string" indexed="false" stored="true" />
<field name="item_category" type="string" indexed="true" stored="true" />
<field name="item_seller" type="text_ik" indexed="true" stored="true" />
<field name="item_brand" type="string" indexed="true" stored="true" />
1.4.2复制域
复制域的作用在于将某一个Field中的数据复制到另一个域中
<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/>
<copyField source="item_title" dest="item_keywords"/>
<copyField source="item_category" dest="item_keywords"/>
<copyField source="item_seller" dest="item_keywords"/>
<copyField source="item_brand" dest="item_keywords"/>
1.4.3动态域
当我们需要动态扩充字段时,我们需要使用动态域。对于品优购,规格的值是不确定的,所以我们需要使用动态域来实现。需要实现的效果如下:
配置:
<dynamicField name="item_spec_*" type="string" indexed="true" stored="true" />
2.品优购-批量数据导入
2.1 需求分析
编写专门的导入程序,将商品数据导入到Solr系统中
2.2 查询商品数据列表
2.2.1 工程搭建
(1)创建pinyougou-solr-util(jar) ,引入pinyougou-dao 以及spring 相关依赖
(2)创建spring 配置文件
内容为:
<context:component-scan base-package="com.pinyougou.solrutil">
</context:component-scan>
2.2.2 代码编写
创建com.pinyougou.solrutil包,创建类SolrUtil ,实现商品数据的查询(已审核商品)
@Component
public class SolrUtil {
@Autowired
private TbItemMapper itemMapper;
/**
* 导入商品数据
*/
public void importItemData(){
TbItemExample example=new TbItemExample();
Criteria criteria = example.createCriteria();
criteria.andStatusEqualTo("1");//已审核
List<TbItem> itemList = itemMapper.selectByExample(example);
System.out.println("===商品列表===");
for(TbItem item:itemList){
System.out.println(item.getTitle());
}
System.out.println("===结束===");
}
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("classpath*:spring/applicationContext*.xml");
SolrUtil solrUtil= (SolrUtil) context.getBean("solrUtil");
solrUtil.importItemData();
}
}
2.3 数据导入Solr索引库
2.3.1实体类
(1)将demo工程中添加了@Field注解的实体类拷贝到pinyougou-pojo中
(2)在pinyougou-pojo中引入依赖
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-solr</artifactId>
<version>1.5.5.RELEASE</version>
</dependency>
2.3.2添加Solr配置文件
添加applicationContext-solr.xml到spring目录
<!-- solr服务器地址 -->
<solr:solr-server id="solrServer" url="http://127.0.0.1:8080/solr" />
<!-- solr模板,使用solr模板可对索引库进行CRUD的操作 -->
<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate">
<constructor-arg ref="solrServer" />
</bean>
2.2.3调用模板类导入solr
修改pinyougou-solr-util的SolrUtil.java
@Autowired
private SolrTemplate solrTemplate;
/**
* 导入商品数据
*/
public void importItemData(){
TbItemExample example=new TbItemExample();
Criteria criteria = example.createCriteria();
criteria.andStatusEqualTo("1");//已审核
List<TbItem> itemList = itemMapper.selectByExample(example);
System.out.println("===商品列表===");
for(TbItem item:itemList){
System.out.println(item.getTitle());
}
solrTemplate.saveBeans(itemList);
solrTemplate.commit();
System.out.println("===结束===");
}
2.4规格导入动态域
2.4.1@Dynamic注解
修改TbItem.java ,添加属性
@Dynamic
@Field("item_spec_*")
private Map<String,String> specMap;
public Map<String, String> getSpecMap() {
return specMap;
}
public void setSpecMap(Map<String, String> specMap) {
this.specMap = specMap;
}
2.4.2修改导入工具
修改pinyougou-solr-util的SolrUtil.java ,引入fastJSON依赖
/**
* 导入商品数据
*/
public void importItemData(){
TbItemExample example=new TbItemExample();
Criteria criteria = example.createCriteria();
criteria.andStatusEqualTo("1");//已审核
List<TbItem> itemList = itemMapper.selectByExample(example);
System.out.println("===商品列表===");
for(TbItem item:itemList){
Map specMap= JSON.parseObject(item.getSpec());//将spec字段中的json字符串转换为map
item.setSpecMap(specMap);//给带注解的字段赋值
System.out.println(item.getTitle());
}
solrTemplate.saveBeans(itemList);
solrTemplate.commit();
System.out.println("===结束===");
}
3.品优购-关键字搜索
3.1需求分析
打开搜索页面,在搜索框输入要搜索的关键字,点击搜索按钮即可进行搜索,展示搜索结果
3.2后端代码
3.2.1服务接口层
(1)创建pinyougou-search-interface模块(搜索服务接口),依赖pinyougou-pojo
(2)创建com.pinyougou.search.service包,创建业务接口
public interface ItemSearchService {
/**
* 搜索
* @param keywords
* @return
*/
public Map<String,Object> search(Map searchMap);
}
3.2.2服务实现层
(1)创建war工程pinyougou-search-service ,引入pinyougou-search-interface spring dubbox 等相关依赖(参加其它服务工程)Tomcat运行端口9004
(2)添加web.xml (参加其它服务工程)
(3)在src/main/resources/spring 下applicationContext-service.xml (参见其它服务工程)dubbo端口20884
(4)在src/main/resources/spring 下创建spring 配置文件applicationContext-solr.xml(同demo工程)
(5)编写服务实现类ItemSearchServiceImpl.java
@Service(timeout=3000)
public class ItemSearchServiceImpl implements ItemSearchService{
@Autowired
private SolrTemplate solrTemplate;
@Override
public Map<String, Object> search(Map searchMap) {
Map<String,Object> map=new HashMap<>();
Query query=new SimpleQuery();
//添加查询条件
Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria);
ScoredPage<TbItem> page = solrTemplate.queryForPage(query, TbItem.class);
map.put("rows", page.getContent());
return map;
}
}
3.2.3控制层
(1)创建pinyougou-search-web 工程 ,引入依赖(参见其它web模块),tomcat运行端口9104
(2)添加web.xml (参加其它web工程)
(3)添加配置文件 (内容参加其它web工程)
(4)创建包com.pinyougou.search.controller 编写控制器类
@RestController
@RequestMapping("/itemsearch")
public class ItemSearchController {
@Reference
private ItemSearchService itemSearchService;
@RequestMapping("/search")
public Map<String, Object> search(@RequestBody Map searchMap ){
return itemSearchService.search(searchMap);
}
}
3.3前端代码
3.3.1拷贝资源
将下列资源拷贝至pinyougou-search-web
将angularJS拷贝到插件文件夹
拷贝base.js到js文件夹
3.3.2服务层
pinyougou-search-web工程创建searchService.js
//搜索服务层
app.service("searchService",function($http){
this.search=function(searchMap){
return $http.post('itemsearch/search.do',searchMap);
}
});
3.3.3控制层
pinyougou-search-web工程searchController.js
app.controller('searchController',function($scope,searchService){
//搜索
$scope.search=function(){
searchService.search( $scope.searchMap ).success(
function(response){
$scope.resultMap=response;//搜索返回的结果
}
);
}
});
3.3.4页面
pinyougou-search-web工程search.html
引入js
<script type="text/javascript" src="plugins/angularjs/angular.min.js"> </script>
<script type="text/javascript" src="js/base.js"> </script>
<script type="text/javascript" src="js/service/searchService.js"> </script>
<script type="text/javascript" src="js/controller/searchController.js"> </script>
指定控制器
<body ng-app="pinyougou" ng-controller="searchController">
绑定搜索框
<div class="input-append">
<input type="text" id="autocomplete" ng-model="searchMap.keywords" type="text" class="input-error input-xxlarge" />
<button class="sui-btn btn-xlarge btn-danger" ng-click="search()" type="button">搜索</button>
</div>
循环显示数据
<li class="yui3-u-1-5" ng-repeat="item in resultMap.rows">
<div class="list-wrap">
<div class="p-img">
<a href="item.html" target="_blank"><img src="{{item.image}}" /></a>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>{{item.price}}</i>
</strong>
</div>
<div class="attr">
<em>{{item.title}}</em>
</div>
<div class="cu">
<em><span>促</span>满一件可参加超值换购</em>
</div>
<div class="commit">
<i class="command">已有2000人评价</i>
</div>
<div class="operate">
<a href="success-cart.html" target="_blank" class="sui-btn btn-bordered btn-danger">加入购物车</a>
<a href="javascript:void(0);" class="sui-btn btn-bordered">对比</a>
<a href="javascript:void(0);" class="sui-btn btn-bordered">关注</a>
</div>
</div>
</li>
第十章 网站前台-搜索页面-搜索解决方案-Solr【2】
1.品优购-高亮显示
1.1需求分析
将用户输入的关键字在标题中以红色的字体显示出来,就是搜索中常用的高亮显示.
1.2后端代码
修改服务层代码ItemSearchServiceImpl.java
创建私有方法,用于返回查询列表的结果(高亮)
/**
* 根据关键字搜索列表
* @param keywords
* @return
*/
private Map searchList(Map searchMap){
Map map=new HashMap();
HighlightQuery query=new SimpleHighlightQuery();
HighlightOptions highlightOptions=new HighlightOptions().addField("item_title");//设置高亮的域
highlightOptions.setSimplePrefix("<em style='color:red'>");//高亮前缀
highlightOptions.setSimplePostfix("</em>");//高亮后缀
query.setHighlightOptions(highlightOptions);//设置高亮选项
//按照关键字查询
Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria);
HighlightPage<TbItem> page = solrTemplate.queryForHighlightPage(query, TbItem.class);
for(HighlightEntry<TbItem> h: page.getHighlighted()){//循环高亮入口集合
TbItem item = h.getEntity();//获取原实体类
if(h.getHighlights().size()>0 && h.getHighlights().get(0).getSnipplets().size()>0){
item.setTitle(h.getHighlights().get(0).getSnipplets().get(0));//设置高亮的结果
}
}
map.put("rows",page.getContent());
return map;
}
修改ItemSearchServiceImpl 的search方法,调用刚才编写的私有方法
@Override
public Map<String, Object> search(Map searchMap) {
Map<String,Object> map=new HashMap<>();
//1.查询列表
map.putAll(searchList(searchMap));
return map;
}
1.3前端代码
我们测试后发现高亮显示的html代码原样输出,这是angularJS为了防止html攻击采取的安全机制。我们如何在页面上显示html的结果呢?我们会用到$sce服务的trustAsHtml方法来实现转换。
因为这个功能具有一定通用性,我们可以通过angularJS的过滤器来简化开发,这样只写一次,调用的时候就非常方便了,看代码:
(1)修改base.js
// 定义模块:
var app = angular.module("pinyougou",[]);
/*$sce服务写成过滤器*/
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"></div>
2.搜索业务规则分析
2.1需求分析
我们今天要完成的目标是在关键字搜索的基础上添加面板搜索功能。
面板上有商品分类、品牌、各种规格和价格区间等条件
业务规则:
(1)当用户输入关键字搜索后,除了显示列表结果外,还应该显示通过这个关键字搜索到的记录都有哪些商品分类。
(2)根据第一个商品分类查询对应的模板,根据模板查询出品牌列表
(3)根据第一个商品分类查询对应的模板,根据模板查询出规格列表
(4)当用户点击搜索面板的商品分类时,显示按照这个关键字查询结果的基础上,筛选此分类的结果。
(5)当用户点击搜索面板的品牌时,显示在以上结果的基础上,筛选此品牌的结果
(6)当用户点击搜索面板的规格时,显示在以上结果的基础上,筛选此规格的结果
(7)当用户点击价格区间时,显示在以上结果的基础上,按价格进行筛选的结果
(8)当用户点击搜索面板的相应条件时,隐藏已点击的条件。
2.2实现思路
(1)搜索面板的商品分类需要使用Spring Data Solr的分组查询来实现
(2)为了能够提高查询速度,我们需要把查询面板的品牌、规格数据提前放入redis
(3)查询条件的构建、面板的隐藏需要使用angularJS来实现
(4)后端的分类、品牌、规格、价格区间查询需要使用过滤查询来实现
3.查询分类列表
3.1需求分析
根据搜索关键字查询商品分类名称列表
3.2后端代码
修改SearchItemServiceImpl.java创建方法
/**
* 查询分类列表
* @param searchMap
* @return
*/
private List searchCategoryList(Map searchMap){
List<String> list=new ArrayList();
Query 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> page = solrTemplate.queryForGroupPage(query, TbItem.class);
//根据列得到分组结果集
GroupResult<TbItem> groupResult = page.getGroupResult("item_category");
//得到分组结果入口页
Page<GroupEntry<TbItem>> groupEntries = groupResult.getGroupEntries();
//得到分组入口集合
List<GroupEntry<TbItem>> content = groupEntries.getContent();
for(GroupEntry<TbItem> entry:content){
list.add(entry.getGroupValue());//将分组结果的名称封装到返回值中
}
return list;
}
search方法调用
@Override
public Map<String, Object> search(Map searchMap) {
Map<String,Object> map=new HashMap<>();
//1.按关键字查询(高亮显示)
......
//2.根据关键字查询商品分类
List categoryList = searchCategoryList(searchMap);
map.put("categoryList",categoryList);
return map;
}
3.3前端代码
修改search.html
<div class="type-wrap" ng-if="resultMap.categoryList!=null">
<div class="fl key">商品分类</div>
<div class="fl value">
<span ng-repeat="category in resultMap.categoryList">
<a href="#">{{category}}</a>
</span>
</div>
<div class="fl ext"></div>
</div>
4.缓存品牌和规格数据
4.1需求分析
将商品分类数据、品牌数据、和规格数据都放入Redis存储。
(1)当用户进入运营商后台的商品分类页面时,将商品分类数据放入缓存(Hash)。以分类名称作为key ,以模板ID作为值
(2)当用户进入运营商后台的模板管理页面时,分别将品牌数据和规格数据放入缓存(Hash)。以模板ID作为key,以品牌列表和规格列表作为值。
4.2缓存商品分类数据
将商品分类表存入缓存 pinyougou-sellergoods-service工程需要引入pinyougou-common工程依赖。
修改pinyougou-sellergoods-service的ItemCatServiceImpl.java,添加redisTemplate
@Autowired
private RedisTemplate redisTemplate;
/**
* 根据上级ID查询列表
*/
@Override
public List<TbItemCat> findByParentId(Long parentId) {
TbItemCatExample example1=new TbItemCatExample();
Criteria criteria1 = example1.createCriteria();
criteria1.andParentIdEqualTo(parentId);
//每次执行查询的时候,一次性读取缓存进行存储 (因为每次增删改都要执行此方法)
//TODO:待修改,每一次查询都要重新获取一次
List<TbItemCat> list = findAll();
for(TbItemCat itemCat:list){
redisTemplate.boundHashOps("itemCat").put(itemCat.getName(), itemCat.getTypeId());
}
System.out.println("更新缓存:商品分类表");
return itemCatMapper.selectByExample(example1);
}
4.3缓存品牌和规格列表数据
(1)修改pinyougou-sellergoods-service的TypeTemplateServiceImpl.java
@Autowired
private RedisTemplate redisTemplate;
/**
* 将数据存入缓存
*/
private void saveToRedis(){
//获取模板数据
List<TbTypeTemplate> typeTemplateList = findAll();
//循环模板
for(TbTypeTemplate typeTemplate :typeTemplateList){
//存储品牌列表
List<Map> brandList = JSON.parseArray(typeTemplate.getBrandIds(), Map.class);
redisTemplate.boundHashOps("brandList").put(typeTemplate.getId(), brandList);
//存储规格列表
List<Map> specList = findSpecList(typeTemplate.getId());//根据模板ID查询规格列表
redisTemplate.boundHashOps("specList").put(typeTemplate.getId(), specList);
}
}
(2)在查询分页方法(findPage) 时调用此方法
public PageResult findPage(TbTypeTemplate typeTemplate, int pageNum, int pageSize) {
......
saveToRedis();//存入数据到缓存
return new PageResult(page.getTotal(), page.getResult());
}
这样在增删改后会自动调用该方法.
4.4加载缓存数据
启动redis ,运行运营商管理后台,打开商品分类和模板管理页,即可将数据放入缓存中。
5.显示品牌和规格数据
5.1需求分析
在搜索面板区域显示第一个分类的品牌和规格列表
5.2后端代码
修改ItemSearchServiceImpl.java ,增加方法
@Autowired
private RedisTemplate redisTemplate;
/**
* 查询品牌和规格列表
* @param category 分类名称
* @return
*/
private Map searchBrandAndSpecList(String category){
Map map=new HashMap();
Long typeId = (Long) redisTemplate.boundHashOps("itemCat").get(category);//获取模板ID
if(typeId!=null){
//根据模板ID查询品牌列表
List brandList = (List) redisTemplate.boundHashOps("brandList").get(typeId);
map.put("brandList", brandList);//返回值添加品牌列表
//根据模板ID查询规格列表
List specList = (List) redisTemplate.boundHashOps("specList").get(typeId);
map.put("specList", specList);
}
return map;
}
Search方法调用此方法
@Override
public Map<String, Object> search(Map searchMap) {
Map<String,Object> map=new HashMap<>();
//1.按关键字查询(高亮显示)
//2.根据关键字查询商品分类
//3.查询品牌和规格列表
if(categoryList.size()>0){
map.putAll(searchBrandAndSpecList(categoryList.get(0)));
}
return map;
}
5.3前端代码
5.3.1获取品牌列表
修改页面search.html,实现品牌列表
<div class="type-wrap logo" ng-if="resultMap.brandList!=null">
<div class="fl key brand">品牌</div>
<div class="value logos">
<ul class="logo-list">
<li ng-repeat="brand in resultMap.brandList">
{{brand.text}}
</li>
</ul>
</div>
<div class="ext">
<a href="javascript:void(0);" class="sui-btn">多选</a>
<a href="javascript:void(0);">更多</a>
</div>
</div>
5.3.2获取规格列表
修改页面search.html,实现规格列表
<div class="type-wrap" ng-repeat="spec in resultMap.specList">
<div class="fl key">{{spec.text}}</div>
<div class="fl value">
<ul class="type-list">
<li ng-repeat="pojo in spec.options">
<a>{{pojo.optionName}}</a>
</li>
</ul>
</div>
<div class="fl ext"></div>
</div>
6.过滤条件构建
6.1需求分析
点击搜索面板上的分类、品牌和规格,实现查询条件的构建。查询条件以面包屑的形式显示。
当面包屑显示分类、品牌和规格时,要同时隐藏搜索面板对应的区域。
用户可以点击面包屑上的X 撤销查询条件。撤销后显示搜索面包相应的区域。
6.2添加搜索项
6.2.1添加搜索项方法
修改pinyougou-search-web的searchController.js
$scope.searchMap={'keywords':'','category':'','brand':'','spec':{}};//搜索对象
//添加搜索项
$scope.addSearchItem=function(key,value){
if(key=='category' || key=='brand'){//如果点击的是分类或者是品牌
$scope.searchMap[key]=value;
}else{
$scope.searchMap.spec[key]=value;
}
}
6.2.2点击搜索项
修改pinyougou-search-web 的search.html ,为搜索面板添加点击事件
点击商品分类标签
<a href="#" ng-click="addSearchItem('category',category)">{{category}}</a>
点击品牌标签
<a href="#" ng-click="addSearchItem('brand',brand.text)">{{brand.text}}</a>
点击规格标签
<a href="#" ng-click="addSearchItem(spec.text,pojo.optionName)"> {{pojo.optionName}}</a>
6.2.3显示面包屑
修改pinyougou-search-web 的search.html,用面包屑形式显示搜索条件
<ul class="fl sui-breadcrumb">搜索条件:</ul>
<ul class="tags-choose">
<li class="tag" ng-if="searchMap.category!=''">商品分类:{{searchMap.category}}<i class="sui-icon icon-tb-close"></i></li>
<li class="tag" ng-if="searchMap.brand!=''">品牌:{{searchMap.brand}}<i class="sui-icon icon-tb-close"></i></li>
<li class="tag" ng-repeat="(key,value) in searchMap.spec">{{key}}:{{value}}<i class="sui-icon icon-tb-close"></i></li>
</ul>
6.3撤销搜索项
6.3.1撤销搜索项的方法
修改pinyougou-search-web工程searchController.js
//移除复合搜索条件
$scope.removeSearchItem=function(key){
if(key=="category" || key=="brand"){//如果是分类或品牌
$scope.searchMap[key]="";
}else{//否则是规格
delete $scope.searchMap.spec[key];//移除此属性
}
}
6.3.2页面调用方法
pinyougou-search-web工程的search.html
<ul class="tags-choose">
<li class="tag" ng-if="searchMap.category!=''" ng-click="removeSearchItem('category')">商品分类:{{searchMap.category}}<i class="sui-icon icon-tb-close"></i></li>
<li class="tag" ng-if="searchMap.brand!=''" ng-click="removeSearchItem('brand')">品牌:{{searchMap.brand}}<i class="sui-icon icon-tb-close"></i></li>
<li class="tag" ng-repeat="(key,value) in searchMap.spec" ng-click="removeSearchItem(key)">{{key}}:{{value}}<i class="sui-icon icon-tb-close"></i></li>
</ul>
6.4 隐藏查询面板
6.4.1 隐藏分类面板
修改search.html
<div class="type-wrap" ng-if="resultMap.categoryList!=null && searchMap.category==''">
<div class="fl key">商品分类</div>
......
</div>
6.4.2隐藏品牌面板
修改search.html
<div class="type-wrap logo" ng-if="resultMap.brandList!=null && searchMap.brand==''">
<div class="fl key brand">品牌</div>
.......
</div>
6.4.3隐藏规格面板
修改search.html
<div class="type-wrap" ng-repeat="spec in resultMap.specList" ng-if="searchMap.spec[spec.text]==null">
<div class="fl key">{{spec.text}}</div>
......
</div>
6.5提交查询
修改searchController.js 在添加和删除筛选条件时自动调用搜索方法
//添加复合搜索条件
$scope.addSearchItem=function(key,value){
if(key=="category" || key=="brand"){//如果是分类或品牌
$scope.searchMap[key]=value;
}else{//否则是规格
$scope.searchMap.spec[key]=value;
}
$scope.search();//执行搜索
}
//移除复合搜索条件
$scope.removeSearchItem=function(key){
if(key=="category" || key=="brand"){//如果是分类或品牌
$scope.searchMap[key]="";
}else{//否则是规格
delete $scope.searchMap.spec[key];//移除此属性
}
$scope.search();//执行搜索
}
7.过滤查询
7.1需求分析
根据上一步构建的查询条件,实现分类、品牌和规格的过滤查询
7.2代码实现
7.2.1分类过滤
修改pinyougou-search-service工程的SearchItemServiceImpl.java
/**
* 根据关键字搜索列表
* @param keywords
* @return
*/
private Map searchList(Map searchMap){
.......
//1.1关键字查询......
//1.2按分类筛选
if(!"".equals(searchMap.get("category"))){
Criteria filterCriteria=new Criteria("item_category").is(searchMap.get("category"));
FilterQuery filterQuery=new SimpleFilterQuery(filterCriteria);
query.addFilterQuery(filterQuery);
}
//高亮显示处理.....
}
7.2.2品牌过滤
修改pinyougou-search-service工程的SearchItemServiceImpl.java
/**
* 根据关键字搜索列表
* @param keywords
* @return
*/
private Map searchList(Map searchMap){
.......
//1.1关键字查询
.......
//1.2按分类筛选
.......
//1.3按品牌筛选
if(!"".equals(searchMap.get("brand"))){
Criteria filterCriteria=new Criteria("item_brand").is(searchMap.get("brand"));
FilterQuery filterQuery=new SimpleFilterQuery(filterCriteria);
query.addFilterQuery(filterQuery);
}
//高亮显示处理...............
}
7.2.3规格过滤
实现思路:规格有多项,需要循环过滤。循环规格查询条件,根据key得到域名称,根据value设置过滤条件。
修改pinyougou-search-service工程的SearchItemServiceImpl.java
/**
* 根据关键字搜索列表
* @param keywords
* @return
*/
private Map searchList(Map searchMap){
......
//1.1关键字查询
....
//1.2按分类筛选
.....
//1.3按品牌筛选
......
//1.4过滤规格
if(searchMap.get("spec")!=null){
Map<String,String> specMap= (Map) searchMap.get("spec");
for(String key:specMap.keySet() ){
Criteria filterCriteria=new Criteria("item_spec_"+key).is( specMap.get(key) );
FilterQuery filterQuery=new SimpleFilterQuery(filterCriteria);
query.addFilterQuery(filterQuery);
}
}
//高亮显示处理.....
}
7.2.4根据分类查询品牌规格列表
@Override
public Map<String, Object> search(Map searchMap) {
Map<String,Object> map=new HashMap<>();
//1.按关键字查询(高亮显示)
......
//2.根据关键字查询商品分类
......
//3.查询品牌和规格列表
String categoryName=(String)searchMap.get("category");
if(!"".equals(categoryName)){//如果有分类名称
map.putAll(searchBrandAndSpecList(categoryName));
}else{//如果没有分类名称,按照第一个查询
if(categoryList.size()>0){
map.putAll(searchBrandAndSpecList(categoryList.get(0)));
}
}
return map;
}