1. 课程计划
1、搜索工程的搭建
2、linux下solr服务的搭建
3、Solrj使用测试
4、把数据库中的数据导入索引库
5、搜索功能的实现
2. 搜索工程搭建
要实现搜索功能,需要搭建solr服务、搜索服务工程、搜索系统(表现层的工程)
2.1. Solr服务搭建
2.1.1. Solr的环境
Solr是java开发。
solr的安装文件需要安装jdk。
安装环境Linux。
需要安装Tomcat。
2.1.2. 搭建步骤
第一步:把solr 的压缩包上传到Linux系统。
Alt+p打开sftp窗口:输入put "F:/java/ziyuan/solr-4.10.3.tgz.tgz"
第二步:解压solr :tar -xvf solr-4.10.3.tgz.tgz
新建一个目录安装solr: cd /usr/local ---> mkdir solr
第三步:安装Tomcat,解压缩即可。
第四步:把solr部署到Tomcat下。
将tomcat拷贝到solr目录下:cp apache-tomcat-7.0.52 /usr/local/solr -r
第五步:解压缩war包。可以启动Tomcat解压。
war包所在位置:solr-4.10.3/example/webapps/solr.war
将该war包拷贝到:cp solr.war /usr/local/solr/apache-tomcat-7.0.52/webapps
启动Tomcat解压:
cd /usr/local/solr/apache-tomcat-7.0.52/bin/
./startup.sh
./shutdown.sh
../webapps
rm -rf solr.war (删除掉这个war文件)
第六步:把/root/solr-4.10.3/example/lib/ext目录下的所有的jar包,添加到solr工程中。
[root@localhost webapps]# cp /root/solr-4.10.3/example/lib/ext/*.jar /usr/local/solr/apache-tomcat-7.0.52/webapps/solr/WEB-INF/lib
第七步:创建一个solrhome。/example/solr目录就是一个solrhome。复制此目录到/usr/local/solr/solrhome:
[root@localhost webapps]# cp /root/solr-4.10.3/example/solr /usr/local/solr/solrhome -r
第八步:关联solr及solrhome。需要修改solr工程的web.xml文件。
cd /usr/local/solr/apache-tomcat-7.0.52/webapps/solr/WEB-INF/
修改web.xml文件: vim web.xml :
第九步:启动Tomcat:
cd /usr/local/solr/apache-tomcat-7.0.52/bin/
./startup.sh
查看输出:
网页测试:http://192.168.25.131:8080/solr/
和windows下的配置完全一样。
2.1.3. Solr的使用
添加文档必须有id域,其他域 必须在solr的schema.xml中定义。
2.2. 配置业务域
schema.xml中定义
1、商品Id 使用schema.xml中的id域
2、商品标题
3、商品卖点
4、商品价格
5、商品图片
6、分类名称
7、商品描述
创建对应的业务域。需要制定中文分析器。创建步骤:
第一步:把中文分析器添加到solr工程中。
1、把IKAnalyzer2012FF_u1.jar添加到solr工程的lib目录下
[root@localhost IKAnalyzer]# cp IKAnalyzer2012FF_u1.jar /usr/local/solr/apache-tomcat-7.0.52/webapps/solr/WEB-INF/lib
2、把扩展词典、配置文件放到solr工程的WEB-INF/classes目录下。
cd /usr/local/solr/apache-tomcat-7.0.52/webapps/solr/WEB-INF
[root@localhost WEB-INF]# mkdir classes
[root@localhost WEB-INF]# cp /root/IKAnalyzer/*.dic *.xml ./classes
第二步:配置一个FieldType,制定使用IKAnalyzer
修改schema.xml文件,添加FieldType:
cd /usr/local/solr/solrhome/collection1/conf/
vim schema.xml
<fieldType name="text_ik" class="solr.TextField"> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/> </fieldType>
第三步:配置业务域,type制定使用自定义的FieldType。
设置业务系统Field(type="text_ik"要分词(string不分词),indexed="true"要索引,stored="true"要存储)
<field name="item_title" type="text_ik" indexed="true" stored="true"/> <field name="item_sell_point" type="text_ik" indexed="true" stored="true"/> <field name="item_price" type="long" indexed="true" stored="true"/> <field name="item_image" type="string" indexed="false" stored="true" /> <field name="item_category_name" type="string" indexed="true" stored="true" /> <field name="item_desc" type="text_ik" indexed="true" stored="false" /> <field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/> <copyField source="item_title" dest="item_keywords"/> <copyField source="item_sell_point" dest="item_keywords"/> <copyField source="item_category_name" dest="item_keywords"/> <copyField source="item_desc" dest="item_keywords"/>
第四步:重启tomcat
cd /usr/local/solr/apache-tomcat-7.0.52/bin
[root@localhost bin]# ./startup.sh
2.3. 搜索服务工程搭建
可以参考taotao-manager创建。
taotao-search(聚合工程pom)
|--taotao-search-interface(jar)
|--taotao-search-Service(war)
(1)taotao-search的pom.xml:
<modules> <module>taotao-search-interface</module> <module>taotao-search-service</module> </modules> <build> <plugins> <!-- tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <port>8084</port> <path>/</path> </configuration> </plugin> </plugins> </build>
(2)taotao-search-interface的pom.xml:
依赖taotao-commom、taotao-manager-pojo
(3)taotao-search-service的pom.xml:
<dependencies> <!-- 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>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> <!-- solr客户端 --> <dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-solrj</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.12.4</version> <configuration> <!-- 跳过测试 --> <skipTests>true</skipTests> </configuration> </plugin> </plugins> </build>
配置文件:
applicationContext-dao.xml:
由于搜索的数据涉及到3张表,需要自己定义mapper,而mapper的使用,只在搜索服务工程中,所以mapper接口及映射文件需要放在taotao-search-service工程中。
<!-- 数据源 --> <!-- sqlsessionfactory --> <!-- mapper扫描器 --> <context:property-placeholder location="classpath:properties/*.properties" /> <!-- 数据库连接池 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="driverClassName" value="${jdbc.driver}" /> <property name="maxActive" value="10" /> <property name="minIdle" value="5" /> </bean> <!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 数据库连接池 --> <property name="dataSource" ref="dataSource" /> <!-- 加载mybatis的全局配置文件 --> <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" /> </bean> <!-- 只用于搜索的mapper --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.taotao.search.mapper" /> </bean>
3. 测试使用solrJ管理索引库
使用SolrJ可以实现索引库的增删改查操作。
3.1. 添加文档
第1步:把solrJ的jar包添加到工程中。
第2步:创建一个SolrServer,使用HttpSolrServer创建对象。
第3步:创建一个文档对象SolrInputDocument对象。
第4步:向文档中添加域。必须有id域,域的名称必须在schema.xml中定义。
第5步:把文档添加到索引库中。
第6步:提交。
@Test public void addDocument() throws Exception { // 第1步:把solrJ的jar包添加到工程中。 // 第2步:创建一个SolrServer,使用HttpSolrServer创建对象。 SolrServer solrServer = new HttpSolrServer("http://192.168.25.131:8080/solr"); // 第3步:创建一个文档对象SolrInputDocument对象。 SolrInputDocument document = new SolrInputDocument(); // 第4步:向文档中添加域。必须有id域,域的名称必须在schema.xml中定义。 document.addField("id", "test001"); document.addField("item_title", "测试商品"); document.addField("item_price", "199"); // 第5步:把文档添加到索引库中。 solrServer.add(document); // 第6步:提交。 solrServer.commit(); }
3.2. 删除文档
3.2.1. 根据id删除
第1步:创建一个SolrServer对象。
第2步:调用SolrServer对象的根据id删除的方法。
第3步:提交。
@Test public void deleteDocumentById() throws Exception { // 第一步:创建一个SolrServer对象。 SolrServer solrServer = new HttpSolrServer("http://192.168.25.131:8080/solr"); // 第二步:调用SolrServer对象的根据id删除的方法。 solrServer.deleteById("1"); // 第三步:提交。 solrServer.commit(); }
3.2.2. 根据查询删除
@Test public void deleteDocumentByQuery() throws Exception { SolrServer solrServer = new HttpSolrServer("http://192.168.25.131:8080/solr"); solrServer.deleteByQuery("title:change.me"); solrServer.commit();
3.3. 查询索引库
查询步骤:
第1步:创建一个SolrServer对象
第2步:创建一个SolrQuery对象。
第3步:向SolrQuery中添加查询条件、过滤条件。。。
第4步:执行查询。得到一个Response对象。
第5步:取查询结果。
第6步:遍历结果并打印。
3.3.1. 简单查询
@Test public void queryDocument() throws Exception { // 第一步:创建一个SolrServer对象 SolrServer solrServer = new HttpSolrServer("http://192.168.25.131: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")); } }
3.3.2. 带高亮显示
@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")); } }
4. 把商品数据导入到索引库中
域包括tb_item(商品表),tb_item_cat(商品类目表),tb_item_desc(商品描述表)这三张表的数据。
要实现功能:从数据库将数据导出来后,导入到索引库。
4.1. 功能分析
在schema.xml中定义以下业务域(已经定义好):
商品Id
商品标题
商品卖点
商品价格
商品图片
分类名称
商品描述
需要从tb_item, tb_item_cat, tb_item_desc表中查询数据。
Sql语句:(返回值是列表,需要有一个POJO封装一行记录,再存放到List中返回)
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;
应该在taotao-manager-web工程中调用导入索引库的服务。
在taotao-manager-web后台系统中 做一个导入索引库的功能界面(例如:有个按钮,点击即可将数据从数据库中导入到索引库)。
业务逻辑:
1、点击按钮,表现层调用服务层的工程的导入索引库的方法
2、服务层实现 调用mapper接口的方法查询所有的商品的数据
3、将数据一条条添加到solrinputdocument文档中
4、将文档添加到索引库中
5、提交,并返回导入成功即可
4.2. Dao层
4.2.1. 创建POJO
创建以下POJO用于存放查询到的用于搜索的商品的数据,并放入taotao-common中
/** * 搜索的商品数据POJO */ public class SearchItem implements Serializable { private Long id; //商品的id private String title;//商品标题 private String sell_point;//商品卖点 private Long price; //价格 private String image;//商品图片的路径 private String category_name;//商品分类名称 private String item_desc;//商品的描述 set/get...... }
4.2.2. 定义mapper接口
接口(SearchItemMapper):
/** * 定义mappre,关联查询3张表 查询出搜索时的商品数据 */ public interface SearchItemMapper { //查询所有商品数据 public List<SearchItem> getSearchItemList(); }
4.2.3. Mapper映射文件(SearchItemMapper.xml)
<?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="getSearchItemList" 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, tb_item_cat b, tb_item_desc c WHERE a.cid = b.id AND a.id = c.item_id AND a.status = 1 </select> </mapper>
4.3. Service层
参数:无
业务逻辑:taotao-search中实现
1、查询所有商品数据。
2、创建一个SolrServer对象。
3、为每个商品创建一个SolrInputDocument对象。
4、为文档添加域
5、向索引库中添加文档。
6、返回TaotaoResult。
4.3.1. 创建applicationContext-solr.xml
在 applicationContext-solr.xml中配置SolrServer对象。
<bean class="org.apache.solr.client.solrj.impl.HttpSolrServer"> <constructor-arg name="baseURL" value="http://192.168.25.131:8080/solr"></constructor-arg> </bean>
4.3.2. 定义service接口
接口:
public interface SearchService { /** * 导入所有的商品数据到索引库中 */ public TaotaoResult importAllItems() throws Exception; }
4.3.3. service实现类
taotao-search-service 的 com.taotao.search.service.impl 包下:
@Service public class SearchServiceImpl implements SearchService { // 1.注入mapper @Autowired private SearchItemMapper searchItemMapper; @Autowired private SolrServer solrServer; @Override public TaotaoResult importAllItems() throws Exception { //2.调用mapper的方法,查询所有的商品的数据 List<SearchItem> searchItemList = searchItemMapper.getSearchItemList(); //3.通过solorj将数据写入到索引库中 //3.1 创建httpSolrServer(配置文件applicationContext-solr.xml已经创建了) //3.2 创建SolrInputDocument ,将列表searchItemList中的元素一个个放到索引库中 for(SearchItem searchItem:searchItemList){ //为每个商品创建一个SolrInputDocument对象。 SolrInputDocument document = new SolrInputDocument(); //为文档添加域 document.addField("id", searchItem.getId().toString());//这里是字符串需要转换 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()); //添加到索引库 solrServer.add(document); } //提交 solrServer.commit(); //4.返回TaotaoResult return TaotaoResult.ok(); } }
4.3.4. 在taotao-search-service中发布服务
<!-- 使用dubbo发布服务 --> <!-- 提供方应用信息,用于计算依赖关系 --> <dubbo:application name="taotao-search" /> <dubbo:registry protocol="zookeeper" address="192.168.25.131:2181" /> <!-- 用dubbo协议在20880端口暴露服务 --> <dubbo:protocol name="dubbo" port="20882" /> <!-- 声明需要暴露的服务接口 --> <dubbo:service interface="com.taotao.search.service.SearchService" ref="searchServiceImpl" timeout="300000"/>
4.4. 表现层
4.4.1. 创建JSP(前端页面实现)
index.jsp中添加网站索引管理:
在taotao-manager-web中创建 indexManager.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"> // 通过ajax 发送请求 function importAll(){ $.ajax({ url:"/index/importAll", type:"GET", success:function(data){ //taotaoresult if(data.status==200){ alert("导入成功"); }else{ alert("导入失败"); } } }); } </script>
4.4.2. 引用服务
在 taotao-manager-web 中的 springmvc.xml 引用服务。
<dubbo:reference interface="com.taotao.search.service.SearchService" id="searchService" timeout="300000"/>
4.4.3. 添加taotao-search-interface的依赖
在taotao-manager-web工程中的pom.xml中添加
4.4.4. Controller
请求的url:/index/importAll
参数:无
返回值:json数据。TaotaoResult。
@Controller public class SearchItemController { @Autowired private SearchService searchService; /** * 导入所有的商品数据到索引库中 * @return */ @RequestMapping("/index/importAll") @ResponseBody public TaotaoResult importAllItems(){ try { return searchService.importAllItems(); } catch (Exception e) { e.printStackTrace(); return TaotaoResult.build(500, "导入数据失败"); } } }
4.4.5. 测试
测试出错,原因是未将工程中的映射文件发布到classpath中。
在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-search-service中加入mybatis和数据库连接池的依赖:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <!-- Mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> </dependency> <!-- 分页插件pagehelper --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> </dependency> <!-- MySql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- 连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency>
效果:
导入成功后solr索引库数据:
5. 商品搜索功能实现
5.1. 搜索表现层工程搭建
搜索结果页面的展示。
Taotao-search-web,打包方式war。可以参考taotao-manager-web创建。
5.1.1. Pom文件
<dependencies> <!-- common --> <dependency> <groupId>com.taotao</groupId> <artifactId>taotao-common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-- search-interface --> <dependency> <groupId>com.taotao</groupId> <artifactId>taotao-search-interface</artifactId> <version>0.0.1-SNAPSHOT</version> </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> <!-- 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> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!-- tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <port>8085</port> <path>/</path> </configuration> </plugin> </plugins> </build>
5.1.2. 配置文件
springmvc.xml:
<!-- 组件扫描 --> <!-- 注解驱动 --> <!-- 视图解析器 --> <!-- 调用服务 --> <context:component-scan base-package="com.taotao.search.controller" /> <mvc:annotation-driven /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean> <!-- 引用dubbo服务 --> <dubbo:application name="taotao-search-web" /> <dubbo:registry protocol="zookeeper" address="192.168.25.131:2181" /> <!-- <dubbo:reference interface="com.taotao.search.service.SearchItemService" id="searchItemService" timeout="30000"/> -->
web.xml:
<display-name>taotao-search-web</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <!-- 解决post乱码 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- springmvc的前端控制器 --> <servlet> <servlet-name>taotao-search-web</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- contextConfigLocation不是必须的, 如果不配置contextConfigLocation, springmvc的配置文件默认在:WEB-INF/servlet的name+"-servlet.xml" --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>taotao-search-web</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping>
5.1.3. 静态页面
5.2. 搜索功能分析
在首页的搜索框中输入搜索条件,然后跳转到搜索结果页面。搜索结果页面在taotao-search-web工程中。
首页搜索框的点击按钮处理函数在:首页的JS中,应当改成8085,如图:
请求的url:/search
http://localhost:8085/search.html?q=
参数:
1、q 查询条件。
2、page 页码。默认为1 每页显示多少行 在controller中写死即可。比如:60
返回值: String。(商品的列表信息,总页数 ,总记录数,数据回显) 定义一个返回结果类SearchResult,存放商品的列表信息,总页数 ,总记录数。
业务逻辑:
1、接收查询条件。
2、创建一个SolrServer对象,需要注入。
3、创建一个SolrQuery对象。
4、需要设置查询条件、分页条件、设置默认搜索域、高亮设置。
5、执行查询,返回QueryResponse对象。
6、取返回结果,封装到List<SearchItem>中。
7、返回查询结果的总记录数,计算查询结果的总页数。
8、得到查询结果,渲染jsp.
5.3. Dao层
5.3.1. 功能分析
访问索引库的类。定义一些通用的数据访问方法。(注:不能用逆向工程了。dao层功能在taotao-search-service工程中的com.taotao.search.dao包中定义)
业务逻辑就是查询索引库。
参数:SolrQuery对象
业务逻辑:
1、根据Query对象进行查询。
2、返回查询结果。包括List<SearchItem>、查询结果的总记录数。
需要把返回结果封装到pojo中,至少包含两个属性:List<SearchItem>、Long recordCount。再包含一个总页数。
创建如下SearchResult对象,放入taotao-common中
public class SearchResult implements Serializable { private List<SearchItem> itemList;//搜索结果列表 private long recordCount;//总记录数 private long pageCount;//总页数 set/get...... }
5.3.2. 创建SearchDao
由于搜索功能只在搜索工程中用到,可以不写接口,只写类(将Search直接定义为类,没必要定义为接口再实现)。返回值:SearchResult
:
/** * 从索引库中搜索商品的DAO * @author smileZTT * */ @Repository public class SearchDao { //1.创建solrServer对象 由sprin管理注入 @Autowired private SolrServer solrServer; /*根据查询条件查询商品的结果集*/ public SearchResult search(SolrQuery query) throws Exception { SearchResult searchResult = new SearchResult(); //2.直接执行查询 QueryResponse response = solrServer.query(query); //3.获取结果集 SolrDocumentList results = response.getResults(); //4.遍历结果集 List<SearchItem> itemList = new ArrayList<SearchItem>(); for(SolrDocument solrDocument : results){ SearchItem item = new SearchItem(); item.setId(Long.parseLong(solrDocument.get("id").toString())); item.setCategory_name(solrDocument.get("item_category_name").toString()); item.setImage(solrDocument.get("item_image").toString()); item.setPrice((long) solrDocument.get("item_price")); item.setSell_point(solrDocument.get("item_sell_point").toString()); //取高亮显示 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 = solrDocument.get("item_title").toString(); } item.setTitle(itemTitle); //添加到商品列表 itemList.add(item); } //5.设置searchResult中的属性,然后返回 searchResult.setItemList(itemList);//设置搜索结果列表 searchResult.setRecordCount(results.getNumFound());//设置总记录数 return searchResult; } }
5.4. Service层
5.4.1. 功能分析
参数:queryString:查询条件
Page:页码
Rows:每页显示的记录数。
业务逻辑:
1、创建一个SolrQuery对象。
2、设置查询条件
3、设置分页条件
4、需要指定默认搜索域。
5、设置高亮
6、执行查询,调用SearchDao。得到SearchResult
7、需要计算总页数。
8、返回SearchResult
5.4.2. service接口
接口已存在,只需要添加方法即可。
:
public interface SearchService { /** * 导入所有的商品数据到索引库中 */ public TaotaoResult importAllItems() throws Exception; /** * 根据搜索条件搜索 * @param queryString 查询的主条件 * @param page 查询的当前页码 * @param rows 每页显示的行数,这个在Controller中写死 * @return * @throws Exception */ public SearchResult search(String queryString, Integer page, Integer rows) throws Exception; }
5.4.3. service接口实现类 SearchServiceImpl :
@Service public class SearchServiceImpl implements SearchService { @Autowired private SearchDao searchDao; @Override public SearchResult search(String queryString, Integer page, Integer rows) throws Exception { //1.创建solrQuery对象 SolrQuery query = new SolrQuery(); //2.设置主查询条件 if(StringUtils.isNotBlank(queryString)){ query.setQuery(queryString); }else { query.setQuery("*:*"); } //2.1 设置过滤条件 设置分页 if(page == null) page = 1; if(rows == null) rows = 60; query.setStart((page - 1) * rows); query.setRows(rows); //2.2 设置默认的搜索域 query.set("df", "item_keywords"); //2.3 设置高亮 query.setHighlight(true);//开启高亮 query.addHighlightField("item_title");//设置高亮显示的域 query.setHighlightSimplePre("<em style="color:red">"); query.setHighlightSimplePost("</em>"); //3.利用dao方法返回的SearchResult只包含了总记录数和商品列表 SearchResult result = searchDao.search(query); //4.设置SearchResult的总页数 long recordCount = result.getRecordCount(); long pageCount = recordCount / rows; if(recordCount % rows > 0) pageCount++; result.setPageCount(pageCount); //5.返回 return result; } }
5.4.4. 在taotao-search-service中发布服务
<!-- 使用dubbo发布服务 --> <!-- 提供方应用信息,用于计算依赖关系 --> <dubbo:application name="taotao-search" /> <dubbo:registry protocol="zookeeper" address="192.168.25.131:2181" /> <!-- 用dubbo协议在20880端口暴露服务 --> <dubbo:protocol name="dubbo" port="20882" /> <!-- 声明需要暴露的服务接口 --> <dubbo:service interface="com.taotao.search.service.SearchService" ref="searchServiceImpl" timeout="300000"/>
5.4. 表现层
功能在 taotao-search-web 中实现。
5.4.1. 引用服务
taotao-search-web的sprinmvc.xml 中引用:
<!-- 引用dubbo服务 --> <dubbo:application name="taotao-search-web" /> <dubbo:registry protocol="zookeeper" address="192.168.25.131:2181" /> <dubbo:reference interface="com.taotao.search.service.SearchService" id="searchService" timeout="30000"/>
5.4.2. Controller
请求的url:/search
参数:
1、q 查询条件。
2、page 页码。默认为1
返回值:逻辑视图,返回值。String。
业务逻辑:
1、接收参数
2、调用服务查询商品列表
3、把查询结果传递给页面。需要参数回显。
@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"; } }
属性文件中配置行数:(文件存放在taotao-search-web中的resource目录下)
还需要配置属性文件加载:在springmvc.xml中
5.4.3. 测试
测试发现有乱码,是GET请求乱码,需要对请求参数进行转码处理:
翻页处理:在taotao-search-web工程中:修改如下:
5.5. 图片显示处理
数据库中保存的图片是以逗号分隔的url列表,只需要展示第一张图片即可。
方法:
1、向索引库中添加文档时,只取第一张写入索引库
2、从文档列表转换为商品列表时可以取一张。
3、在jsp中对列表拆分,只取一张展示。
可以在SearchItem中添加一个getImages方法:
在search.jsp中取属性: