SpringDataSolr

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库中添加数据

  1. 引入spring相关的坐标,以及fastjson(用于添加动态域)坐标,和实体类工程的依赖坐标

  2. 配置相关的配置文件。(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>
    
  3. 编写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();  //提交
    
        }
    }
    
  4. 编写一个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 页面大小

后端

  1. 获取页码和页面大小

  2. 设置query查询的起始索引页面大小

  3. 把总页数、总记录数存入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':''};
  1. 构建分页栏

    //构建分页栏
    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);
        }
    };
    
  2. 页码查询

    //分页查询
    $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;
        }
    }
    
  3. 搜索跳转页码

    注意:

    ​ 关键字查询的时候,必须初始化:searchMap.pageNo = 1,否则搜索跳转页码的时候会出错

    <div><span>共 {{resultMap.totalPages}} 页&nbsp;</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,这样得出的是评价的综合得分。

案例:广告首页搜索与搜索页对接

  1. 在模块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;
    }
    
  2. 搜索页接收keywords值,进行绑定后搜索

    ​ 使用angularJS自带的**$location**进行值得获取.

    //接收主页传递过来的keywords
    $scope.loadkeywords = function () {
        if($location.search()['keywords'] != null){
            //接收keywords,存入搜索对象中
            $scope.searchMap.keywords = $location.search()['keywords'];
            $scope.search();    //查询
        }else{
            return;
        }
    }
    
  3. 初始化搜索

    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时才显示
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值