壹立方商城----实现商品搜索功能

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对象

业务逻辑:

  1. 根据Query对象进行查询。
  2. 返回查询结果。包括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:每页显示的记录数。

业务逻辑:

  1. 创建一个SolrQuery对象。
  2. 设置查询条件
  3. 设置分页条件
  4. 需要指定默认搜索域。
  5. 设置高亮
  6. 执行查询,调用SearchDao。得到SearchResult
  7. 需要计算总页数。
  8. 返回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列表,只需要展示第一张图片即可。

方法:

  1. 向索引库中添加文档时,只取第一张写入索引库
  2. 从文档列表转换为商品列表时可以取一张。
  3. 在jsp中对列表拆分,只取一张展示。

可以在SearchItem中添加一个getImages方法:
壹立方商城----实现商品搜索功能

public String[] getImages() {
		if(this.image != null&&!this.image.equals("")) {
			String[] strings = this.image.split(",");
			return strings;
		}
		return null;
	}

使用el表达式执行方法,获取第一张图片壹立方商城----实现商品搜索功能

 

 

 

 

 

 

参考文章

原文:https://blog.****.net/pdsu161530247/article/details/81974760