练手项目1笔记 day11

目标

  • 实现品优购价格区间筛选功能
  • 实现搜索结果分页功能
  • 理解多关键字搜索
  • 实现搜索结果排序功能
  • 实现隐藏品牌列表功能
  • 实现搜索页和首页对接功能
  • 完成更新索引库的功能

1. 按价格区间筛选

1. 需求分析

点击搜索面板的价格区间,实现按价格筛选

2. 前端代码

1. 前端控制层

修改search-web的searchController.js 搜索条件的定义

$scope.searchMap = {"keywords":"","category":"","brand":"","spec":{},"price":""};// 搜索对象

修改search-web的searchController.js 添加搜索项和删除搜索项的方法

// 添加搜索项,改变searchMap的值
$scope.addSearchItem = function (key, value) {
  if(key==="category" || key==="brand" || key==="price"){
    $scope.searchMap[key] = value;
  }else{
    $scope.searchMap.spec[key] = value;
  }
  $scope.search();//执行搜索
};

// 撤销搜索项
$scope.removeSearchItem = function (key) {
  if(key==="category" || key==="brand" || key==="price"){
    $scope.searchMap[key] = "";
  }else{
    delete $scope.searchMap.spec[key];
  }
  $scope.search();//执行搜索
}
2. 页面

修改search.html,在标签上调用方法

<div class="type-wrap"  ng-if="searchMap.price==''">
  <div class="fl key">价格</div>
  <div class="fl value">
    <ul class="type-list">
      <li>
        <a ng-click="addSearchItem('price','0-500')">0-500元</a>
      </li>
      <li>
        <a ng-click="addSearchItem('price','500-1000')">500-1000元</a>
      </li>
      <li>
        <a ng-click="addSearchItem('price','1000-1500')">1000-1500元</a>
      </li>
      <li>
        <a ng-click="addSearchItem('price','1500-2000')">1500-2000元</a>
      </li>
      <li>
        <a ng-click="addSearchItem('price','2000-3000')">2000-3000元 </a>
      </li>
      <li>
        <a ng-click="addSearchItem('price','3000-*')">3000元以上</a>
      </li>
    </ul>
  </div>
  <div class="fl ext">
  </div>
</div>

修改search.html,增加面包屑

<li class="tag" ng-if="searchMap.price!=''" ng-click="removeSearchItem('price')">品牌:{{searchMap.price}}<i class="sui-icon icon-tb-close"></i></li>

2. 后端代码

修改search-service的ItemSearchServiceImpl.java

// 1.5 价格区间过滤
if (!"".equals(searchMap.get("price"))) {
  String[] price = ((String) searchMap.get("price")).split("-");
  if(!price[0].equals("0")){// 如果最低价格不是0
    FilterQuery filterQuery = new SimpleFilterQuery();
    Criteria filterCriteria = new Criteria("item_price").greaterThanEqual(price[0]);
    filterQuery.addCriteria(filterCriteria);
    query.addFilterQuery(filterQuery);
  }
  if(!"*".equals(price[1])){
    FilterQuery filterQuery = new SimpleFilterQuery();
    Criteria filterCriteria = new Criteria("item_price").lessThanEqual(price[1]);
    filterQuery.addCriteria(filterCriteria);
    query.addFilterQuery(filterQuery);
  }
}

2. 搜索结果分页

1. 需求分析

在上述功能基础上实现分页查询

思路:

如果总页数小于等于5页,显示全部页码

如果总页数大于5页,

以当前页为中心的5个页码

eg. 8 9 10 11 12

如果当前页页码小于等于3

显示前5页

1 2 3 4 5

如果当前页页码大于总页数-2 eg.100页 当前是99

显示后5页

96 97 98 99 100


2. 后端代码

// 1.6 分页查询
Integer pageNo = Integer.valueOf(searchMap.get("pageNo") + "");//提取页码
if(pageNo==null){
  pageNo=1;//默认第一页
}
Integer pageSize = (Integer) searchMap.get("pageSize");// 每页记录数
if(pageSize==null){
  pageSize=20; //默认每页20条记录
}
query.setOffset((pageNo-1)*pageSize);//开始索引
query.setRows(pageSize);//每页记录数


// ************** 获取高亮结果集 ***************
// 高亮页对象
// ....

map.put("rows",page.getContent());
map.put("totalPages",page.getTotalPages());//返回总页数
map.put("total",page.getTotalElements());//返回总记录数
return map;

3. 前端代码

1. 构建分页标签

需求:

  1. 如果需要修改默认页码和每页的记录数,可以修改searchController.js的searchMap,为搜索对象添加属性
 $scope.searchMap = {"keywords":"","category":"","brand":"","spec":{},"price":"","pageNo":1,"pageSize":40};// 搜索对象
  1. 修改searchController.js 实现页码的构建
// 分页标签的构建
buildPageLabel = function(){

  $scope.pageLabel = [];//新增分页栏属性
  var maxPageNo = $scope.resultMap.totalPages;// 得到最后页码
  var firstPage = 1; // 显示的开始页码
  var lastPage = maxPageNo;// 显示的截止页码
  if($scope.resultMap.totalPages>5){//如果总页数大于5页
    if($scope.searchMap.pageNo<=3){ // 当前页小于等于3
      lastPage = 5;//前5页
    }else if($scope.searchMap.pageNo>=lastPage-2){//如果当前页大于等于最大页码-2
      firstPage=maxPageNo-4;//后5页
    }else{// 显示以当前页为中心的5页
      firstPage = $scope.searchMap.pageNo-2;
      lastPage = $scope.searchMap +2;
    }
  }

  // 循环产生页码标签
  for(var i=firstPage;i<=lastPage;i++){
    $scope.pageLabel.push(i);
  }
};
  1. 在查询后调用该方法
// 搜索
$scope.search = function () {

  searchService.search($scope.searchMap).success(
    function (response) {
      $scope.resultMap = response; // 搜索返回的结果
      buildPageLabel();//页码的构建
    }
  );
};
  1. 修改search.html,循环产生页码
<li ng-repeat="page in pageLabel">
  <a href="#">{{page}}</a>
</li>
...
<div><span>共{{resultMap.totalPages}}页&nbsp;</span><span>
  1. 显示总条数

在面包屑后边加搜索条数

<ul class="fl sui-breadcrumb">搜索条件</ul>
<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>
...
  搜索结果:{{resultMap.total}}条记录
</ul>
2. 提交页码查询
  1. 在searchController.js增加方法,修改页码执行查询
// 根据页码查询,点击页码能够查询
$scope.queryByPage = function(pageNo){
  // 页码验证
  if(pageNo<1 || pageNo>$scope.resultMap.totalPages){
    return;
  }
  $scope.searchMap.pageNo = pageNo;
  $scope.search();
};
  1. 修改页码调用方法
<div class="fr page">
  <div class="sui-pagination pagination-large">
    <ul>
      <li class="prev disabled">
        <a href="#" ng-click="queryByPage(searchMap.pageNo-1)">«</a>
      </li>
      <!--<li class="active">
<a href="#">1</a>
</li>-->
      <li ng-repeat="page in pageLabel">
        <a href="#" ng-click="queryByPage(page)">{{page}}</a>
      </li>

      <li class="dotted"><span>...</span></li>
      <li class="next">
        <a href="#" ng-click="queryByPage(searchMap.pageNo+1)">»</a>
      </li>
    </ul>
    <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>
  </div>
  1. 修改search方法,在执行查询前,转换为int类型,否则提交到后端可能变成字符串
// searchMap是传往后端的,resultMap是接收后端传回的数据,返回有rows内容 totalPages总页数 total总记录数
// 搜索
$scope.search = function () {
  $scope.searchMap.pageNo = parseInt($scope.searchMap.pageNo);
  //...
3. 显示省略号
// 分页标签的构建
buildPageLabel = function(){

  $scope.pageLabel = [];//新增分页栏属性
  var firstPage = 1; // 显示的开始页码
  var lastPage = $scope.resultMap.totalPages;// 显示的截止页码
  $scope.firstDot = true;//前面有省略号
  $scope.lastDot = true;//后面有省略号
  if($scope.resultMap.totalPages>5){//如果总页数大于5页
    if($scope.searchMap.pageNo<=3){ // 当前页小于等于3
      lastPage = 5;//前5页
      $scope.firstDot = false; // 前面没有省略号
    }else if($scope.searchMap.pageNo>=$scope.resultMap.totalPages-2){//如果当前页大于等于最大页码-2
      firstPage=$scope.resultMap.totalPages-4;//后5页
      $scope.lastDot = false;//后面没有省略号
    }else{// 显示以当前页为中心的5页
      firstPage = $scope.searchMap.pageNo-2;
      lastPage = $scope.searchMap.pageNo +2;
    }
  }else{//总页数小于5,前后都没有省略号
    $scope.firstDot = false;
    $scope.lastDot = false;
  }

  // 循环产生页码标签
  for(var i=firstPage;i<=lastPage;i++){
    $scope.pageLabel.push(i);
  }
};

修改页面:页码前的省略号,页码后的省略号

<li class="dotted" ng-if="firstDot==true"><span>...</span></li>
<li ng-repeat="page in pageLabel" class="">
  <a href="#" ng-click="queryByPage(page)">{{page}}</a>
</li>
<li class="dotted" ng-if="lastDot==true"><span>...</span></li>
4. 页码不可用样式
// 判断当前页为第一页
$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;
  }
};

修改页面

