SpringDataSolr
Spring Data Solr就是为了方便Solr的开发所研制的一个框架,其底层是对SolrJ(官方API)的封装。
SolrJ原理 : 是http的请求和响应。向solr中发送一个post请求,solr响应数据
入门 Demo
1、搭建环境,maven jar工程,引入坐标
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-solr</artifactId>
<version>1.5.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
</dependencies>
2、添加配置文件:applicationContext-solr.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:solr="http://www.springframework.org/schema/data/solr"
xsi:schemaLocation="http://www.springframework.org/schema/data/solr
http://www.springframework.org/schema/data/solr/spring-solr-1.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 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>
</beans>
3、在实体类中使用 @field 注解配置
配置schema.xml文件中配置的字段域。
注意:实体类中配置的域名 必须和 配置文件中配置的name域名一 一对应,不能多也不能少
属性使用 @Field 注解标识 。 如果属性与配置文件定义的域名称不一致,需要在注解中指定域名称。
/**
* 配置 域和域名
*/
public class TbItem implements Serializable {
@Field
private Long id;
@Field("item_title")
private String title;
private String sellPoint;
@Field("item_price")
private BigDecimal price;
//省略..............................
}
4、对Solr操作
1. 增加、修改
调用saveBean(obj)方法,传入一个实体类对象。如果实体类的 id 不存在,SolrTemplate会自动进行增加操作;如果实体类的 id 已经存在,则会进行修改操作。
public class solrTemplateTest {
@Autowired
private SolrTemplate solrTemplate;
@Test //添加和删除
public void testAdd(){
TbItem item = new TbItem();
item.setId(1L);
item.setTitle("荣耀V20");
item.setPrice(new BigDecimal(3000.00));
item.setGoodsId(111L);
item.setCategory("手机");
item.setBrand("荣耀");
item.setSeller("荣耀旗舰店");
//添加或修改
solrTemplate.saveBean(item);
solrTemplate.commit(); //修改
}
}
2. 根据主键查询、删除
@Test //通过id查询
public void findById(){
TbItem item = solrTemplate.getById(1, TbItem.class);
System.out.println(item.getBrand()+"..."+item.getTitle());
}
@Test //通过id删除,参数是字符串类型
public void deleteById(){
solrTemplate.deleteById("1");
solrTemplate.commit();
}
3. 批量插入数据
注意:在用 List集合 插入数据的时候。调用saveBean的方法时,必须选择参数是collection的,如果选择参数是obj的,则会报错:Document is missing mandatory uniqueKey field: id
@Test //添加100条数据
public void add(){
List<TbItem> list = new ArrayList<TbItem>();
for (int i=0;i<100;i++){
TbItem item = new TbItem();
item.setId(i+1L); //id需要唯一
item.setTitle("荣耀V20");
item.setPrice(new BigDecimal(3000.00+i));
item.setGoodsId(100L);
item.setCategory("手机");
item.setBrand("荣耀");
item.setSeller("荣耀旗舰店");
list.add(item);
}
solrTemplate.saveBeans(list); //注意调用方法时的选择
solrTemplate.commit();
}
4. 分页查询
@Test //分页查询所有
public void findAllByPage(){
Query query = new SimpleQuery("*:*"); //查询所有
query.setOffset(10); //开始的索引(默认0)
query.setRows(20); //每页的大小(默认10)
ScoredPage<TbItem> page = solrTemplate.queryForPage(query, TbItem.class);
System.out.println("总记录数:"+page.getTotalElements());
System.out.println("总页数:"+page.getTotalPages());
for(TbItem item : page.getContent()){
System.out.println(item.getBrand()+"..."+item.getTitle()+"..."+item.getPrice());
}
}
5. 条件查询
@Test //分页条件查询
public void findByPageMutil(){
Query query = new SimpleQuery("*:*");
//条件
Criteria criteria = new Criteria("item_brand").contains("荣耀"); //查询品牌中含有“荣耀”
criteria = criteria.and("item_title").contains("v20"); //标题含有"v20"
criteria = criteria.and("item_category").is("手机"); //分类是“手机”
query.addCriteria(criteria); //添加条件到查询query中
query.setOffset(10); //开始的索引(默认0)
query.setRows(20); //每页的大小(默认10)
ScoredPage<TbItem> page = solrTemplate.queryForPage(query, TbItem.class);
System.out.println("总记录数:"+page.getTotalElements());
System.out.println("总页数:"+page.getTotalPages());
for(TbItem item : page.getContent()){
System.out.println(item.getBrand()+"..."+item.getTitle()+"..."+item.getPrice());
}
}
6. 删除操作
@Test //删除所有
public void deleteAll(){
Query query = new SimpleQuery("*:*");
solrTemplate.delete(query);
solrTemplate.commit();
}
@Test //按条件删除
public void deleteByMutil(){
Query query = new SimpleQuery("*:*");
Criteria criteria = new Criteria("item_title").contains("v20"); //删除标题中含有“v20”的数据
query.addCriteria(criteria); //添加条件
solrTemplate.delete(query);
solrTemplate.commit();
}
案例一:添加数据到solr库
1、 在实体类中添加 @field 注解
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-solr</artifactId>
<version>1.5.5.RELEASE</version>
</dependency>
</dependencies>
/**
* 配置 域和域名
*/
public class TbItem implements Serializable {
//省略 不需要配置域对象的属性....
@Field
private Long id;
@Field("item_title")
private String title;
@Field("item_price")
private BigDecimal price;
@Field("item_image")
private String image;
@Field("item_goodsid")
private Long goodsId;
@Field("item_category")
private String category;
@Field("item_brand")
private String brand;
@Field("item_seller")
private String seller;
@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、创建一个jar工程,用于向Solr库中添加数据
-
引入spring相关的坐标,以及fastjson(用于添加动态域)坐标,和实体类工程的依赖坐标
-
配置相关的配置文件。(spring配置文件、springDataSolr配置文件)
<!--spring配置文件。applicationContext.xml--> <!--扫描包--> <context:component-scan base-package="cn.lxh.xianghaigou.solrutil"></context:component-scan>
<!--SpringDataSolr配置文件。applicationContext-solr.xml--> <!-- 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>
-
编写Solr的工具类
用于查询数据库,把数据添加到solr库中
/** * solr 操作的工具类 */ @Component("solrUtils") public class SolrUtils { @Autowired private TbItemMapper itemMapper; @Autowired private SolrTemplate solrTemplate; /** * 导入数据 */ public void importItemData(){ TbItemExample example = new TbItemExample(); TbItemExample.Criteria criteria = example.createCriteria(); criteria.andStatusEqualTo("1"); //只查询状态为"1"的 List<TbItem> itemList = itemMapper.selectByExample(example); for (TbItem item : itemList) { //System.out.println(item.getId()+"..."+item.getBrand()+"..."+item.getTitle()); Map specMap = JSON.parseObject(item.getSpec());//将spec字段的json字符串转换为map item.setSpecMap(specMap); //给带注解的属性字段赋值 } solrTemplate.saveBeans(itemList); //添加数据到solr索引库 solrTemplate.commit(); //提交 } }
-
编写一个main方法,操作solr工具类进行添加
/** * 操作solrUtils工具类,添加数据到solr库 */ public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:spring/applicationContext*.xml"); SolrUtils solrUtils = (SolrUtils) context.getBean("solrUtils"); solrUtils.importItemData(); } }
案例二:实现搜索
关键字搜索—普通显示结果
从页面传入一个map搜索集合,key为:keywords
在业务层实现搜索:
@Service (timeout = 10000) //设置连接dubbox超市时间为10s
public class ItemSearchServiceImpl implements ItemSearchService {
@Autowired
private SolrTemplate solrTemplate;
/**
* 搜索
* @param searchMap
* @return
*/
@Override
public Map<String, Object> search(Map searchMap) {
//【关键字去除空格】
String keywords = (String) searchMap.get("keywords");
searchMap.put("keywords",keywords.replace(" ","")); //把关键字中的空格去掉,然后再返回给searchMap中
Map<String,Object> map = new HashMap<>(); //存储返回的数据
Query query = new SimpleQuery();
//添加复制域item_keywords的查询条件,条件是controller传递过来的map集合,集合的key为"keywords"
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;
}
}
关键字搜索—高亮显示结果
后端
@Service (timeout = 10000) //设置连接dubbox超市时间为10s
public class ItemSearchServiceImpl implements ItemSearchService {
@Autowired
private SolrTemplate solrTemplate;
/**
* 搜索
* @param searchMap
* @return
*/
@Override
public Map<String, Object> search(Map searchMap) {
//【关键字去除空格】
String keywords = (String) searchMap.get("keywords");
searchMap.put("keywords",keywords.replace(" ","")); //把关键字中的空格去掉,然后再返回给searchMap中
Map<String,Object> 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);
//添加复制域item_keywords的查询条件,条件是controller传递过来的map集合,集合的key为"keywords"
Criteria criteria = new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria); //添加查询的条件
HighlightPage<TbItem> page = solrTemplate.queryForHighlightPage(query, TbItem.class);
//循环高亮入口集合
List<HighlightEntry<TbItem>> highlighted = page.getHighlighted();
for (HighlightEntry<TbItem> highlightEntry : highlighted) {
//获取高亮列表(如果高亮域有多个,则需要循环 )
List<HighlightEntry.Highlight> highlightsList = highlightEntry.getHighlights();
/* for (HighlightEntry.Highlight highlight : highlights) { //每个域存储的值个数
System.out.println(highlight.getSnipplets());
}*/
if(highlightsList.size() > 0 && highlightsList.get(0).getSnipplets().size() >0) {
TbItem item = highlightEntry.getEntity(); //获取原实体类
//设置高亮的结果
item.setTitle(highlightsList .get(0).getSnipplets().get(0));
}
}
map.put("rows",page.getContent());
return map;
}
}
前端
使用 AngularJs 来实现。测试后发现高亮显示的html代码原样输出,这是angularJS为了防止html攻击采取的安全机制。
所以需要使用AngularJS中的**$sce服务的trustAsHtml**方法来实现转换。因为这个功能具有一定通用性,我们可以通过angularJS的过滤器来简化开发,这样只写一次,调用的时候就非常方便了
1、在base.js中定义trustHtml过滤器
//定义过滤器
app.filter('trustHtml',['$sce',function ($sce) {
return function (data) {
return $sce.trustAsHtml(data);
}
}]);
2、修改页面
在需要高亮显示的地方,使用ng-bind-html标签来完成
<div class="attr" ng-bind-html="item.title | trustHtml"><!--使用过滤器 高亮显示-->
<!--<em>{{item.title}}</em>--><!--原样显示-->
</div>
分组查询
查询商品分类:
/**
* 查询商品分类列表
* @param searchMap
* @return
*/
private List<String> searchCategoryList(Map searchMap){
List<String> list = new ArrayList<>();
Query query = new SimpleQuery("*:*");
//设置分组选项
GroupOptions groupOptions = new GroupOptions().addGroupByField("item_category");
query.setGroupOptions(groupOptions);
//按照关键字查询
Criteria criteria = new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria); //添加查询的条件
//得到分组页
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()); //把结果字符串添加到list集合
}
return list;
}
过滤查询
根据页面点击的条件,过滤查询。
在原有【关键字】查询的全部数据里面添加 过滤条件
/**
* 搜索框---关键字搜索
* @param searchMap
* @return
*/
private Map<String, Object> searchList(Map searchMap) {
Map<String,Object> 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);
//1.1 添加复制域item_keywords的查询条件,条件是controller传递过来的map集合,集合的key为"keywords"
Criteria criteria = new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria); //添加查询的条件
//2.1按【商品分类】添加过滤条件
if(!"".equals(searchMap.get("category"))) {
FilterQuery filterQuery = new SimpleFilterQuery();
Criteria filterCriteria = new Criteria("item_category").is(searchMap.get("category"));
filterQuery.addCriteria(filterCriteria);
query.addFilterQuery(filterQuery);
}
//3.1 按【品牌】添加过滤条件
if(!"".equals(searchMap.get("brand"))) {
FilterQuery filterQuery = new SimpleFilterQuery();
Criteria filterCriteria = new Criteria("item_brand").is(searchMap.get("brand"));
filterQuery.addCriteria(filterCriteria);
query.addFilterQuery(filterQuery);
}
//3.2 按【规格】添加过滤条件
//获取规格的map集合
if(searchMap.get("spec") != null) {
//获取传递过来的规格map集合
Map<String,String> specMap = (Map<String, String>) searchMap.get("spec");
for (String key : specMap.keySet()) {
FilterQuery filterQuery = new SimpleFilterQuery();
Criteria filterCriteria = new Criteria("item_spec_"+key).is(specMap.get(key));
filterQuery.addCriteria(filterCriteria);
query.addFilterQuery(filterQuery);
}
}
//4.1 按【价格】添加过滤查询
if(!"".equals(searchMap.get("price"))){
String price = (String) searchMap.get("price"); //获取价格区间
String[] prices = price.split("-"); //获取价格数组
if(!"0".equals(prices[0])){ //最低价格不等于0
FilterQuery filterQuery = new SimpleFilterQuery();
Criteria filterCriteria = new Criteria("item_price").greaterThanEqual(prices[0]);
filterQuery.addCriteria(filterCriteria);
query.addFilterQuery(filterQuery);
}
if(!"*".equals(prices[1])){ //最高价格不等于*
FilterQuery filterQuery = new SimpleFilterQuery();
Criteria filterCriteria = new Criteria("item_price").lessThanEqual(prices[1]);
filterQuery.addCriteria(filterCriteria);
query.addFilterQuery(filterQuery);
}
}
//5 【分页】查询
Integer pageNo = (Integer) searchMap.get("pageNo"); //5.1获取当前页码
if(pageNo == null){
pageNo = 1;
}
Integer pageSize = (Integer) searchMap.get("pageSize"); //5.2获取页面大小
if(pageSize == null){
pageSize = 40;
}
//5.3设置分页选项
query.setOffset((pageNo-1)*pageSize);//开始索引
query.setRows(pageSize);//页面大小
//6.按【综合(默认)】/【价格】/【新品】查询
//获取排序的要求
String sortValue = (String) searchMap.get("sort"); //获取排序值(ASC/DESC)
String sortField = (String) searchMap.get("sortField"); //排序的字段
if(!"".equals(sortValue) && sortValue != null){
if("ASC".equals(sortValue)){ //按【升序】查询
Sort sort = new Sort(Sort.Direction.ASC,"item_"+sortField);
query.addSort(sort);
}
if("DESC".equals(sortValue)){ //按【降序】查询
Sort sort = new Sort(Sort.Direction.DESC,"item_"+sortField);
query.addSort(sort);
}
}
//高亮页对象
HighlightPage<TbItem> page = solrTemplate.queryForHighlightPage(query, TbItem.class);
//循环高亮入口集合
List<HighlightEntry<TbItem>> highlighted = page.getHighlighted();
for (HighlightEntry<TbItem> highlightEntry : highlighted) {
//获取高亮列表(如果高亮域有多个,则需要循环 )
List<HighlightEntry.Highlight> highlightsList = highlightEntry.getHighlights();
/* for (HighlightEntry.Highlight highlight : highlights) { //每个域存储的值个数
System.out.println(highlight.getSnipplets());
}*/
if(highlightsList.size() > 0 && highlightsList.get(0).getSnipplets().size() >0) {
TbItem item = highlightEntry.getEntity(); //获取原实体类
//设置高亮的结果
item.setTitle(highlightsList .get(0).getSnipplets().get(0));
}
}
map.put("rows",page.getContent());
return map;
}
AngularJS 前端 循环 map集合对象:
ng-repeat="(key,value) in searchMap.spec"
分页栏显示
<ul>
<li class="prev {{isFirstPage() ? 'disabled':''}}">
<a href="#" ng-click="queryByPage(1)">首页</a>
</li>
<li class="prev {{isFirstPage() ? 'disabled':''}}">
<a href="#" ng-click="queryByPage(searchMap.pageNo - 1)">«上一页</a>
</li>
<li class="dotted" ng-if="resultMap.totalPages > 5 && searchMap.pageNo > 3">
<span>...</span>
</li>
<li ng-repeat="page in pageLabel" class="{{isCurrentPage(page) ? 'active':''}}">
<a href="#" ng-click="queryByPage(page)">{{page}}</a>
</li>
<li class="dotted" ng-if="resultMap.totalPages > 5 && searchMap.pageNo < resultMap.totalPages -2">
<span>...</span>
</li>
<li class="next {{isLastPage() ? 'disabled':''}}">
<a href="#" ng-click="queryByPage(searchMap.pageNo + 1)">下一页»</a>
</li>
<li class="next {{isLastPage() ? 'disabled':''}}">
<a href="#" ng-click="queryByPage(resultMap.totalPages)">尾页</a>
</li>
</ul>
前台传递过来:pageNo 页码、pageSize 页面大小
后端
-
获取页码和页面大小
-
设置query查询的起始索引、页面大小
-
把总页数、总记录数存入map中返回
//5 【分页】查询 Integer pageNo = (Integer) searchMap.get("pageNo"); //5.1获取当前页码 if(pageNo == null){ pageNo = 1; } Integer pageSize = (Integer) searchMap.get("pageSize"); //5.2获取页面大小 if(pageSize == null){ pageSize = 40; } //5.3设置分页选项 query.setOffset((pageNo-1)*pageSize);//开始索引 query.setRows(pageSize);//页面大小 //.......... map.put("totalPages",page.getTotalPages());//返回总页码 map.put("total",page.getTotalElements());//返回总记录数
前端
//定义页面搜索实体(keywords:关键字,category:商品分类,brand:品牌,spec:规格,price:价格,
// pageNo:当前页页码,pageSize:页面大小,sort:排序(升/降),sortField:排序字段)
$scope.searchMap = {'keywords':'','category':'','brand':'','spec':{},'price':'','pageNo':1,'pageSize':40,'sort':'','sortField':''};
-
构建分页栏
//构建分页栏 bulidPageLabel = function () { $scope.pageLabel = [];//定义分页栏集合,用于前端遍历页码 var beginPage = 1;//页面显示的起始页 var endPage = $scope.resultMap.totalPages;//页面显示的结束页 var totalPages = $scope.resultMap.totalPages;//获取总页数 if(totalPages > 5){ //总页数大于5,只显示部分页码 if($scope.searchMap.pageNo <= 3){ //显示前5页 endPage = 5; }else if($scope.searchMap.pageNo >= totalPages - 2){ //显示最后5页 beginPage = totalPages - 4 ; }else{ //以当前页为基准,显示5页 beginPage = $scope.searchMap.pageNo - 2; endPage = $scope.searchMap.pageNo + 2; } } //循环产生页码标签 for(var i = beginPage;i <= endPage;i++){ $scope.pageLabel.push(i); } };
-
页码查询
//分页查询 $scope.queryByPage = function (pageNo) { if(pageNo < 1 || pageNo > $scope.resultMap.totalPages){ return; } $scope.searchMap.pageNo = pageNo ; $scope.search();//查询 } //判断当前页是否是第一页 $scope.isFirstPage = function () { if($scope.searchMap.pageNo == 1){ return true; }else{ return false; } } //判断当前页是否是最后一页 $scope.isLastPage = function () { if($scope.searchMap.pageNo == $scope.resultMap.totalPages){ return true; }else{ return false; } } //判断是否是当前页,显示激活状态 $scope.isCurrentPage = function (page) { if($scope.searchMap.pageNo == page ){ return true; }else{ return false; } }
-
搜索跳转页码
注意:
关键字查询的时候,必须初始化:searchMap.pageNo = 1,否则搜索跳转页码的时候会出错
<div><span>共 {{resultMap.totalPages}} 页 </span> <span>到第<input type="text" class="page-num" ng-model="searchMap.pageNo">页 <button class="page-confirm" ng-click="queryByPage(searchMap.pageNo)">确定</button> </span> </div>
排序查询
默认就是按【综合排序】
按价格排序
按新品排序
新品:也就是按商品的更新时间来降序排序
前端页面:
<ul class="sui-nav">
<li class="active">
<a href="#" ng-click="sortSearch('','')">综合</a>
</li>
<li>
<a href="#" ng-click="sortSearch('DESC','updatetime')">新品</a>
</li>
<li>
<a href="#" ng-click="sortSearch('ASC','price')">价格↑</a>
</li>
<li>
<a href="#" ng-click="sortSearch('DESC','price')">价格↓</a>
</li>
</ul>
前端控制器方法:
$scope.searchMap = {'keywords':'','category':'','brand':'','spec':{},'price':'','pageNo':1,'pageSize':40,'sort':'','sortField':''};
//排序查询(sort:排序方式,sortField:排序字段)
$scope.sortSearch = function (sort, sortField) {
$scope.searchMap.sort = sort;
$scope.searchMap.sortField = sortField;
$scope.search();//查询
}
后端:
//6.按【综合(默认)】/【价格】/【新品】查询
//获取排序的要求
String sortValue = (String) searchMap.get("sort"); //获取排序值(ASC/DESC)
String sortField = (String) searchMap.get("sortField"); //排序的字段
if(!"".equals(sortValue) && sortValue != null){
if("ASC".equals(sortValue)){ //按【升序】查询
Sort sort = new Sort(Sort.Direction.ASC,"item_"+sortField);
query.addSort(sort);
}
if("DESC".equals(sortValue)){ //按【降序】查询
Sort sort = new Sort(Sort.Direction.DESC,"item_"+sortField);
query.addSort(sort);
}
}
按销量排序
(1)增加域item_salecount 用于存储每个SKU的销量数据
(2)编写定时器程序,用于更新每个SKU的销量数据(查询近1个月的销量数据,不是累计数据)
(3)定时器每天只需执行一次,可以设定为凌晨开始执行。
定时器可以使用spring task技术来实现,学员们自行百度。
按评价排序
与按销量排序思路基本相同,有一个细节需要注意:
评论分为好评、中评、差评。我们不能简单地将评论数相加,而是应该根据每种评论加权进行统计。
比如:好评的权重是3 ,中评的权重是1,而差评的权重是-3,这样得出的是评价的综合得分。
案例:广告首页搜索与搜索页对接
-
在模块protal-web的广告首页绑定keywords值,传递到搜索页,
<div class="input-append"> <input type="text" id="autocomplete" type="text" ng-model="keywords" class="input-error input-xxlarge" /> <button class="sui-btn btn-xlarge btn-danger" ng-click="search()" type="button">搜索</button> </div>
//定义方法,把keywords传递给搜索页 $scope.search = function () { location.href = "http://localhost:9104/search.html#?keywords="+$scope.keywords; }
-
在搜索页接收keywords值,进行绑定后搜索
使用angularJS自带的**$location**进行值得获取.
//接收主页传递过来的keywords $scope.loadkeywords = function () { if($location.search()['keywords'] != null){ //接收keywords,存入搜索对象中 $scope.searchMap.keywords = $location.search()['keywords']; $scope.search(); //查询 }else{ return; } }
-
初始化搜索
ng-init="loadkeywords()"
关于搜索页的细节
去除关键字中的空格
当用户在搜索的时候,中间会打一些空格,这对solr分词会有影响。所以,我们需要在搜索之前把空格去除。
//【关键字去除空格】
if(((String)searchMap.get("keywords")).contains(" ")){
//获取关键字
String keywords = (String) searchMap.get("keywords");
searchMap.put("keywords",keywords.replace(" ","")); //把关键字中的空格去掉,再返回给searchMap中
}
当关键字中含有品牌的关键字时,把品牌列表隐藏
定义一个方法来判断关键字是否包含品牌
//判断关键字中是否包含品牌,如果包含,则不显示品牌列表
$scope.keywordsIsBrand = function () {
//遍历结果集中品牌列表,与关键字一一比较
for(var i=0;i<$scope.resultMap.brandList.length;i++){
if($scope.searchMap.keywords.indexOf($scope.resultMap.brandList[i].text) >= 0){
//关键字中包含品牌
return true;
}
}
return false;//不包含品牌
}
//在展示品牌列表的地方进行判断
ng-if=" keywordsIsBrand()== false" //放返回值是false时才显示