tomcat基础介绍和配置详解

tomcat企业级Web应用服务器配置与实战

  环境背景:公司业务经过长期发展,有了很大突破,已经实现盈利,现公司要求加强技术架构应用功能和安全性以及开始向企业应用、移动APP等领域延伸,此时原来开发web服务的php语言已经不适应新的场景,需要上java技术架构,现要求你根据公司需要,实现基于java平台的web应用服务选型、搭建、实现和应用,此时你如何选择?

实战一:在linux上安装tomcat

1、下载安装java所需要的环境和开发工具包

(1)Java 所需要的环境和开发工具包介绍

JRE: Java Runtime Environment

JDK:Java Development Kit JRE

JRE顾名思义是java运行时环境,包含了java虚拟机,java基础类库。是使用java语言编写的程序运行所需要的软件环境,是提供给想运行java程序的用户使用的。

JDK顾名思义是java开发工具包,是程序员使用java语言编写java程序所需的开发工具包,是提供给程序员使用的。JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。如果你需要运行java程序,只需安装JRE就可以了。如果你需要编写java程序,需要安装JDK。JRE根据不同操作系统(如:windows,linux等)和不同JRE提供商(IBM,ORACLE等)有很多版本,最常用的是Oracle公司收购SUN公司的JRE版本。

(2)安装相应版本的rpm包 jdk-VERSION-OS-ARCH.rpm(centos自带的jdk包)

[root@centos-7 ~]# yum install java-1.8.0-openjdk  -y

(3)使用Oracle官网的JDK 8的rpm安装 

官方下载JDK地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

[root@centos-7 ~]#  yun install jdk-8u211-linux-x64.rpm -y

java配置全局

[root@centos-7 ~]# vim /etc/profile.d/jdk.sh 
export JAVA_HOME=/usr/java/default
export PATH=$JAVA_HOME/bin:$PATH

[root@centos-7 ~]# . /etc/profile.d/jdk.sh

查看jdk版本

[root@centos-7 ~]# java -version
java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)

2、下载安装tomcat

方法一:二进制安装(推荐)

(1)从官网下载tomcat二进制安装包 http://tomcat.apache.org/

下载路径:https://archive.apache.org/dist/tomcat/

(2)解包,设置目录

① 解包

[root@centos-7 ~]# tar xvf  apache-tomcat-8.5.42.tar.gz  -C /usr/local

② 为了方便管理,设置软连接,若以后换版本了,可以很容易切换

[root@centos-7 local]# ln -s /usr/local/apache-tomcat-8.5.42/  /usr/local/tomcat 

 

 (3)启动tomcat服务

[root@centos-7 bin]# cd  /usr/local/tomcat/bin #切换到bin目录下
[root@centos-7 bin]# ./startup.sh   #启动tomcat服务
Using CATALINA_BASE:   /usr/local/tomcat
Using CATALINA_HOME:   /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME:        /usr/java/default
Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Tomcat started.
[root@centos-7 bin]# ss -nlt  #查看此时的8080端口是否打开
State       Recv-Q Send-Q                           Local Address:Port                                          Peer Address:Port              
LISTEN      0      100                                  127.0.0.1:25                                                       *:*                  
LISTEN      0      32                              192.168.43.100:1194                                                     *:*                  
LISTEN      0      128                                          *:22                                                       *:*                  
LISTEN      0      100                                      [::1]:25                                                    [::]:*                  
LISTEN      0      1                           [::ffff:127.0.0.1]:8005                                                  [::]:*                  
LISTEN      0      100                                       [::]:8009                                                  [::]:*                  
LISTEN      0      100                                       [::]:8080                                                  [::]:*                  
LISTEN      0      128                                       [::]:22                                                    [::]:*                  

另外一种启动tomcat服务的方法:

#cd  /usr/local/tomcat/bin   #切换到此目录下启动tomcata服务
# ./catalina.sh --help
[root@centos-7 bin]# ./catalina.sh version   #查看此时的版本
Using CATALINA_BASE: /usr/local/tomcat
Using CATALINA_HOME: /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME: /usr/java/default
Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Server version: Apache Tomcat/8.5.42
Server built: Jun 4 2019 20:29:04 UTC
Server number: 8.5.42.0
OS Name: Linux
OS Version: 3.10.0-1062.el7.x86_64
Architecture: amd64
JVM Version: 1.8.0_211-b12
JVM Vendor: Oracle Corporation

# ./catalina.sh start  #启动tomcata服务
# ./catalina.sh stop   #停止tomcata服务

(4)为了tomcat服务安全起见,最好不要用root用户登录,防止被破解之后存在安全隐患,建议自己新建一个普通用户进行登录

[root@centos-7 bin]# useradd -r java   #创建一个系统账号,此时就没有家目录
[root@centos-7 ~]# chown -R java.java /usr/local/tomcat/  #将tomcat目录下的文件所有者和所属组都进行修改
[root@centos-7 ~]# su - java -c /usr/local/tomcat/bin/startup.sh  #以java用户形式进行启动tomcat服务

 (5)查看此时启动的服务是以java用户进行启动的

  

方法二:yum安装tomcat包

(1)yum安装tomcat包(版本较低)

# yum install tomcat -y #安装tomcat主程序
# yum install -y tomcat-admin-webapps  tomcat-webapps  #安装tomcat对应的页面

(2)启动tomcat服务

[root@centos-7 ~]# systemctl start tomcat

(3)查看端口,默认是8080端口

  

查看此时访问的tomcat页面:

   

 在默认主目录下添加一个文件此,优先级顺序是index.html、index.htm、index.jsp,由大到小排序:

[root@centos-7 ROOT]#cd  /usr/share/tomcat/webapps/ROOT #主站点程序都放在此目录下
[root@centos-7 ROOT]# cat index.html
<h>hello!</>

  启动tomcat服务:systemctl start tomcat 

 由于没有index.htm文件,此时优先就访问index.html文件。

 

想要看到index.jsp页面,将URL路径补全即可,此时点开jsp结尾的网页,会显示比较慢,那么访问网页慢的原因是什么呢?

答:是因为此时的jsp页面需要转换为二进制的字节码,再将二进制的字节码转换为.class后缀的文件,,最后才会显示网页,当第二次点击时,就不再需要jsp文件;

需要解决第一次点击慢的过程,需要一个执行第一次点击网页的自动化运行脚本,会为自己将所有的链接都去点击一遍。

 

 3、目录结构

 编译的二进制tomcat文件,默认访问网页的路径:/usr/local/tomcat/webapps/ROOT/

 

 4、配置文件

 

 5、组件分类

顶级组件

Server,代表整个Tomcat容器

服务类组件

Service,组织Engine和Connector,里面只能包含一个Engine

连接器组件

Connector,有HTTP、HTTPS、A JP协议的连接器

容器类

Engine、Host、Context都是容器类组件,可以嵌入其它组件,内部配置如何运行应用程序。

内嵌类

可以内嵌到其他组件内,valve、logger、realm、loader、manager等。以logger举例,在不同容器组件内定义。

集群类组件

listener、cluster

Tomcat内部组成 

由上述组件就构成了Tomcat,如下图

名称 说明
Server tomcat的进程示例
Connector 负责客户端的HTTP/HTTPS/AJP等协议的连接,一个Connter只属于一个Engine
Service 用来组织Connter和Engine之间的关系
Engine 响应并处理用户请求。一个引擎可以绑定多个Connter。
Host 虚拟主机
Context 应用的上下文,配置路径映射path=>directory

AJP(Apache Jserv protocol)是一种基于TCP的二进制通讯协议。

核心组件  

(1)Tomcat启动一个Server进程。可以启动多个Server,但一般只启动一个。

(2)创建一个Service提供服务。可以创建多个Service,但一般也只创建一个。

  • 每个Service中,是Engine和其连接器Connector的关联配置

(3)可以为这个Server提供多个连接器Connector,这些Connector使用了不同的协议,绑定了不同的端口。其作用就是处理来自客户端的不同的连接请求或响应。

(4)Service内部还定义了Engine,引擎才是真正的处理请求的入口,其内部定义多个虚拟主机Host。

  • Engine对请求头做了分析,将请求发送给相应的虚拟主机
  • 如果没有匹配,数据就发往Engine上的defaultHost缺省虚拟主机
  • Engine上的缺省虚拟主机可以修改

(5)Host定义虚拟主机,虚拟主机有name名称,通过名称匹配

(6)Context定义应用程序单独的路径映射和配置

举例:

假设来自客户的请求为:http://localhost:8080/test/index.jsp

(1)浏览器端的请求被发送到服务端端口8080,Tomcat进程监听在此端口上。通过侦听的HTTP/1.1 Connector获得此请求。

