---------------------- android培训、java培训、期待与您交流! ------------------------------------------------------------------------------------------------------------------------------------------------
JavaWeb
注意术语: 应用服务器,web网站(Host),web应用(Context),web资源(servlet)。一个应用服务器中可以承载很多web网站,
一个web网站中可以包含多个web应用,一个web应用中可以包含多个web资源
其实这就是利用之前学习的TCP。其实服务端就是用TCP编写的应用程序。而客户端不用自己编写。是浏览器。浏览器通过
发送访问请求给服务端,服务端读取本地的资源,然后通过Socket输出流将资源信息返回到客户端浏览器。
Tomcat就是一款写好的服务端程序。
常用到的协议以及该协议的工作端口号:
HTTP:80 ; POP3:110 ; FTP:23 ; HTTPS:443 ;SMTP: 25
我们在开发的时候让服务器运行在8080端口,如果是部署的话,就要运行在80端口上。
这里还要解释一下就是我们平时所说的服务器一般是指的电脑。是我们说的不准确。
服务器指的是网络应用程序(例如Tomcat)。一台电脑上可以运行多个服务器。
因为Tomcat服务器是用java写的程序,所以要用到java虚拟机的支持,所以在启动的时候,要找寻Jdk。
所以要配置环境变量。
启动tomcat的程序所在的位置是:
tomcat所在目录下—>bin-àstartup.bat.
在我电脑上是:
C:\apache-tomcat-6.0.33\bin\startup.bat.
我们平时访问新浪,一般都是输入网址:http://www.sina.com.cn/。
仅仅是www.sina.com.cn这句
只能是定位到主机,相当于是IP地址,是不能访问相应的程序,要访问相应的程序要指定端口号。但是指定端口号太麻烦。所以因为前边的协议头是http,所以就会知道用的是http协议,浏览器就会默认的访问80端口。这样就方便了用户。
其实tomcat设计是基于配置文件的,可以在配置文件中修改端口号。
这个配置文件位于tomcat目录下—>conf-àserver.xml中
我的是位于:
C:\apache-tomcat-6.0.33\conf\server.xml.
一般来说的话web应用都是存在于tomcat目录下的webapps下。
例如我在我的电脑上这样做:
在webapps目录下,我新建了一个文件夹html,里边存储的1.html页面。
然后我启动服务器
我打开浏览器,在地址栏中输入:http://localhost:8080/html/1.html.
就访问到了这个页面。
Web虚拟目录的映射:
web应用程序指供浏览器访问的程序。通常也叫做web应用。
一个web应用由多个静态web资源和动态web资源组成。
包括html ,css,js文件
JSP页面,java程序,支持jar包。配置文件等等。
组成web应用的这些文件通常我们会使用一个目录组织,这个目录称为
web应用所在目录。
Web应用开发好后,若想供外界访问,需要把web应用所在目录交给web服务器管理
这个过程称之为虚拟目录的映射。
虚拟目录的配置一般是通过在配置文件中添加Context标记来完成的。
通常有以下5中方式:
For Tomcat 6, unlike Tomcat 4.x, it is NOT recommendedto place <Context> elements directly in the server.xml file. This is because it makes modifying theContextconfiguration more invasive since the main conf/server.xml
filecannot be reloaded without restarting Tomcat.
Context elements may be explicitly defined:
- In the
$CATALINA_BASE/conf/context.xml
file: the Context element informationwill be loaded by all webapps. - In the
$CATALINA_BASE/conf/[enginename]/[hostname]/context.xml.default
file: the Context element information will be loaded by all webapps of that host. - In individual files (with a ".xml" extension) in the
$CATALINA_BASE/conf/[enginename]/[hostname]/
directory. The name of the file (less the .xml extension) will be used as the context path. Multi-level context paths may be defined using #, e.g.foo#bar.xml
for a context path of/foo/bar
. The default web application may be defined by using a file calledROOT.xml
. - Only if a context file does not exist for the application in the
$CATALINA_BASE/conf/[enginename]/[hostname]/
, in an individual file at/META-INF/context.xml
inside the application files. If the web application is packaged as a WAR then/META-INF/context.xml
will be copied to$CATALINA_BASE/conf/[enginename]/[hostname]/
and renamed to match the application's context path. Once this file exists, it will not be replaced if a new WAR with a newer/META-INF/context.xml
is placed in the host's appBase. - Inside a Host element in the main
conf/server.xml
.
以上摘自Tomcat文档中。
$CATALINA_BASE
指的是tomcat所在的目录。
[enginename]
指的是Catalina目录。
[hostname]
指的是localhost
对Context就可以理解为web应用的配置。
<Context path=”虚拟路径” docBase=”硬盘上的实际路径”>。
其中的path配置的意思为指定外部访问web应用的在地址栏中的书写路径。
而docBase配置的意思是:web应用在硬盘上实际存放的位置。
例如:<Context path=”/itcast” docBase=”C:\news”>。
含义:C盘下的文件夹news中存放了一个1.html页面。
这样配置后,如果要访问1.html页面。则在IE地址栏中输入的是:
http://localhost:8080/itcast/1.html.
建议使用第3种。
主要介绍的是第3,5种。
第3中方式配置的后,服务器是不需要重新启动的。
第3:在tomcat目录的conf下的Catalina下的localhost的目录中建立一个以xml为扩展名的文件,在该文件中配置。那么这个文件的名称将会被用作contextpath.也就是虚拟目录名。
例如:如果文件名为a.xml. 内容为:<Context docBase=”C:\news”/>.
这样访问的话,IE地址输入为:http://localhost:8080/a/1.html.
如果文件名为 a#b#c.xml
则访问路径为:http://localhost:8080/a/b/c/1.html.
配置缺省的web应用
在上边所说的目录中只要将Context配置文件命名为:ROOT.xml就好了。
这是什么意思呢?例如Tomcat服务器启动后,你输入http://localhost:8080/,按回车,这时就会默认的跳转到一个tom猫界面。这就是运行了默认的web应用,不过该web应用由默认的起始页。
而我们把文件名改为此后,就在地址栏中输入:http://localhost:8080/1.html.就可以访问我们的1.html页面。
第5种配置以后是要启动服务器的。
第5:
在conf 下的server.xml 的<Host></Host>标记之中配置。
例如:
<Host>
<Context path=”/itcast” docBase=”C:\news”>
</Host>
IE地址栏中的路径为:http://localhost:8080/itcast/1.html.
配置缺省的web应用:
<Host>
<Context path=”” docBase=”C:\news”>
</Host>
IE地址栏中的路径为:
http://localhost:8080/1.html.
其实在开发的过程中:
服务器会将tomcat目录下的webapps 下所有的目录都映射为虚拟目录,文件夹的名字就是虚拟路径名。
例如…..webapps/news/new/1.html。
这是news的内部结构。
这样的话,访问的时候,就IE地址栏输入的是
http://localhost:8080/news/new/1.html.
就可以访问1.html页面了。
针对上述两种方式:一个是手动的配置web应用,一个是tomcat自动映射。
手动配置适用的场合是:
服务器在C盘下,而web应用在D盘下。这样就无法将web应用放置到webapps目录下。所以就用手动配置。
Web目录的组成结构WEB项目首页需要在web应用的WEB-INF下配置web.xml.
它的配置参考tomcat目录下\conf\web.xml.
假设在Server.xml中配置的话:
<Context path=”/itcast” docBase=”C:\news”>配置完后,
访问该web应用的话,就不用再指定html页面,就可以直接写这个
http://localhost:8080/itcast/
就可以访问到1.html。
如果将其配置为默认的web应用。配置修改为:
<Context path=”” docBase=”C:\news”>
访问地址为:http://localhost:8080/,就访问了1.html。
如果想省略端口号,在Server.xml中将端口从8080修改为80。
IE地址栏为http://localhost/,可以访问到1.html。
配置虚拟主机:
在一个tomcat服务器服务器中可以放置多个网站,所谓配置虚拟主机,就是在tomcat服务器中配置一个网站。
需要说明一点的是,一个网站可以包含多个web应用。
如果在WEB服务器中配置一个网站,需要使用Host标记在server.xml中配置。
例如:
<Host name=”www.sina.com” appBase=”c:\application”></Host>
name指定的是主机名,appBase指定的是网站在硬盘上的存放位置。
例如http://www.google.com/res.html中
www.google.com就是主机名。可以通过查找本机的host配置文件或DNS服务器来
查找该主机对应的IP地址。
配置的主机(网站)如果要想被外界访问,必须在DNS服务器或Windows系统中注册。
打包web应用为war包:
例如 在C盘下的google目录是一个网站,内部有news这么个web应用。
则打war包就是在控制台进入到google目录下
则输入命令就好了:
-cvf news.war news
这样就会出现一个war包。前边的 –cvf 是命令,后边先写war包名称(名称可以自定义),再写web应用名称。
当将war包拷贝到服务器的webapps目录下后,服务器会自动将该war包解压,从而运行。
配Context标记的reloadable属性,让tomcat自动加载更新后的web应用。
<Context path=”/itcast” docBase=”C:\news” reloadable=”true”>
如果是在server.xml中这样配置的话,如果修改news 这个web应用中的java的代码的话,不用重新发布这个应用,服务器会自动加载。
如果是在 tomcat 目录下的conf context.xml中配置该属性的话。会被服务器中所有的web应用所共享。
这个属性在开发中不建议使用。
Http协议:
客户端连上web服务器后,若想获得web服务器中的某个web资源,需要遵守一定的通讯格式,HTTP协议用于定义客户端与web服务器通讯的格式。
HTTP是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的过程。
HTTP协议的版本:
HTTP1.0和HTTP1.1
HTTP1.0协议中,客户端与WEB服务器建立连接后,只能获取一个web资源。该资源获取后,就会断开连接。
HTTP1.1协议中,允许客户端与WEB服务器建立连接后,在一个连接上获取多个web资源。
经典面试题目:
一个web页面中,使用img标签引用了三幅图片,当客户端访问服务器中的这个web页面时候,客户端总共访问几次服务器?
即客户端向服务器发送了几次HTTP请求。
答案是4次。
例如该页面如下:
aaaaaaaaaaaaaaaaaaa
<img src=”1.jpg”>
<img src=”2.jpg”>
<img src=”3.jpg”>
为什么是4次呢?整个过程是这个样子的。
首先,第一次访问,服务器返回给浏览器的响应是html中的内容数据:
aaaaaaaaaaaaaaaaa
<img src=”1.jpg”>
<img src=”2.jpg”>
<img src=”3.jpg”>
然后浏览器开始解析执行这个html文本,而这个img标签是告诉浏览器去获取服务器中的1.jpg这个图片。
依次类推。
类似的JS、CSS的引用,和图片处理的方式差不多。
例如:
aaaaaaaaaaaaaaaaa
<script src=”1.js”>
<script src=”2.js”>
这时候,也是向服务器发送3此请求。
所以在web优化中,界面的设计也是一个重要的方面,差的界面设计会增加服务器的压力,影响网站的性能。
Http请求:
客户端连上服务器后,向服务器请求某个web资源,称之为客户端向服务器发送了一个HTTP请求。一个完整的HTTP请求包括如下内容:
一个请求行,若干请求头,以及实体内容。
请求行
中的请求方式:
常用的有2中:GET和POST。
用户如果没有设置,默认情况下浏览器向服务器发送的都是get请求,例如在浏览器直接输
地址访问,点超链接访问等都是get.用户如想把请求方式改为post.可通过修改表单的提交方式实现。
提交表单的时候用的是POST。其他的一般都是GET。
区别:
主要区别表现在数据的传送上。
如果请求方式是GET方式,则可以在请求的URL地址后以?的形式带上交给服务器的数据,多个数据之间以&进行分隔。
例如: GET/mail/1.html? name=abc& password=xyz HTTP/1.1
这个仅是get方式提交数据后,观看的请求形式。
但是在URL地址后附带的参数是有限制的,其数据量通常不能超过1K。
如果请求方式是POST。则可以在请求的实体内容中向服务器发送数据。
传送的数据量无限制。
传送的数据位于请求的空行下边的部分。
<a href=”/2.html ? name=aaaaa”>提交</a>
当点击提交这个超链接的时候,会访问2.html这个web资源。同时会将name=aaaaa,传递。
消息头:
Accept:告诉服务器,客户机支持的数据类型。
例如:
Accept:text/html,image/* 就是客户端支持html和image。
Accept:*/*;表示所有类型都支持。
Accept-Charset:告诉服务器,客户端采用的编码。
eg:Accept-Charset:ISO8859-1
Accept-Encoding:告诉服务器,客户机支持的数据压缩格式。
eg: Accept-Encoding:gzip,compress
Accept-Language:客户机的语言环境。
eg: Accept-Language:en-us
Host:告诉服务器,想访问的主机名(虚拟主机)。
If-Modified-Since:客户机告诉服务器,资源的缓存时间。
例如我们访问新浪首页,客户端就将这个首页缓存起来了,如果再次访问新浪首页的时候
会将缓存首页时的那个时间点带过去,这时服务端就会查看该网页的最后更新时间和带过来的时间哪个靠前。如果缓存的时间点早于网页更新的最后时间,就从服务端返回该网页资源,否则就直接用客户端的缓存。
Referer:告诉服务器,该请求是通过哪个资源来访问服务器的。
例如在1.html的页面上有一个超链接,点击后能访问到2.html。那么这个头内容是:1.html
User-Agent:告诉服务器,客户机的软件环境。
例如采用的是什么浏览器,操作系统的内核是什么等等。
Cookie:客户机通过这个头可以向服务器带数据。
Connection:该请求结束之后是保持连接还是关闭连接。
HTTP响应:
一个HTTP响应代表服务器向客户端回送的数据
它包括:
一个状态行,若干消息头,以及实体内容。
状态行:
使用的协议和状态标记就不说了,关键分析的是状态码。
格式:HTTP版本号 状态码 原因叙述<CRLF>
例子:HTTP/1.1 200 OK.
状态码用于表示服务器对请求的处理结果,它是一个三位的10进制数。响应码分为5类。
对几个状态码的解释:
302:客户端发送请求,服务端返回一个302,同时也会返回来一个location响应头。该响应头指定一个地址。
意思是:客户端发送给服务端请求,服务端发送给客户端一个地址,让客户端去找该地址。
307和304是一个含义:
如果客户端请求后返回来307或304,就代表着要让客户端去拿缓存中的资源。
404:
说明请求的web资源在服务器中不存在。
403:
当服务器有客户端要访问的资源,但是客户端的权限不够,就会返回来403。
响应头:
Location:这个头配合302状态码使用。用于告诉客户端找谁?
Location和302实现请求重定向。
Server:服务器通过这个头,告诉浏览器服务器的类型。
Context-Endcoding: 服务器通过这个头,告诉浏览器数据的压缩格式。
类如:如果服务器向浏览器回送的数据高达10M,可能压缩后就只有几十KB,这样给
大型网站省了钱。因为大型的门户网站都是按照送出去的流量被电信或是联通收费的。
Context-Length: 服务器通过这个头,告诉浏览器回送数据的长度。
Context-Type: 服务器通过这个头,告诉浏览器回送数据类型。
浏览器接资源后,它是怎么知道显示资源时是以文本还是以图片的形式显示该资源呢?
就是通过该响应头来控制的。
last-Modified: 服务器通过这个头,告诉浏览器当前请求资源的最后更新时间。
Refresh: 服务器通过这个头,告诉浏览器每隔多长时间刷新(请求访问)一次该资源。
Context-Disposition: 服务器通过这个头,告诉浏览器以下载方式打开回送数据。
Transfer-Encoding: 服务器通过这个头,告诉浏览器数据的传送格式。
ETag:
和缓存相关的头。
服务器对其内部的每个web资源根据其内容会生成一个随机数串。如果内容更改了,这个标志串也会更改。如果浏
览器访问某个web资源的时候,服务端会将该资源的标志串回送给客户端。当客户机再次访问该资源的时候,会将
该标志串带来,服务端就会对比,如果该标志串没有变,那么就让客户机去拿缓存,如果标志串不相同,则服务端
给客户端回送更新后的web资源。这个头多用在实时要求很高的系统。此头具有实时性的更新。
而前边的客户端的请求头:If-Modified-Since是以秒为级别的更新。
Expires: 服务器通过这个头,告诉浏览器把回送的资源缓存多长时间。-1或0的话是不缓存。
Cache-Control:no-cache
Pragma:no-cache
服务器通过以上两个头,也是控制浏览器不要缓存数据。
为什么这么多头来控制缓存:这是因为浏览器的种类很多。
web.xml
所有的web资源如果需要配置的话,都配置在web.xml中。
Servlet:
Sun公司在其API中提供了一个servlet接口,用户若想开发一个动态的web资源(即开发一个Java程序向浏览器输出数据),需要完成以下两个步骤:
编写一个Java类,实现servlet接口。
把开发好的Java类部署到Web服务器中。
解决两个问题:
输出数据的Java代码应该写在servlet接口中的哪个方法内?
如何向IE浏览器输出数据?
对Servlet API的一些解释:
servlet是一个小型的运行在web服务器中的java程序。用来接收和响应从web客户端发来的请求,通常用的是HTTP协议。
为了实现该接口,一般情况下需要实现该接口中所有的方法。但是Java为我们提供了方便。
Java已经写好了两个实现了该接口的两个默认实现类。
我们开发的时候只需要写一个servlet类,该类继承自GernricServlet,或是HttpServlet.覆写其中的方法即可了。简化了开发。
生命周期方法:
就是在特定的时间阶段一定会执行的方法。
servlet对象实际可以看做是一个web资源。
servlet中以下三个方法是生命周期方法:执行顺序如下:
1. init()方法,用来对servlet进行初始化。
当servlet对象被创建,init()方法就会被执行了。
2.service(ServletRequest req, ServletResponse res)
用来响应客户端的请求。
任何客户端发来请求该servlet(资源)时,应用服务器会调用servlet对象的service方法。
3.destroy()
从服务器中移除一个servlet对象。
以下是非生命周期方法:
ServletConfig getServletConfig()
该方法可以获取到servlet的一些初始化,启动信息。
String getServletInfo()
获取servlet的版本号,作者等信息。
对几个方法的详细解释:
service(ServletRequest req, ServletResponse res)
该service方法具有两个参数,req代表请求参数,res代表的是响应参数。
ServletRequest 和 ServletResponse这两个都是接口。
当客户端第一次调用该servlet(资源)时,会创建servlet对象。
这里说的意思是:
假设该servlet字节码文件代表的是新浪首页这个资源。在新浪这个门户网站刚发布的第一天,肯定有一个人是第一时间访问到该新浪首页的,这时服务器就创建了一个servlet对象(新浪首页),该servlet对象不会消失,而是驻留在新浪服务器所在电脑的内存中,供世界各地的用户使用。
然后服务器调用该servlet对象的service方法,因为是服务器调用的service方法,所以service方法的参数理应也就应该由服务器来提供,在我看来,服务器实现了ServletRequest ,ServletResponse两个接口,在调用service方法的时候,创建了这两个接口的子类对象传递到参数中。
因为service方法的参数res代表的是响应,该参数有一个方法getOutputStream,来获取流对象,将回送的数据写入到res这个对象中,服务器从res中取出数据,构建一个http响应,
回写给客户机。浏览器解析http响应,提取数据显示。
destroy()方法代表的是servlet对象摧毁的时候才会执行。
什么时候servlet对象才会被摧毁呢?
一种是:当服务器停止运行了。第二种是:该web资源(servlet.class)被从服务器中删除了。
在第4个文件夹中的2个视频中的Servlet调用图没有总结。
这里有文字描述Servlet调用过程的:
Servlet程序是由应用服务器调用,应用服务器收到客户端的Servlet访问请求后:
(1) Web服务器首先检查是否已经装载并创建了该Servlet的实例对象,如果是执行第
(4)步,否则,执行第(2)步。
(2) 装载并创建该Servlet的一个实例对象。
(3) 调用Servlet实例对象的init()方法。
(4) 创建一个用HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的
HttpServletResponse对象,然后调用Servlet对象的service()方法并将请求和响应对象,作为参数传递进去。
(5)web应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet。并将卸载之前调用的。
Servlet的一些细节:
由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到
一个URL地址上,这个工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。
<servlet>元素用于注册Servlet,它包含有两个主要的子元素:<servlet-name>和<servlet-class>,分别用于设置
Servlet的注册名称和Servlet的完整类名。
一个<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name>
和<url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径
<web-app>
<servlet>
<servlet-name>AnyName</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>/demo/hello.html</url-pattern>
</servlet-mapping>
</web-app>
同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。
在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”,另一种格式是以正斜杠(/)开头并以“/*”结尾。
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern> *.do </url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>/action/*</url-pattern>
</servlet-mapping>
对于如下的一些映射关系:
Servlet1 映射到 /abc/*
Servlet2 映射到 /*
Servlet3 映射到 /abc
Servlet4 映射到 *.do
问题:
当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应
Servlet引擎将调用Servlet3。
当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。
针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它
就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁。
在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次
servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的
HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求
方式分别调用doXXX方法。
如果在<servlet>元素中配置了一个<load-on-startup>元素,那么WEB应用程序在启动时,就会装载并创建Servlet的实例对象、
以及调用Servlet实例对象的init()方法。
举例:
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
用途:为web应用写一个InitServlet,这个servlet配置为启动时装载,为整个web应用创建必要的数据库表和数据
如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。
凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,
缺省Servlet用于处理所有其他Servlet都不处理的访问请求。
在<tomcat的安装目录>\conf\web.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServlet的Servlet,并
将这个Servlet设置为了缺省Servlet。
当访问Tomcat服务器中的某个静态HTML文件和图片时,实际上是在访问这个缺省Servlet。
当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上
调用Servlet的service方法,因此service方法内如果访问了同一个资源的话,就有可能引发线程安全问题。
如果某个Servlet实现了SingleThreadModel接口,那么Servlet引擎将以单线程模式来调用其service方法。
SingleThreadModel接口中没有定义任何方法,只要在Servlet类的定义中增加实现SingleThreadModel接口的声明即可。
对于实现了SingleThreadModel接口的Servlet,Servlet引擎仍然支持对该Servlet的多线程并发访问,其采用的方式是
产生多个Servlet实例对象,并发的每个线程分别调用一个独立的Servlet实例对象。
实现SingleThreadModel接口并不能真正解决Servlet的线程安全问题,因为Servlet引擎会创建多个Servlet实例对象,而
真正意义上解决多线程安全问题是指一个Servlet实例对象被多个线程同时调用的问题。事实上,在Servlet API 2.4中,
已经将SingleThreadModel标记为Deprecated(过时的)。
ServletConfig对象:
在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。
当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象
中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以得到
当前servlet的初始化参数信息。
阅读ServletConfig API,并举例说明该对象的作用:
获得字符集编码
获得数据库连接信息
获得配置文件,查看struts案例的web.xml文件
SservletContext:
WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
ServletContext对象被包含在ServletConfig对象中,开发人员在编写servlet时,可以通过ServletConfig.getServletContext
方法获得对ServletContext对象的引用。
由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来
实现通讯。ServletContext对象通常也被称之为context域对象。
HttpServletResponse:
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象和代表响应的response对象。
request和response对象既然代表请求和响应,那我们要获取客户机提交过来的数据,只要找request对象就可以了。要向客户机输出数据,只要找response对象就可以了。
void setHeader(String name, String value)
Sets a response header with the given name and value.
void addHeader(String name, String value)
Adds a response header with the given name and value.
add和set的区别是:假如本来就有一个a=b的头。这个时候,用add方法加入一个a=c的头,这个时候,就有两个头:a=b,a=c。
而用set的话,就会将a=b覆盖掉,最后只有一个头,就是a=c.
void setStatus(int sc)
Sets the status code for this response.
这两个方法位于:ServletResponse类中。
ServletOutputStream
getOutputStream()
Returns a ServletOutputStream suitable for writing binary data in the response.
PrintWriter
getWriter()
Returns a PrintWriter object that can send character text to the client.
以上是response的部分方法摘要,可以用来设置请求头,请求状态码,可以写入数据等等。
程序以什么码表输出了,程序就一定要控制浏览器以什么码表打开。
Servlet使用OutputStream向客户端输出中文和数字的问题。
这个乱码问题的解决,牵涉不到response的编码问题。因为写入response对象中的数据就是byte字节。所以
response就不会对其进行编码了。服务器发现response中有数据,直接发送给客户端了。这时候涉及到乱码
问题有:OutputStream以何种编码将数据写入到response对象中,浏览器以何种编码打开数据。response对
象只不过是个中间机构罢了。
Servlet使用PrintWriter向客户端输出中文的问题。
因为是将字符数据写入到response中的。因为网络上传递都要是字节数据才可以。为了让服务器将response中
的数据打给浏览器。所以,response会将字符数据编码为字节数据,用到的编码表是ISO8859-1。但是欧洲编
码表中不会出现中文字符,所以编码后的字节数据也是不正确的。然后服务器将response中的数据打给浏览器,
浏览器采用GBK编码表来解码,从而出现乱码。
注意:此处response会将字符数据自动编码,对于字节数据,则是直接存储的。
请求重定向:
重定向特点:
1. 浏览器会向服务器发送两次请求,意味着就有两个 request/response
2. 用重定向技术,浏览器地址栏会发生变化。
应用的场景:
用户登录以后跳转到首页和购物车。
例如购物车:
如果采用请求转发的话:
用户单击购买,购买servlet执行,并将结算金额等等请求转发到结账页面。但是用户可能闲来无事,可能会随意刷
新页面。因为此时浏览器的地址栏是不变化的。所以每刷新一次,就会请求一次购买servlet,就会购买一次商
品。这是用户所不希望的。
如果采用请求重定向的话:
用户单击购买,购买servlet执行,并将结算金额等等请求重定向到结账页面。但是请求重定向后,浏览器的地址栏
已经发生了变化,此时地址是结账页面。此时再刷新的话,就不会请求那个购买的servlet了。这是用户所希望的。
response细节:
1. getOutputStream和getWriter方法分别用于得到输出二进制数据、输出文本数据的ServletOutputStream、PrintWriter.
2. getOutputStream和getWriter这两个方法互相排斥。在同一个请求中(一般情况是同一个servlet或者jsp,同一个请求还
包括请求转发,因为用的是同一个response对象,当然请求重定向不是同一个请求,因为用到的是不同的response),调用
了其中的一个方法,就不能调用另一个方法。
3. Servlet程序向ServletOutputStream或PrintWriter对象中写入的数据被Servlet引擎从response里边获取到,Servlet引擎
将这些数据当做响应消息的正文,然后在与响应状态行和各响应头组合后输出到客户端。
4. Servlet的service方法结束后,Servlet引擎将检查getWriter或getOutputStream方法返回的输出流对象是否调用了close
方法。
如果没有,Servlet引擎将调用close方法关闭该输出流对象。
HttpServletRequest:
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时候,HTTP请求头中的所有信息都封装到这个对象中,开发人员通过这个对象的方法,可以获得客户这些信息。
获取request中的信息,参看HttpServletRequest的API。
URL和URI的区别:
URI标识任意一个资源;URL标识互联网上的一个资源。
request的中文乱码产生原因:
因为IE要构造一个HTTP请求给服务器,要用字节才可以在网络之间进行传输。所以,IE会将输入网页的数据编码,网页一
般采用UTF-8进行编码。所以,会去查询UTF-8的码表。将数据传递给服务器,服务器将数据封装在request中,request
代表服务器发出的一个请求。而在servlet程序中, request.getParameter(“name”)方法返回的是文本数据,所以要对编码的
数据进行解码,而request的方法都是默认去查找ISO8859-1这个编码表,从而出现了乱码现象。
解决方案用两种:
对于Post方式提交的请求,一般是修改request的编码表。
对于Get方式提交的请求,在servlet中获取到的文本数据先编码,然后再解码。
request实现请求转发:
请求转发指一个web资源收到客户端请求后,通知服务器去调用另外一个Web资源进行处理。
请求转发的应用场景:MVC设计模式。
request对象提供了一个getRequestDispatcher方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发。
请求转发forward的细节:
1. forward方法用于将请求转发到RequestDispatcher对象封装的资源。
2. 如果在调用forward方法之前,在Servlet程序中写入的部分内容已经被真正地传送到了客户端,forward方法将抛出IllegalStateException异常
3. 如果在调用forward方法之前向Servlet引擎的缓冲区中写入了内容,只要写入到缓冲区中的内容还没有被真正输出到客户端,forward方法就可以被正常执行,原来写入到输出缓冲区中的内容将被清空。但是,已写入到HttpServletResponse对象中的响应头字段信息保持有效
请求转发的流程请参看PPT。
请求转发的特点:
1. 客户端只发出一次请求,而服务器端有多个资源调用。
2. 客户机浏览器地址栏没有变化。
请求重定向和请求转发的含义:
1. 一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理,称之为请求转发。
2. 一个web资源收到客户端请求后,通知浏览器去访问另外一个web资源,称之为请求重定向。
请求重定向和请求转发的区别:
RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect 方法还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。
如果传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头,它是相对于整个WEB站点的根目录;如果创建RequestDispatcher对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录。
调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。
HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求;RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。
RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程。
WEB工程中,各类地址的写法:
每个地址前边都最好要加“/”。如果该地址是给服务器用的,则该斜杠代表的是当前web应用。
如果该地址是给浏览器用的,则斜杠代表的是当前网站(一个网站有多个web应用)。
会话管理:
会话可以简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器。整个过程称之为一个会话。
会话过程中要解决的一些问题:
每个用户在使用浏览器与服务器进行会话的过程中,不可避免的各自会产生一些数据。服务器要想办法为每个用户保存这些数据。
例如:多个用户点击超链接通过一个servlet各自购买了一个商品,服务器应该想办法把每一个用户购买的商品保存在各自的地方。以
便于这些用户点击结账servlet时,结账servlet可以得到用户各自购买的商品为用户结账。
提问:这些数据保存在request中可以否?保存在servletContext中可以否?
保存在request是不可以的,因为点击购买和点击结账是向服务器发送了两次请求,没有共享同一个request对象,所以是不可以的。
保存在servletContext则会出现线程安全问题。
Cookie的细节:
1. 一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(name),和设置值(value)。
2. 一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie.
3. 浏览器一般只允许存放300个Cookie。每个站点最多存放20个Cookie。每个Cookie的大小限制为4KB。
4. 如果创建了一个cookie,并将他发送到浏览器,默认情况下它是会话级别的cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除。若希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。将最大时效设置为0则是命令浏览器删除该cookie。
5. 注意:删除cookie时,path必须一致,否则不会删除。
Session:
request.getSession()方法:判断是以cookie的形式带过来的JSESSIONID还是以超链接的形式带过来的JSESSIONID,如果带过来了
,就从服务器中取session出来用。否则,服务器创建一个session。
在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象)。注意:一个浏览器(包括最初开的那个网页以及
从该网页中打开的新的网页)独占一个session对象(默认情况下)如果再重启浏览器打开新的网页,则又从新创建一个session。因此,
在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程
序可以从用户的session中取出该用户的数据,为用户服务。
这个会话对象:只针对浏览器最初开的网页以及该网页生出来的网页有效。
Session和Cookie的主要区别在于:
Cookie是把用户的数据写给用户的浏览器。
Session技术把用户的数据写到用户独占的session中。
Session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。
Session对象的声明周期:
当会话用户第一次访问到request.getSession()这个代码的时候,服务器就会为会话用户创建session对象。
当创建的session对象从创建时候起,30分钟都没有使用,那么服务器就会摧毁session对象。
30分钟都没有使用:例如:打开一个浏览器,访问了request.getSession(),创建了session对象,这个时候会话窗口不关闭,但是不进行
操作,出去玩了1个小时。这样也没有用到session。30分钟后,session就会被摧毁。
还有就是该会话结束了,会话网页都关闭了。这个时候,session对象也没有被摧毁,而是也要30分钟后才可以被摧毁。
服务器如何实现一个session为一个用户浏览器服务:
当会话浏览器A访问Servlet1的时候,服务器会为该会话创建session对象。同时为该session对象生成唯一id,以cookie的形式将id回写给浏览器。当会话浏览器A访问Servlet2的时候,会带着该cookie过来。然后serlvet2就知道取哪个session对象为会话浏览器A服务。值得注意的是:默认情况下,服务器回写的Jsession这个cookie没有设置有效期。所以会话浏览器一关毕,Jsession这个cookie也就消失了。
例如会话A浏览器访问了Servlet1,关闭了。这个时候重新打开一个浏览器的话,访问servlet2,这个时候因为Jsession这个cookie已经不存在了,浏览器就不会带着它去访问servlet2。所以就会重新创建一个sesssion对象。
这对购物网站来说是有很大影响的,不能购买了商品,不小心关闭了。然后再登录的时候,之前购买的商品不存在了。
如何实现多个IE浏览器共享同一session?(应用:关掉IE后,再开IE,上次购买的商品还在。)
这个时候需要做的就是回写一个同名(Jsession)的cookie给浏览器,并将session的id作为该cookie的值部分,设置有效期等。将服务器自动回送的cookie覆盖掉。
通过以上可以知道:Session是基于cookie来工作的。
如果用户禁用了cookie,那么该怎样解决呢?解决方案:url重写。
禁用cookie的操作:Internet选项----隐私-----高级-----替代自动cookie处理-----将第一方Cookie和第三方Cookie都设置为阻止就可以了。
第一方Cookie的意思就是:你访问本站,服务器给用户浏览器提供本网站相关的cookie。
第三方 Cookie的意思就是:你访问本站,服务器给用户浏览器提供其他网站相关的cookie。例如访问淘宝,回送一个新浪的cookie。
注意浏览器不阻止localhost的cookie,如果要进行测试的时候,用127.0.0.1代替就可以了。
例如:http://127.0.0.1:8080/day05/product.jsp。而不是http://localhost:8080/day05/product.jsp
解决方案:URL重写
1. response. encodeRedirectURL(java.lang.String url)
用于对sendRedirect方法后的url地址进行重写。
2. response. encodeURL(java.lang.String url)
用于对表单action和超链接的url地址进行重写
具体实现参看day05/welcome.jsp页面。
这种解决方案就适用于会话范围。对于关掉IE后,再开IE,上次购买的商品还在。这种问题不能解决
注意的是:
如果既采用了URL重写,也没有禁用cookie。那么会出现什么现象呢?
当浏览器第一次访问首页的时候,服务器不知道是否浏览器禁用了cookie。这个时候,重写了URL地址。服务器也给浏览器回写了cookie。
当刷新首页的时候,这次浏览器就带着cookie来了。服务器看浏览器带过来了cookie。就知道了浏览器没有禁用cookie。从而服务器的 response. encodeURL(java.lang.String url) ;response. encodeURL(java.lang.String url)这两个方法根据某些条件判断了后,不起作用。
针对ie8以上,包括ie8。如过是多个浏览器打开时间有重叠,则共享一个session。
如果是一个浏览器,基于该浏览器从新窗口打开或者打开的新选项卡都是共享一个session。
JSP技术:
JSP全称为Java Server Pages,是一种用于开发动态web资源的技术。
写JSP虽然就像在写html,但是在JSP 技术允许在页面中编写Java代码,并且允许开发人员在页面中获取request和response等web开发常用的对象,实现与浏览器的交互,所以JSP 是一种动态web资源的开发技术。
当IE浏览器访问JSP 页面的时候,WEB服务器是如何调用并执行一个JSP 页面的。
之前说的,JSP实际上就是一个Servlet,这是为什么呢?
当服务器发现浏览器要访问的是一个JSP资源,web服务器就会将该JSP资源翻译为一个Servlet.存放的目录是
Tomcat目录下>work目录>Catalina>localhost>项目名称目录(例如JavaJsp)>org>apache>jsp>
就可以看到JSP翻译后的.java源文件和.class文件。
这是我写的一个JSP被服务器翻译后的servlet。
从上边的例子中可以看出。
该servlet的内部已经 定义好了
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
JspWriter _jspx_out = null;
PageContext _jspx_page_context = null;
这些属性,这就是为什么我们直接可以在JSP页面中直接调用相应的对象的原因。
JSP的最佳的实践:
servlet作为web应用中的控制器组件来使用,而把JSP技术作为数据显示模板来使用。
这是因为,JSP既要用Java代码产生动态的数据,又做美化会导致页面的维护困难。
让servlet即产生数据,又在里边套嵌html代码,美化数据,同样可读性差,且难以维护。
因此做好的是,servlet只负责响应请求产生数据,并把数据通过转发技术带给JSP,数据的显示JSP来做。
JSP语法:
JSP脚本表达式:用于将程序数据输出到客户端语法是:<%=变量或是表达式%>
举例如:<%=new Date()%>
JSP引擎在翻译脚本表达式的时候,会将数据装换为字符串,然后在相应的位置用
out.write(…)将数据输出到客户端。
JSP脚本表达式中的变量或是表达式后边不能有分号。
JSP脚本片段:
用于在JSP页面中编写多行JAVA代码。
语法格式为:
<%
多行java代码。
%>
注意,JSP脚本片段中只能出现java代码,不能出现其他模板元素,JSP引擎在翻译JSP页面中,会将JSP脚本片段中的JAVA代码被原封不动的放到Servlet的_jspService方法中。
JSP脚本片段中的java代码必须严格遵循Java语法,例如,每行执行语句后边,必须要有分号结束。
在一个JSP 页面中可以有多个脚本片段,在两个或多个脚本片段之间可以嵌入文本,HTML标记,或其他JSP 元素。
多个脚本片段中的代码可以相互访问,
例如:
<%
int x=10;
out.println(x);
%>
<p>这是JSP页面文本</p>
<%
int y=20;
out.println(x);
%>
这是因为服务器将所有的这些脚本片段中的java代码都放在了翻译后的jspservice方法中,所以,也就是在同同一个类的同一个方法中,当然是可以相互访问的。
单个脚本片段中的java代码可以是不完整的,但是,多个脚本片段组合后的结果必须是完整的java代码。
例如:
<%
for(int i=0;i<5;i++){
%>
<H1> www.baidu.com </H1>
<%
}
%>
意思就是输出5次www.baidu.com。
JSP声明:
JSP页面中编写的所有代码,默认会被翻译到servlet的service方法中,而JSP声明中的JAVA代码会被翻译到_jspService方法的外边。
语法:
<%!
java代码。
%>
所以,JSP声明可用于定义JSP页面装换成的servlet程序的静态代码块,成员变量,和成员方法。
例如“
<%
public void run(){
out.write(“你好”);
}%>
这样写 是不正确的,因为,方法中不能套嵌方法。
正确的写法是:
<%!
public void run(){
out.write(“你好”);
} %>
这样,在JSP页面翻译的类中,就会出现一个run方法。
多个静态代码块,变量和函数可以定义在一个JSP声明中,也可以分别定义在多个JSP申明中。
JSP隐式对象的作用范围仅限于servlet的_jspService方法中,所以在jsp声明中不能使用这些隐式对象
指令:
JSP全称为Java Server Pages,是一种用于开发动态web资源的技术。
写JSP虽然就像在写html,但是在JSP 技术允许在页面中编写Java代码,并且允许开发人员在页面中获取request和response等web开发常用的对象,实现与浏览器的交互,所以JSP 是一种动态web资源的开发技术。
当IE浏览器访问JSP 页面的时候,WEB服务器是如何调用并执行一个JSP 页面的。
之前说的,JSP实际上就是一个Servlet,这是为什么呢?
当服务器发现浏览器要访问的是一个JSP资源,web服务器就会将该JSP资源翻译为一个Servlet.存放的目录是
Tomcat目录下>work目录>Catalina>localhost>项目名称目录(例如JavaJsp)>org>apache>jsp>
就可以看到JSP翻译后的.java源文件和.class文件。
这是我写的一个JSP被服务器翻译后的servlet。
从上边的例子中可以看出。
该servlet的内部已经 定义好了
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
JspWriter _jspx_out = null;
PageContext _jspx_page_context = null;
这些属性,这就是为什么我们直接可以在JSP页面中直接调用相应的对象的原因。
JSP的最佳的实践:
servlet作为web应用中的控制器组件来使用,而把JSP技术作为数据显示模板来使用。
这是因为,JSP既要用Java代码产生动态的数据,又做美化会导致页面的维护困难。
让servlet即产生数据,又在里边套嵌html代码,美化数据,同样可读性差,且难以维护。
因此做好的是,servlet只负责响应请求产生数据,并把数据通过转发技术带给JSP,数据的显示JSP来做。
jsp语法:
JSP脚本表达式:用于将程序数据输出到客户端语法是:<%=变量或是表达式%>
举例如:<%=new Date()%>
JSP引擎在翻译脚本表达式的时候,会将数据装换为字符串,然后在相应的位置用
out.write(…)将数据输出到客户端。
JSP脚本表达式中的变量或是表达式后边不能有分号。
JSP脚本片段:
用于在JSP页面中编写多行JAVA代码。
语法格式为:
<%
多行java代码。
%>
注意,JSP脚本片段中只能出现java代码,不能出现其他模板元素,JSP引擎在翻译JSP页面中,会将JSP脚本片段中的JAVA代码被原封不动的放到Servlet的_jspService方法中。
JSP脚本片段中的java代码必须严格遵循Java语法,例如,每行执行语句后边,必须要有分号结束。
在一个JSP 页面中可以有多个脚本片段,在两个或多个脚本片段之间可以嵌入文本,HTML标记,或其他JSP 元素。
多个脚本片段中的代码可以相互访问,
例如:
<%
int x=10;
out.println(x);
%>
<p>这是JSP页面文本</p>
<%
int y=20;
out.println(x);
%>
这是因为服务器将所有的这些脚本片段中的java代码都放在了翻译后的jspservice方法中,所以,也就是在同同一个类的同一个方法中,当然是可以相互访问的。
单个脚本片段中的java代码可以是不完整的,但是,多个脚本片段组合后的结果必须是完整的java代码。
例如:
<%
for(int i=0;i<5;i++){
%>
<H1> www.baidu.com </H1>
<%
}
%>
意思就是输出5次www.baidu.com。
JSP声明:
JSP页面中编写的所有代码,默认会被翻译到servlet的service方法中,而JSP声明中的JAVA代码会被翻译到_jspService方法的外边。
语法:
<%!
java代码。
%>
所以,JSP声明可用于定义JSP页面装换成的servlet程序的静态代码块,成员变量,和成员方法。
例如“
<%
public void run(){
out.write(“你好”);
}%>
这样写 是不正确的,因为,方法中不能套嵌方法。
正确的写法是:
<%!
public void run(){
out.write(“你好”);
} %>
这样,在JSP页面翻译的类中,就会出现一个run方法。
多个静态代码块,变量和函数可以定义在一个JSP声明中,也可以分别定义在多个JSP申明中。
JSP隐式对象的作用范围仅限于servlet的_jspService方法中,所以在jsp声明中不能使用这些隐式对象
对转发和包含的总结:
forward:
request.getRequestDispatcher(relativeURL).forward(request,response);
pageContext.forward(relativeURL);
<jsp:forward path=”relativeURL”>
include:
request.getRequestDispatcher(relativeURL).include(request,response)
pageContext.include(relativeURL);
<jsp:include path=relativeRUL>
以上三个是动态包含。
<%@include path=relativeURL ….%>
这个是静态包含。会将包含的资源翻译为一个servlet。
JSP映射路径:
jsp就是一个servlet,所以可以像servlet一样,可以配置在浏览器中输入的虚拟的访问的路径。
这样在浏览器中输入http://localhost:8080/项目名/xxx/yyy.html就能访问这个jsp页面了。
路径书写的总结:
当在资源中配置的时候:
如果是在jsp页面或是servlet中配置的话,如果是给浏览器发起的,/代表的是webapps.
后边是虚拟的访问路径。也就是:/web应用名称/虚拟映射路径。
如果是给服务器转发,获取服务器中web应用的信息,这时候/代笔的是当前的web应用。
后边的是访问的资源在web服务器中的真实的目录。例如:/WEB-INF/1.jsp.
当在配置文件中配置的时候:
/代表的是当前的web应用,后边跟的是虚拟路径名称。
例如:/servlerdeom1.因为这个是给浏览器来访问书写的,但是web应用的虚拟路径已经配好,所以就无需再写,就用/来代替了。
JavaBean:
javabean有如下特点:
这个java类必须具有一个无参数的构造方法。
属性必须私有化。
私有化的属性必须通过public类型的方法暴漏给其他程序,并且方法的命名也必须遵守一定的命名规范。
JavaBean在J2EE开发中,通常用于封装数据,对于遵循以上写法的javabean。
其他程序可以通过反射技术实例化JavaBean对象,并且通过反射那些遵循命名规范的方法,从而获知JavaBean的属性,进而调用其属性保存数据。
属性是根据get和set方法来确定的,而不是根据类中成员变量的名称来确定的。
JSP中提供了三个关于JavaBean组件的动作元素,即JSP标签,他们分别为:
<jsp:useBean>标签:用于在JSP页面中查找或实例化一个JavaBean组件。
<jsp:setProperty>标签:用于在JSP页面中设置一个javabean组件的属性。
<jsp:getProperty>标签:用于在JSP页面中获取一个javabean组件的属性。
<jsp:useBean>标签用于在指定的域范围内查找指定名称的JavaBean对象:
如果存在则直接返回该JavaBean对象的引用。
如果不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围中。
常用语法:
<jsp:useBeanid="beanName"class="package.class"scope="page|request|session|application"/>
id属性用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称。
class属性用于指定JavaBean的完整类名(即必须带有包名)。
scope属性用于指定JavaBean实例对象所存储的域范围,其取值只能是page、request、session和application等四个值中的一个,其默认值是page。
EL和JSTL技术快速入门
EL获取数据:
EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的web域中检索java对象,
获取数据。
某个web域中的对象,包括普通的数据变量,javabean,list,map.
1、访问javabean的属性。
包括javabean的简单属性和复杂属性。
2、访问list结合中的元素
3、访问map集合中的元素。
语法格式为:${ 标识符 }。
EL表达式执行时,会调用pageContext.findAttribute方法,用标识符为关键字,分别从page、request、session、application四个域中查找相应的对象,找不到则返回 ” ”,而不是null。
EL表达式也可以轻松的获取javabean的属性.数组、collection、Map类型集合中的数据。
具体参照程序。
结合JSTL的foreach标签,使用EL表达式可以很轻松的迭代各种类型的数组或集合。
JSTL是sun公司开发的一套标签库,可以在页面实现简单的逻辑功能,可以替换一部分脚本代码。
在页面中使用jstl。需要完成以下两个步骤:
导入jstl.jar和standerd.jar包。但是如果用的是jdk1.5以上版本的话可以不用导入。
在jsp页面中使用<%@ taglib uri=””, prefix=””%> 元素导入标签库。
在奶瓶那个地方,也就是
JavaEE 5 Libraries-------jstl-1.2.jar下边打开,找到META-INF下的c.tld.
这个配置文件中的uri就是taglib指令中的uri,拷贝以下就可以了。prefix可以随便写,但建议是c.
XML技术:
XML:Extensible Markup Language,翻译过来就是可扩展性标记语言,XML技术是W3C组织发布的,目前遵循的是W3C组织与2000发布的XML1.0规范。
XML语言是用来描述现实生活中有关系的数据。在XML语言中,他允许用户自定义标签,一个标签用来描述一段数据,一个标签额可以分为开始标签和结束标签,在开始标签和结束标签之间,又可以使用其他标签描述其他数据,以此来实现数据关系的描述。
XML技术除了用于保存有关系的数据之外,它还经常用作软件的配置文件,以描述程序模块之间的关系。
在一个软件系统中,为提高系统的灵活性,它所启用的模块通常由配置文件决定。
例如:一个软件在启动时,它需要启动A.B两个模块。而A,B这两个模块在启动时,又分别需要A1,A2和B1,B2两个模块的支持,为了准确的描述这种关系,此时使用XML文件最合适不过。
xml语法:
xml文档声明:
<? xml version=”1.0” encoding=”UTF-8” ?>
version指定使用的xml的版本号,而encoding指定打开该文档时候所用到的编码。
如果是用eclipse开发的话,那么eclipse会自动按照encoding所指定的编码在硬盘上保存该xml文件。
xml元素
XML元素指XML文件中出现的标签,一个标签分为开始标签和结束标签,一个标签有如下几种书写形式。例如:
包含标签体的:<a>www.baidu.com</a>
不包含标签体的:<a></a>,简写为<a/>.
一个标签中可以套嵌若干子标签,但是标签必须合理的套嵌,绝对不允许交叉嵌套。
格式良好的XML文档必须且有且仅有一个根标签,其他标签都是这个根标签的子孙标签。
对XML标签中出现的所有空格和换行、缩进等方式,XML解析程序都会当做标签的内容进行处理。
例如:下边的两个标签的意义是不一样的:
1、<网址>www.baidu.com</网址>
2、<网址>
www.buidu.com
</网址>
xml元素命名规范:
一个xml元素可以包含字母,数字,以及一些其他可见的字符,但必须遵守下面的一些规范:
1、 区分大小写。<a>和<A>是两个不同的标签。
2、 不能以数字或”_”(下划线)开头。
3、 不能以xml(或XML,或Xml等)开头
4、 不能包含空格
5、 名称中间不能包含冒号”:”
XML标签的属性:
一个标签可以有多个属性,每个属性都有它自己的名称和取值。
例如<input name=”text”>
属性值一定要用双引号或是单引号引起来。
定义属性必须遵循与标签相同的命名规范。
在XML技术中,标签属性所代表的信息,也可以被改成用子元素的形式来描述,例如:
<input>
<name>text</name>
</input>
CDATA区:
在编写XML文件时候,有些内容可能不想然解析引擎解析执行,而是当做原始内容处理。
遇到这种情况的时候,可以把内容放置到CDATA区中,对应CDATA区中的内容,XML解析程序是不会处理,而是原封不动的输出。
语法:<![CDATA[内容]]>
例如:
<![CDATA[
<a>
helloworld
</a>
]]>
对于一些单个字符,若想显示其原始的样式,也可以使用转义字符的形式予以处理。
如果< a > < /a > 则显示如果显示的话,为<a></a>.
处理指令:
处理指令,简称PI,处理指令用来指挥解析引擎如何解析XML文档内容。
处理指令必须是以”<?”作为开头,以”?>”作为结尾。
类如:
在XML文档中可以使用xml-stylesheet指令,通知XML解析引擎,应用css文件显示xml文档的内容。
<? xml-stylesheet type”text/css” href=”1.css” ?>
XML约束
什么是xml约束?在XML技术中,可以编写一个文档来约束一个XML文档的书写规范,这称之为XML约束。
为什么需要XML约束?
这是在框架中经常要用到的,一般我们用框架的时候,要进行XML配置,所以框架的作者就定义了XML文档的约束文档来限制XML的配置。
常用到的约束技术有:
XMLDTD 和XMLShcema.
编写DTD约束的两种方式:
DTD约束既可以作为一个单独的文件编写,也可以在XML文件内编写。
在文件内部编写的例子:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE 书架 [
<!ELEMENT 书架 (书+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>
]>
<书架>
<书>
<书名>Java就业培训教程</书名>
<作者>张孝祥</作者>
<售价>39.00元</售价>
</书>
...
</书架>
当dtd文件和xml文件分开写的时候,就有两种方式来引用。
XML文件使用 DOCTYPE 声明语句来指明它所遵循的DTD文件,DOCTYPE声明语句有两种形式:
当引用的文件在本地时,采用如下方式:
<!DOCTYPE 文档根结点 SYSTEM "DTD文件的URL">
例如: <!DOCTYPE 书架 SYSTEM “book.dtd”>
当引用的文件是一个公共的文件时,采用如下方式:
<!DOCTYPE 文档根结点 PUBLIC "DTD名称" "DTD文件的URL">
例如:<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"这个是dtd的名称。
"http://java.sun.com/dtd/web-app_2_3.dtd">这个是dtd的url
DTD的语法细节:
在DTD文档中使用ELEMENT声明一个XML元素,语法格式如下所示:
<!ELEMENT 元素名称 元素类型>
元素类型可以是元素内容、或类型
如为元素内容:则需要使用()括起来,如
<!ELEMENT 书架 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
如为元素类型,则直接书写,DTD规范定义了如下几种类型:
EMPTY:用于定义空元素,例如
<!ELEMENT 书架 EMPTY>
ANY:表示元素内容为任意类型。
<!ELEMENT 书架 ANY>
元素内容中可以使用如下方式,描述内容的组成关系
元素内容使用空白符分隔,表示出现顺序没有要求:
<!ELEMENT MYFILE (TITLE AUTHOR EMAIL)>
表示MYFILE标签中出现的TITLE AUTHOR EMAIL可以没有顺序。
用逗号分隔,表示内容的出现顺序必须与声明时一致:
<!ELEMENT MYFILE (TITLE,AUTHOR,EMAIL)>
则MYFILE标签中出现的子标签顺序必须是 TITLE-AUTHOR-EMAIL。
用|分隔,表示任选其一,即多个只能出现一个
<!ELEMENT MYFILE (TITLE|AUTHOR|EMAIL)>
在元素内容中也可以使用+、*、?等符号表示元素出现的次数:
+: 一次或多次 (书+)
?: 0次或一次 (书?)
*: 0次或多次 (书*)
(书):必须仅出现一次。
元素属性的定义:
xml文档中的标签属性需通过ATTLIST为其设置属性
语法格式:
<!ATTLIST 元素名
属性名1 属性值类型 设置说明
属性名2 属性值类型 设置说明
……
>
设置说明:
#REQUIRED:必须设置该属性
#IMPLIED:可以设置也可以不设置
#FIXED:说明该属性的取值固定为一个值,在 XML 文件中不能为该属性设置其它值,所以不用再xml中写这个属性。但需要在dtd文件中为该属性提供这个值
直接使用默认值:在 XML 中可以设置该值也可以不设置该属性值。但需要在dtd中设置一个值。若没设置则使用默认值。
<!ATTLIST 页面作者
姓名 CDATA #IMPLIED
年龄 CDATA #IMPLIED
联系信息 CDATA #REQUIRED
网站职务 CDATA #FIXED "页面作者"
个人爱好 CDATA "上网"
>
< 页面作者 联系信息=”12356” />
这样的话,这个标签实际上有3个属性,一个联系信息,网站职务,个人爱好。
属性值类型:
CDATA:表示属性值为普通文本字符串。
ENUMERATED
ID
ENTITY(实体)
属性值类型àENUMERATED
属性的值可以是一组取值的列表,在 XML 文件中设置的属性值只能是这个列表中的某个值(枚举)
例如:
<?xml version = "1.0" encoding="GB2312" standalone="yes"?>
<!DOCTYPE 购物篮 [
<!ELEMENT 肉 EMPTY>
<!ATTLIST 肉
品种 ( 鸡肉 | 牛肉 | 猪肉 | 鱼肉 ) "鸡肉">
]>
这个的意思是:肉标签里不能放置其他的子元素。
肉标签有个品种这个属性,属性值类型为ENUMERATED ,值为:( 鸡肉 | 牛肉 | 猪肉 | 鱼肉 ) 而设置说明采用了默认值的形式。
遵循该dtd文件的一个xml文档为:
<购物篮>
<肉 品种="鱼肉"/>
<肉 品种="牛肉"/>
<肉/>
</购物篮>
属性值类型à ID
表示属性的设置值为一个唯一值。
ID 属性的值只能由字母,下划线开始,不能出现空白字符
<?xml version = "1.0" encoding="GB2312" ?>
<!DOCTYPE 联系人列表[
<!ELEMENT 联系人列表 ANY>
<!ELEMENT 联系人(姓名,EMAIL)>
<!ELEMENT 姓名(#PCDATA)>
<!ELEMENT EMAIL(#PCDATA)>
<!ATTLIST 联系人 编号 ID #REQUIRED>
]>
<联系人列表>
<联系人 编号=“a1">
<姓名>张三</姓名>
<EMAIL>zhang@it315.org</EMAIL>
</联系人>
<联系人 编号=“a2">
<姓名>李四</姓名>
<EMAIL>li@it315.org</EMAIL>
</联系人>
</联系人列表>
这个例子中,联系人这个标签有一个编号的属性,属性类型为ID,设置说明为#REQUIRED。
实体定义
实体用于为一段内容创建一个别名,以后就可以使用别名引用这段内容了。
在DTD定义中,一条<!ENTITY …>语句用于定义一个实体。
实体可分为两种类型:引用实体和参数实体。
引用实体主要在 XML 文档中被应用
语法格式:
<!ENTITY 实体名称 “实体内容” >:直接转变成实体内容
在xml文档中的引用方式:
&实体名称;
例如:
book.dtd文档
book.xml文档
参数实体被 DTD 文件自身使用
语法格式:
<!ENTITY % 实体名称 "实体内容" >
引用方式:
%实体名称;
举例1:
<!ENTITY % TAG_NAMES "姓名 | EMAIL | 电话 | 地址">
<!ELEMENT 个人信息 (%TAG_NAMES; | 生日)>
<!ELEMENT 客户信息 (%TAG_NAMES; | 公司名)>
举例2:
<!ENTITY % common.attributes " id ID #IMPLIED
account CDATA #REQUIRED "
>
<!ATTLIST purchaseOrder %common.attributes;>
<!ATTLIST item %common.attributes;>
XML解析技术概述
XML解析方式分为两种:dom和sax
dom:(Document Object Model, 即文档对象模型) 是 W3C 组织推荐的处理 XML 的一种方式。
sax: (Simple API for XML) 不是官方标准,但它是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。
如果是进行DOM解析的话,一开始会将整个xml文档放入内存,作为创建该文档的Document对象。同时也将每个节点在内存中创建出Element对象。将文本作为Text对象,将属性作为Attribute对象。
SAX解析方式:从上往下读,读取一行处理一行。不能往回读。
DOM解析方式和SAM解析方式各自的优缺点:
DOM解析方式:比较消耗内存,如果文件过大,可能会导致内存泄露。但是比较有利于对文档节点的CRUD.
SAX 解析方式:内存不会有压力,只适合文件的读取,不适合对文件的节点进行CRUD操作。
XML解析开发包
Jaxp、Jdom、dom4j
JAXP 开发包是J2SE的一部分,它由javax.xml、org.w3c.dom 、org.xml.sax 包及其子包组成
在 javax.xml.parsers 包中,定义了几个工厂类,程序员调用这些工厂类,可以得到对xml文档进行解析的 DOM 或 SAX 的解析器对象。
使用JAXP进行DOM解析
javax.xml.parsers 包中的DocumentBuilderFactory用于创建DOM模式的解析器对象 , DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法 ,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。
获得JAXP中的DOM解析器
调用 DocumentBuilderFactory.newInstance() 方法得到创建 DOM 解析器的工厂。
调用工厂对象的 newDocumentBuilder方法得到 DOM 解析器对象。
调用 DOM 解析器对象的 parse() 方法解析 XML 文档,得到代表整个文档的 Document 对象,进行可以利用DOM特性对整个XML文档进行操作了。
DOM编程
DOM模型(document object model)
DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点)。这个Node对象可能是Element,Text,Attr.
在dom中,节点之间关系如下:
1、位于一个节点之上的节点是该节点的父节点(parent)
2、一个节点之下的节点是该节点的子节点(children)
3、同一层次,具有相同父节点的节点是兄弟节点(sibling)
4、一个节点的下一个层次的节点集合是节点后代(descendant)
5、父、祖父节点及所有位于节点上面的,都是节点的祖先(ancestor)
Node对象
Node对象提供了一系列常量来代表结点的类型,当开发人员获得某个Node类型后,就可以把Node节点转换成相应的节点对象(Node的子类对象),以便于调用其特有的方法。(查看API文档)
Node对象提供了相应的方法去获得它的父结点或子结点。编程人员通过这些方法就可以读取整个XML文档的内容、或添加、修改、删除XML文档的内容了
更新XML文档
javax.xml.transform包中的Transformer类用于把代表XML文件的Document对象转换为某种格式后进行输出,例如把xml文件应用样式表后转成一个html文档。利用这个对象,当然也可以把Document对象又重新写入到一个XML文件中。
Transformer类通过transform方法完成转换操作,该方法接收一个源和一个目的地。我们可以通过:
javax.xml.transform.dom.DOMSource类来关联要转换的document对象,
用javax.xml.transform.stream.StreamResult 对象来表示数据的目的地。
Transformer对象通过TransformerFactory获得
SAX解析
在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。
SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作
SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:
解析器和事件处理器:
解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。
解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理
SAX方式解析XML文档
使用SAXParserFactory创建SAX解析工厂
SAXParserFactory spf = SAXParserFactory.newInstance();
通过SAX解析工厂得到解析器对象
SAXParser sp = spf.newSAXParser();
通过解析器对象得到一个XML的读取器
XMLReader xmlReader = sp.getXMLReader();
设置读取器的事件处理器
xmlReader.setContentHandler(new BookParserHandler());
解析xml文件
xmlReader.parse("book.xml");
阅读ContentHandler 接口的API文档,常用方法:startElement、endElement、characters
Dom4j
可以参考文档中的内容。
Schema快速入门。
XML Schema 文件自身就是一个XML文件,但它的扩展名通常为.xsd。
一个XML Schema文档通常称之为模式文档(约束文档),遵循这个文档书写的xml文件称之为实例文档。
和XML文件一样,一个XML Schema文档也必须有一个根结点,但这个根结点的名称为Schema。
编写了一个XML Schema约束文档后,通常需要把这个文件中声明的元素绑定到一个URI地址上,在XML Schema技术中有一个专业术语来描述这个过程,即把XML Schema文档声明的元素绑定到一个名称空间上,以后XML文件就可以通过这个URI(即名称空间)来告诉解析引擎,xml文档中编写的元素来自哪里,被谁约束。
Schema快速入门:book.xsd文件
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www. itcast.cn"
elementFormDefault="qualified">
<xs:element name='书架' >
<xs:complexType>
<xs:sequence maxOccurs='unbounded' >
<xs:element name='书' >
<xs:complexType>
<xs:sequence>
<xs:element name='书名' type='xs:string' />
<xs:element name='作者' type='xs:string' />
<xs:element name='售价' type='xs:string' />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
targetNamespace=http://www. itcast.cn声明该schema的默认的命名空间。
elementFormDefault="qualified"如果取值为qualified的话,意思是,将该schema文档中声明的所有的元素都绑定在这个命名空间中。
<xs:complexType>该标签内部是复杂类型的。
<xs:sequence maxOccurs='unbounded' >该标签内部元素是有顺序, 且标签内部出现的内容是无上限的本例中,也就是<书架>中可以出现多个<书>标签。
遵循上边的schema文档写出的的一个xml文档的例子:
<?xml version="1.0" encoding="UTF-8"?>
<itcast:书架 xmlns:itcast="http://www.itcast.cn"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=“http://www.itcast.cn book.xsd">
<itcast:书>
<itcast:书名>JavaScript网页开发</itcast:书名>
<itcast:作者>张孝祥</itcast:作者>
<itcast:售价>28.00元</itcast:售价>
</itcast:书>
</itcast:书架>
xmlns是XML Namespaces的缩写
在XML Schema中,每个约束模式文档都可以被赋以一个唯一的名称空间,名称空间用一个唯一的URI(Uniform Resource Identifier,统一资源标识符)表示。 在Xml文件中书写标签时,可以通过名称空间声明(xmlns),来声明当前编写的标签来自哪个Schema约束文档。如:
<itcast:书架 xmlns:itcast=“http://www.itcast.cn”>
<itcast:书>……</itcast:书>
</itcast:书架>
此处使用itcast来指向声明的名称,以便于后面对名称空间的引用。
xmlns:itcast=http://www.itcast.cn
通过声明指明itcast是这个名称空间的引用。
xsi:schemaLocation=http://www.itcast.cn book.xsd
schemaLocation此属性有两个值。第一个值是需要使用的命名空间。第二个值是供命名空间使用的 XML schema 的位置,两者之间用空格分隔。
就像<itcast:书>,xsi也是一个命名空间的引用。
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance就是xsi命名空间的声明。但是该命名空间是一个广泛熟知的命名空间,所以就不用再指定该命名空间使用的XMLschema所在的位置。
注意:名称空间的名字语法容易让人混淆,尽管以 http:// 开始,那个 URL 并不指向一个schema文件。事实上,这个 URL:http://www.itcast.cn根本没有指向任何文件,只是一个分配的名字,而是在schemaLocation属性的第二个值才指向真正的schema。
在xml中使用默认名称空间
举例:
<书架 xmlns="http://www.it315.org/xmlbook/schema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=“http://www.itcast.cn book.xsd">
<书>
<书名>JavaScript网页开发</书名>
<作者>张孝祥</作者>
<售价>28.00元</售价>
</书>
<书架>
在XML文档中使用名称空间引入多个XML Schema文档
xmlbook.xml
<?xml version="1.0" encoding="UTF-8"?>
<书架
xmlns="http://www.it315.org/xmlbook/schema"
xmlns:demo="http://www.it315.org/demo/schema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=“
http://www.it315.org/xmlbook/schema http://www.it315.org/xmlbook.xsd
http://www.it315.org/demo/schema http://www.it315.org/demo.xsd">
<书>
<书名>JavaScript网页开发</书名>
<作者>张孝祥</作者>
<售价 demo:币种=”人民币”>28.00元</售价>
</书>
</书架>
黄色部分是xml中对两个schema文档的引用,一个使用了默认的命名空间,一个使用了demo作为引用的命名空间。
在xml文档中不使用名称空间引入XML Schema文档
xmlbook.xml
<?xml version="1.0" encoding="UTF-8"?>
<书架
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="xmlbook.xsd">
<书>
<书名>JavaScript网页开发</书名>
<作者>张孝祥</作者>
<售价>28.00元</售价>
</书>
</书架>
更多的schema的语法细节请参考XmlSchema标准参考手册文档。
XML Schema 和 DTD的比较:
XML Schema符合XML语法结构。
DOM、SAX等XML API很容易解析出XML Schema文档中的内容。
XML Schema对名称空间支持得非常好。
XML Schema比XML DTD支持更多的数据类型,并支持用户自定义新的数据类型。
XML Schema定义约束的能力非常强大,可以对XML实例文档作出细致的语义限制。
XML Schema不能像DTD一样定义实体,比DTD更复杂,但Xml Schema现在已是w3c组织的标准,它正逐步取代DTD
-----------------------android培训、java培训、期待与您交流! --------------------------------------------------------------------------------------------------------------------------------------------------