<ul>
  <li class="prev {{isFirstPage()?'disabled':''}}">
    <a href="#" ng-click="queryByPage(searchMap.pageNo-1)">«</a>
  </li>
  <!--<li class="active">
<a href="#">1</a>
</li>-->
  <li class="dotted" ng-if="firstDot==true"><span>...</span></li>
  <li ng-repeat="page in pageLabel" class="page==searchMap.pageNo?'active':''">
    <a href="#" ng-click="queryByPage(page)">{{page}}</a>
  </li>

  <li class="dotted" ng-if="lastDot==true"><span>...</span></li>
  <li class="next {{isLastPage()?'disabled':''}}">
    <a href="#" ng-click="queryByPage(searchMap.pageNo+1)">»</a>
  </li>
</ul>
5. 搜索起始页码处理

搜索“手机”后,得到页数是19,点击18页查询,再根据“三星”关键字查询,发现没有结果显示,需要每次查询关键字时重置页码为1

<button ng-click="searchMap.pageNo=1;search()" class="sui-btn btn-xlarge btn-danger" type="button">搜索</button>

3. 多关键字搜索

1. 多关键字搜索规则

如果输入的关键字时一个复合的词组(如三星手机),那solr如何进行搜索呢?

测试发现,solr在搜索时是将关键字进行分词,然后按照或的关系进行搜索。

为什么不是并的关系而是或的关系?

如果你是电商网站的运营者,肯定希望用户搜到的数据更多,如果用并,搜索可能极少甚至没有。另外还很智能的排序策略,按照关键字匹配度进行排序,如果某些记录同时包含三星和手机,这部分数据会排在前面显示。

2. 多关键字搜索空格处理

有些用户会在关键字中间习惯性输入一些空格,测试输入“三星 手机”结果并没有查询到任何结果。因此还要对空格进行处理,删除关键字中的空格。

修改search-service的ItemSearchServiceImpl.java

@Override
public Map search(Map searchMap) {
  Map map = new HashMap();
  // 空格处理
  String keywords = (String) searchMap.get("keywords");
  searchMap.put("keywords",keywords.replace(" ",""));

4. 排序

1. 价格排序

按照价格排序(升降可切换)

1. 后端代码

修改search-service的ItemSearchServiceImpl.java 添加排序代码

// 1.7 排序
String sortValue = (String) searchMap.get("sort");// ASC DESC
String sortField = (String) searchMap.get("sortField");// 排序的关键字
Sort sort = null;
if (sortValue!=null && !sortField.equals("")) {
  if (sortValue.equals("ASC")) {
    sort = new Sort(Sort.Direction.ASC,"item_"+sortField);
  }
  if(sortValue.equals("DESC")){
    sort = new Sort(Sort.Direction.DESC,"item_"+sortField);
  }
}
query.addSort(sort);
2. 前端代码

修改searchController.js的searchMap,增加排序

$scope.searchMap = {"keywords":"","category":"","brand":"","spec":{},"price":"","pageNo":1,"pageSize":40,"sort":"","sortField":""};// 搜索对象

修改searchController.js,增加方法实现查询

// 排序查询
$scope.sortSearch = function (sortField, sort) {
  $scope.searchMap.sortField = sortField;
  $scope.searchMap.sort = sort;
  $scope.search();
}

修改页面

<ul class="sui-nav">
  <li class="active">
    <a href="#" ng-click="sortSearch('','')">综合</a>
  </li>
  <li>
    <a href="#">销量</a>
  </li>
  <li>
    <a href="#">新品</a>
  </li>
  <li>
    <a href="#">评价</a>
  </li>
  <li>
    <a href="#" ng-click="sortSearch('price','ASC')">价格↑</a>
  </li>
  <li>
    <a href="#" ng-click="sortSearch('price','DESC')">价格↓</a>
  </li>
</ul>

2. 按上架时间排序

在这里插入图片描述

1. 增加域定义

修改solrhome的schema.xml添加域定义

<field name="item_updateTime" type="date" indexed="true" stored="true" />
2. 修改实体类

为updateTime属性添加注解

@Field("item_updateTime")
private Date updateTime;
3. 重新运行导入程序

重启solr

安装pinyougou-pojo

重新运行

4. 修改页面
<li>
  <a href="#" ng-click="sortSearch('updateTime','DESC')">新品</a>
</li>

3. 按销量排序(实现思路)

销量需要订单,还没做,先说整体思路

  1. 增加域item_saleCount 用于存储每个SKU的销量数据
  2. 编写定时器程序,用于更新每个SKU的销量数据(查询近一个月的销量数据,不是累积数据,防止新品排不上)
  3. 定时器每天只需执行一次,一般凌晨开始执行(便于维护)

定时器可以使用spring task技术实现,专门做任务调用。

4. 按评价排序(思路)

和销量类似,有个细节需要注意:

评价分好评、中评、差评,不能简单将评论数相加,而是进行加权统计。如好评权重为3,中评为1,差评权重为-3,最终得到综合评分。

5. 隐藏品牌列表

1. 需求分析

需求:如果用户输入的是品牌的关键字,则隐藏品牌列表

2. 思路:

关键字:三星

品牌列表:

循环品牌列表

其中有一个品牌时关键字的子字符串,就认为关键字是品牌

{id:11,text:''}

3. 代码实现

  1. 修改searchController.js
// 判断关键字是否是品牌
$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;
}
  1. 修改页面
<div class="type-wrap logo" ng-if="resultMap.brandList!=null && searchMap.brand=='' && keywordsIsBrand()==false">
  <div class="fl key brand">品牌</div>

6. 搜索页与首页对接

1. 需求分析

用户在首页的搜索框输入关键字,点击搜索后自动跳转到搜索页查询

2. 实现思路:

传递参数(关键字)

首页把关键字传递给搜索页

搜索页接收关键字并自动查询

3. 代码实现

1. 首页传递关键字

修改portal-web的contentController.js

// 搜索跳转
$scope.search = function () {
  location.href = "http://localhost:9104/search.html#?keywords="+$scope.keywords;
}

修改protal-web的index.html

<input type="text" ng-model="keywords" id="autocomplete" type="text" class="input-error input-xxlarge" />
<button ng-click="search()" class="sui-btn btn-xlarge btn-danger" type="button">搜索</button>
2. 搜索页接收关键字

修改search-web的searchController.js

添加location服务用于接收参数

app.controller("searchController",function ($scope,$location, searchService) {}
// 加载查询字符串
$scope.loadkeywords = function () {
  $scope.searchMap.keywords = $location.search()['keywords'];

  $scope.search();
}

在搜索页面添加初始化

<body ng-app="pinyougou" ng-controller="searchController" ng-init="loadkeywords()">

7. 更新索引库

1. 需求分析

在进行商品审核之后更新到solr索引库,在商品删除后删除solr索引库中相应的记录。

思路:

  1. 商家商品服务 查询方法:根据SPU的id集合来查询SKU列表(状态已审核)
  2. 搜索服务 批量导入方法:接收参数为SKU列表
  3. 运营商后台 调用上面的两个方法

2. 查询审核商品列表(SKU)

1. 服务接口层

修改sellergoods-interface的GoodsService.java,新增方法

// 根据商品id和状态查询item表信息
public List<TbItem> findItemListByGoodsIdAndStatus(Long[] goodsIds,String status);
2. 服务实现层

修改sellergoods-service的GoodsServiceImpl.java

@Override
public void updateStatus(Long[] ids, String status) {
  for (Long id : ids) {
    TbGoods goods = goodsMapper.selectByPrimaryKey(id);
    goods.setAuditStatus(status);
    goodsMapper.updateByPrimaryKey(goods);
  }
}

3. 更新到索引库

1. 服务接口层

修改search-interface的ItemSearchService.java

// 导入数据
public void importList(List list);
2. 服务实现层

修改search-service的ItemSearchServiceImpl.java

@Override
public void importList(List list) {
  solrTemplate.saveBeans(list);
  solrTemplate.commit();
}
3. 控制层
  1. manager-web工程引入依赖search-interface
  2. 修改manager-web的GoodsController.java
@RequestMapping("/updateStatus")
public Result updateStatus(Long[] ids,String status){
  try {
    goodsService.updateStatus(ids,status);

    // 按照SPU的id查询 SKU列表(状态为1)
    if("1".equals(status)){
      List<TbItem> itemList = goodsService.findItemListByGoodsIdAndStatus(ids, status);
      if (itemList.size()>0) {
        itemSearchService.importList(itemList);
      }else{
        System.out.println("没有明细数据");
      }
    }

    return new Result(true,"成功");
  } catch (Exception e) {
    e.printStackTrace();
    return new Result(false,"失败");
  }
}

4. 商品删除同步索引数据

1. 服务接口层

修改search-interface的ItemSearchService.java

// 删除数据
public void deleteByGoodsId(List goodsIdList);
2. 服务实现层
@Override
public void deleteByGoodsId(List goodsIdList) {
  Query query = new SimpleQuery("*:*");
  Criteria criteria = new Criteria("item_goodsid").in(goodsIdList);
  query.addCriteria(criteria);
  solrTemplate.delete(query);
  solrTemplate.commit();
}
3. 控制层

修改manager-web的GoodsController.java

@RequestMapping("/delete")
public Result delete(Long [] ids){
  try {
    goodsService.delete(ids);
    itemSearchService.deleteByGoodsId(Arrays.asList(ids));
    return new Result(true, "删除成功"); 
  } catch (Exception e) {
    e.printStackTrace();
    return new Result(false, "删除失败");
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值