day73_淘淘商城項目_06_搜索工程的搭建 + linux下solr索引庫的搭建 + 把商品數據導入到索引庫中(後臺) + 商品搜索功能實現(前臺) + 圖片顯示等問題解決_匠心筆記

課程計劃javascript

  • 第六天:
    • 一、搜索工程的搭建
    • 二、linux下solr服務的搭建
    • 三、測試使用solrJ管理索引庫
    • 四、把商品數據導入到索引庫中(後臺功能)
    • 五、商品搜索功能實現(前臺功能)

一、搜索工程的搭建


要實現搜索功能,須要 搭建solr服務搜索服務工程搜索系統(表現層的工程)

1.一、Solr服務搭建

1.1.一、solr的環境

  solr是java開發的。
  solr的安裝文件。
  推薦在Linux環境下使用Solr,須要安裝環境Linux。
  須要安裝jdk。參考連接:https://www.cnblogs.com/chenmingjun/p/9931593.html
  須要安裝tomcat。php

1.1.二、solr的搭建步驟

第一步:使用SecureCRT的SFTP功能,把solr-4.10.3.tgz.tgz的壓縮包上傳到Linux系統。
第二步:解壓縮solr後,刪除該安裝包。css

[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系統,解壓後刪除安裝包。html

[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.warjava

[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啓動日誌linux

[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包也會一併刪除掉。git

[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工程中。github

[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目錄下web

[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.三、solr的使用

  • 添加文檔時必須有id域,其餘域必須在solr的schema.xml中進行定義。

1.二、配置業務域

1.2.一、在schema.xml中須要定義如下字段

  一、商品id(根據id查詢商品描述頁(詳情頁))
  二、商品標題title
  三、商品賣點sell_point
  四、商品價格price
  五、商品圖片image
  六、分類名稱category_name(不是分類id,咱們通常不會根據商品分類id去查詢商品,而是根據商品分類名稱去查)
  七、商品描述tb_item_desc(商品詳情)(實際開發中不須要搜索商品描述(商品詳情),爲了練習須要,咱們也把該表加入索引庫)
  一共涉及到三張表:tb_item、tb_item_cat、tb_item_desc。
  建立對應的業務域。同時須要指定中文分析器。

1.2.二、建立自定義業務域步驟

第一步:把中文分析器添加到solr工程中。
  0、把文件夾IK Analyzer 2012FF_hf1上傳至linux中。
  一、把IKAnalyzer2012FF_u1.jar拷貝到solr工程的lib目錄下。
  二、把擴展詞詞典停用詞字典配置文件拷貝到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.三、搜索服務層工程的搭建

1.3.一、搜索服務工程的建立能夠參考taotao-content的建立

taotao-search(聚合工程pom)
  |--taotao-search-interface(jar)
  |--taotao-search-service(war)
這裏再也不贅圖了。
目錄結構以下:

1.3.二、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>
        <!-- 配置對taotao-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>
        <!-- 配置對taotao-manager-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>
        <!-- 配置對taotao-manager-dao的依賴 -->
        <dependency>
            <groupId>com.taotao</groupId>
            <artifactId>taotao-manager-dao</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的依賴 -->
        <!-- 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.三、框架整合的配置文件能夠參考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的配置。

二、測試使用solrJ管理索引庫

使用solrJ能夠實現索引庫的增刪改查操做。

2.一、經過SolrJ向索引庫中添加/更新索引

第一步:把solrJ的jar包添加到工程中。在Maven工程中則是添加依賴。
在/taotao-search-service/pom.xml添加對solrj客戶端的依賴,以下:

    <!-- 配置對solr客戶端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.二、經過SolrJ從索引庫中刪除索引

(1)根據指定ID來刪除索引

    /**
     * 根據指定ID來刪除索引
     * @throws Exception
     */

    @Test
    public void deleteIndexByIdTest() throws Exception {
        // 一、建立HttpSolrServer對象,經過它和solr服務器創建鏈接。 
        HttpSolrServer server = new HttpSolrServer("http://192.168.25.154:8080/solr/collection1"); // 參數:是solr服務器的訪問地址
        // 二、根據指定ID來刪除索引
        server.deleteById("test001");
        // 三、提交。 
        server.commit();
    }

(2)根據指定條件刪除索引

    /**
     * 根據指定條件來刪除索引
     * @throws Exception
     */

    @Test
    public void deleteIndexByConditionTest() throws Exception {
        // 一、建立HttpSolrServer對象,經過它和solr服務器創建鏈接。 
        HttpSolrServer server = new HttpSolrServer("http://192.168.25.154:8080/solr/collection1"); // 參數:是solr服務器的訪問地址
        // 二、根據指定條件來刪除索引
        server.deleteByQuery("id:test002");
        // 刪除所有(慎用)
        // server.deleteByQuery("*:*");
        // 三、提交。 
        server.commit();
    }

2.三、經過SolrJ從索引庫中查詢索引

2.3.一、簡單查詢

    /**
     * 簡單查詢
     * @throws Exception
     */

    @Test
    public void queryIndexTest01() throws Exception 
{
        // 一、建立SolrServer對象,經過它和solr服務器創建鏈接。 
        SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr/collection1"); // 參數:是solr服務器的訪問地址
        // 二、建立SolrQuery對象
        SolrQuery query = new SolrQuery();

        // 設置查詢條件,名稱"q"是固定的且必須的!
        // query.set("q", "item_category_name:手機"); // 等價於    query.setQuery("item_category_name:手機");
        query.setQuery("item_category_name:手機");
        // 三、調用solrServer的查詢方法,查詢索引庫
        QueryResponse response = solrServer.query(query);
        // 四、獲取查詢結果
        SolrDocumentList results = response.getResults();
        // 五、處理查詢結果
        System.out.println("查詢結果總數爲:" + results.getNumFound());
        // 六、遍歷結果並打印,示例只打印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.二、複雜查詢

   /**
     * 複雜查詢
     * @throws Exception
     */

    @Test
    public void queryIndexTest02() throws Exception 
{
        // 一、建立SolrServer對象,經過它和solr服務器創建鏈接。 
        SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr/collection1"); // 參數:是solr服務器的訪問地址
        // 二、建立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>");

        // 三、調用solrServer的查詢方法,查詢索引庫
        QueryResponse response = solrServer.query(query);
        // 四、獲取查詢結果
        SolrDocumentList results = response.getResults();

        // 五、處理查詢結果
        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.一、功能分析

在schema.xml中定義如下業務域(已經定義好):

    1、商品id(根據id查詢商品描述頁)
    2、商品標題title
    3、商品賣點sell_point
    4、商品價格price
    5、商品圖片image
    6、分類名稱category_name(不是分類id,咱們通常不會根據商品分類id去查詢商品,而是根據商品分類名稱去查)
    7、商品描述tb_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.二、Dao層

3.2.一、建立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.二、定義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.三、編寫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.三、Service層

參數:無
業務邏輯:
  一、查詢全部商品數據。
  二、建立一個SolrServer對象(抽象類),使用HttpSolrServer建立鏈接對象(鏈接單機版solr),使用CloudSolrServer建立鏈接對象(鏈接集羣版solr)。
  三、爲每一個商品建立一個文檔對象SolrInputDocument對象。
  四、爲文檔添加域。必須有id域,且域的名稱必須在schema.xml中定義。
  五、把文檔對象添加到索引庫中。
  六、提交修改。
  七、返回TaotaoResult。

3.3.一、配置單機版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.二、定義service接口

接口放在taotao-search-interface中

/**
 * 從數據庫中查詢到數據導入索引庫
 * @author    chenmingjun
 * @date    2018年11月21日下午2:38:41
 * @version 1.0
 */

public interface SearchItemService {

    /**
     * 導入搜索的商品數據到索引庫中
     * @return
     * @throws Exception
     */

    TaotaoResult importSearchItemsToIndex();
}

3.3.三、定義service實現類

要想注入SearchItemMapper成功,須要在taotao-search-serviceapplicationContext-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,要能注入進來,須要配置Mapper映射文件的包掃描器
    @Autowired
    private SearchItemMapper searchItemMapper;

    // 注入SolrServer,要能注入進來,須要配置一個bean是SolrServer
    @Autowired
    private SolrServer solrServer;

    @Override
    public TaotaoResult importSearchItemsToIndex() {
        try {
            // 一、查詢數據庫中全部商品數據(此爲新的商品數據)。 
            List<SearchItem> searchItemList = searchItemMapper.getSearchItemList();
            // 二、建立一個SolrServer對象(抽象類),使用HttpSolrServer建立鏈接對象(鏈接單機版solr),使用CloudSolrServer建立鏈接對象(鏈接集羣版solr)。 
            // SolrServer咱們使用spring容器生成後注入進來
            for (SearchItem searchItem : searchItemList) {
                // 三、爲每一個商品建立一個文檔對象SolrInputDocument對象。 
                SolrInputDocument document = new SolrInputDocument();
                // 四、爲文檔添加域。必須有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());
                // 五、把文檔對象添加到索引庫中。 
                solrServer.add(document);
            }
            // 六、提交修改。
            solrServer.commit();
        } catch (Exception e) {
            e.printStackTrace();
            return TaotaoResult.build(500"數據導入失敗");
        }
        // 七、返回TaotaoResult,數據導入成功。
        return TaotaoResult.ok();
    }
}

3.3.四、在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.四、表現層

3.4.一、引用服務

因爲把從數據庫中查詢到的新的商品數據導入到索引庫中屬於後臺功能,因此咱們在taotao-manager-web中引用服務。
在/taotao-manager-web/src/main/resources/spring/springmvc.xml中引用服務:

3.4.二、添加對taotao-search-interface的依賴

在taotao-manager-web工程中的pom.xml中添加以下:

3.4.三、修改index.jsp

因爲把從數據庫中查詢到的新的商品數據導入到索引庫中屬於後臺功能,因此咱們在taotao-manager-web的後臺系統中作一個導入索引庫的功能界面。(例如:有個按鈕,點擊便可將從數據庫中查詢到的數據導入到索引庫)。
業務邏輯:

    一、點擊按鈕,表現層調用服務層的工程的導入索引庫的方法。
    二、服務層實現調用Mapper接口的方法查詢全部的商品的數據。
    三、將數據一條條添加到SolrInputDocument文檔中。
    四、將文檔添加到索引庫中。
    五、提交,並返回導入成功便可。

添加以下代碼到index.jsp中:

    <li>
         <span>網站前臺搜索管理</span>
         <ul>
             <li data-options="attributes:{'url':'import-index'}">導入索引庫</li>
         </ul>
     </li>

3.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.五、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.六、測試

測試以前咱們先將索引庫中的測試數據清空,不然會對咱們測試有影響,方法以下:


測試出錯,緣由是:未將工程中新建的映射文件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.一、搜索表現層工程的搭建

能夠參考taotao-portal-web的建立。
打包方式war。
taotao-search-web。
這裏再也不贅圖了。

4.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>
        <!-- 配置對taotao-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.二、配置文件

目錄結構以下:

4.1.三、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.四、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.五、搜索結果的前臺靜態頁面


將上面的搜索結果靜態頁面放入到taotao-search-web工程中

4.二、搜索功能分析

首頁的搜索框中輸入搜索條件,而後跳轉到搜索結果頁面。搜索結果頁面在taotao-search-web工程中(端口爲8085)。
首頁搜索框的點擊按鈕處理函數在:在taotao-portal-web工程首頁的JS中,應當改爲8085,如圖:


請求的url:/search
以搜索手機爲例:http://localhost:8085/search.html?q=手機

參數:
  一、q,表示查詢條件。
  二、page,頁碼。默認爲1。每頁顯示多少行,咱們在controller中寫死便可。好比:60。
返回值: String。(包括:新的商品列表信息、總頁數、總記錄數、數據回顯)
業務邏輯:
  一、接收查詢條件。
  二、建立一個SolrServer對象,須要注入。
  三、建立一個SolrQuery對象。
  四、須要設置查詢條件、分頁條件、設置默認搜索域、高亮設置。
  五、執行查詢,返回QueryResponse對象。
  六、取返回結果,封裝到List中。
  七、返回查詢結果的總記錄數,計算查詢結果的總頁數。
  八、獲得查詢結果,渲染jsp

4.三、Dao層

4.3.一、功能分析

訪問索引庫的類。定義一些通用的數據訪問方法。
業務邏輯就是查詢索引庫。
參數:SolrQuery對象
業務邏輯:
  一、根據Query對象進行查詢。
  二、返回查詢結果。包括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.二、建立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 {
        // 一、根據SolrServer對象查詢索引庫
        QueryResponse response = solrServer.query(query);
        // 二、取出查詢結果
        SolrDocumentList solrDocumentList = response.getResults();

        // 三、處理查詢結果(即把取出的查詢結果進行封裝,即設置值)
        SearchResult result = new SearchResult();
        // 1) 取出總記錄數放到SearchResult中去
        Long recordCount = solrDocumentList.getNumFound();
        result.setRecordCount(recordCount);

        // 2) 取出新的商品列表放到SearchResult中去(注意:新的商品=>SearchItem,要與以前的商品Item區分開)
        List<SearchItem> searchItemList = new ArrayList<>();
        // 獲取高亮列表
        Map<StringMap<StringList<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"));
            /*            
             // 取第一張圖片地址存儲進索引庫
            String image = (String) solrDocument.get("item_image");
            if (StringUtils.isNotBlank(image)) {
                image = image.split(",")[0];
            }
            searchItem.setImage(image);
            */

            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);

        // 四、返回結果
        return result;
    }
}

4.四、Service層

4.4.一、功能分析

參數:
  queryString:查詢條件
  page:頁碼
  rows:每頁顯示的記錄數。
業務邏輯:
  一、建立一個SolrQuery對象。
  二、設置主查詢條件。
  三、設置分頁條件。
  四、須要指定默認的搜索域。
  五、設置高亮。
  六、執行查詢,調用SearchDao。獲得SearchResult
  七、須要計算總頁數。
  八、返回SearchResult。

4.4.二、定義service接口

/**
 * 網站前臺根據搜索條件進行搜索
 * @author    chenmingjun
 * @date    2018年11月21日下午2:38:41
 * @version 1.0
 */

public interface SearchService {

    /**
     * 根據查詢條件搜索
     * @param queryString 頁面傳過來的查詢條件
     * @param page 頁碼
     * @param rows 每頁顯示的記錄數
     * @return
     */

    SearchResult search(String queryString, Integer page, Integer rows);
}

4.4.三、定義service接口實現類

代碼以下:

/**
 * 網站前臺搜索功能實現類
 * @author chenmingjun
 * @date 2019年1月2日
 * @version V1.0
 */

public class SearchServiceImpl implements SearchService {

    // 注入SearchDaoImpl
    @Autowired
    private SearchDaoImpl searchDaoImpl;

    @Override
    public SearchResult search(String queryString, Integer page, Integer rows) {
        // 一、建立一個SolrQuery對象。
        SolrQuery query = new SolrQuery();
        // 二、設置主查詢條件。
        if (StringUtils.isNotBlank(queryString)) {
            query.setQuery(queryString); // 按傳遞過來的條件進行查詢
        } else {
            query.setQuery("*:*"); // 查詢全部
        }
        // 三、設置過濾條件:分頁、默認搜索域、高亮等等
        // 1) 設置分頁
        if (page == null) {
            page = 1;
        }
        if (rows == null) {
            rows = 60;
        }
        query.setStart((page - 1) * rows);
        query.setRows(rows);
        // 2) 設置默認的搜索域
        query.set("df""item_title");
        // 3) 設置高亮顯示
        query.setHighlight(true);
        query.addHighlightField("item_title");
        query.setHighlightSimplePre("<font color='red'>");
        query.setHighlightSimplePost("</font>");

        // 四、調用solr服務的Dao的實現類方法,執行搜索,返回的是SearchResult,該返回值裏面只包含了"總記錄數"和"新的商品列表"
        SearchResult result = null;
        try {
            result = searchDaoImpl.search(query);
            // 五、設置總頁數,須要先計算出總頁數
            Long recordCount = result.getRecordCount();
            Long pageCount = recordCount / rows;
            if (recordCount % rows > 0) {
                pageCount++;
            }
            result.setPageCount(pageCount); // 把總頁數設置到SearchResult
            // 六、返回SearchResult
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

4.4.四、發佈服務

在taotao-search-service工程applicationContext-service.xml文件中發佈服務:


要想讓掃描組件掃描到SearchDaoImpl,須要修改組件掃描的配置:

4.五、表現層

該功能在taotao-search-web中實現。

4.5.一、引用服務

在taotao-search-web工程springmvc.xml文件中引用服務:

4.5.二、Controller

請求的url:/search
參數:
  一、q 查詢條件。
  二、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) {

        // 一、引用服務
        // 二、注入searchService
        // 三、調用方法
        // 對請求參數進行轉碼處理
        try {
            queryString = new String(queryString.getBytes("iso8859-1"), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        SearchResult result = searchService.search(queryString, page, ITEM_ROWS);
        // 四、設置數據傳遞到jsp中進行回顯
        model.addAttribute("query", queryString);
        model.addAttribute("page", page);

        model.addAttribute("totalPages", result.getPageCount());
        model.addAttribute("itemList", result.getItemList());

        // 五、返回邏輯視圖:search.jsp
        return "search";
    }
}

4.5.三、屬性文件中配置行數

搜索的結果頁面中顯示的每頁的行數,咱們查詢到數據進行回顯,每頁顯示多少條數據由咱們決定。


文件存放在taotao-search-web中的resource目錄下
還須要配置屬性文件加載:在taotao-search-web的springmvc.xml中

4.5.四、測試

一、測試發現有亂碼,是GET請求亂碼,須要對get請求的參數進行轉碼處理:
方式一:在Controller中改


方式二:修改tomcat的配置文件,修改tomcat的默認字符集,可是咱們使用的tomcat插件,根本不知道配置文件在哪!!!
對於方式二,若是是集羣的話,會將該工程部署到不一樣的tomcat中,須要每個tomcat都要改,麻煩,不推薦方式二!

二、翻頁處理:在taotao-search-web工程中:
/taotao-search-web/src/main/webapp/js/search_main.js,修改以下:

4.六、圖片顯示處理

數據庫中保存的圖片是以逗號分隔的url列表,咱們顯示只須要展現第一張圖片便可。
方法1
  一、向索引庫中添加(導入)文檔時,只取第一張圖片的地址寫入索引庫。
  二、從文檔列表轉換爲商品列表時能夠取一張。
  三、在jsp中對列表拆分,只取一張展現。


方法2
能夠在SearchItem中添加一個getImages()方法,用於頁面獲取通過處理的pojo的字段數據:

在jsp中取屬性:
相關文章
相關標籤/搜索