• 商城06——solr索引库搭建&solr搜索功能实现&图片显示问题解决


    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>
    View Code

    (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>
    View Code

      配置文件:

    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>
    View Code

    效果:

    导入成功后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>
    View Code

    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>
    View Code

    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中取属性:

          

  • 相关阅读:
    〖Python〗-- Tornado自定义session组件
    〖Python〗-- Tornado异步非阻塞
    〖Python〗-- Tornado基础
    〖Python〗-- Flask
    〖Python〗-- 设计模式
    〖Python〗-- Celery分布式任务队列
    〖Demo〗-- CosPlayPermission
    05——wepy框架中的一些细节
    04——wepy框架搭建
    03——微信小程序官方demo讲解——page部分
  • 原文地址:https://www.cnblogs.com/toria/p/taotao06.html
Copyright © 2020-2023  润新知