- 课程计划
第六天:
- Solrj使用测试
- 把数据库中的数据导入索引库
- 搜索功能的实现
- 使用solrJ管理索引库
使用SolrJ可以实现索引库的增删改查操作。
-
- 添加文档
第一步:把solrJ的jar包添加到工程中。
第二步:创建一个SolrServer,使用HttpSolrServer创建对象。
第三步:创建一个文档对象SolrInputDocument对象。
第四步:向文档中添加域。必须有id域,域的名称必须在schema.xml中定义。
第五步:把文档添加到索引库中。
第六步:提交。
@Test
扫描二维码关注公众号,回复:
10468693 查看本文章
public void addDocument() throws Exception { // 第一步:把solrJ的jar包添加到工程中。 // 第二步:创建一个SolrServer,使用HttpSolrServer创建对象。 SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr"); // 第三步:创建一个文档对象SolrInputDocument对象。 SolrInputDocument document = new SolrInputDocument(); // 第四步:向文档中添加域。必须有id域,域的名称必须在schema.xml中定义。 document.addField("id", "test001"); document.addField("item_title", "测试商品"); document.addField("item_price", "199"); // 第五步:把文档添加到索引库中。 solrServer.add(document); // 第六步:提交。 solrServer.commit(); } |
-
- 删除文档
- 根据id删除
- 删除文档
第一步:创建一个SolrServer对象。
第二步:调用SolrServer对象的根据id删除的方法。
第三步:提交。
@Test public void deleteDocumentById() throws Exception { // 第一步:创建一个SolrServer对象。 SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr"); // 第二步:调用SolrServer对象的根据id删除的方法。 solrServer.deleteById("1"); // 第三步:提交。 solrServer.commit(); } |
-
-
- 根据查询删除
-
@Test public void deleteDocumentByQuery() throws Exception { SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr"); solrServer.deleteByQuery("title:change.me"); solrServer.commit(); } |
-
- 查询索引库
查询步骤:
第一步:创建一个SolrServer对象
第二步:创建一个SolrQuery对象。
第三步:向SolrQuery中添加查询条件、过滤条件。。。
第四步:执行查询。得到一个Response对象。
第五步:取查询结果。
第六步:遍历结果并打印。
-
-
- 简单查询
-
@Test public void queryDocument() throws Exception { // 第一步:创建一个SolrServer对象 SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr"); // 第二步:创建一个SolrQuery对象。 SolrQuery query = new SolrQuery(); // 第三步:向SolrQuery中添加查询条件、过滤条件。。。 query.setQuery("*:*"); // 第四步:执行查询。得到一个Response对象。 QueryResponse response = solrServer.query(query); // 第五步:取查询结果。 SolrDocumentList solrDocumentList = response.getResults(); System.out.println("查询结果的总记录数:" + solrDocumentList.getNumFound()); // 第六步:遍历结果并打印。 for (SolrDocument solrDocument : solrDocumentList) { System.out.println(solrDocument.get("id")); System.out.println(solrDocument.get("item_title")); System.out.println(solrDocument.get("item_price")); } } |
-
-
- 带高亮显示
-
@Test public void queryDocumentWithHighLighting() throws Exception { // 第一步:创建一个SolrServer对象 SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr"); // 第二步:创建一个SolrQuery对象。 SolrQuery query = new SolrQuery(); // 第三步:向SolrQuery中添加查询条件、过滤条件。。。 query.setQuery("测试"); //指定默认搜索域 query.set("df", "item_keywords"); //开启高亮显示 query.setHighlight(true); //高亮显示的域 query.addHighlightField("item_title"); query.setHighlightSimplePre("<em>"); query.setHighlightSimplePost("</em>"); // 第四步:执行查询。得到一个Response对象。 QueryResponse response = solrServer.query(query); // 第五步:取查询结果。 SolrDocumentList solrDocumentList = response.getResults(); System.out.println("查询结果的总记录数:" + solrDocumentList.getNumFound()); // 第六步:遍历结果并打印。 for (SolrDocument solrDocument : solrDocumentList) { System.out.println(solrDocument.get("id")); //取高亮显示 Map<String, Map<String, List<String>>> highlighting = response.getHighlighting(); List<String> list = highlighting.get(solrDocument.get("id")).get("item_title"); String itemTitle = null; if (list != null && list.size() > 0) { itemTitle = list.get(0); } else { itemTitle = (String) solrDocument.get("item_title"); } System.out.println(itemTitle); System.out.println(solrDocument.get("item_price")); } } |
- 把商品数据导入到索引库中
- 功能分析
schema.xml中定义
- 商品Id
- 商品标题
- 商品卖点
- 商品价格
- 商品图片
- 分类名称
- 商品描述
需要从tb_item, tb_item_cat, tb_item_desc表中查询数据。
Sql1:
SELECT
a.id,
a.title,
a.sell_point,
a.price,
a.image,
b. NAME category_name,
c.item_desc
FROM
tb_item a,
tb_item_cat b,
tb_item_desc c
WHERE
a.cid = b.id
AND a.id = c.item_id
AND a.`status` = 1;
Sql2:
SELECT
a.id,
a.title,
a.sell_point,
a.price,
a.image,
b. NAME category_name,
c.item_desc
FROM
tb_item a
JOIN tb_item_cat b ON a.cid = b.id
JOIN tb_item_desc c ON a.id = c.item_id
WHERE
a.`status` = 1
参数:无
业务逻辑:taotao-search中实现
- 查询所有商品数据。
- 创建一个SolrServer对象。
- 为每个商品创建一个SolrInputDocument对象。
- 为文档添加域
- 向索引库中添加文档。
- 返回TaotaoResult。
在taotao-manager-web中调用服务。实现数据导入功能。
-
- Dao层
返回一个pojo对应查询的sql语句。
public class SearchItem implements Serializable{
private String id; private String title; private String sell_point; private long price; private String image; private String category_name; private String item_desc; } |
放到taotao-common中。
接口的返回值:List<SearchItem>
接口定义:
public interface SearchItemMapper {
List<SearchItem> getItemList(); } |
Mapper映射文件:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.taotao.search.mapper.SearchItemMapper" >
<select id="getItemList" resultType="com.taotao.common.pojo.SearchItem"> SELECT a.id, a.title, a.sell_point, a.price, a.image, b. NAME category_name, c.item_desc FROM tb_item a JOIN tb_item_cat b ON a.cid = b.id JOIN tb_item_desc c ON a.id = c.item_id WHERE a.status = 1 </select> </mapper> |
-
- Service层
参数:无
业务逻辑:taotao-search中实现
1、查询所有商品数据。
2、创建一个SolrServer对象。
3、为每个商品创建一个SolrInputDocument对象。
4、为文档添加域
5、向索引库中添加文档。
6、返回TaotaoResult。
在 applicationContext-solr.xml中配置SolrServer对象。
@Service public class SearchItemServiceImpl implements SearchItemService {
@Autowired private SearchItemMapper searchItemMapper; @Autowired private SolrServer solrServer;
@Override public TaotaoResult importAllItems() throws Exception{ // 1、查询所有商品数据。 List<SearchItem> itemList = searchItemMapper.getItemList(); // 2、创建一个SolrServer对象。 // 3、为每个商品创建一个SolrInputDocument对象。 for (SearchItem searchItem : itemList) { SolrInputDocument document = new SolrInputDocument(); // 4、为文档添加域 document.addField("id", searchItem.getId()); document.addField("item_title", searchItem.getTitle()); document.addField("item_sell_point", searchItem.getSell_point()); document.addField("item_price", searchItem.getPrice()); document.addField("item_image", searchItem.getImage()); document.addField("item_category_name", searchItem.getCategory_name()); document.addField("item_desc", searchItem.getItem_desc()); // 5、向索引库中添加文档。 solrServer.add(document); } //提交修改 solrServer.commit(); // 6、返回TaotaoResult。 return TaotaoResult.ok(); }
} |
-
-
- 发布服务
-
-
- 表现层
- 引用服务
- 表现层
在taotao-manager-web中引用服务。
-
-
- Controller
-
请求的url:/index/importall
参数:无
返回值:json数据。TaotaoResult。
@Controller public class SearchItemController {
@Autowired private SearchItemService searchItemService;
@RequestMapping("/index/importall") @ResponseBody public TaotaoResult importAllItems() { try { TaotaoResult result = searchItemService.importAllItems(); return result; } catch (Exception e) { e.printStackTrace(); return TaotaoResult.build(500, "导入数据失败"); } } } |
-
-
- Jsp
-
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <div> <a href="javascript:void(0)" class="easyui-linkbutton" onclick="importAll()">一键导入商品数据到索引库</a> </div> <script type="text/javascript">
function importAll() { $.post("/index/importall",null,function(data){ if (data.status==200) { $.messager.alert('提示','商品数据导入成功!'); } else {
$.messager.alert('提示','商品数据导入失败!'); }
}); } </script> |
taotao-search-service工程的pom文件中添加如下配置:
<!-- 如果不添加此节点mybatis的mapper.xml文件都会被漏掉。 --> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> <!-- 如果没有此节点,src/main/resources目录下的配置文件将被忽略 --> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build> |
- 商品搜索功能实现
- 搜索表现层工程搭建
搜索结果页面的展示。
可以参考taotao-manager-web创建。
打包方式war。
Taotao-search-web
-
-
- Pom文件
-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.taotao</groupId> <artifactId>taotao-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <groupId>com.taotao</groupId> <artifactId>taotao-search-web</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>com.taotao</groupId> <artifactId>taotao-search-interface</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <!-- JSP相关 --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <scope>provided</scope> </dependency> <!-- dubbo相关 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <!-- 排除依赖 --> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> <exclusion> <groupId>org.jboss.netty</groupId> <artifactId>netty</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> </dependencies> <!-- 配置tomcat插件 --> <build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <port>8085</port> <path>/</path> </configuration> </plugin> </plugins> </build> </project> |
-
-
- 框架整合
-
-
- 搜索功能分析
在首页的搜索框中输入搜索条件,然后跳转到搜索结果页面。搜索结果页面在taotao-search-web工程中。
请求的url:/search
参数:
1、q 查询条件。
2、page 页码。默认为1
返回值:
逻辑视图,返回值。String。
业务逻辑:
- 接收查询条件。
- 创建一个SolrServer对象,需要注入。
- 创建一个SolrQuery对象。
- 需要设置查询条件、分页条件、设置默认搜索域、高亮设置。
- 执行查询,返回QueryResponse对象。
- 取返回结果,封装到List<SearchItem>中。
- 返回查询结果的总记录数,计算查询结果的总页数。
- 得到查询结果,渲染jsp
-
- Dao层
访问索引库的类。定义一些通用的数据访问方法。
业务逻辑就是查询索引库。
参数:SolrQuery对象
业务逻辑:
- 根据Query对象进行查询。
- 返回查询结果。List<SearchItem>、查询结果的总记录数。
需要把返回结果封装到pojo中,至少包含两个属性:List<SearchItem>、Long recordCount
再包含一个总页数。
public class SearchResult implements Serializable {
private List<SearchItem> itemList; private long recordCount; private long pageCount;
} |
返回值:SearchResult
@Repository public class SearchDao {
@Autowired private SolrServer solrServer;
public SearchResult search(SolrQuery query) throws Exception { //根据query对象查询索引库 QueryResponse response = solrServer.query(query); //取商品列表 SolrDocumentList solrDocumentList = response.getResults(); //商品列表 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")); //取高亮显示 Map<String, Map<String, List<String>>> highlighting = response.getHighlighting(); List<String> list = highlighting.get(solrDocument.get("id")).get("item_title"); String itemTitle = ""; //有高亮显示的内容时。 if (list != null && list.size() > 0) { itemTitle = list.get(0); } else { itemTitle = (String) solrDocument.get("item_title"); } item.setTitle(itemTitle); //添加到商品列表 itemList.add(item); } SearchResult result = new SearchResult(); //商品列表 result.setItemList(itemList); //总记录数 result.setRecordCount(solrDocumentList.getNumFound());
return result; } } |
-
- Service层
参数:queryString:查询条件
Page:页码
Rows:每页显示的记录数。
业务逻辑:
- 创建一个SolrQuery对象。
- 设置查询条件
- 设置分页条件
- 需要指定默认搜索域。
- 设置高亮
- 执行查询,调用SearchDao。得到SearchResult
- 需要计算总页数。
- 返回SearchResult
返回值:SearchResult
@Service public class SearchServiceImpl implements SearchService {
@Autowired private SearchDao searchDao;
@Override public SearchResult search(String queryString, int page, int rows) throws Exception { // 1、创建一个SolrQuery对象。 SolrQuery query = new SolrQuery(); // 2、设置查询条件 query.setQuery(queryString); // 3、设置分页条件 query.setStart((page - 1) * rows); query.setRows(rows); // 4、需要指定默认搜索域。 query.set("df", "item_title"); // 5、设置高亮 query.setHighlight(true); query.addHighlightField("item_title"); query.setHighlightSimplePre("<em style=\"color:red\">"); query.setHighlightSimplePost("</em>"); // 6、执行查询,调用SearchDao。得到SearchResult SearchResult result = searchDao.search(query); // 7、需要计算总页数。 long recordCount = result.getRecordCount(); long pageCount = recordCount / rows; if (recordCount % rows > 0) { pageCount++; } result.setPageCount(pageCount); // 8、返回SearchResult return result; }
} |
-
-
- 发布服务
-
-
- 表现层
需要taotao-search-web中实现。引用服务
请求的url:/search
参数:
1、q 查询条件。
2、page 页码。默认为1
返回值:
逻辑视图,返回值。String。
业务逻辑:
- 接收参数
- 调用服务查询商品列表
- 把查询结果传递给页面。需要参数回显。
@Controller public class SearchController {
@Value("${ITEM_ROWS}") private Integer ITEM_ROWS;
@Autowired private SearchService searchService;
@RequestMapping("/search") public String search(@RequestParam("q")String queryString, @RequestParam(defaultValue="1")Integer page, Model model) throws Exception {
SearchResult result = searchService.search(queryString, page, ITEM_ROWS); //传递给页面 model.addAttribute("query", queryString); model.addAttribute("totalPages", result.getPageCount()); model.addAttribute("itemList", result.getItemList()); model.addAttribute("page", page);
//返回逻辑视图 return "search";
} } |
需要对请求参数进行转码处理:
翻页处理:
-
- 图片显示处理
数据库中保存的图片是以逗号分隔的url列表,只需要展示第一张图片即可。
方法:
- 向索引库中添加文档时,只取第一张写入索引库
- 从文档列表转换为商品列表时可以取一张。
- 在jsp中对列表拆分,只取一张展示。
可以在SearchItem中添加一个getImages方法:
在jsp中取属性:
转存失败重新上传取消转存失败重新上传取消转存失败重新上传取消转存失败重新上传取消转存失败重新上传取消转存失败重新上传取消转存失败重新上传取消转存失败重新上传取消转存失败重新上传取消转存失败重新上传取消转存失败重新上传取消
-
- 创建全局异常处理器
public class GlobalExceptionReslover implements HandlerExceptionResolver {
Logger logger = LoggerFactory.getLogger(GlobalExceptionReslover.class);
@Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { //写日志文件 logger.error("系统发生异常", ex); //发邮件、发短信 //Jmail:可以查找相关的资料 //需要在购买短信。调用第三方接口即可。 //展示错误页面 ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("message", "系统发生异常,请稍后重试"); modelAndView.setViewName("error/exception"); return modelAndView; }
} |
-
- Springmvc中配置异常处理器