JavaWeb开发内幕

来源:互联网 发布:淘宝品牌销售排行 编辑:程序博客网 时间:2024/05/17 20:00

声明:

如果引用或借鉴本书稿中的图例、解说和讲解技巧,请标明出处,以示对我的辛勤劳动的尊重!这些东西虽然谈不上创造发明,但确实也是花费了我很多时间和精力去总结、归纳出来的。如果有人等我总结、消化后再“巧妙借鉴”,精华和核心全部拿走,然后在随便从书上找到别的知识作补充,以示区别的行为将会极大挫伤我的积极性,希望网友们从道义上对这种行为进行谴责!因涉及商业机密和出版合同,本书中的一些最富有技巧的知识和讲解手法没有提供出来,敬请谅解!

                            ————张孝祥

1 XML基础

XML作为一种通用的数据交换格式,应用越来越广泛。目前许多系统的配置文件都使用XML格式,本书中所涉及到的众多配置文件都是XML格式的,新的JSP规范也推出了采用XML语法的JSP文档,因此,要深入学习和掌握Java Web开发技术,必须有一些基本的XML语言知识。由于XML的通用性和广泛应用,在读者以后实际项目开发和应用中,很多地方都要用到XML方面的知识,所以,对XML知识的了解和掌握,已经是从事电子商务网站和相关系统开发的编程人员所必须掌握的基本知识。

F指点迷津:什么是配置文件

配置文件就是记录应用程序的配置信息的文件。例如,某个程序要连接网络上的数据库系统时,需要指定数据库服务器的ip地址、服务器的网络监听端口号、数据库的名称、用户名和密码等信息,这些信息可以作为应用程序的配置信息来对待,即不要将这些信息写死在源程序中,而是写在一个文本文件中。应用程序要连接数据库系统时,从该文本文件中读取所需要的信息,如果连接的数据库系统的信息发生了改变,则只需要修改该文本文件,而不用修改源程序,这个文本文件就是应用程序的配置文件。传统的配置文件通常采用如下格式:

#Db.Properties

DBServer=192.168.0.100

Port=1443

Database=emp

Username=zxx

Password=123

上面这种格式的配置文件只能表述一些简单的信息,而很难表达具有层次结构和数据项目要动态增加的信息。例如,如果要在一个文件中表达出“一个国家中的每个省及省长的名称、每个省下面的每个市及市长的名称、每个市下面的每个镇及镇长名称”,使用上面的格式就很难表达。采用XML格式的配置文件很容易表达出这种层次结构,具体细节请参看本章后面部分的讲解。

1.2.1 文档声明

在一个完整的XML文档中必须包含一个XML文档声明,该声明必须位于文档的第一行。这个声明表示该文档是一个XML文档,以及遵循的是哪个XML版本的规范。最简单的XML文档声明语法如下:

<?xml version="1.0" ?>

在“<”和“?”之间、“?”和“>”之间以及第一个“?”和xml之间不能有空格,这就是XML语法严格性的一个体现。在第二个“?”之前可以没有、也可以有一个或多个空格。声明语句中的version属性表示XML的版本,因为解析器对不同的版本的解析肯定会有区别,尽管目前只有1.0版本,但在声明中必须指定version属性。

由于人们可以采用不同的字符编码集来书写一个字符内容完全相同的XML文档,所以,XML软件工具(包括分析器)就需要知道该XML文档所使用的字符编码方式。这可以通过在XML文档声明中指定encoding属性来说明,例如,使用下面的语句来指明文档中的字符编码方式为GB2312编码。

       <?xml version="1.0" encoding="GB2312" ?>

W3CXML1.0规范里规定,所有的XML解析器必须接受UTF-8UTF-16编码的Unicode字符,所以,符合 XML 规范的软件工具一定都支持这两种Unicode编码。如果XML声明中没有设置encoding属性来明确指定文档所用的字符编码方式,则一律以Unicode编码看待。XML解析器通过寻找XML文档开始处的字节顺序标记,能够自动检测出文档中的Unicode编码是UTF8,还是UTF16。也就是说,encoding属性默认的设置是Unicode编码,如果文档中的字符是以UTF-8或者是UTF-16作为编码,则可以不设置这个属性。

XML文档声明语句中,还可以指定另外一个可选属性:standalone,例如:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>

standalone属性用于说明文档是否是独立的,如果将其设置为“yes”,则表示该文档没有依赖外面的任何文件而可以独立存在,即不需要DTD文件来验证其中的标识是否有效,也不需要XSLCSS文件来控制其显示外观;将standalone属性设置为“no”时,则表示该文档依赖于外面的某个文件,例如,依赖于某个DTD文件或XSLCSS文件。standalone属性的默认值为“yes”。

注意:如果同时设置了encodingstandalone属性,standalone属性要位于encoding属性之后。

:动手体验:加深对encoding属性的理解

对于含有中文字符的XML,其中的字符可以采用unicode来编码或GB2312(简体中文字符编码)编码来表示,如果文档中的字符使用的是GB2312编码,则必需设置为encoding属性为GB2312,下面通过一个实验来说明这个问题。

1)用Windows自带的记事本程序创建一个名为book.xml的文件,文件内容如例程1-1所示。

例程1-1  book.xml

 


 

<?xml version="1.0" ?>

<书架>

    <>

        <书名>Java就业培训教程</书名>

        <作者>张孝祥</作者>

        <售价>39.00</售价>

    </>

    <>

        <书名>JavaScript网页开发</书名>

        <作者>张孝祥</作者>

        <售价>28.00</售价>

    </>

</书架>

 

 


 

2)用IE5.0以上的浏览器打开book.xml文件,看到的结果如图1.2所示。

1.2

错误提示的信息是“文本内容中发现无效字符”,这就是因为在book.xmlXML文档声明语句中没有明确指定文档中的字符编码方式,浏览器就会用默认的Unicode编码来解析该文档,而该文档中的字符实际上使用的是GB2312编码,而非Unicode编码。

3)单击浏览器的“查看”à“源文件”菜单,将打开的book.xml文件内容中的第一行修改成如下形式:

    <?xml version="1.0" encoding="GB2312" ?>

保存修改后,刷新显示book.xml文件的浏览器窗口,看到的结果如图1.3所示。单击某个标签前面的减号(-),嵌套在该标签中的所有内容将被折叠起来,标签前面的减号(-)也将变成加号(+)。单击某个标签前面的加号(+),嵌套在该标签中的所有内容将被展开,标签前面的加号(+)也将变成减号(-)。

1.3

4)在上面打开book.xml文件的记事本程序中,单击“文件”à“另存为”菜单,在打开的“另存为”对话框中,选择“保存类型”为“所有文件”,编码为“UTF-8”,如图1.4所示。

1.4

UTF-8编码保存book.xml文件后,尽管在记事本程序窗口中显示的效果没有任何变化,但是book.xml文件内部存储的数据已经改变,这通过比较book.xml保存前后的文件大小就可以看出来。刷新显示book.xml文件的浏览器窗口,看到的结果如图1.5所示。

1.5

因为现在的book.xml文件的字符编码已经转换为UTF-8,而文档的起始声明中指定encoding属性为GB2312,所以,浏览器在解析book.xml文件时会发生错误。

5)将book.xml文档起始声明的encoding属性修改为UTF-8,保存后刷新显示book.xml文件的浏览器窗口,就又可以看到类似图1.3所示的正常显示效果了。

2 Tomcat构建WEB站点

2.1.3 网站系统的组成

只要在一台计算机上安装了WEB服务器软件,从功能上讲,这台计算机就可以称为WEB服务器。一个网站的规模可大可小,功能可多可少,最简单的网站只需要一台Web服务器即可对外提供网页浏览服务。复杂的网站包括多台WEB服务器组成的群集系统、负载均衡设备、具有缓存功能的代理服务器(可以有多级,甚至包括放置在服务器端的缓存系统)、数据库系统等,如图2.2所示。

2.2

www.sina.com网站系统采用的基本上就是图2.2所示的架构,不同地区的人们在访问www.sina.com站点时,浏览器实际上所访问的服务器是不一样的,例如,吉林省的用户访问的服务器实际是sina放在吉林地区的代理服务器,湖北省的用户访问的服务器实际是sina放在湖北地区的代理服务器。各地区的浏览器访问www.sina.com站点的过程如图2.3所示。

2.3

为了能够让浏览器透明地访问到WEB站点,让用户感觉不到是在访问区域代理服务器,在DNS系统中需要将www.sina.com主机名指向所有的区域代理服务器的IP地址。在浏览器访问www.sina.com站点中的页面而向DNS服务器请求解析www.sina.com主机名时,DNS服务器根据访问者的地理位置信息返回他附近的区域代理服务器的IP地址,这样,浏览器的访问请求将发送给该区域代理服务器。只有当区域代理服务器中没有浏览器要访问的页面时,区域代理服务器才去从真正的www.sina.com站点服务器上获取该页面并进行缓存,以后该区域的其他浏览器就都可以就近从区域代理服务器中访问到该页面了,从而大大提高了访问效率和减少了网络流量。

2.5.3 基于主机名的虚拟主机

WEB浏览器与WEB服务器建立连接后,除了将请求URL中的资源路径发送给WEB服务器外,还会将URL中的主机名部分作为HTTP请求消息的Host头发送给WEB服务器。例如,在浏览器地址栏中输入http://www.it315.org,浏览器发送给www.it315.org主机上的WEB服务器的请求消息内容如下:

       GET  /  HTTP/1.1<回车>

       Host:  www.it315.org<回车>

       <回车>

WEB服务器接收到浏览器的访问请求消息后,根据Host头字段中所设置的主机名,就知道该选择哪个WEB站点来进行响应,因此,可以使用不同的主机名来作为区分同一个WEB服务器上的不同站点的标识信息。

TomcatServer.xml配置文件中有一个<Host>元素,一个<Host>元素用于建立一个WEB站点,使用多个<Host>元素则可以建立多个WEB站点。<Host>元素的父级元素为<Engine>元素,嵌套在同一个<Engine>元素中的多个<Host>元素的name属性不能相同,<Host>元素的name属性指定WEB站点所对应的主机名称。TomcatServer.xml配置文件中初始设置的<Host>元素内容如下:

<Host name="localhost" appBase="webapps" …>

</Host>

<Host>元素中的appBase属性指定了一个路径,该路径将作为嵌套在它里面的<Context>元素的docBase属性中设置的相对路径的基准路径。

Tomcat接收到访问请求时,将比较请求消息中的Host头字段的值与<Host>元素的name属性值,并以匹配的<Host>元素所创建的WEB站点来响应。如果Server.xml文件中没有与请求消息的Host头字段匹配的<Host>元素,Tomcat将以默认的WEB站点来响应。只要<Engine>元素的defaultHost属性设置为嵌套在它里面的某个<Host>元素的name属性值,该<Host>元素所创建的WEB站点就成了该引擎的默认WEB站点。例如,TomcatServer.xml文件中的<Engine>元素的默认设置如下:

<Engine name="Standalone" defaultHost="localhost" debug="0">

       <Host name="localhost" appBase="webapps" …>

      

       </Host>

</Engine>

上面的这段配置信息说明,该引擎的默认WEB站点为嵌套在<Engine>元素中的name属性为“localhost”的<Host>元素所创建的WEB站点。

在同一台计算机上建立了多个基于主机名的虚拟主机后,WEB浏览器要访问其中的某个虚拟主机的资源时,在访问URL中必须采用主机名,而不能采用IP地址。这是因为WEB浏览器要将URL中的主机名部分作为HTTP请求消息的Host头发送给WEB服务器,如果URL中的主机名部分使用的是IP地址,那么,浏览器发出的请求消息中的Host头字段的值就是这个IP地址,而在同一台计算机上建立的多个基于主机名的虚拟主机共享同一个IP地址,在Host头字段使用IP地址根本就无法区分不同的站点。

即使在URL中指定的是主机名时,WEB浏览器还是要先获得该主机名所对应的IP地址,然后再使用这个IP去连接WEB服务器。所以,在建立基于主机名的虚拟主机时,除了要在Tomcatserver.xml文件中进行设置外,还需要在整个网络系统中建立主机名与IP地址的映射关系,即必须将主机名添加到名称解析系统,以便WEB浏览器能够从名称解析系统中查询出主机名所对应的IP地址。建立主机名与IP地址的映射关系的惯用方式有两种:一是使用客户机本地的Hosts 文件,二是使用DNS(Domain Name System,域名系统)服务器。Hosts 文件和DNS的作用都是允许用户使用“友好”的、文本格式的主机名称,而不是数字格式的IP地址来访问网络中的计算机。Hosts文件可用于小型的Intranet(企业内部网),网络中的所有计算机上都需要使用Hosts文件。DNS通常用于大型的网络,特别是Internet上对外提供服务的计算机都是通过DNS来建立其主机名与IP地址的映射关系。客户机首先在本地的Hosts文件中查找主机名称所映射的IP地址,如果没有找到,再去查询DNS服务器。为了简单起见,这里仅介绍一下Hosts文件。对于Windows 2000系统,Hosts 文件位于操作系统根目录(取决操作系统所在的分区,通常是c:/winnt)下的System32/Drivers/Etc子目录中,默认情况下,该文件中有如下一行内容:

       127.0.0.1       localhost

这行文本的作用就是将IP地址(127.0.0.1)映射成主机名(localhost),这也就是在IE浏览器地址栏中可以使用localhost访问本地WEB服务器的原因。如果要增加更多的主机名与IP地址的映射,可以在Hosts文件中增加更多的行,然后参照上面这行内容的格式在每行中填写IP地址和相应的主机名。

:动手体验:使用Tomcat建立基于主机名的虚拟主机

1)用UltraEdit打开<Tomcat主目录>/conf目录下的Server.xml文件,使用“查找”菜单查找内容为“</Host>”的行,紧接该行下面增加一对<Host></Host>标签。参照前面的<Host>标签的属性设置情况,设置新增的<Host>标签的属性,并在它里面嵌套一个设置该WEB站点根目录的<Context>元素,最终的内容如下:

       <Host name="site1" debug="0" appBase="d:/VirtualHost1">

              <Context path="" docBase="." debug="0"/>

       </Host>

这样,将创建一个新的WEB站点。上面的<Context>元素的docBase属性值被设置为一个点(.),即表示使用<Host>元素的appBase属性中所设置的路径作为这个<Context>所映射的目录。

2)在上面新增的<Host></Host>标签对下面再增加一对<Host></Host>标签,并将它设置为如下形式:

       <Host name="site2" debug="0" appBase="d:/VirtualHost2">

              <Context path="" docBase="." debug="0"/>

       </Host>

这又创建了一个新的WEB站点,该站点的主机名称为site2,根目录对应的本地文件系统目录为d:/VirtualHost2

3)在d:盘下创建名称为VirtualHost1VirtualHost2两个目录,并在这两个目录中分别创建一个名为test.html的文件,在d:/VirtualHost1/test.html文件中写入如下一行内容:

    这是d:/VirtualHost1目录中的test.html文件

d:/VirtualHost2/test.html文件中写入如下一行内容:

    这是d:/VirtualHost2目录中的test.html文件

4)保存修改后的Server.xml文件,重新启动Tomcat WEB服务器程序。打开一个新的命令行窗口中,并在这个命令行窗口中执行如下命令:

telnet 127.0.0.1 8080

接着在连接成功的telnet程序命令窗口中,输入如下内容:

       GET /test.html HTTP/1.1<回车>

       Host:<空格>site1<回车>

       <回车>

这时在telnet程序窗口中可以看到,WEB服务器返回内容的正文部分为d:/VirtualHost1/test.html文件中的内容。接着WEB服务器返回内容的下边,输入如下内容:

       GET /test.html HTTP/1.1<回车>

       Host:<空格>site2<回车>

       <回车>

telnet程序窗口中又可以看到,WEB服务器这次返回内容的正文部分为d:/VirtualHost2/test.html文件中的内容。接着WEB服务器返回内容的下边,输入如下内容:

       GET /test.html HTTP/1.1<回车>

       Host:<空格><回车>

       <回车>

telnet程序窗口中又可以看到,WEB服务器这次返回内容的正文部分为d:/test/test.html文件中的内容。接着WEB服务器返回内容的下边,再次输入如下内容:

       GET /test.html HTTP/1.1<回车>

       Host:<空格>xxx<回车>

       <回车>

telnet程序窗口中又可以看到,WEB服务器这次返回内容的正文部分仍然为d:/test/test.html文件中的内容。

上面的整个交互过程如图2.34所示,Tomcat根据第1次和第2次请求中所指定Host头的值,查找Server.xml文件中与之相匹配的<Host>元素的name属性值,并以匹配的<Host>元素所设置的WEB站点来响应;在第3次和第4次请求中所指定Host头的值,在Server.xml文件中没有与之对应的<Host>元素的name属性值,Tomcat将以默认的WEB站点来响应。

2.34

5)在Windows 2000系统中,用记事本程序打开c:/winnt/System32/Drivers/Etc/Hosts文件,可以看到有如下一行内容:

       127.0.0.1       localhost

紧接这行文本的下面,用它复制出两行文本,并将这两行文本中的localhost分别修改成site1site2,这样,就使用Hosts文件为当前计算机设置了多个主机名。如果要用site1site2这个两主机名访问其他计算机上的WEB站点,则应将127.0.0.1修改成其他计算机的实际IP地址。保存Hosts文件后,在命令行窗口中执行“ping site1”和“ping site2”命令,查看该主机名是否被正确解析到了相应的IP地址上。建立site1site2与计算机IP地址的映射后,在IE浏览器地址栏中输入http://localhost:8080/test.htmlhttp://site1:8080/test.htmlhttp://site2:8080/test.html,可以看到浏览器将显示出各自站点中的test.html网页文件的内容。

 

可见,使用主机名的方式在同一台WEB服务器上创建多个虚拟主机后,在WEB浏览器中使用主机名访问Web服务器时,Web服务器将选择与该主机名关联的WEB站点进行响应。通过这种方式,多个WEB站点可以共享同一个IP地址和相同的端口号,唯一不足的就是WEB浏览不能通过IP地址去访问这些WEB站点。基于主机名的虚拟主机是目前Internet上的大多数虚拟主机业务提供商所通常采用的方式。只要找出几个小型公司或个人的网站,如果在WEB浏览器地址栏中输入“http://主机名”可以访问到该WEB站点,接着在命令行窗口中执行“ping 主机名”,查看到该域名对应的IP地址,然后在WEB浏览器地址栏中输入“http://IP地址”时,却无法访问这个WEB站点了,那么,这个WEB站点就是一个基于主机名的虚拟主机,它与其他一些WEB站点共享一台WEB服务器,而不是自己独享一台WEB服务器。

注意:当使用安全套接字层 (SSL) 时,不能使用主机头字段来实现虚拟主机,这是因为使用SSLHTTP请求有加密保护。主机头字段是加密内容的一部分,不能被解释和路由到正确的站点。

3  HTTP协议详解

3.1.3 HTTP 1.1HTTP 1.0的比较

一个WEB站点每天可能要接收到上百万的用户请求,为了提高系统的效率,HTTP 1.0规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求。但是,这也造成了一些性能上的缺陷,例如,一个包含有许多图像的网页文件中并没有包含真正的图像数据内容,而只是指明了这些图像的URL地址,当WEB浏览器访问这个网页文件时,浏览器首先要发出针对该网页文件的请求,当浏览器解析WEB服务器返回的该网页文档中的HTML内容时,发现其中的<img>图像标签后,浏览器将根据<img>标签中的src属性所指定的URL地址再次向服务器发出下载图像数据的请求,如图3.3所示。

 

3.3

显然,访问一个包含有许多图像的网页文件的整个过程包含了多次请求和响应,每次请求和响应都需要建立一个单独的连接,每次连接只是传输一个文档和图像,上一次和下一次请求完全分离。即使图像文件都很小,但是客户端和服务器端每次建立和关闭连接却是一个相对比较费时的过程,并且会严重影响客户机和服务器的性能。当一个网页文件中包含AppletJavaScript文件,CSS文件等内容时,也会出现类似上述的情况。

为了克服HTTP 1.0的这个缺陷,HTTP 1.1支持持久连接,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。一个包含有许多图像的网页文件的多个请求和应答可以在一个连接中传输,但每个单独的网页文件的请求和应答仍然需要使用各自的连接。HTTP 1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少了整个下载过程所需要的时间。基于HTTP 1.1协议的客户机与服务器的信息交换过程,如图3.4所示。

3.4

可见,HTTP 1.1在继承了HTTP 1.0优点的基础上,也克服了HTTP 1.0的性能问题。不仅如此,HTTP 1.1还通过增加更多的请求头和响应头来改进和扩充HTTP 1.0的功能。例如,由于HTTP 1.0不支持Host请求头字段,WEB浏览器无法使用主机头名来明确表示要访问服务器上的哪个WEB站点,这样就无法使用WEB服务器在同一个IP地址和端口号上配置多个虚拟WEB站点。在HTTP 1.1中增加Host请求头字段后,WEB浏览器可以使用主机头名来明确表示要访问服务器上的哪个WEB站点,这才实现了在一台WEB服务器上可以在同一个IP地址和端口号上使用不同的主机名来创建多个虚拟WEB站点。HTTP 1.1的持续连接,也需要增加新的请求头来帮助实现,例如,Connection请求头的值为Keep-Alive时,客户端通知服务器返回本次请求结果后保持连接;Connection请求头的值为close时,客户端通知服务器返回本次请求结果后关闭连接。HTTP 1.1还提供了与身份认证、状态管理和Cache缓存等机制相关的请求头和响应头。

3.4.4 Accept-Language

Accept-Language头字段用于指定客户机期望服务器返回哪个国家语言的文档,可以指定多个以逗号分隔的国家语言。对于一些WEB站点,可以根据用户所使用的浏览器国家语言版本的不同,分别返回该国家语言的网页文档。例如,使用中文的IE浏览器访问www.google.com站点时,服务器返回的是使用中文语言的网页文件。单击IE浏览器的“工具”àInternet选项”菜单,在打开的“Internet选项”对话框中,单击“语言”按钮,在打开的“语言首选项”对话框中添加英语,并将其上移到语言列表中的第一个位置,如图3.14所示。

3.14

设置好语言首选项后,再次访问www.google.com站点,这时服务器返回的是使用英语的网页文件。上面的实验结果很可能会受到google站点策略调整和Cookie的影响,例如,作者在编写本书的初稿时,按照上面的操作,看到了预期的效果,但等到作者几个月后再次校稿时,即使将英语设置成了语言首先项,但所看到的结果却仍然是中文网页。这可能是由于英语已成为了国际通用语言的原因,google对语言首选项设置成英语的情况进行了忽略吧!如果把语言首选项设置成日语后,服务器可以返回日语的网页文件。

WEB服务器上实现上述功能的原理非常简单,因为,IE浏览器会根据“语言首选项”对话框中的语言列表,生成相应的Accept-Language请求头,例如,

    Accept-Language: en-gb,zh-cn

WEB服务器只要检查Accept-Language请求头中的信息,按照其中设置的国家语言的先后顺序,就知道应该返回哪种国家语言的网页文档给浏览器。如果WEB服务器不能返回位于Accept-Language设置值前面的国家语言的网页文档时,WEB服务器将返回后面的国家语言的网页文档。关于各个国家语言的名称信息,例如,中国是zh-cn,可以参阅RFC 1766,其实,只要在图3.14中添加进某个国家的语言,显示在中括号里面的内容就是这个国家语言的名称。

:动手体验:Accept-Language头字段的作用

1)在命令行窗口中执行telnet www.google.com 80,在成功连接后启动的telnet程序窗口中,输入如下几行内容:

    GET / HTTP/1.1

    Host:

    Accept-Language: en-us,zh-cn

    <空行>

可以看到google返回的正文部分是英文字符的网页文档。省略上面的Accept-Language字段部分,google默认返回的正文部分也是英文字符的网页文档。

2)重新连接上google站点,在成功连接后启动的telnet程序窗口中,输入如下几行内容:

    GET / HTTP/1.1

    Host:

    Accept-Language: zh-cn

    <空行>

可以看到google返回的正文部分是中文字符的网页文档。

 

 

原创粉丝点击