(2)Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的响应

(3)Engine获得请求localhost:8080/test/index.jsp,匹配它所有虚拟主机Host。

(4)Engine匹配到名为localhost的Host。即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机

(5)localhost Host获得请求/test/index.jsp,匹配它所拥有的所有Context

(6)Host匹配到路径为/test的Context,Context里边可以定义不同的应用程序,交给这些应用程序去处理,最后拿到响应,响应报文直接通过connect返回给客户端。

(7)path=/test的Context获得请求/index.jsp,在它的mapping table中寻找对应的servlet(到此可以结束,后面都是开发的过程)

(8)Context匹配到URL PATTERN为*.jsp 的servlet,对应于JspServlet类构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法。

(9)Context把执行完了之后的HttpServletResponse对象返回给Host

(10)Host把HttpServletResponse对象返回给Engine

(11)Engine把HttpServletResponse对象返回给Connector

(12)Connector把HttpServletResponse对象返回给浏览器端

应用部署  

根目录

Tomcat中默认网站根目录是CATALINA_BASE/webapps/(/usr/local/tomcat/webapps  软连接的主站点根目录)

在Tomcat中部署主站应用程序和其他应用程序,和之前WEB服务程序不同。

nginx

  1. 假设在nginx中部署2个网站应用eshop、bbs,假设网站根目录是/var/www/html,那么部署可以是这样的。
  2. eshop解压缩所有文件放到/var/www/html/目录下。
  3. bbs的文件放在/var/www/html/bbs下。

Tomcat

  1. Tomcat中默认网站根目录是CATALINA_BASE/webapps/
  2. 在Tomcat的webapps目录中,有个非常特殊的目录ROOT,它就是网站默认根目录。
  3. 将eshop解压后的文件放到这个ROOT中。
  4. bbs解压后文件都放在CATALINA_BASE/webapps/bbs目录下。
  5. 每一个虚拟主机的目录都可以使用appBase配置自己的站点目录,里面都可以使用ROOT目录作为主站目录。

JSP WebApp目录结构  

  1. 主页配置:一般指定为index.jsp或index.html
  2. WEB-INF/:当前WebApp的私有资源路径,通常存储当前应用使用的web.xml和context.xml配置文件
  3. META-INF/:类似于WEB-INF
  4. classes/:类文件,当前webapp需要的类
  5. lib/:当前应用依赖的jar包

实验

默认情况下,/usr/local/tomcat/webapps/ROOT/下添加一个index.html文件,观察访问到了什么?

将/usr/local/tomcat/conf/web.xml中的下面<welcome-file-list>标签内容(默认页),复制到/usr/local/tomcat/webapps/ROOT/WEB-INF/web.xml中,如下

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1"
  metadata-complete="true">

  <display-name>Welcome to Tomcat</display-name>
  <description>
     Welcome to Tomcat
  </description>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>  #将jsp后缀的文件放在最上面
        <welcome-file>index.htm</welcome-file> 
        <welcome-file>index.html</welcome-file> #将html后缀文件放在最后面
    </welcome-file-list>
</web-app>

修改完以上配置文件,需要重启tomcata服务,默认访问网站的优先级是:html、htm、jsp后缀的文件,所以将jsp文件放在最前面,此时就是个缺省路径,默认访问jsp网页,不需要指定jsp的URL全路径,查看访问网页效果

 

 webapp归档格式

  1. .war:WebApp打包
  2. .jar:EJB类打包文件
  3. .rar:资源适配器类打包文件
  4. .ear:企业级WebApp打包 

传统,应用开发测试后,通常打包为war格式,这种文件部署到了Tomcat的webapps下,还可以自动展开。

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">

部署Deploy  

1、部署:将webapp的源文件放置到目标目录,通过web.xml和context.xml文件中配置的路径就可以访问该webapps,通过类加载器加载其特有的类和依赖的类到JVM上,生产中我们用的是冷部署方式。

(1)自动部署Auto Deploy:Tomcat发现多了这个应用就把它加载并启动起来

(2)手动部署

冷部署:将webapp放到指定目录,才去启动Tomcat
热部署:Tomcat服务不停止,需要依赖工具manager、ant脚本、tcd(tomcat client deployer)等

2、反部署undeploy:停止webapp的运行,并从JVM上清除已经加载的类,从Tomcat实例上卸载掉webapp

3、启动start:是webapp能够访问

4、停止stop:webapp不能访问,不能提供服务,但是JVM并不清除它

实验

1、先创建一个存放页面的目录

[root@centos-7 ~]# mkdir /projects/myapp/{WEB-INF,classes,lib}  -pv
mkdir: created directory ‘/projects’
mkdir: created directory ‘/projects/myapp’
mkdir: created directory ‘/projects/myapp/WEB-INF’
mkdir: created directory ‘/projects/myapp/classes’
mkdir: created directory ‘/projects/myapp/lib’

2、在新建的/projects/myapp/目录下新建一个index.jsp文件。

vim  /projects/myapp/index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
        <meta charset="utf-8">
        <title>jsp例子</title>
</head>
<body>
myapp-index.jsp 后面的内容是服务器端动态生成字符串,最后拼接在一起   #显示的效果是这行内容
<%
out.println("hello jsp");
%>
</body>
</html>

3、将新建的index.jsp文件存放在/usr/local/tomcat/webapps目录下:

[root@centos-7 ~]# cp -r /projects/myapp/  /usr/local/tomcat/webapps/

4、查看网页显示效果:

 

 配置详解

vim  /usr/local/tomcat/conf/service.xml

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
   <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t "%r" %s %b" />

      </Host>
    </Engine>
  </Service>
</Server>>

SHUTDOWN详解:

<Server port="8005" shutdown="SHUTDOWN">

8005是Tomcat的管理端口,默认监听在127.0.0.1上。SHUTDOWN这个字符串接收到后就会关闭此Server。 

# telnet 127.0.0.1 8005
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
SHUTDOWN

为安全起见:这个管理功能建议禁用,改shutdown为一串猜不出的字符串。

<Server port="8005" shutdown="44ba3c71d57f494992641b258b965f28">

创建一个用户管理界面账号

创建manager-gui角色

用户认证,配置文件是/usr/local/tomcat/conf/tomcat-users.xml。  

打开tomcat-users.xml,我们需要一个角色manager-gui

<tomcat-users xmlns="http://tomcat.apache.org/xml"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
              version="1.0">
<role rolename="manager-gui"/>   #主要加入此行,添加的用户名为tomcat
<user username="tomcat" password="tomcat" roles="manager-gui"/> #主要加入此行,添加的用户密码是tomcat

</tomcat-users>

 

 Tomcat启动加载后,这些内容是常驻内存的。如果配置了新的用户,需要重启Tomcat。

访问192.168.7.100:8080/manager/管理页面时,此时就会报403,身份验证错误,但是提示中告诉去manager的context.xml中修改

 修改配置文件路径:/usr/local/tomcat/webapps/manager/META-INF/context.xml:

可以在后面追加一个全路径的IP地址,或者是直接192.*即可:

allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1|192\.168\.\d+\.\d+"

 

 重新启动tomcat服务:

# /usr/local/tomcat/bin/shutdown.sh
# /usr/local/tomcat/bin/start.sh

  再访问网页时,就会显示用户登录:

 

 输入新建的账号和密码,此时就能访问管理界面:

用户账号:tomcat

用户密码:tomcat

 

 创建admin-gui角色

 1、如法炮制,与上面类似,但是我们需要进入到host-manager文件中进行修改里边的conttext.xml文件,在配置文件中添加本地的IP地址的正则表达式,允许本地的IP地址进行管理

# vim /usr/local/tomcat/webapps/host-manager/META-INF/context.xml

# allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1|192.*" />

修改配置文件,添加admin-gui新角色:

[root@centos-7 conf]# vim /usr/local/tomcat/conf/tomcat-users.xml
<role rolename="admin-gui"/> #添加一个角色admin-gui
<role rolename="manager-gui"/>
<user username="tomcat" password="tomcat" roles="manager-gui,admin-gui"/> #逗号后面添加admin-gui

 

重启tomcat服务:

[root@centos-7 tomcat]# bin/shutdown.sh 
[root@centos-7 tomcat]# bin/startup.sh 

 查看此时的端口是否打开:8009和8080端口

此时已经可以登录到host-manager管理界面:

 

service配置: 

vim  /usr/local/tomcat/conf/server.xml文件中查看此时的service服务名称:

一般情况下,一个Server实例配置一个Service,name属性相当于该Service的ID。

<Service name="Catalina">

连接器配置:

redirectPort,如果访问HTTPS协议,自动转向这个连接器。但大多数时候,Tomcat并不会开启HTTPS,因为Tomcat往往部署在内部,HTTPS性能较差。

<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />

引擎配置:

<Engine name="Catalina" defaultHost="localhost">  

defaultHost指向内部定义某虚拟主机。缺省虚拟主机可以改动,默认localhost。  

虚拟主机配置:

name必须是主机名,用主机名来匹配。
appBase,当期主机的网页根目录,相对于CATALINA_HOME,也可以使用绝对路径
unpackWARs是否自动解压war格式
autoDeploy 热部署,自动加载并运行应用

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">

虚拟主机配置实验  

1、修改主配置文件,添加域名解析的目录

[root@centos-7 ROOT]# vim /usr/local/tomcat/conf/server.xml 
      </Host>
     <Host name="node1.baidu.com" appBase="/data/webapps/" unpackWARs="True" autoDeploy="false" />   #指定域名和要访问的文件路径
    </Engine>

 

2、创建一个访问文件的目录,并在指定的目录下创建ROOT目录,将上面创建的myapp目录文件复制过来:

[root@centos-7 ROOT]# mkdir /data/webapps/ -p
[root@centos-7 webapps]# cp -r /usr/local/tomcat/webapps/myapp/ /data/webapps/ROOT

3、修改/data/webapps/ROOT目录下的文件,修改为自己要访问到的页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
        <meta charset="utf-8">
        <title>jsp例子</title>
</head>
<body>
node1.baidu.com-index.jsp 后面的内容是服务器端动态生成字符串,最后拼接在一起  #修改此处的域名地址
<%
out.println("hello jsp");
%>
</body>
</html>

4、重启tomcat服务:

[root@centos-7 tomcat]# bin/shutdown.sh 
Using CATALINA_BASE:   /usr/local/tomcat
Using CATALINA_HOME:   /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME:        /usr/java/default
Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
[root@centos-7 tomcat]# bin/startup.sh 
Using CATALINA_BASE:   /usr/local/tomcat
Using CATALINA_HOME:   /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME:        /usr/java/default
Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Tomcat started.

5、在本地hosts配置文件中将IP地址进行域名解析为node1.baidu.net:C:\Windows\System32\drivers\etc目录下修改

  

6、访问网页进行测试:

 Context配置

Context作用:

  • 路径映射
  • 应用独立配置,例如单独配置应用日志、单独配置应用访问控制
<Context path="/test" docBase="/data/test" reloadable="" />

1、path指的是访问的路径

2、docBase,可以是绝对路径,也可以是相对路径(相对于Host的appBase)

3、reloadable,true表示如果WEB-INF/classes或META-INF/lib目录下.class文件有改动,就会将WEB应用重新加载。

4、生成环境中,会使用false来禁用。

实验:

1、将前面创建好的myapp目录复制到data目录下并起名为myappv1,并且创建一个软连接

[root@centos-7 data]# cp -r /usr/local/tomcat/webapps/myapp  /data/myappv1
[root@centos-7 data]# ln -s myappv1/ test

2、修改/data/myappv1中的index.jsp配置文件

# vim /data/myappv1/index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
        <meta charset="utf-8">
        <title>jsp例子</title>
</head>
<body>
myappv1-test.jsp 后面的内容是服务器端动态生成字符串,最后拼接在一起  #修改问网页要显示的页面
<%
out.println("hello jsp");
%>
</body>
</html> 

3、修改tomcat配置文件

vim  /usr/local/tomcat/conf/server.xml  

      </Host>
     <Host name="node1.baidu.com" appBase="/data/webapps/" unpackWARs="True" autoDeploy="false" >  #创建在配置文件下面就不能封口
    <Context path="/test" docBase="/data/test" reloadable="" />  #指定当前要访问的文件目录路径,写完需要封口/
   </Host> 
   </Engine>
  </Service>
</Server>

 

访问网页测试:http://node1.baidu.com:8080/test/

  

注意:这里特别使用了软链接,原因就是以后版本升级,需要将软链接指向myappv1,重启Tomcat。如果新版上

线后,出现问题,重新修改软链接到上一个版本的目录,并重启,就可以实现回滚。

  

  

  

  

  

  

  

  

 

猜你喜欢

转载自www.cnblogs.com/struggle-1216/p/12175446.html