1. 程式人生 > >電商專案day11(商品搜尋功能實現&排序&結果分頁)

電商專案day11(商品搜尋功能實現&排序&結果分頁)

今日目標:

    完成關鍵字搜尋功能
    能夠實現高亮顯示效果
    完成查詢分類列表的功能
    完成條件過濾構建功能
    完成分頁動態頁碼展示

一、完成關鍵字搜尋

1.首先構建工程    pinyougou_search_interface    pinyougou_search_service    pinyougou_search_web

參考content的工程,因為也不需要安全框架

2.關鍵字的需求分析

我們分析輸入關鍵字,可以通過商品或者商家或者title等四個引數進行所有

引數的分析:首先我們的返回的引數可能是itemList   規格  品牌   分類   價格區間    當前頁   每頁顯示的條數,兩種方法,一種是自己封裝一個類,把這些引數封裝起來,還有一種是通過Map實現,因為考慮到還要維護這個類,所以我們採用map的方式進行封裝

後端程式碼實現:

service層的程式碼實現過程
/**
 * 搜尋功能的實現類
 */
@Service
@Transactional
public class SearchServiceImpl implements SearchService {

    @Autowired
    private SolrTemplate solrTemplate;//注意新增solr的配置檔案
    @Override
    public Map<String, Object> search(Map searchMap) {
        //建立高亮顯示物件
        HighlightQuery query = new SimpleHighlightQuery();//介面我們通過其子類實現即可
 // 一.  1.關鍵字搜尋
        String keywords = (String) searchMap.get("keywords");
        Criteria criteria = null;
        //2.判斷關鍵字是否為空
        if (keywords!=null&&!"".equals(keywords)){
            //不等於空
            //輸入關鍵字條件條件
            criteria = new Criteria("item_keywords").is(keywords);
        }else{
            //關鍵字為空,查詢所有 通過一個表示式  *:*
            criteria = new Criteria().expression("*:*");
        }

        //3.將查詢的條件新增到criteria中
        query.addCriteria(criteria);
        //4.這個條件已經封裝了,query需要查詢的所有條件
        HighlightPage<TbItem> page = solrTemplate.queryForHighlightPage(query, TbItem.class);
        //當前頁的資訊
        List<TbItem>  content = page.getContent();
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("rows",content);
        return resultMap;
    }
}
介面方法;
/**
 * 搜尋介面的方法
 */
public interface SearchService {
    //商品的搜尋引數   通過map格式,Object是不同的型別,包括品牌,規格,分類 價格區間 每頁顯示條數 每頁記錄數
    public Map<String,Object> search(Map searchMap);
}

controller層的實現

@RestController
@RequestMapping("search")
public class SearchController {

    @Reference
    private SearchService searchService;

    /**
     * 搜尋功能那的實現
     * @param searchMap
     * @return
     */
    @RequestMapping("searchMap")
    Map <String,Object> search(@RequestBody Map searchMap){
      return  searchService.search(searchMap);
    }
}

前臺程式碼的實現:

controller層

app.controller("searchController",function ($scope,$controller,searchService) {

    //控制器繼承程式碼
    $controller("baseController",{$scope:$scope});

    //構建封裝搜尋條件的物件
    $scope.searchMap={
      keywords:"",
        category:"",
        brand:"",
        spec:{},//規格屬性,需要規格名稱和規格選項
        price:"",
        sort:"ASC",
        sortField:"",
        pageNo:1,//當前頁
        pageSize:60//每頁記錄數
    };
    //商品搜尋
    $scope.search=function () {
        searchService.search($scope.searchMap).success(function (response) {
            $scope.resultMap=response;
            //構建分頁工具條
            //
        })
    }
    
})

service:

//服務層
app.service('searchService',function($http){

    //搜尋功能的實現
    this.search=function(searchMap){
        return $http.post('itemsearch/search.do',searchMap);
    }
});

注意:一定要把方法裡面的引數寫對

二.實現搜尋高亮顯示

思路分析:我們通過在一個搜尋關鍵字上新增字首和字尾,以此來顯示關鍵字的高亮,我們把業務模組都寫在service層

