壹立方商城----實現商品搜尋功能
1.效果展示
啟動專案,進入淘淘商城首頁,我們搜尋小米
然後商品搜尋頁面就會展示,所有搜尋到的商品(圖片無法顯示,是因為圖片地址失效了,可以顯示的是我自己新增的)
搜尋時,會有關鍵字分詞+高亮
還有分頁效果
2.功能分析
我們在e3-portal-web首頁展示中分析,輸入關鍵字後,點選搜尋後到底發生了什麼。
由於搜尋框是通用的,在搜尋結果頁面,上面也會有搜尋框,所以搜尋相關程式碼在header.jsp
在header.jsp中,使用者點選搜尋,或者按回車(event.keyCode==13),會將id=key提交到search函式。search函式在header.jsp唯一引入的base-v1.js中
我們搜尋search函式,發現在第33行。encodeURIComponent(document.getElementById(a).value)獲取到id=a(也就是key)的值,進行url編碼就是"%xx%xxx"這種,然後拼接到"http://localhost:8085/search.html?q="後面。window.location.href表示跳轉至url。
所以我們知道,當用戶點選搜尋時,跳轉"http://localhost:8085/search.html?q=xxx",並攜帶查詢關鍵字q,所以我們只需要,接收關鍵字,從索引庫查詢即可。這裡有個隱含的引數 "page頁碼",在搜尋結果頁面用於分頁,在搜尋頁面僅僅是搜尋,並不設定及
,所以預設page=1,搜尋時預設搜尋第一頁。
3.dao層
3.1功能分析
訪問索引庫的類。定義一些通用的資料訪問方法。
業務邏輯就是查詢索引庫。
引數:SolrQuery物件
業務邏輯:
- 根據Query物件進行查詢。
- 返回查詢結果。包括List<SearchItem>、查詢結果的總記錄數。
需要把返回結果封裝到pojo中,至少包含兩個屬性:List<SearchItem>、Long recordCount
再包含一個總頁數。
建立如下SearchResult物件,放入e3-common中
SearchResult.java
package cn.e3mall.common.pojo; import java.io.Serializable; import java.util.List; public class SearchResult implements Serializable { private long recordCount;//總記錄數 private int totalPages;//總頁數 private List<SearchItem> itemList;//搜尋結果列表 public long getRecordCount() { return recordCount; } public void setRecordCount(long recordCount) { this.recordCount = recordCount; } public int getTotalPages() { return totalPages; } public void setTotalPages(int totalPages) { this.totalPages = totalPages; } public List<SearchItem> getItemList() { return itemList; } public void setItemList(List<SearchItem> itemList) { this.itemList = itemList; } }
3.2建立SearchDao
由於搜尋功能只在搜尋工程中用到,可以不寫介面,只寫類。返回值:SearchResult
在e3-search-service中建立com.taotao.search.dao包,在包中SearchDao建立用於訪問索引庫
從service層接收封裝好的SolrQuery查詢索引庫,獲取QueryResponse,從QueryResponse獲取SolrDocumentList,在從SolrDocumentList中獲取solr業務域中的欄位,並取出service層封裝的高亮,封裝成List<SearchItem>,放入SearchResult中SearchDao.java
package cn.e3mall.search.dao;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.e3mall.common.pojo.SearchItem;
import cn.e3mall.common.pojo.SearchResult;
/**
* 商品搜尋dao
* <p>
* Title: SearchDao
* </p>
*
* @version 1.0
*/
@Repository
public class SearchDao {
@Autowired
private SolrServer solrServer;
/**
* 根據SolrQuery查詢索引庫,封裝SearchResult的itemList、recordCount
* <p>
* Title: search
* </p>
* <p>
* Description:
* </p>
*
* @param query
* @return
*/
public SearchResult search(SolrQuery query) throws Exception {
// 1、根據query查詢索引庫
QueryResponse queryResponse = solrServer.query(query);
// 2、獲取商品列表
SolrDocumentList solrDocumentList = queryResponse.getResults();
// 3、取查詢結果總記錄數
long numFound = solrDocumentList.getNumFound();
SearchResult result = new SearchResult();
result.setRecordCount(numFound);
// 取商品列表,需要取高亮顯示
Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting();
// 封裝List<SearchItem>
List<SearchItem> itemList = new ArrayList<>();
for (SolrDocument solrDocument : solrDocumentList) {
SearchItem item = new SearchItem();
item.setId((String) solrDocument.get("id"));
item.setCategory_name((String) solrDocument.get("item_category_name"));
item.setImage((String) solrDocument.get("item_image"));
item.setPrice((long) solrDocument.get("item_price"));
item.setSell_point((String) solrDocument.get("item_sell_point"));
// 取高亮顯示
List<String> list = highlighting.get(solrDocument.get("id")).get("item_title");
String title = "";
if (list != null && list.size() > 0) {
title = list.get(0);
} else {
title = (String) solrDocument.get("item_title");
}
item.setTitle(title);
// 新增到商品列表
itemList.add(item);
}
result.setItemList(itemList);
// 返回結果
return result;
}
}
4.service層
4.1功能分析
引數:queryString:查詢條件
Page:頁碼
Rows:每頁顯示的記錄數。
業務邏輯:
- 建立一個SolrQuery物件。
- 設定查詢條件
- 設定分頁條件
- 需要指定預設搜尋域。
- 設定高亮
- 執行查詢,呼叫SearchDao。得到SearchResult
- 需要計算總頁數。
- 返回SearchResult
4.2建立service介面
在e3-search-interface的SearchService建立介面
SearchService.java
package cn.e3mall.search.service;
import cn.e3mall.common.pojo.SearchResult;
public interface SearchService {
/**
* 根據查詢條件查詢
* @param queryString
* @param page
* @param rows
* @return
* @throws Exception
*/
SearchResult search(String keyword, int page, int rows) throws Exception;
}
4.3建立service實現類
在e3-search-service的cn.e3mall.search.service.impl包的SearchServiceImpl實現介面
要注意注入searchDao依賴
設定查詢索引庫的主查詢條件和分頁條件,還需要設定高亮,最後獲取SearchResult封裝總頁數
package cn.e3mall.search.service.impl;
import org.apache.solr.client.solrj.SolrQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.e3mall.common.pojo.SearchResult;
import cn.e3mall.search.dao.SearchDao;
import cn.e3mall.search.service.SearchService;
/**
* 商品搜尋Service
* <p>
* Title: SearchServiceImpl
* </p>
*
* @version 1.0
*/
@Service
public class SearchServiceImpl implements SearchService {
@Autowired
private SearchDao searchDao;
@Override
public SearchResult search(String keyword, int page, int rows) throws Exception {
// 建立一個SolrQuery物件
SolrQuery query = new SolrQuery();
// 設定查詢條件
query.setQuery(keyword);
// 設定分頁條件
if (page <= 0)
page = 1;
query.setStart((page - 1) * rows);
query.setRows(rows);
// 設定預設搜尋域
query.set("df", "item_title");
// 開啟高亮顯示
query.setHighlight(true);
query.addHighlightField("item_title");
query.setHighlightSimplePre("<em style=\"color:red\">");
query.setHighlightSimplePost("</em>");
// 呼叫dao執行查詢
SearchResult searchResult = searchDao.search(query);
// 計算總頁數
long recordCount = searchResult.getRecordCount();
int totalPage = (int) (recordCount / rows);
if (recordCount % rows > 0)
totalPage++;
// 新增到返回結果
searchResult.setTotalPages(totalPage);
// 返回結果
return searchResult;
}
}
4.4applicationContext-service.xml
dao層包掃描與釋出service服務
配置包掃面的時候,可以擴大包掃描的範圍
<!-- 配置包掃描器 -->
<context:component-scan base-package="cn.e3mall.search" />
<!-- 宣告需要暴露的服務介面 釋出服務 服務層暴露出來以後,表現層(web層)才能引用 -->
<dubbo:service interface="cn.e3mall.search.service.SearchItemService" ref="searchItemServiceImpl" timeout="600000" />
5.表現層
5.1匯入搜尋結果靜態頁面
5.2引入服務
5.3建立controller
請求的url:/search
引數:
1、q 查詢條件。
2、page 頁碼。預設為1
返回值:
邏輯檢視,返回值。String。
業務邏輯:
接收引數 呼叫服務查詢商品列表 把查詢結果傳遞給頁面。需要引數回顯。 在e3-search-web建立cn.e3mall.search.controller包,在cn.e3mall.search.controller建立SearchController
cn.e3mall.search.controller.SearchController.java
package cn.e3mall.search.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import cn.e3mall.common.pojo.SearchResult;
import cn.e3mall.search.service.SearchService;
/**
* 商品搜尋Controller
* <p>
* Title: SearchController
* </p>
*
* @version 1.0
*/
@Controller
public class SearchController {
@Autowired
private SearchService searchService;
@Value("${SEARCH_RESULT_ROWS}")
private Integer SEARCH_RESULT_ROWS;
@RequestMapping("/search")
public String searchItemList(String keyword, @RequestParam(defaultValue = "1") Integer page, Model model)
throws Exception {
//get請求中文亂碼解決
keyword = new String(keyword.getBytes("iso-8859-1"), "utf-8");
// 查詢商品列表
SearchResult searchResult = searchService.search(keyword, page, SEARCH_RESULT_ROWS);
// 把結果傳遞給頁面
model.addAttribute("query", keyword);
model.addAttribute("totalPages", searchResult.getTotalPages());
model.addAttribute("page", page);
model.addAttribute("recourdCount", searchResult.getRecordCount());
model.addAttribute("itemList", searchResult.getItemList());
// 返回邏輯檢視
return "search";
}
}
5.4配置分頁大小
分頁大小放入配置檔案中
/e3-search-web/src/main/resources/conf/resource.properties
#搜尋結果每頁顯示的記錄數
SEARCH_RESULT_ROWS=60
還需要在springmvc.xml載入配置檔案
<!-- 載入配置檔案 -->
<context:property-placeholder location="classpath:conf/resource.properties" />
5.5測試
發現無法翻頁。
翻頁處理:在e3-search-web工程中:修改如下:
修改url的埠,在這裡可以看到前面說的page引數
5.6圖片無法顯示 這裡說的是有圖片的情況無法顯示。
資料庫中儲存的圖片是以逗號分隔的url列表,只需要展示第一張圖片即可。
方法:
- 向索引庫中新增文件時,只取第一張寫入索引庫
- 從文件列表轉換為商品列表時可以取一張。
- 在jsp中對列表拆分,只取一張展示。
可以在SearchItem中新增一個getImages方法:
public String[] getImages() {
if(this.image != null&&!this.image.equals("")) {
String[] strings = this.image.split(",");
return strings;
}
return null;
}
使用el表示式執行方法,獲取第一張圖片