• day74_淘淘商城项目_07_ zookeeper集群搭建 + solrcloud集群搭建 + 使用solrJ管理solr集群 + 搜索功能切换到集群版 + httpclient学习 + 全局异常处理器 + 附录_匠心笔记


    课程计划

    • 1、solr集群的搭建
    • 2、使用solrJ管理solr集群
    • 3、把搜索功能切换到solr集群版
    • 4、httpclient
    • 5、全局异常处理

    1、什么是SolrCloud

      SolrCloud(solr 云)是Solr提供的分布式搜索方案,当你需要大规模、容错、分布式索引和检索能力时使用 SolrCloud。当索引量很大搜索请求并发很高,这时需要使用SolrCloud来满足这些需求。
      SolrCloud是基于Solr和Zookeeper的分布式搜索方案,它的主要思想是使用Zookeeper作为集群的配置信息中心
      Zookeeper它有几个特色功能:
        1)集中式的配置信息(数据库连接池的配置文件,修改文件不用重启就可以生效)
        2)自动容错
        3)近实时搜索
        4)查询时自动负载均衡

    2、Solr集群的系统架构


    详解如下:

    2.1、SolrCloud的物理结构

      三个Solr实例(每个实例包括两个Core),组成一个SolrCloud。

    2.2、SolrCloud的逻辑结构

      索引集合包括两个Shard(Shard1和Shard2),Shard1和Shard2分别由三个Core组成,其中一个Leader两个Replication,Leader是由ZooKeeper选举产生,zookeeper控制每个shard上三个Core的索引数据一致,解决高可用问题。
      用户发起索引请求分别从Shard1和Shard2上获取,解决高并发问题。

    2.2.1、Collection

      Collection在SolrCloud集群中是一个逻辑意义上的完整的索引结构。它常常被划分为一个或多个Shard(分片),它们使用相同的配置信息。
      比如:针对商品信息搜索可以创建一个Collection。
      Collection = Shard1 + Shard2 + … + Shardx

    2.2.2、Core

      每个Core是Solr中一个独立运行单位,提供索引搜索服务。一个Shard需要由一个Core或多个Core组成。由于Collection由多个Shard组成所以Collection一般由多个Core组成。

    2.2.3、Master或Slave

      Master是Master-Slave结构中的主结点(通常说主服务器),Slave是Master-Slave结构中的从结点(通常说从服务器或备服务器)。  同一个Shard下Master和Slave存储的数据是一致的,这是为了达到高可用目的。

    2.2.4、Shard

      Collection的逻辑分片。每个Shard被化成一个或者多个Replication,通过选举确定哪个是Leader。

    2.3、我们需要实现简单的Solr集群架构


    ZooKeeper作为集群的管理工具。
      1、集群管理:容错、负载均衡。
      2、配置文件的集中管理。
      3、集群的入口。
      需要实现ZooKeeper高可用。需要搭建集群。建议是奇数节点。需要三个ZooKeeper服务器。
      搭建Solr集群至少需要7台服务器。
      ZooKeeper有自己的投票机制,类似于Redis,需要半数以上的节点判断其他的节点挂掉,才能算挂掉。
    搭建伪分布式
      需要三个ZooKeeper节点
      需要四个Tomcat节点。
    建议虚拟机的内存1G以上。

    3、环境准备

      Win10
      CentOS 7.5
      jdk-7u80-linux-x64.tar.gz
      apache-tomcat-7.0.47.tar.gz
      zookeeper-3.4.6.tar.gz
      solr-4.10.3.tgz.gz

    4、安装步骤

    4.1、ZooKeeper集群的搭建

    第一步:Linux上需要安装jdk环境。(已安好jdk1.7)
    第二步:把zookeeper的压缩包上传到Linux服务器。
    第三步:解压缩后删除压缩包。

    [root@itheima ~]# pwd
    /root
    [root@itheima ~]# tar zxvf zookeeper-3.4.6.tar.gz
    [root@itheima ~]# rm -rf zookeeper-3.4.6.tar.gz 

    第四步:把zookeeper复制三份。

    [root@itheima ~]# mkdir /usr/local/solr-cloud
    [root@itheima ~]# cp -r zookeeper-3.4.6/ /usr/local/solr-cloud/zookeeper01
    [root@itheima ~]# cp -r zookeeper-3.4.6/ /usr/local/solr-cloud/zookeeper02
    [root@itheima ~]# cp -r zookeeper-3.4.6/ /usr/local/solr-cloud/zookeeper03

    第五步:在每个zookeeper目录下创建一个data目录。
    第六步:在data目录下创建一个myid文件,文件名就叫做“myid”。内容就是每个实例的id。例如1、2、3。

    [root@itheima ~]# cd /usr/local/solr-cloud/
    [root@itheima solr-cloud]# ll
    总用量 12
    drwxr-xr-x. 10 root root 4096 11月 23 16:59 zookeeper01
    drwxr-xr-x. 10 root root 4096 11月 23 16:59 zookeeper02
    drwxr-xr-x. 10 root root 4096 11月 23 16:59 zookeeper03
    [root@itheima solr-cloud]# cd zookeeper01
    [root@itheima zookeeper01]# mkdir data
    [root@itheima zookeeper01]# cd data/
    [root@itheima data]# echo 1 >> myid
    [root@itheima data]# ll
    总用量 4
    -rw-r--r--. 1 root root 2 11月 23 17:05 myid
    [root@itheima data]# cat myid 
    1
    [root@itheima data]

    其他zookeeper目录同理。注意:myid中的id要和服务器的标识对应起来。
    注意:命令:touch myid是创建一个文件myid,但是不写入内容;echo 1 >> myid不仅创建一个文件myid,还写入内容1。
    第七步:修改配置文件。把每一个zookeeper下的conf目录下的zoo_sample.cfg文件改名为zoo.cfg。
    在zookeeper01目录下的配置如下:(注意:配置的端口都不能冲突

    [root@itheima conf]# pwd
    /usr/local/solr-cloud/zookeeper01/conf
    [root@itheima conf]# mv zoo_sample.cfg zoo.cfg
    [root@itheima conf]# vim zoo.cfg 

    配置如下图所示:


    server.1 这个1是服务器的标识也可以是其他的数字, 表示这个是第几号服务器,用来标识服务器,这个标识要写到快照目录下面myid文件里。
    同理在zookeeper02、zookeeper03下配置,注意端口不能冲突
    /usr/local/solr-cloud/zookeeper01/data/

    server.1=192.168.25.154:2881:3881
    server.2=192.168.25.154:2882:3882
    server.3=192.168.25.154:2883:3883

    第八步:启动每个zookeeper实例。

    a) 创建启动实例的批处理文件:在solr-cloud下创建,命令如下:

    [root@itheima solr-cloud]# vim zookeeper_start_all.sh

    b) 使用vim编辑内容如下:

    cd /usr/local/solr-cloud/zookeeper01/bin
    ./zkServer.sh start

    cd /usr/local/solr-cloud/zookeeper02/bin
    ./zkServer.sh start

    cd /usr/local/solr-cloud/zookeeper03/bin
    ./zkServer.sh start

    ESC
    输入:wq保存退出。
    修改文件可执行权限:

    [root@localhost solr-cloud]# chmod u+x zookeeper_start_all.sh

    c) 启动所有zookeeper实例

    [root@itheima solr-cloud]# ./zookeeper_start_all.sh 
    JMX enabled by default
    Using config: /usr/local/solr-cloud/zookeeper01/bin/../conf/zoo.cfg
    Starting zookeeper ... STARTED
    JMX enabled by default
    Using config: /usr/local/solr-cloud/zookeeper02/bin/../conf/zoo.cfg
    Starting zookeeper ... STARTED
    JMX enabled by default
    Using config: /usr/local/solr-cloud/zookeeper03/bin/../conf/zoo.cfg
    Starting zookeeper ... STARTED
    [root@itheima solr-cloud]#

    查看zookeeper的状态:

    [root@itheima solr-cloud]# zookeeper01/bin/zkServer.sh status
    JMX enabled by default
    Using config: /usr/local/solr-cloud/zookeeper01/bin/../conf/zoo.cfg
    Error contacting service. It is probably not running.
    [root@itheima solr-cloud]

    明明已经启动了,但是zookeeper的状态却是没有启动,为什么呢?
    原因是:本博主的是CentOS7,防火墙使用的是firewalld,我们使用修改配置文件的方式来添加用到的端口(修改后需要重启firewalld服务):

    [root@itheima zones]# pwd
    /etc/firewalld/zones
    [root@itheima zones]# vim public.xml

    添加内容如下:


    保存退出后,然后我们重启firewalld服务:
    [root@itheima zones]# service firewalld restart
    Redirecting to /bin/systemctl restart firewalld.service
    [root@itheima zones]#

    其实我们在启动所有zookeeper实例之前还可以关闭虚拟机的防火墙,但是生产环境中不建议这么做

    systemctl stop firewalld.service        #停止firewall服务
    systemctl disable firewalld.service     #禁止firewall服务开机启动
    firewall-cmd --state                    #查看默认防火墙状态(关闭后显示notrunning,开启后显示running)

    d) 再次启动所有zookeeper实例,查看zookeeper的状态:
    效果如下:

    [root@itheima solr-cloud]# zookeeper01/bin/zkServer.sh status
    JMX enabled by default
    Using config: /usr/local/solr-cloud/zookeeper01/bin/../conf/zoo.cfg
    Mode: follower
    [root@itheima solr-cloud]# zookeeper02/bin/zkServer.sh status 
    JMX enabled by default
    Using config: /usr/local/solr-cloud/zookeeper02/bin/../conf/zoo.cfg
    Mode: follower
    [root@itheima solr-cloud]# zookeeper03/bin/zkServer.sh status 
    JMX enabled by default
    Using config: /usr/local/solr-cloud/zookeeper03/bin/../conf/zoo.cfg
    Mode: leader

    4.2、Solr集群的搭建

    第一步:创建四个tomcat实例。每个tomcat运行在不同的端口。8180、8280、8380、8480。

    [root@itheima ~]# ll
    总用量 4
    drwxr-xr-x.  9 root  root   160 11月 20 17:09 apache-tomcat-7.0.47
    drwxr-xr-x.  4 root  root   225 11月 20 19:23 IK Analyzer 2012FF_hf1
    drwxr-xr-x.  8 root  root   218 11月 20 17:07 solr-4.10.3
    drwxr-xr-x. 10 bruce bruce 4096 2月  20 2014 zookeeper-3.4.6
    [root@itheima ~]# cp -r apache-tomcat-7.0.47/ /usr/local/solr-cloud/tomcat01
    [root@itheima ~]# cp -r apache-tomcat-7.0.47/ /usr/local/solr-cloud/tomcat02
    [root@itheima ~]# cp -r apache-tomcat-7.0.47/ /usr/local/solr-cloud/tomcat03
    [root@itheima ~]# cp -r apache-tomcat-7.0.47/ /usr/local/solr-cloud/tomcat04
    [root@itheima ~]# vim /usr/local/solr-cloud/tomcat01/conf/server.xml
    [root@itheima ~]# vim /usr/local/solr-cloud/tomcat02/conf/server.xml
    [root@itheima ~]# vim /usr/local/solr-cloud/tomcat03/conf/server.xml
    [root@itheima ~]# vim /usr/local/solr-cloud/tomcat04/conf/server.xml

    修改内容为:8005-->81058080-->81808009-->8109
    修改内容为:8005-->82058080-->82808009-->8209
    修改内容为:8005-->83058080-->83808009-->8309
    修改内容为:8005-->84058080-->84808009-->8409

    其余tomcat同理。
    第二步:部署solr的war包。把单机版的solr工程实例复制到集群中的tomcat中去。

    [root@itheima solr-cloud]# cp -r ../solr/tomcat/webapps/solr/ tomcat01/webapps/ 
    [root@itheima solr-cloud]# cp -r ../solr/tomcat/webapps/solr/ tomcat02/webapps/
    [root@itheima solr-cloud]# cp -r ../solr/tomcat/webapps/solr/ tomcat03/webapps/
    [root@itheima solr-cloud]# cp -r ../solr/tomcat/webapps/solr/ tomcat04/webapps/

    第三步:为每个solr工程实例创建一个对应的solrhome。使用单机版的solrhome复制四份。

    [root@itheima solr-cloud]# cp -r ../solr/solrhome/ solrhome01
    [root@itheima solr-cloud]# cp -r ../solr/solrhome/ solrhome02
    [root@itheima solr-cloud]# cp -r ../solr/solrhome/ solrhome03
    [root@itheima solr-cloud]# cp -r ../solr/solrhome/ solrhome04
    [root@itheima solr-cloud]# ll
    总用量 24
    drwxr-xr-x.  4 root root   85 11月 23 18:59 solrhome01
    drwxr-xr-x.  4 root root   85 11月 23 18:59 solrhome02
    drwxr-xr-x.  4 root root   85 11月 23 18:59 solrhome03
    drwxr-xr-x.  4 root root   85 11月 23 18:59 solrhome04
    drwxr-xr-x.  9 root root  160 11月 23 18:41 tomcat01
    drwxr-xr-x.  9 root root  160 11月 23 18:37 tomcat02
    drwxr-xr-x.  9 root root  160 11月 23 18:37 tomcat03
    drwxr-xr-x.  9 root root  160 11月 23 18:37 tomcat04
    drwxr-xr-x. 11 root root 4096 11月 23 17:03 zookeeper01
    drwxr-xr-x. 11 root root 4096 11月 23 17:08 zookeeper02
    drwxr-xr-x. 11 root root 4096 11月 23 17:09 zookeeper03
    -rwxr--r--.  1 root root  185 11月 23 17:33 zookeeper_start_all.sh
    -rwxr--r--.  1 root root  188 11月 23 18:31 zookeeper_status_all.sh
    -rwxr--r--.  1 root root  182 11月 23 17:59 zookeeper_stop_all.sh
    [root@itheima solr-cloud]

    第四步:需要修改solr的web.xml文件。把solr和solrhome关联起来。

    [root@itheima tomcat01]# pwd
    /usr/local/solr-cloud/tomcat01
    [root@itheima tomcat01]# vim webapps/solr/WEB-INF/web.xml

    修改内容如下:


    其余的web.xml同理修改。
    第五步:配置SolrCloud相关的配置。每个solrhome下都有一个solr.xml,把其中的ip及端口号配置好。
    [root@itheima solrhome01]# pwd
    /usr/local/solr-cloud/solrhome01
    [root@itheima solrhome01]# vim solr.xml

    修改内容如下:
    192.168.25.154
    8180

    192.168.25.154
    8280

    192.168.25.154
    8380

    192.168.25.154
    8480

    修改配置如下:


    其余的solr.xml同理。
    第六步:修改(4个)每一个tomcat/bin目录下的catalina.sh 文件,关联solr和zookeeper。
    把此配置添加到配置文件中:JAVA_OPTS="-DzkHost=192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183"
    [root@itheima solr-cloud]# vim  tomcat01/bin/catalina.sh

    添加内容如下:


    其余的tomcat同理修改。
    第七步:让zookeeper统一管理solr的配置文件。需要把solrhome/collection1/conf目录上传到zookeeper。上传任意solrhome中的配置文件即可。(前提:需要保证zookeeper集群是启动的状态)
    使用工具上传配置文件,工具位置:/root/solr-4.10.3/example/scripts/cloud-scripts/zkcli.sh
    [root@itheima cloud-scripts]# pwd
    /root/solr-4.10.3/example/scripts/cloud-scripts
    [root@itheima cloud-scripts]# ./zkcli.sh -zkhost 192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183 -cmd upconfig -confdir /usr/local/solr-cloud/solrhome01/collection1/conf/ -confname myconf

    查看是否上传成功,查看zookeeper上的配置文件:
    使用zookeeper目录下的bin/zkCli.sh命令查看zookeeper上的配置文件:

    [root@itheima solr-cloud]# pwd
    /usr/local/solr-cloud
    [root@itheima solr-cloud]# cd zookeeper01/bin/
    [root@itheima bin]# ./zkCli.sh 
    [zk: localhost:2181(CONNECTED) 0] ls /
    [configs, zookeeper]
    [zk: localhost:2181(CONNECTED) 1] ls /configs
    [myconf]
    [zk: localhost:2181(CONNECTED) 2] ls /configs/myconf
    [admin-extra.menu-top.html, currency.xml, protwords.txt, mapping-FoldToASCII.txt, _schema_analysis_synonyms_english.json, _rest_managed.json, solrconfig.xml, _schema_analysis_stopwords_english.json, stopwords.txt, lang, spellings.txt, mapping-ISOLatin1Accent.txt, admin-extra.html, xslt, synonyms.txt, scripts.conf, update-script.js, velocity, elevate.xml, admin-extra.menu-bottom.html, schema.xml, clustering]
    [zk: localhost:2181(CONNECTED) 3] quit
    Quitting...
    2018-11-23 20:32:38,846 [myid:] - INFO  [main:ZooKeeper@684] - Session: 0x16740142eaf0000 closed
    2018-11-23 20:32:38,851 [myid:] - INFO  [main-EventThread:ClientCnxn$EventThread@512] - EventThread shut down
    [root@itheima bin]

    注意:如果连接的默认端口2181被占用,想要连接其他节点使用如下命令:

    [root@itheima bin]# ./zkCli.sh -server 192.168.25.154:2182

    解释:
        -server     指定ip地址
        :2182       指定连接的端口

    第八步:启动每个tomcat实例。注意:要保证zookeeper集群是启动状态。
    我们可以写一个批处理文件,批量启动tomcat。

    [root@itheima solr-cloud]# ./tomcat_start_all.sh
    Using CATALINA_BASE:   /usr/local/solr-cloud/tomcat01
    Using CATALINA_HOME:   /usr/local/solr-cloud/tomcat01
    Using CATALINA_TMPDIR: /usr/local/solr-cloud/tomcat01/temp
    Using JRE_HOME:        /usr/local/java/jdk1.7.0_80/jre
    Using CLASSPATH:       /usr/local/solr-cloud/tomcat01/bin/bootstrap.jar:/usr/local/solr-cloud/tomcat01/bin/tomcat-juli.jar
    Using CATALINA_BASE:   /usr/local/solr-cloud/tomcat02
    Using CATALINA_HOME:   /usr/local/solr-cloud/tomcat02
    Using CATALINA_TMPDIR: /usr/local/solr-cloud/tomcat02/temp
    Using JRE_HOME:        /usr/local/java/jdk1.7.0_80/jre
    Using CLASSPATH:       /usr/local/solr-cloud/tomcat02/bin/bootstrap.jar:/usr/local/solr-cloud/tomcat02/bin/tomcat-juli.jar
    Using CATALINA_BASE:   /usr/local/solr-cloud/tomcat03
    Using CATALINA_HOME:   /usr/local/solr-cloud/tomcat03
    Using CATALINA_TMPDIR: /usr/local/solr-cloud/tomcat03/temp
    Using JRE_HOME:        /usr/local/java/jdk1.7.0_80/jre
    Using CLASSPATH:       /usr/local/solr-cloud/tomcat03/bin/bootstrap.jar:/usr/local/solr-cloud/tomcat03/bin/tomcat-juli.jar
    Using CATALINA_BASE:   /usr/local/solr-cloud/tomcat04
    Using CATALINA_HOME:   /usr/local/solr-cloud/tomcat04
    Using CATALINA_TMPDIR: /usr/local/solr-cloud/tomcat04/temp
    Using JRE_HOME:        /usr/local/java/jdk1.7.0_80/jre
    Using CLASSPATH:       /usr/local/solr-cloud/tomcat04/bin/bootstrap.jar:/usr/local/solr-cloud/tomcat04/bin/tomcat-juli.jar
    [root@itheima solr-cloud]#

    第九步:查看每一个tomcat启动状态。发现tomcat都启动成功。

    [root@itheima ~]# cd /usr/local/solr-cloud/tomcat01
    [root@itheima tomcat01]# tail -f logs/catalina.out

    第十步:通过浏览器访问solr集群。
    访问地址:http://192.168.25.154:8180/solr


    点击Cloud按钮

    第十一步:创建新的Collection并进行分片处理。
    在浏览器地址栏输入:http://192.168.25.154:8180/solr/admin/collections?action=CREATE&name=collection2&numShards=2&replicationFactor=2

    再重新访问地址:http://192.168.25.154:8180/solr

    第十二步:删除不用的Collection。
    在浏览器地址栏输入:http://192.168.25.154:8180/solr/admin/collections?action=DELETE&name=collection1

    再重新访问地址:http://192.168.25.154:8180/solr

    5、使用solrJ管理solr集群

    5.1、添加文档

    使用步骤:
      第一步:把solrJ相关的jar包添加到工程中。在Maven工程中则是添加依赖。
      第二步:创建一个SolrServer对象(抽象类),使用HttpSolrServer创建对象(连接单机版solr),使用CloudSolrServer创建对象(连接集群版solr)。需要使用CloudSolrServer子类。构造方法的参数是zookeeper的地址列表
      第三步:需要设置DefaultCollection属性。不设置,会报错。
      第四步:创建一个文档对象SolrInputDocument对象。
      第五步:向文档对象中添加域。
      第六步:把文档对象写入索引库。
      第七步:提交。
    测试代码如下:

        /**
         * 向索引库中添加索引(集群版)
         * @throws Exception
         */

        @Test
        public void solrCloudAddDocumentTest() throws Exception {
            // 第一步:把solrJ相关的jar包添加到工程中。在Maven工程中则是添加依赖。
            // 第二步:创建一个SolrServer对象(抽象类),使用HttpSolrServer创建对象(连接单机版solr),使用CloudSolrServer创建对象(连接集群版solr)。
            // 需要使用CloudSolrServer子类。构造方法的参数是zookeeper的地址列表。使用逗号分隔。
            CloudSolrServer solrServer = new CloudSolrServer("192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183");
            // 第三步:需要设置DefaultCollection属性。不设置,会报错。
            solrServer.setDefaultCollection("collection2");
            // 第四步:创建一个文档对象SolrInputDocument对象。
            SolrInputDocument document = new SolrInputDocument();
            // 第五步:向文档对象中添加域。
            document.addField("id""test001");
            document.addField("item_title""测试商品名称");
            document.addField("item_price"100);
            // 第六步:把文档对象写入索引库。
            solrServer.add(document);
            // 第七步:提交。
            solrServer.commit();
        }

    5.2、查询文档

      创建一个CloudSolrServer对象,其他处理和单机版一致。不在赘述!

    6、把搜索功能切换到solr集群版

    我们先将上面5、使用solrJ管理solr集群生成的测试数据从集群版的solr索引库中删除掉。
    点击【Documents】--> 点击【Document Type】选择为【XML】,在【Document(s)】中输入如下内容:

    <delete>
        <query>*:*</query>
    </delete>
    <commit/>

    点击【Submit Document】按钮。
    因为我们使用的SolrServer对象(抽象类),是HttpSolrServer对象和CloudSolrServer对象的父类,所以我们的实现类代码不需要进行修改,只要修改solr的配置文件applicationContext-solr.xml即可,如下:

    7、HttpClient

    7.1、HttpClient简介

      HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
      HttpClient 提供的主要的功能:
        (1)实现了所有 HTTP 的方法(GET、POST、PUT、DELETE等)
        (2)支持自动转向
        (3)支持 HTTPS 协议
        (4)支持代理服务器等(翻墙)
      我们所用的solrj其实就封装了HttpClient。

    7.2、学习HttpClient

    http状态码:


    常用的:200、201、202、400、404、405、406、415、500、501、502、503

    由于我们没有手机端,所以我们通过以下工程进行学习httpclient:

    7.2.1、无参数的GET请求

    HttpClient它是模拟浏览器请求。通过代码来模拟浏览器请求。

    7.2.2、带参数的GET请求

    public class DoGETParam {

        public static void main(String[] args) throws Exception {

            // 创建HttpClient对象
            CloseableHttpClient httpclient = HttpClients.createDefault();

            // 定义请求的参数
            // 方式一:new URIBuilder("http://localhost:8081/item/list").addParameter("a", "1").addParameter("a", "2").build(); 
            // 方式一效果:http://localhost:8081/item/list?a=1&a=2
            // 方式二:new URIBuilder("http://localhost:8081/item/list").setParameter("a", "1").setParameter("a", "10").build();
            // 方式二效果:http://localhost:8081/item/list?a=2
            URI uri = new URIBuilder("http://localhost:8081/item/list").setParameter("page""1").setParameter("rows""10").build();

            System.out.println(uri);

            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);

            CloseableHttpResponse response = null;
            try {
                // 执行请求
                response = httpclient.execute(httpGet);
                // 判断返回状态是否为200
                if (response.getStatusLine().getStatusCode() == 200) {
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                    System.out.println(content);
                }
            } finally {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            }
        }
    }

    7.2.3、无参数的POST请求

    public class DoPOST {

        public static void main(String[] args) throws Exception {

            // 创建HttpClient对象
            CloseableHttpClient httpclient = HttpClients.createDefault();

            // 创建http POST请求
            HttpPost httpPost = new HttpPost("http://www.oschina.net/");

            httpPost.setHeader("User-Agent""");

            CloseableHttpResponse response = null;
            try {
                // 执行请求
                response = httpclient.execute(httpPost);
                // 判断返回状态是否为200
                if (response.getStatusLine().getStatusCode() == 200) {
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                    System.out.println(content);
                }
            } finally {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            }
        }
    }

    7.2.4、带参数的POST请求

    public class DoPOSTParam {

        public static void main(String[] args) throws Exception {

            // 创建HttpClient对象
            CloseableHttpClient httpclient = HttpClients.createDefault();

            // 创建http POST请求
            // 添加商品的url:/item/save
            HttpPost httpPost = new HttpPost("http://localhost:8081/item/save");

            //cid=560&title=httpclient&sellPoint=asfdafaf...
            // 设置2个post参数,一个是scope、一个是q
            List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
            parameters.add(new BasicNameValuePair("cid""560"));
            parameters.add(new BasicNameValuePair("title""httpclient"));
            parameters.add(new BasicNameValuePair("sellPoint""asfdafaf"));
            parameters.add(new BasicNameValuePair("price""1200"));
            parameters.add(new BasicNameValuePair("num""213"));
            // 构造一个form表单式的实体
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);
            // 将请求实体设置到httpPost对象中
            httpPost.setEntity(formEntity);

            CloseableHttpResponse response = null;
            try {
                // 执行请求
                response = httpclient.execute(httpPost);
                // 判断返回状态是否为200
                if (response.getStatusLine().getStatusCode() == 200) {
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                    System.out.println(content);
                }
            } finally {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            }
        }
    }

    8、使用HttpClient调用接口

    8.1、编写返回响应的实体类

    /**
     * 返回响应的实体类
     * @author    chenmingjun
     * @date    2018年11月24日下午4:52:44
     * @version 1.0
     */

    public class HttpResult {

        private Integer code; // 响应状态码

        private String body; // 响应的内容

        public HttpResult(Integer code, String body) {
            super();
            this.code = code;
            this.body = body;
        }

        public HttpResult() {
            super();
        }

        public Integer getCode() {
            return code;
        }

        public void setCode(Integer code) {
            this.code = code;
        }

        public String getBody() {
            return body;
        }

        public void setBody(String body) {
            this.body = body;
        }

        @Override
        public String toString() {
            return "HttpResult [code=" + code + ", body=" + body + "]";
        }
    }

    8.2、封装HttpClient

    /**
     * HttpClient API
     * @author    chenmingjun
     * @date    2018年11月24日下午5:11:33
     * @version 1.0
     */

    public class APIService {

        /**
         * 1.不带参数的GET请求的方法
         * @param url 请求的URL
         * @return HttpResult 要返回http状态码以及响应的内容
         * @throws Exception
         */

        public HttpResult doget(String url) throws Exception {
            return doGet(url, null);
        }

        /**
         * 2.带参数的GET请求的方法
         * @param url 请求的URL
         * @param map 请求传递的参数(可以多个)
         * @return HttpResult 要返回http状态码以及响应的内容
         * @throws Exception
         */

        public HttpResult doGet(String url, Map<String, Object> map) throws Exception {
            // 1.创建HttpClient对象
            CloseableHttpClient httpClient = HttpClients.createDefault();

            // 2.创建http get请求
            // 创建URIBuilder,构建URL及设置参数
            URIBuilder uriBuilder = new URIBuilder(url);
            // 循环遍历参数集合 设置参数
            // 判断如果map不为空
            if (map != null) {
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    uriBuilder.setParameter(entry.getKey(), entry.getValue().toString());
                }
            }
            HttpGet httpGet = new HttpGet(uriBuilder.build());

            // 3.执行请求(发送请求)
            CloseableHttpResponse response = httpClient.execute(httpGet);

            // 4.接收响应内容,进行解析后封装到HttpResult中
            // 内容有的时候
            Integer code = response.getStatusLine().getStatusCode(); // 响应的状态码
            if (response.getEntity() != null) {
                String body = EntityUtils.toString(response.getEntity(), "utf-8"); // 获取响应的内容,转换成字符串
                HttpResult result = new HttpResult(code, body);
                return result;
            } else {
                HttpResult result = new HttpResult(code, null);
                return result;
            }
        }

        /**
         * 3.不带参数的POST请求的方法
         * @param url 请求的URL
         * @return HttpResult 要返回http状态码以及响应的内容
         * @throws Exception
         */

        public HttpResult doPost(String url) throws Exception{
            return doPost(url,null);
        }

        /**
         * 4.带参数的POST请求的方法
         * @param url 请求的URL
         * @param map 请求传递的参数(可以多个)
         * @return HttpResult 要返回http状态码以及响应的内容
         * @throws Exception
         */

        public HttpResult doPost(String url, Map<String, Object> map) throws Exception {

            // 1.创建HttpClient
            CloseableHttpClient httpClient = HttpClients.createDefault();

            // 2.创建http post请求
            HttpPost httpPost = new HttpPost(url);

            // 3.构建参数的列表
            // 判断参数不为空的情况
            if (map != null) {
                List<NameValuePair> params = new ArrayList<>();
                // 遍历集合:构建参数列表
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    params.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
                }
                // 4.创建form表单传递参数的实体对象
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "utf-8");
                // 设置http post请求的实体对象
                httpPost.setEntity(entity);
            }

            // 5.执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);

            // 6.接收响应 封装到httpresult中
            // 内容有的时候
            Integer code = response.getStatusLine().getStatusCode(); // 响应的状态码
            if (response.getEntity() != null) {
                String body = EntityUtils.toString(response.getEntity(), "utf-8"); // 获取响应的内容,转换成字符串
                HttpResult result = new HttpResult(code, body);
                return result;
            } else {
                HttpResult result = new HttpResult(code, null);
                return result;
            }
        }
    }

    这样:如果手机客户端,需要搜索,则我们只需要提供给它这个APIService类,再告诉它调用的URL,以及各参数的含义。手机客户端调用这些方法,返回的JSON数据自己做处理便可以了。这样就实现了系统之间的通信。

    8.3、测试使用封装了HttpClient的APIService

    /**
     * 测试使用封装了HttpClient的APIService
     * @author    chenmingjun
     * @date    20181124日下午5:25:12
     * @version 1.0
     */
    public class APIServcieTest {

        @Test
        public void doGetParamTest() throws Exception {
            APIService service = new APIService();
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("page""1");
            map.put("rows""20");

            HttpResult doGet = service.doGet("http://localhost:8081/item/list", map);
            System.out.println(doGet.getCode());
            System.out.println(doGet.getBody());
        }

        @Test
        public void doPostParamTest() throws Exception{
            APIService service = new APIService();
            Map<String , Object> map =new HashMap<String, Object>();

            /**
             * parameters.add(new BasicNameValuePair("cid""560"));
             * parameters.add(new BasicNameValuePair("title""httpclient"));
             * parameters.add(new BasicNameValuePair("sellPoint""asfdafaf"));
             * parameters.add(new BasicNameValuePair("price""1200"));
             * parameters.add(new BasicNameValuePair("num""213"));
             */
            map.put("cid""560");
            map.put("title""apiservicehttpclienttest");
            map.put("sellPoint""asfdafaf");
            map.put("price""1200");
            map.put("num""213");

            HttpResult doPost = service.doPost("http://localhost:8081/item/save", map);
            System.out.println(doPost.getCode());
            System.out.println(doPost.getBody());
        }
    }

    9、全局异常处理器

    9.1、处理思路

    9.2、创建全局异常处理器

    在taotao-search-web工程中,导入日志配置文件log4j.properties,放在classpath路径下:


    使用默认名称log4j.properties,SpringMVC会自动加载该文件。
    在taotao-search-web工程中创建全局异常处理器类:
    注意:这里的全局指的是针对于该工程taotao-search-web的全局,不是所有的工程哦!!!
    /**
     * 全局异常处理器:捕获整个系统中发生的异常。
     * @author    chenmingjun
     * @date    2018年11月24日下午7:02:36
     * @version 1.0
     */

    public class GlobalExceptionReslover implements HandlerExceptionResolver {

        private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionReslover.class);

        @Override
        public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, 
                Object handler, Exception e)
     
    {
            // 0、控制台打印异常
            e.printStackTrace();

            // 1、异常写入日志文件。
            logger.info("进入全局异常处理器");
            logger.debug("测试handler的类型:" + handler.getClass());
            logger.error("系统发生异常", e);

            // 2、及时通知开发人员。发邮件、短信。
            // 使用Jmail邮件客户端:可以查找相关的资料。例如:先注册一个网易邮箱(相当于服务器),使用该网易邮箱向外发消息。通过邮件客户端Jmail向网易邮箱中发送邮件,网易邮箱就会将该邮件发送到指定的邮箱中去。
            // 需要购买短信。调用第三方接口即可。

            // 3、展示一个友好的错误页面,例如:您的网络故障,请重试。
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("message""系统发生异常,请稍后重试"); // 向页面中传递参数需要使用ModelAndView
            modelAndView.setViewName("error/exception"); // 设置跳转的逻辑视图名称
            return modelAndView;
        }
    }

    9.3、在springmvc中配置taotao-search-web工程的全局异常处理器

    (要是不配的话,就不知全局异常处理器在哪)
    在taotao-search-web工程中的springmvc.xml文件中添加以下内容:

    10、附录

    我们在搭建zookeeper集群和solr集群的时候,会写一些自定义的批处理文件,如下图所示:


    具体内容如下:
    tomcat_start_all.sh
    cd /usr/local/solr-cloud/tomcat01/bin/
    ./startup.sh

    cd /usr/local/solr-cloud/tomcat02/bin/
    ./startup.sh

    cd /usr/local/solr-cloud/tomcat03/bin/
    ./startup.sh

    cd /usr/local/solr-cloud/tomcat04/bin/
    ./startup.sh

    tomcat_status_all.sh

    cd /usr/local/solr-cloud/tomcat01
    tail -f logs/catalina.out

    cd /usr/local/solr-cloud/tomcat02
    tail -f logs/catalina.out

    cd /usr/local/solr-cloud/tomcat03
    tail -f logs/catalina.out

    cd /usr/local/solr-cloud/tomcat04
    tail -f logs/catalina.out

    tomcat_shutdown_all.sh

    cd /usr/local/solr-cloud/tomcat01/bin/
    ./shutdown.sh

    cd /usr/local/solr-cloud/tomcat02/bin/
    ./shutdown.sh

    cd /usr/local/solr-cloud/tomcat03/bin/
    ./shutdown.sh

    cd /usr/local/solr-cloud/tomcat04/bin/
    ./shutdown.sh

    zookeeper_start_all.sh

    cd /usr/local/solr-cloud/zookeeper01/bin
    ./zkServer.sh start

    cd /usr/local/solr-cloud/zookeeper02/bin
    ./zkServer.sh start

    cd /usr/local/solr-cloud/zookeeper03/bin
    ./zkServer.sh start

    zookeeper_status_all.sh

    cd /usr/local/solr-cloud/zookeeper01/bin
    ./zkServer.sh status

    cd /usr/local/solr-cloud/zookeeper02/bin
    ./zkServer.sh status

    cd /usr/local/solr-cloud/zookeeper03/bin
    ./zkServer.sh status

    zookeeper_stop_all.sh

    cd /usr/local/solr-cloud/zookeeper01/bin
    ./zkServer.sh stop

    cd /usr/local/solr-cloud/zookeeper02/bin
    ./zkServer.sh stop

    cd /usr/local/solr-cloud/zookeeper03/bin
    ./zkServer.sh stop
  • 相关阅读:
    Jackson Annotation Examples
    Java 8 Stream API说明
    Spring Enable* 注解
    1568: [JSOI2008]Blue Mary开公司
    BZOJ1558: [JSOI2009]等差数列
    BZOJ3155: Preprefix sum
    BZOJ4552 [Tjoi2016&Heoi2016]排序
    BZOJ4653 [Noi2016]区间
    BZOJ4487 [Jsoi2015]染色问题
    Luogu2664 树上游戏
  • 原文地址:https://www.cnblogs.com/chenmingjun/p/10013389.html
Copyright © 2020-2023  润新知