我們通過分析,在返回值的resultMap中的title沒有設定高亮的樣式,那麼我們繼續往上面找,如上圖所示,我們通過遍歷highlighted來獲取,注意判斷裡面的list集合是否為空,得到值後直接進行賦值操作

後端程式碼實現:

//當前頁的資訊
        List<TbItem>  content = page.getContent();
        for (TbItem item : content) {
            //處理高亮結果
            List<HighlightEntry.Highlight> highlights = page.getHighlights(item);
            //判斷highlightsshif為空
            if (highlights!=null&& highlights.size()>0){
                //獲取高亮結果集
                List<String> snipplets = highlights.get(0).getSnipplets();
                //在判斷是否為空
                if (snipplets!=null&& snipplets.size()>0){
                    item.setTitle(snipplets.get(0));
                }
            }
        }

注意出現這個問題,html程式碼直接沒有被解析而是直接顯示在頁面上,這是angularjs出於安全考慮,防止hmtl注入,我們將設定許可權

我們寫一個filter的過濾器

////定義過濾器,處理字串為HTML標籤
//使用方式:<em ng-bind-html="帶標籤的資料 | trustHtml"></em>
app.filter("trustHtml",function($sce){
	return function(data){
		return $sce.trustAsHtml(data);
	};
});

頁面處理:

通過angularjs的一個指令實現:

<em ng-bind-html="entity.title | trustHtml"></em>

效果如圖:

三.過濾新增條件

思路分析:在這我們只涉及一些寫死的資料提交,也可以通過查詢實現,分類,品牌,以及規格的顯示,通過模板關聯品牌和規格,注意:規格我們需要提交精確的其值,那麼我們需要判斷要對那個條件進行封裝

1.組合查詢條件的實現  

前端程式碼實現:

 //組合條件的查詢
    $scope.addFilterCondition=function (key,value) {
        if (key=="category" || key=="price" || key=="brand"){
            $scope.searchMap[key]=value;
        }else{
            $scope.searchMap.spec[key]=value;
        }

        //呼叫查詢方法
        $scope.search();
    }

後臺實現:

 //3.將查詢的條件新增到criteria中
        query.addCriteria(criteria);
        //三.1.構建分類的查詢條件
        String category = (String) searchMap.get("category");
        //2.判斷查詢條件是否為空
        if (category!=null&&!"".equals(category)){
            //構建分類查詢條件
            Criteria categoryCriteria = new Criteria("item_category").is(category);
            //構建過濾條件查詢
            FilterQuery filterQuery = new SimpleFilterQuery(categoryCriteria);
            //將查詢的條件新增到query 中
            query.addFilterQuery(filterQuery);
        }
        //四.構建品牌查詢條件
        String brand = (String)searchMap.get("brand");
        //判斷是否為空
        if (brand!=null&&!"".equals(brand)){
            //構建品牌查詢提哦案件
            Criteria brandCriteria = new Criteria("item_brand").is(brand);
            //構建過濾條件查詢
            FilterQuery filterQuery  = new SimpleFilterQuery(brandCriteria);
            //將查詢的條件新增到總的query 中
            query.addFilterQuery(filterQuery);
        }

2.規格的功能的實現,由於我們分裝的是一個實體類 spec  所以我們也沒有必要在建立一個實體類,我們通過Map格式封裝

後臺程式碼實現:

//五.  封裝規格
        //獲取spec的物件格式
        Map<String,String> specMap = (Map<String, String>) searchMap.get("spec");
        //判斷map的結果是否Wie空
        if (specMap!=null){
            //通過遍歷它的key值,獲得value值,就是規格選項的值
            for (String key: specMap.keySet()){
                //構建品牌查詢提哦案件
                Criteria specificationCriteria = new Criteria("item_spec_"+key).is(specMap.get(key));
                //構建過濾條件查詢
                FilterQuery filterQuery  = new SimpleFilterQuery(specificationCriteria);
                //將查詢的條件新增到總的query 中
                query.addFilterQuery(filterQuery);
            }
        }

3.根據價格實現功能

思路:我們要對字串進行判斷處理,splic("-")   然後通過這個第一個值  0 和最後一個值*  判斷

 //六.價格的條件查詢
        String price = (String)searchMap.get("price");
        //分析:
        /*
        ('price','0-500')
        ('price','500-1000')
        ('price','1000-1500')
        ('price','2000-3000')
          ('price','3000-*')分析可知通過分隔符分開,然後分割後成為一個數組,最後
          通過臨界值判斷
         */
        //判斷是否為空
        if (price!=null&&!"".equals(price)){
            String[] split = price.split("-");
            //通過價格臨界值判斷
            if (!"0".equals(split[0])){
                //構建查詢條件  大於0這個區間
                Criteria priceCriteria= new Criteria("item_price").greaterThanEqual(split[0]);
                //構建過濾條件查詢
                FilterQuery filterQuery  = new SimpleFilterQuery(priceCriteria);
                //將查詢的條件新增到總的query 中
                query.addFilterQuery(filterQuery);
            }

            //通過* 判斷  小於等於1的這個區間
            if (!"*".equals(split[1])){
                //構建查詢條件
                Criteria priceCriteria= new Criteria("item_price").lessThanEqual(split[1]);
                //構建過濾條件查詢
                FilterQuery filterQuery  = new SimpleFilterQuery(priceCriteria);
                //將查詢的條件新增到總的query 中
                query.addFilterQuery(filterQuery);
            }
        }

 

四.排序功能實現

需求:

實現如下圖:

查詢操作實現,新品和價格排序

 

 

 

 

這個是上一個模組移除的內容,點選已經新增的條件,實現移除的功能

思路:我們通過點選傳過來的的key值,刪除value注意還要判斷是spec,因為這個是物件,我們通過這個delete   方法刪除這個key以及value

//移除查詢條件操作  //通過key移除值
$scope.removeSearchItem=function (key) {

    if (key=="category" || key=="price" || key=="brand"){
        $scope.searchMap[key]="";
    }else{
      delete  $scope.searchMap.spec[key];
    }
    //呼叫查詢方法
    $scope.search();
}

五.搜尋分頁功能實現

思想:通過傳過來pageNo當前頁,pageSize總頁數,作為條件,後臺做處理,然後返回給前臺

 

後臺程式碼:

 //八.構建分頁查詢
        Integer pageNo = (Integer) searchMap.get("pageNo");
        Integer pageSize = (Integer) searchMap.get("pageSize");
        query.setOffset((pageNo-1)*pageSize);//設定分頁起始值
        query.setRows(pageSize);//設定總頁數
//最後還的封裝一下
 Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("rows",content);
        resultMap.put("totalpagee",page.getTotalPages());//總頁數
        resultMap.put("pageNo",pageNo);//當前頁
        return resultMap;

前臺程式碼實現:

   //構建分頁工具條程式碼
    buildPageLabel=function(){
        $scope.pageLabel = [];// 新增分頁欄屬性,存放分頁的頁面
        var maxPageNo = $scope.resultMap.totalPages;// 得到最後頁碼

        // 定義屬性,顯示省略號
        $scope.firstDot = true;
        $scope.lastDot = true;

        var firstPage = 1;// 開始頁碼
        var lastPage = maxPageNo;// 截止頁碼

        if ($scope.resultMap.totalPages > 5) { // 如果總頁數大於5頁,顯示部分頁碼
            if ($scope.resultMap.pageNo <= 3) {// 如果當前頁小於等於3
                lastPage = 5; // 前5頁
                // 前面沒有省略號
                $scope.firstDot = false;

            } else if ($scope.searchMap.pageNo >= lastPage - 2) {// 如果當前頁大於等於最大頁碼-2
                firstPage = maxPageNo - 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);
        }
    }


    //分頁查詢
    $scope.queryForPage=function(pageNo){
        $scope.searchMap.pageNo=pageNo;

        //執行查詢操作
        $scope.search();

    }

    //分頁頁碼顯示邏輯分析:
    // 1,如果頁面數不足5頁,展示所有頁號
    // 2,如果頁碼數大於5頁
    // 1) 如果展示最前面的5頁,後面必須有省略號.....
    // 2) 如果展示是後5頁,前面必須有省略號
    // 3) 如果展示是中間5頁,前後都有省略號

    // 定義函式,判斷是否是第一頁
    $scope.isTopPage = 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;
        }
    }

六.總結