課程計劃
- 第六天:
- 1、搜索工程的搭建
- 2、linux下solr服務的搭建
- 3、測試使用solrJ管理索引庫
- 4、把商品數據導入到索引庫中(後臺功能)
- 5、商品搜索功能實現(前臺功能)
1、搜索工程的搭建
要實現搜索功能,需要搭建solr服務
、搜索服務工程
、搜索系統(表現層的工程)
1.1、Solr服務搭建
1.1.1、solr的環境
solr是java開發的。 solr的安裝文件。 推薦在Linux環境下使用Solr,需要安裝環境Linux。 需要安裝jdk。參考鏈接:https://www.cnblogs.com/chenmingjun/p/9931593.html 需要安裝tomcat。
1.1.2、solr的搭建步驟
第一步:使用SecureCRT的SFTP功能,把solr-4.10.3.tgz.tgz
的壓縮包上傳到Linux系統。
第二步:解壓縮solr
後,刪除該安裝包。
[root@itheima ~]# tar -zxvf solr-4.10.3.tgz.tgz ...... ...... [root@itheima ~]# ll 總用量 146496 drwxr-xr-x. 8 root root 218 11月 20 17:07 solr-4.10.3 -rw-r--r--. 1 root root 150010621 9月 26 23:16 solr-4.10.3.tgz.tgz [root@itheima ~]# rm -rf solr-4.10.3.tgz.tgz [root@itheima ~]# ll 總用量 0 drwxr-xr-x. 8 root root 218 11月 20 17:07 solr-4.10.3 [root@itheima ~]#
第三步:使用SecureCRT的SFTP功能,把apache-tomcat-7.0.47.tar.gz
的壓縮包上傳到Linux系統,解壓後刪除安裝包。
[root@itheima ~]# tar -zxvf apache-tomcat-7.0.47.tar.gz [root@itheima ~]# # rm -rf apache-tomcat-7.0.47.tar.gz
第四步:創建solr存放的目錄
,複製apache-tomcat-7.0.47目錄
到/usr/local/solr/tomcat目錄
下
[root@itheima ~]# mkdir /usr/local/solr [root@itheima ~]# cp -r apache-tomcat-7.0.47/ /usr/local/solr/tomcat
第五步:把solr-4.10.3/dist/solr-4.10.3.war文件
部署(複製)到tomcat
目錄下,並重命名爲solr.war
。
[root@itheima ~]# cp solr-4.10.3/dist/solr-4.10.3.war /usr/local/solr/tomcat/webapps/solr.war
注意:複製目錄(文件夾)的時候需要加-r
,複製文件的時候不需要加-r
。
第六步:解壓縮solr.war包
。啓動tomcat即可自動解壓war包
,並查看tomcat啓動日誌
。
[root@itheima ~]# cd /usr/local/solr/tomcat/bin/ [root@itheima bin]# ./startup.sh Using CATALINA_BASE: /usr/local/solr/tomcat Using CATALINA_HOME: /usr/local/solr/tomcat Using CATALINA_TMPDIR: /usr/local/solr/tomcat/temp Using JRE_HOME: /usr/local/java/jdk1.7.0_80/jre Using CLASSPATH: /usr/local/solr/tomcat/bin/bootstrap.jar:/usr/local/solr/tomcat/bin/tomcat-juli.jar [root@itheima bin]# cd .. [root@itheima tomcat]# tail -f logs/catalina.out 十一月 20, 2018 5:23:24 下午 org.apache.catalina.startup.HostConfig deployDirectory 信息: Deploying web application directory /usr/local/solr/tomcat/webapps/host-manager 十一月 20, 2018 5:23:25 下午 org.apache.catalina.startup.HostConfig deployDirectory 信息: Deploying web application directory /usr/local/solr/tomcat/webapps/manager 十一月 20, 2018 5:23:25 下午 org.apache.coyote.AbstractProtocol start 信息: Starting ProtocolHandler ["http-bio-8080"] 十一月 20, 2018 5:23:25 下午 org.apache.coyote.AbstractProtocol start 信息: Starting ProtocolHandler ["ajp-bio-8009"] 十一月 20, 2018 5:23:25 下午 org.apache.catalina.startup.Catalina start 信息: Server startup in 11144 ms
第六步:關閉tomcat後,刪除掉沒用的solr.war包
。原則:沒用的東西及時刪掉。
注意:要是想刪掉沒用的solr.war
包,必須在關閉tomcat的情況
下,否則解壓縮後的solr包也會一併刪除掉。
[root@itheima tomcat]# bin/shutdown.sh Using CATALINA_BASE: /usr/local/solr/tomcat Using CATALINA_HOME: /usr/local/solr/tomcat Using CATALINA_TMPDIR: /usr/local/solr/tomcat/temp Using JRE_HOME: /usr/local/java/jdk1.7.0_80/jre Using CLASSPATH: /usr/local/solr/tomcat/bin/bootstrap.jar:/usr/local/solr/tomcat/bin/tomcat-juli.jar [root@itheima tomcat]# rm -rf webapps/solr.war
第七步:想要啓動solr工程
,還需要添加solr的擴展服務包
。
把/root/solr-4.10.3/example/lib/ext
目錄下的所有的jar包,添加到solr工程
中。
[root@itheima ext]# pwd /root/solr-4.10.3/example/lib/ext [root@itheima ext]# cp * /usr/local/solr/tomcat/webapps/solr/WEB-INF/lib/
第八步:創建一個solrhome
目錄。
我們知道:/root/solr-4.10.3/example/solr
目錄就是一個solrhome
目錄。
複製此目錄中所有內容到/usr/local/solr/solrhome
目錄下
[root@itheima example]# pwd /root/solr-4.10.3/example [root@itheima example]# cp -r solr /usr/local/solr/solrhome
第九步:關聯solr工程
及solrhome
。需要修改solr工程
的web.xml
文件。
[root@itheima ~]# cd /usr/local/solr/tomcat/webapps/solr/WEB-INF/ [root@itheima WEB-INF]# vim web.xml
修改如下圖所示:
第九步:再次啓動tomcat
[root@itheima ~]# cd /usr/local/solr/tomcat/ [root@itheima tomcat]# bin/startup.sh
第十步:修改防火牆配置
CentOS 7.X 默認的防火牆不是iptables,而是firewalld。我們可以試一下systemctl stop firewalld關閉防火牆,但是不推薦該方式。
CentOS 6.X 是iptables,可以使用vim /etc/sysconfig/iptables
修改配置即可。
本博主的是CentOS7,防火牆使用的是firewalld,我們使用命令的方式來添加端口(修改後需要重啓firewalld服務):
[root@itheima ~]# cd /etc/firewalld/zones/ [root@itheima zones]# firewall-cmd --permanent --add-port=8080/tcp success [root@itheima zones]# service firewalld restart Redirecting to /bin/systemctl restart firewalld.service [root@itheima zones]#
第十一步:測試連接 訪問地址:http://192.168.25.154:8080/solr/ 其實和在windows下的配置完全一樣。 瀏覽器界面如下:
點擊按鈕“collection1”
1.1.3、solr的使用
添加文檔時必須有id域
,其他域必須在solr的schema.xml
中進行定義。
1.2、配置業務域
1.2.1、在schema.xml中需要定義以下字段
1、商品id(根據id查詢商品描述頁) 2、商品標題title 3、商品賣點sell_point 4、商品價格price 5、商品圖片image 6、分類名稱category_name(不是分類id,我們一般不會根據商品分類id去查詢商品,而是根據商品分類名稱去查) 7、商品描述item_desc(實際開發中不需要搜索商品描述) 一共涉及到三張表:tb_item、item_cat、item_desc。 創建對應的業務域。同時需要指定中文分析器。
1.2.2、創建業務域步驟
第一步:把中文分析器添加到solr工程中。
0、把文件夾IK Analyzer 2012FF_hf1
上傳至linux中。
1、把IKAnalyzer2012FF_u1.jar
拷貝到solr工程的lib目錄
下。
2、把擴展詞詞典
、停用詞字典
、配置文件
拷貝到solr工程的WEB-INF/classes
目錄下。(沒有classes目錄就先創建該目錄)
[root@itheima IK Analyzer 2012FF_hf1]# pwd /root/IK Analyzer 2012FF_hf1 [root@itheima IK Analyzer 2012FF_hf1]# cp IKAnalyzer2012FF_u1.jar /usr/local/solr/tomcat/webapps/solr/WEB-INF/lib/ [root@itheima IK Analyzer 2012FF_hf1]# mkdir /usr/local/solr/tomcat/webapps/solr/WEB-INF/classes [root@itheima IK Analyzer 2012FF_hf1]# cp mydict.dic ext_stopword.dic IKAnalyzer.cfg.xml /usr/local/solr/tomcat/webapps/solr/WEB-INF/classes [root@itheima IK Analyzer 2012FF_hf1]# ll /usr/local/solr/tomcat/webapps/solr/WEB-INF/classes 總用量 12 -rw-r--r--. 1 root root 168 11月 20 19:29 ext_stopword.dic -rw-r--r--. 1 root root 419 11月 20 19:29 IKAnalyzer.cfg.xml -rw-r--r--. 1 root root 34 11月 20 19:29 mydict.dic [root@itheima IK Analyzer 2012FF_hf1]#
第二步:配置一個自定義的fieldType
,使用指定的中文分詞器IKAnalyzer
。
修改solr工程下的schema.xml
文件,在文件末尾添加一個自定義的fieldType
,注意:要在標籤<schema></schema>
裏面添加。
[root@itheima conf]# pwd /usr/local/solr/solrhome/collection1/conf [root@itheima conf]# vim schema.xml
添加內容如下:
<fieldType name="text_ik" class="solr.TextField"> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/> </fieldType>
第三步:配置業務域,type指定使用自定義的fieldType。 設置業務系統的field
<schema> ...... ...... <fieldType name="text_ik" class="solr.TextField"> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/> </fieldType> <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"/> </schema>
注意:分類名稱是不分詞只建立索引。商品描述是分詞但是不存儲。
第四步:重啓tomcat,測試我們自定義的業務域是否好使。 測試結果如下:
1.3、搜索服務層工程的搭建
1.3.1、搜索服務工程的創建可以參考taotao-content的創建
taotao-search(聚合工程pom) |--taotao-search-interface(jar) |--taotao-search-Service(war) 這裏不再贅圖了。 目錄結構如下:
1.3.2、pom.xml的配置可以參考taotao-content的配置
/taotao-search/pom.xml
<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> <artifactId>taotao-search</artifactId> <packaging>pom</packaging> <modules> <module>taotao-search-interface</module> <module>taotao-search-service</module> </modules> <dependencies> <!-- 配置對common的依賴 --> <dependency> <groupId>com.taotao</groupId> <artifactId>taotao-common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> <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> </project>
/taotao-search-interface/pom.xml
<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-search</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>taotao-search-interface</artifactId> <dependencies> <!-- 配置對pojo的依賴 --> <dependency> <groupId>com.taotao</groupId> <artifactId>taotao-manager-pojo</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> </project>
/taotao-search-service/pom.xml
<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-search</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>taotao-search-service</artifactId> <packaging>war</packaging> <dependencies> <!-- 配置對dao的依賴 --> <dependency> <groupId>com.taotao</groupId> <artifactId>taotao-manager-dao</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-- 配置對interface的依賴:服務層發佈服務要通過該接口 --> <dependency> <groupId>com.taotao</groupId> <artifactId>taotao-search-interface</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-- 配置對spring的依賴 --> <!-- 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> <!-- 配置對dubbo的依賴 --> <!-- dubbo相關 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <!-- 排除對低版本jar包的依賴 --> <exclusions> <exclusion> <artifactId>spring</artifactId> <groupId>org.springframework</groupId> </exclusion> <exclusion> <artifactId>netty</artifactId> <groupId>org.jboss.netty</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> </dependency> </dependencies> </project>
1.3.3、框架整合的配置文件可以參考taotao-content-service的配置
由於搜索的數據涉及到3張表,所以需要自己定義mapper。 而mapper的使用,只在搜索服務工程中,所以mapper接口及映射文件需要放在taotao-search-service工程中。 applicationContext-dao.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd"> <!-- 配置數據庫連接池 --> <!-- 加載配置文件 --> <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.mapper" /> </bean> </beans>
其他配置文件,參考taotao-content-service的配置。
2、測試使用solrJ管理索引庫
使用solrJ可以實現索引庫的增刪改查操作。
2.1、通過SolrJ向索引庫中添加/更新索引
第一步:把solrJ的jar包添加到工程中。在Maven工程中則是添加依賴。 在/taotao-search-service/pom.xml添加對solrj客戶端的依賴,如下:
<!-- 配置對solrj客戶端的依賴 --> <dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-solrj</artifactId> </dependency>
第二步:創建一個SolrServer對象(抽象類),使用HttpSolrServer創建對象(連接單機版solr),使用CloudSolrServer創建對象(連接集羣版solr)。 第三步:創建一個文檔對象SolrInputDocument對象。 第四步:向文檔中添加域。必須有id域,且域的名稱必須在schema.xml中定義。 第五步:把文檔對象添加到索引庫中。 第六步:提交。 測試代碼如下:
/** * 向索引庫中添加索引 * @throws Exception */ @Test public void addDocumentTest() throws Exception { // 第一步:把solrJ的jar包添加到工程中。在Maven工程中則是添加依賴。 // 第二步:創建一個SolrServer對象(抽象類),使用HttpSolrServer創建連接對象(連接單機版solr),使用CloudSolrServer創建連接對象(連接集羣版solr)。 SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr/collection1"); // 默認是collection1,可寫可不寫 // 第三步:創建一個文檔對象SolrInputDocument對象。 SolrInputDocument document = new SolrInputDocument(); // 第四步:向文檔中添加域。必須有id域,且域的名稱必須在schema.xml中定義。 document.addField("id", "test001"); // 注意:id是字符串類型,如果是數值類型,會自動轉爲字符串 document.addField("item_title", "測試商品"); document.addField("item_price", 1999); // 第五步:把文檔對象添加到索引庫中。 solrServer.add(document); // 第六步:提交。 solrServer.commit(); }
2.2、通過SolrJ從索引庫中刪除索引
(1)根據指定ID來刪除索引
/** * 根據指定ID來刪除索引 * @throws Exception */ @Test public void deleteIndexByIdTest() throws Exception { // 1、創建HttpSolrServer對象,通過它和solr服務器建立連接。 HttpSolrServer server = new HttpSolrServer("http://192.168.25.154:8080/solr/collection1"); // 參數:是solr服務器的訪問地址 // 2、根據指定ID來刪除索引 server.deleteById("test001"); // 3、提交。 server.commit(); }
(2)根據指定條件刪除索引
/** * 根據指定條件來刪除索引 * @throws Exception */ @Test public void deleteIndexByConditionTest() throws Exception { // 1、創建HttpSolrServer對象,通過它和solr服務器建立連接。 HttpSolrServer server = new HttpSolrServer("http://192.168.25.154:8080/solr/collection1"); // 參數:是solr服務器的訪問地址 // 2、根據指定條件來刪除索引 server.deleteByQuery("id:test002"); // 刪除全部(慎用) // server.deleteByQuery("*:*"); // 3、提交。 server.commit(); }
2.3、通過SolrJ從索引庫中查詢索引
2.3.1、簡單查詢
/** * 簡單查詢 * @throws Exception */ @Test public void queryIndexTest01() throws Exception { // 1、創建SolrServer對象,通過它和solr服務器建立連接。 SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr/collection1"); // 參數:是solr服務器的訪問地址 // 2、創建SolrQuery對象 SolrQuery query = new SolrQuery(); // 設置查詢條件,名稱"q"是固定的且必須的! // query.set("q", "item_category_name:手機"); // 等價於 query.setQuery("item_category_name:手機"); query.setQuery("item_category_name:手機"); // 3、調用solrServer的查詢方法,查詢索引庫 QueryResponse response = solrServer.query(query); // 4、獲取查詢結果 SolrDocumentList results = response.getResults(); // 5、處理查詢結果 System.out.println("查詢結果總數爲:" + results.getNumFound()); // 6、遍歷結果並打印,示例只打印2個字段 for (SolrDocument solrDocument : results) { System.out.println(solrDocument.get("id")); System.out.println(solrDocument.get("item_title")); System.out.println(solrDocument.get("item_price")); System.out.println("--------------------"); } }
2.3.2、複雜查詢
/** * 複雜查詢 * @throws Exception */ @Test public void queryIndexTest02() throws Exception { // 1、創建SolrServer對象,通過它和solr服務器建立連接。 SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr/collection1"); // 參數:是solr服務器的訪問地址 // 2、創建SolrQuery對象 SolrQuery query = new SolrQuery(); // 設置查詢條件 // query.set("q", "item_category_name:手機"); query.setQuery("item_category_name:手機"); // 設置過濾條件,如果設置多個過濾條件的話,需要使用query.addFilterQuery(fq); // query.setFilterQueries("item_price:[1 TO 20]"); // 設置排序 query.setSort("item_price", ORDER.desc); // 設置分頁信息(使用默認的) query.setStart(0); query.setRows(10); // 設置顯示的field的域集合 query.setFields("id,item_title,item_sell_point,item_price,item_image,item_category_name"); // 設置默認搜素域 query.set("df", "item_keywords"); // 設置高亮信息 query.setHighlight(true); query.addHighlightField("item_title"); query.setHighlightSimplePre("<span color='red'>"); query.setHighlightSimplePost("</span>"); // 3、調用solrServer的查詢方法,查詢索引庫 QueryResponse response = solrServer.query(query); // 4、獲取查詢結果 SolrDocumentList results = response.getResults(); // 5、處理查詢結果 System.out.println("查詢結果總數爲:" + results.getNumFound()); // 獲取高亮列表 Map<String, Map<String, List<String>>> highlighting = response.getHighlighting(); // 遍歷結果並打印,示例打印所有的字段 for (SolrDocument solrDocument : results) { System.out.println(solrDocument.get("id")); 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_sell_point")); System.out.println(solrDocument.get("item_price")); System.out.println(solrDocument.get("item_image")); System.out.println(solrDocument.get("item_category_name")); System.out.println("--------------------"); } }
3、把商品數據導入到索引庫中(後臺功能)
3.1、功能分析
在schema.xml中定義以下業務域(已經定義好):
1、商品id(根據id查詢商品描述頁) 2、商品標題title 3、商品賣點sell_point 4、商品價格price 5、商品圖片image 6、分類名稱category_name(不是分類id,我們一般不會根據商品分類id去查詢商品,而是根據商品分類名稱去查) 7、商品描述item_desc(實際開發中不需要搜索商品描述) 需要從 tb_item、tb_item_cat、tb_item_desc表中查詢數據。 我們先創建對應的業務域(已經創建好了)。同時需要指定中文分析器。
solr服務我們已經搭建好了,自定義的業務域我們也配置好了,現在我們要實現商品搜素功能,那麼就需要有數據,需要把數據從數據庫中導入進來,之前我們可以使用dataimportHandler插件
,該插件可以將數據庫中指定的sql語句的結果導入到solr索引庫中
。現在我們需要通過我們網站後臺來管理索引庫
,而不是通過dataimportHandler插件了,而且我們要做solr集羣
的話,插件dataimportHandler會有干擾。所以我們現在不推薦使用dataimportHandler插件。
所以我們在測試環境
下可以使用dataimportHandler插件,但是生產環境
下需要我們手工導入數據。
插件dataimportHandler,使用參考鏈接:https://www.cnblogs.com/chenmingjun/p/9887696.html#_label2_3
我們使用手工導入數據,需要我們先從數據庫中把我們分析出來的業務域取出來,取出來之後,循環插入索引庫中去,由於涉及到3張表的查詢,所以不能在使用逆向工程生成的Mapper代碼了。需要我們手寫Mapper代碼。我們先把SQL語句寫出來,如下:
SQL1:
SELECT a.id, a.title, a.sell_point, a.price, a.image, b. NAME AS category_name, c.item_desc FROM tb_item a LEFT JOIN tb_item_cat b ON a.cid = b.id LEFT JOIN tb_item_desc c ON a.id = c.item_id WHERE a.`status` = 1
SQL2:
SELECT a.id, a.title, a.sell_point, a.price, a.image, b. NAME AS 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;
3.2、Dao層
3.2.1、創建POJO
創建以下POJO用於存放從數據庫中查詢到的商品數據
和用於存放從索引庫中搜索到的商品數據
,並放入taotao-common中。
/** * 搜索商品數據使用的POJO,用於存放“從數據庫中查詢到的商品數據”和用於存放“從索引庫中搜索到的商品數據” * @author chenmingjun * @date 2018年11月21日上午1:05:12 * @version 1.0 */ public class SearchItem implements Serializable { private static final long serialVersionUID = 1L; private String id; // 商品的id,我們使用文檔的id域作爲商品的id,文檔的id域默認定義的是String類型 private String title; // 商品的標題 private String sell_point; // 商品的賣點 private Long price; // 商品的價格 private String image; // 商品的圖片路徑 private String category_name; // 商品的分類名稱 private String item_desc; // 商品的描述 // getter和setter方法 }
注意:在我們schema.xml文件中,我們使用文檔的id域作爲商品的id,而文檔的id域默認定義的是String類型,索引庫會自動轉換將數值類型轉換爲字符串進行存儲,我們從索引庫中取出數據,我們也使用字符串進行接收。
3.2.2、定義Mapper接口
SearchItemMapper.java
/** * 搜索商品的Mapper * @author chenmingjun * @date 2018年11月21日上午11:23:28 * @version 1.0 */ public interface SearchItemMapper { /** * 查詢所有商品數據。(注意:是從3張表中查,此商品非彼商品) * @return */ List<SearchItem> getSearchItemList(); }
3.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 AS category_name, c.item_desc FROM tb_item a LEFT JOIN tb_item_cat b ON a.cid = b.id LEFT JOIN tb_item_desc c ON a.id = c.item_id WHERE a.`status` = 1 </select> </mapper>
3.3、Service層
參數:無 業務邏輯: 1、查詢所有商品數據。 2、創建一個SolrServer對象(抽象類),使用HttpSolrServer創建連接對象(連接單機版solr),使用CloudSolrServer創建連接對象(連接集羣版solr)。 3、爲每個商品創建一個文檔對象SolrInputDocument對象。 4、爲文檔添加域。必須有id域,且域的名稱必須在schema.xml中定義。 5、把文檔對象添加到索引庫中。 6、提交修改。 7、返回TaotaoResult。
3.3.1、配置單機版solr的連接:HttpSolrServer
SolrServer我們使用spring容器生成後注入進來,需要在配置文件進行配置: applicationContext-solr.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd"> <!-- 配置單機版solr的連接:HttpSolrServer--> <bean id="httpSolrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer"> <constructor-arg name="baseURL" value="http://192.168.25.154:8080/solr/collection1"></constructor-arg> </bean> </beans>
3.3.2、定義service接口
接口放在taotao-search-interface中
/** * 從數據庫中查詢到數據導入索引庫 * @author chenmingjun * @date 2018年11月21日下午2:38:41 * @version 1.0 */ public interface SearchItemService { /** * 導入搜索的商品數據到索引庫中 * @return * @throws Exception */ TaotaoResult importSearchItemsToIndex() throws Exception; }
3.3.3、定義service實現類
要想注入SearchItemMapper成功,需要在taotao-search-service
的applicationContext-dao.xml
文件中進行配置Mapper映射文件的包掃描器
:
有兩種配置方式:
方式一:
<!-- 配置Mapper映射文件的包掃描器 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.taotao.mapper" /> </bean> <!-- 配置只用於搜索功能的Mapper --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.taotao.search.mapper" /> </bean>
方式二:
<!-- 配置Mapper映射文件的包掃描器,掃描多個包,使用逗號進行分割 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.taotao.mapper,com.taotao.search.mapper" /> </bean>
本案例中我們使用方式二。 實現類代碼如下:
/** * 從數據庫中查詢到數據導入索引庫 * @author chenmingjun * @date 2018年11月21日下午2:42:11 * @version 1.0 */ @Service public class SearchItemServiceImpl implements SearchItemService { // 注入SearchItemMapper @Autowired private SearchItemMapper searchItemMapper; // 注入SolrServer @Autowired private SolrServer solrServer; @Override public TaotaoResult importSearchItemsToIndex() throws Exception { // 1、查詢所有商品數據。 List<SearchItem> searchItemList = searchItemMapper.getSearchItemList(); // 2、創建一個SolrServer對象(抽象類),使用HttpSolrServer創建連接對象(連接單機版solr),使用CloudSolrServer創建連接對象(連接集羣版solr)。 // SolrServer我們使用spring容器生成後注入進來 for (SearchItem searchItem : searchItemList) { // 3、爲每個商品創建一個文檔對象SolrInputDocument對象。 SolrInputDocument document = new SolrInputDocument(); // 4、爲文檔添加域。必須有id域,且域的名稱必須在schema.xml中定義。 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); } // 6、提交修改。 solrServer.commit(); // 7、返回TaotaoResult。 return TaotaoResult.ok(); } }
3.3.4、在taotao-search-service中發佈服務
特別注意:
由於我們的dubbo和zooKeeper是安裝在虛擬機CentOS 7.5 上的,CentOS 7.X 默認的防火牆不是iptables,而是firewalld。我們可以試一下systemctl stop firewalld關閉防火牆,但是不推薦該方式。CentOS 6.X 是iptables,可以使用vim /etc/sysconfig/iptables
修改配置即可。
本博主的是CentOS7,防火牆使用的是firewalld,我們使用命令的方式來添加端口20882(修改後需要重啓firewalld服務):
[root@itheima ~]# cd /etc/firewalld/zones/ [root@itheima zones]# firewall-cmd --permanent --add-port=20882/tcp success [root@itheima zones]# service firewalld restart Redirecting to /bin/systemctl restart firewalld.service [root@itheima zones]#
3.4、表現層
3.4.1、引用服務
由於把從數據庫中查詢到的新的商品數據導入到索引庫中
屬於後臺功能
,所以我們在taotao-manager-web中引用服務。
在/taotao-manager-web/src/main/resources/spring/springmvc.xml中引用服務:
3.4.2、添加對taotao-search-interface的依賴
在taotao-manager-web工程中的pom.xml中添加如下:
3.4.3、修改index.jsp
由於把從數據庫中查詢到的新的商品數據導入到索引庫中
屬於後臺功能
,所以我們在taotao-manager-web
的後臺系統中做一個導入索引庫的功能界面
。(例如:有個按鈕,點擊即可將從數據庫中查詢到的數據導入到索引庫)。
業務邏輯:
1、點擊按鈕,表現層調用服務層的工程的導入索引庫的方法。 2、服務層實現調用Mapper接口的方法查詢所有的商品的數據。 3、將數據一條條添加到SolrInputDocument文檔中。 4、將文檔添加到索引庫中。 5、提交,並返回導入成功即可。
添加如下代碼到index.jsp中:
<li> <span>網站前臺搜索管理</span> <ul> <li data-options="attributes:{'url':'import-index'}">導入索引庫</li> </ul> </li>
3.4.4、創建一個jsp
在taotao-manager-web中創建一個import-index.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() { // 移除原有按鈕 $('.l-btn-text').remove("span"); // 追加不可點擊按鈕 $('.l-btn-left').after('<input type="button" disabled="true" id="disabledButton" value="正在導入商品搜索索引庫,請稍後......">'); $.post("/index/importAll",null,function(data) { // 移除不可點擊按鈕 $('#disabledButton').remove("input"); // 追加原有按鈕 $('.l-btn-left').after('<span class="l-btn-text">一鍵導入商品數據到索引庫</span>'); if (data.status==200) { $.messager.alert('提示','商品數據導入索引庫成功!'); } else { $.messager.alert('提示','商品數據導入索引庫失敗!'); } }); } </script>
3.4.5、Controller
請求的url:/index/importall 參數:無 返回值:json數據。TaotaoResult。
/** * 索引庫維護Controller * @author chenmingjun * @date 2018年11月21日下午4:02:43 * @version 1.0 */ @Controller public class SearchItemController { @Autowired private SearchItemService searchItemService; @RequestMapping("/index/importAll") @ResponseBody public TaotaoResult importSearchItemsToIndex() { try { TaotaoResult result = searchItemService.importSearchItemsToIndex(); return result; } catch (Exception e) { e.printStackTrace(); return TaotaoResult.build(500, "商品數據一鍵導入索引庫失敗!"); } } }
3.4.6、測試
測試之前我們先將索引庫中的測試數據清空,否則會對我們測試有影響,方法如下:
測試出錯,原因是:未將工程中新建的映射文件SearchItemMapper.xml發佈到classpath中。錯誤截圖如下:
由於maven發佈代碼和配置文件時,在src/main/java
下,maven只會將*.java
文件編譯成*.class
文件發佈到classpath下,對於*.xml
文件等,maven是不會理會的,所以我們需要配置maven掃描src/main/java下的*.xml
文件。但是又不能影響maven掃描src/main/resources下面的*.xml、*.properties
文件,所以我們需要在taotao-search-service中這樣配置:
<build> <!-- 如果不添加此節點,mybatis的mapper.xml文件都會被漏掉 --> <!-- 注意:配置了此方式,原來的默認的資源拷貝行爲將無效了 --> <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>
瀏覽器頁面展示結果:
4、商品搜索功能實現(前臺功能)
4.1、搜索表現層工程的搭建
可以參考taotao-portal-web的創建。 打包方式war。 taotao-search-web。 這裏不再贅圖了。
4.1.1、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> <artifactId>taotao-search-web</artifactId> <packaging>war</packaging> <dependencies> <!-- 配置對common的依賴 --> <dependency> <groupId>com.taotao</groupId> <artifactId>taotao-common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-- 配置對taotao-search-interface的依賴:表現層調用服務要通過該接口 --> <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的依賴 --> <!-- dubbo相關 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <!-- 排除對低版本jar包的依賴 --> <exclusions> <exclusion> <artifactId>spring</artifactId> <groupId>org.springframework</groupId> </exclusion> <exclusion> <artifactId>netty</artifactId> <groupId>org.jboss.netty</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> </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> </project>
4.1.2、配置文件
目錄結構如下:
4.1.3、springmvc.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> <!-- 配置加載屬性文件 --> <context:property-placeholder location="classpath:resource/resource.properties"/> <!-- 配置包掃描器,掃描所有需要帶@Controller註解的類 --> <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的約束--> <dubbo:application name="taotao-search-web"/> <dubbo:registry protocol="zookeeper" address="192.168.25.128:2181"/> <!-- <dubbo:reference interface="com.taotao.content.service.ContentService" id="contentService" /> --> </beans>
4.1.4、web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <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> <!-- 攔截(*.html)結尾的請求,實現了網頁的僞靜態化,SEO:搜索引擎優化--> <url-pattern>*.html</url-pattern> </servlet-mapping> </web-app>
4.1.5、搜索結果的前臺靜態頁面
將上面的搜索結果靜態頁面放入到taotao-search-web工程中
4.2、搜索功能分析
在首頁的搜索框
中輸入搜索條件,然後跳轉到搜索結果頁面
。搜索結果頁面在taotao-search-web工程中(端口爲8085)。
首頁搜索框的點擊按鈕處理函數在:在taotao-portal-web工程首頁的JS中,應當改成8085,如圖:
請求的url:/search 以搜索手機爲例:http://localhost:8085/search.html?q=手機
參數: 1、q,表示查詢條件。 2、page,頁碼。默認爲1。每頁顯示多少行,我們在controller中寫死即可。比如:60。 返回值: String。(包括:新的商品列表信息、總頁數、總記錄數、數據回顯) 業務邏輯: 1、接收查詢條件。 2、創建一個SolrServer對象,需要注入。 3、創建一個SolrQuery對象。 4、需要設置查詢條件、分頁條件、設置默認搜索域、高亮設置。 5、執行查詢,返回QueryResponse對象。 6、取返回結果,封裝到List中。 7、返回查詢結果的總記錄數,計算查詢結果的總頁數。 8、得到查詢結果,渲染jsp
4.3、Dao層
4.3.1、功能分析
訪問索引庫的類。定義一些通用的數據訪問方法。
業務邏輯就是查詢索引庫。
參數:SolrQuery對象
業務邏輯:
1、根據Query對象進行查詢。
2、返回查詢結果。包括List<SearchItem>
、查詢結果的總記錄數。
需要把返回結果封裝到pojo中,至少包含兩個屬性:List<SearchItem>(搜索的結果列表)
、Long recordCount(總記錄數)
,
再包含一個總頁數(Long pageCount)。
創建如下SearchResult對象,放入taotao-common中。
SearchResult.java
package com.taotao.common.pojo; import java.io.Serializable; import java.util.List; /** * 商品搜索的分頁信息結果對象 * @author chenmingjun * @date 2018年11月21日下午11:33:14 * @version 1.0 */ public class SearchResult implements Serializable { private static final long serialVersionUID = 1L; private List<SearchItem> itemList; // 搜索的結果列表(列表中放的是新的商品數據!不是之前的Item) private Long recordCount; // 總記錄數 private Long pageCount; // 總頁數 public List<SearchItem> getItemList() { return itemList; } public void setItemList(List<SearchItem> itemList) { this.itemList = itemList; } public Long getRecordCount() { return recordCount; } public void setRecordCount(Long recordCount) { this.recordCount = recordCount; } public Long getPageCount() { return pageCount; } public void setPageCount(Long pageCount) { this.pageCount = pageCount; } }
4.3.2、創建SearchDaoImpl
在Dao層,查詢索引庫的方式和處理查詢結果的方式都是一樣的,查詢索引庫的參數是SolrQuery對象。 在服務層,我們拼裝不同的查詢條件SolrQuery即可。 因爲搜索功能只在搜索工程中用到,所以可以不寫接口,只寫實現類。返回值:SearchResult。 我們這裏是爲了方便,但是在實際工作中,我們不能偷懶,一定要是一個接口對應至少一個實現類。 在taotao-search-service中創建com.taotao.search.dao包,在包中SearchDao創建用於訪問索引庫。 代碼如下:
/** * 因爲搜索功能只在搜索工程中用到,所以可以不寫接口,只寫實現類。但是實際工作中不推薦。 * @author chenmingjun * @date 2018年11月22日上午1:02:03 * @version 1.0 */ @Repository // @Service也可以,只是我們把Dao和Service層寫在一起了 public class SearchDaoImpl { // 注入SolrServer @Autowired private SolrServer solrServer; public SearchResult search(SolrQuery query) throws Exception { // 1、根據SolrServer對象查詢索引庫 QueryResponse response = solrServer.query(query); // 2、取出查詢結果 SolrDocumentList solrDocumentList = response.getResults(); // 3、處理查詢結果(即把取出的查詢結果進行封裝,即設置值) SearchResult result = new SearchResult(); // 1) 取出總記錄數放到SearchResult中去 Long recordCount = solrDocumentList.getNumFound(); result.setRecordCount(recordCount); // 2) 取出新的商品列表放到SearchResult中去(注意:新的商品=>SearchItem,要與之前的商品Item區分開) List<SearchItem> searchItemList = new ArrayList<>(); // 獲取高亮列表 Map<String, Map<String, List<String>>> highlighting = response.getHighlighting(); for (SolrDocument solrDocument : solrDocumentList) { SearchItem searchItem = new SearchItem(); searchItem.setId((String) solrDocument.get("id")); searchItem.setSell_point((String) solrDocument.get("item_sell_point")); searchItem.setPrice((Long) solrDocument.get("item_price")); searchItem.setImage((String) solrDocument.get("item_image")); searchItem.setCategory_name((String) solrDocument.get("item_category_name")); // 取出高亮顯示的內容 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"); } searchItem.setTitle(itemTitle); // 將新的商品添加到商品列表 searchItemList.add(searchItem); } // 將新的商品列表放到SearchResult中去 result.setItemList(searchItemList); // 4、返回結果 return result; } }
4.4、Service層
4.4.1、功能分析
參數: queryString:查詢條件 page:頁碼 rows:每頁顯示的記錄數。 業務邏輯: 1、創建一個SolrQuery對象。 2、設置主查詢條件。 3、設置分頁條件。 4、需要指定默認的搜索域。 5、設置高亮。 6、執行查詢,調用SearchDao。得到SearchResult 7、需要計算總頁數。 8、返回SearchResult。
4.4.2、定義service接口
接口已存在,只需要添加方法即可。
/** * 根據查詢條件搜索 * @param queryString 頁面傳過來的查詢條件 * @param page 頁碼 * @param rows 每頁顯示的記錄數 * @return * @throws Exception */ SearchResult search(String queryString, Integer page, Integer rows) throws Exception;
4.4.3、定義service接口實現類
代碼如下:
// 注入SearchDaoImpl @Autowired private SearchDaoImpl searchDaoImpl; @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("*:*"); // 查詢所有 } // 3、設置過濾條件:分頁、默認搜索域、高亮等等 // 1) 設置分頁 if (page == null) { page = 1; } if (rows == null) { rows = 60; } query.setStart((page - 1) * rows); query.setRows(rows); // 2) 設置默認的搜索域 query.set("df", "item_keywords"); // 3) 設置高亮顯示 query.setHighlight(true); query.addHighlightField("item_title"); query.setHighlightSimplePre("<span color='red'>"); query.setHighlightSimplePost("</span>"); // 4、調用Dao的方法,執行搜索,返回的是SearchResult,該返回值裏面只包含了"總記錄數"和"新的商品列表" SearchResult result = searchDaoImpl.search(query); // 5、設置總頁數,需要先計算出總頁數 Long recordCount = result.getRecordCount(); Long pageCount = recordCount / rows; if (recordCount % rows > 0) { pageCount++; } result.setPageCount(pageCount); // 6、返回SearchResult return result; }
4.4.4、發佈服務
在taotao-search-service工程applicationContext-service.xml文件中發佈服務:
要想讓掃描組件掃描到SearchDaoImpl,需要修改組件掃描的配置:
4.5、表現層
該功能在taotao-search-web中實現。
4.5.1、引用服務
在taotao-search-web工程springmvc.xml文件中引用服務:
4.5.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 SearchItemService searchItemService; @RequestMapping("/search") public String search(@RequestParam("q")String queryString, @RequestParam(defaultValue="1")Integer page, Model model) throws Exception { // 1、引用服務 // 2、注入searchItemService // 3、調用方法 SearchResult result = searchItemService.search(queryString, page, ITEM_ROWS); // 4、設置數據傳遞到jsp中進行回顯 model.addAttribute("query", queryString); model.addAttribute("page", page); model.addAttribute("totalPages", result.getPageCount()); model.addAttribute("itemList", result.getItemList()); // 5、返回邏輯視圖:search.jsp return "search"; } }
4.5.3、屬性文件中配置行數
搜索的結果頁面中顯示的每頁的行數,我們查詢到數據進行回顯,每頁顯示多少條數據由我們決定。
文件存放在taotao-search-web中的resource目錄下 還需要配置屬性文件加載:在taotao-search-web的springmvc.xml中
4.5.4、測試
1、測試發現有亂碼,是GET請求亂碼
,需要對請求參數進行轉碼處理:
方式一:在Controller中改
方式二:修改linux系統上tomcat的配置文件
[root@itheima conf]# pwd /usr/local/solr/tomcat/conf [root@itheima conf]# vim server.xml
增加一句代碼如下:
對於方式二,如果是集羣的話,需要改的地方很多,不推薦此方式!
2、翻頁處理:在taotao-search-web工程中: /taotao-search-web/src/main/webapp/js/search_main.js,修改如下:
4.6、圖片顯示處理
數據庫中保存的圖片是以逗號分隔的url列表,只需要展示第一張圖片即可。 方法1: 1、向索引庫中添加(導入)文檔時,只取第一張圖片的地址寫入索引庫。 2、從文檔列表轉換爲商品列表時可以取一張。 3、在jsp中對列表拆分,只取一張展示。 方法2: 可以在SearchItem中添加一個getImages()方法,用於頁面獲取經過處理的pojo的字段數據:
在jsp中取屬性: