電商專案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;
}
}
六.總結