一、Servlet的有关概念与前置知识
- 什么是动态网页
如果浏览器在不同时刻或不同条件下访问Web服务器上的某个页面,
浏览器所获得的页面内容可以发生变化,那么这个页面就称之为动态网页。
动态网页与静态网页最明显的区别就是针对页面的访问请求,
Web服务器在不同条件下返回给客户端的网页内容是否总是相同。
一般来说,Web服务器发送的静态内容直接来自于文本或数据文件,例如HTML或JPEG文件,
而动态内容需要依靠一个程序来临时产生。
这里所说的动态网页,是指Web服务器在不同时刻和不同的条件下
返回给客户端的网页文档内容会发生变化的网页。 - 动态网页程序与引擎
动态网页的创建过程包含两个步骤:首先使用某种编程语言编写出相应的动态网页程序;
然后由一个专门的Web服务器程序模块来解释执行该动态网页程序。
Web程序开发就是指使用某种编程语言来编写动态网页程序。
动态网页程序需要有一个专门的Web服务器程序模块来解释执行,专门解释和执行某种动态网页程序的
Web服务器程序模块习惯上被称为引擎,譬如ASP引擎、Servlet引擎、JSP引擎等等。
引擎以Web服务器的扩展模块的形式提供。
引擎提供的API有两种基本的作用:将访问请求的相关信息传递给动态网页程序,
将动态网页程序产生的结果传递给引擎。
如果客户端请求的URL后缀名不是.htm或.html,而是符合某种引擎所处理的资源名的特征,
Web服务器将把请求转交给相应的引擎去处理,然后由引擎去调用某个程序文件,
并将程序动态产生的内容返回给客户端。 - Servlet技术简介
Servlet技术是Sun公司提供的一种实现动态网页的解决方案,它是基于Java编程语言的Web服务端编程技术,
主要用于在Web服务器端获得客户端的访问请求信息和动态生成对客户端的响应消息。
一个Servlet程序就是一个实现了特殊接口的Java类,它由支持Servlet的Web服务器(具有Servlet引擎)
调用和启动运行。一个Servlet程序负责处理它所对应的一个或一组URL地址的访问请求,
并用于接收客户端发出的访问请求信息和产生响应内容。
Servlet程序具有如下的一些基本功能:
获取客户端通过HTML的FORM表单递交的数据和URL后面的参数信息。
创建对客户端的响应消息内容。
访问服务器端的文件系统。
连接数据库并开发基于数据库的应用。
调用其他Java类。 - B/S系统架构和C/S系统架构
C/S架构是Client/Server的简写,也就是客户机/服务器架构,它是早期出现的一种分布式架构。
B/S架构是Browser/Server的简写,也就是浏览器/服务器架构,它是随着Internet技术的兴起,
对C/S架构的一种变化和改进的架构。
C/S架构缺陷:
如果每个客户端程序都与数据库保持持久的连接,而数据库系统支持的并发连接数有限,
那么这就限制了同时运行的客户端程序的数目。如果不设计持久连接,
给程序的事务处理带来极大困难,并且客户端每次与数据库建立连接的过程需要相对较长的时间。
业务逻辑处理和页面显示都由客户端程序负责处理,不利于软件的维护和功能扩展。
由于在每个客户机上都需要安装客户端程序,工作量之大和效率之低是可想而知的。
C/S架构优点:
C/S架构中的客户端程序就是计算机上的一个桌面程序,功能可以做得非常强大。
B/S架构优点:
只要在Web服务器端这一个地方进行更新即可完成整个系统的更新。
由于客户端不直接与数据库建立连接,而是只有Web服务器端的程序需要与数据库建立连接,
所以数据库并发连接数量有限的问题也得到解决。
Servlet和JSP就是使用Java语言开发B/S架构的应用软件的核心技术。 - Servlet开发设计的相关知识
Java、HTML、CSS、JavaScript、SQL、XML、Tomcat、HTTP
二、Servlet开发入门
- Servlet API介绍
Sun公司定义了一套专门用于开发Servlet程序的Java类和接口,这些类和接口提供Servlet程序开发中
所涉及的各种功能,它们统称为Servlet API(Servlet Application Programming Interface)。
Servlet引擎和Servlet程序之间采用ServletAPI进行通讯。
Servlet API存在方式:
被集成到了Sun公司的JavaEE开发工具包中;
支持Servlet的Web服务器软件都会自带Servlet API的Jar包。
一些通用的Servlet API类和接口包含在javax.servlet包中,
专用于HTTP协议的Servlet API类和接口包含在javax.servlet.http包中,
javax.servlet.jsp与javax.servlet.jsp.tagext这两个包中包含了JSP相关的API。 - 编写与编译Servlet程序
一个Servlet程序就是一个在Web服务器端运行的特殊Java类,这个特殊Java类必须实现
javax.servlet.Servlet接口,Servlet接口定义了Servlet引擎与Servlet程序之间通讯的协议约定。
为了简化Servlet程序的编写,Servlet API中也提供了一个实现Servlet接口的最简单的Servlet类,
其完整名称为javax.servlet.GenericServlet,这个类实现了Servlet程序的基本特征和功能。
Servlet API中还提供了一个专用于HTTP协议的Servlet类,其名称是javax.servlet.http.HtppServlet,
它是GenericServlet的子类,在GenericServlet类的基础上进行了一些针对HTTP特点的扩充。
HtppServlet有一个名为service的方法,我们自己编写的Servlet程序通常只需要在HttpServlet类的
基础上覆盖这个方法。service方法接受两个参数:一个是用于封装HTTP请求消息的对象,其类型
是HttpServletRequest;另一个是代表HTTP响应消息的对象,其类型是HttpServletResponse。 - Servlet的注册与运行
1、注册Servlet
在web.xml文件中,一个<servlet>元素用于注册一个Servlet,<servlet>元素中包含有
两个主要的子元素:<servlet-name>和<servlet-class>。
<servlet>
<servlet-name>AnyName</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-class>子元素指定了当前注册的Servlet的完整类名。
<servlet-name>指定了Servlet的注册名称,可以是任意的合法友好的,
但不能与其他Servlet的注册名相冲突。
2、映射Servlet
在web.xml文件中,一个<servlet-mapping>元素用于映射一个已注册的
Servlet的一个对外访问路径。
<servlet-mapping>元素中包含有两个子元素:<servlet-name>和<url-pattern>
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>/demo/hello.html</url-pattern>
</servlet-mapping>
<url-pattern>子元素中的访问路径必须以正斜杠(/)开头,这个正斜杠(/)表示
当前Web应用程序的根目录,而不是整个Web站点的根目录。路径名可以是多级目录的形式。
在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”,
在*前面不能有目录分隔符“/”结尾,例如,“*.do”表示匹配以“.do”结尾的所有URL;另一种
格式是以正斜杠(/)开头并以“/*”结尾,例如,“/*”表示匹配当前Web应用程序下的所有URL。
当Servlet引擎收到一个访问请求时,它将采用最具体匹配原则来查找请求URL的映射,
其中,“*.扩展名”的匹配优先级最低。
Servlet程序不能被设置为Web应用程序的目录默认网页文档。 - Servlet激活器
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
注册名称为invoker的Servlet的作用就是去激活和调用任何其他Servlet,故被称为Servlet
激活器,它被设置为随Tomcat服务器启动时加载(通过<load-on-startup>元素)。由于
Servlet激活器将把请求URL中的额外路径信息(映射URL中的“*”部分所匹配的内容)当作
某个Servlet的类名去进行调用,所以,在每个Web应用程序中为Servlet激活器所映射的
访问路径可以各不相同,但是必须以“/*”结尾。经过这样的设置以后,即是某个Servlet程序
没有在Web.xml文件中进行注册,我们只需要将Servlet激活器所映射的访问路径中的通配符
(*)替换为这个Servlet的完整类名,就可以通过Servlet激活器来调用这个Servlet程序。
位置是在<tomcat的安装目录>\conf\web.xml - 缺省Servlet
如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前
Web应用程序的缺省Servlet。凡是在web.xml文件中找不到匹配的
<servlet-mapping>元素的URL,它们的访问请求都交给缺省Servlet处理,
也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。
位置在<tomcat的安装目录>\conf\web.xml文件。
当访问Tomcat服务器中的某个静态HTML文件和图片时,实际上是在访问这个缺省Servlet。 - Servlet的类装载器
1、类装载器
类装载器负责根据一个类的名称来定位和生成类的字节码数据后返回给Java虚拟机。
当一个类被加载后,Java虚拟机将其编译为可执行代码存储在内存中,
并将索引信息存储进一个HashTable中,其索引关键字就是这个类的完整名称。
当Java虚拟机要用到某个类时,它先使用类名作为关键字在HashTable中查找相应的信息,
如果该可执行代码已经存在,Java虚拟机直接从内存里调用该可执行代码,
反之则调用类装载器加载并进行加载和编译。
要想在程序中获得代表某个类的字节码数据的Class实例对象,可以采用下面三种方式:
类名.class,例如:System.class
对象.getClass(),例如,new Date().getClass();
Class.forName("类名"),例如,Class.forName("java.util.Date");
Java类库中提供了一个java.lang.ClassLoader来作为类装载器的基类,
Java虚拟机和程序都调用ClassLoader类的loadClass方法来加载类。
Java虚拟机通过以下一些方式来选择类装载器:
(1)Java虚拟机中内嵌了一个称为Bootstrap的类装载器,它是用特定于操作系统的本地代码实现的,
属于Java虚拟机的内核,这个BootStrap类装载器不用专门的类装载器去进行装载。
Bootstrap类装载器负责加载Java核心包的类(即rt.jar文件中的类)。
Java核心包中有另外两个类装载器:ExtClassLoader和AppClassLoader,
ExtClassLoader类装载器负责加载存放在<JAVA_HOME>/jre/lib/ext目录下的Jar包中的类,
AppClassLoader负责加载CLASSPATH环境变量指定的路径中的类。
(2)每个ClassLoader本身只能分别加载特定位置和目录中的类,但是,ClassLoader被设计成了
一种委托模式,使得某一个ClassLoader可以委托它的父级类装载器去加载类,从而
让应用程序可以借助某一个子级的ClassLoader去多个位置和目录中进行类的加载。
(3)依据一个类的存放位置,这个类最终只能由一个特定的类装载器装载。对于一个已被父级
类装载器装载的类来说,Java虚拟机默认也使用这个父级类装载器去装载它所调用的其他类,
由于父级类装载器不会委托子级类装载器去装载类,所以,在一般情况下,
一个已被父级类装载器装载的类无法调用那些只能被子级类装载器发现和装载的其他类。
(4)每个运行中的线程都有一个关联的上下文类装载器,可以使用Thread.setContextClassLoader()
方法设置线程的上下文类装载器。每个线程默认的上下文类装载器是其父线程的上下文
类装载器,而主线程的类装载器初始被设置为ClassLoader.getSystemClassLoader()
方法返回的系统类装载器。
2、Tomcat中的类装载器
Bootstrap<--System<--Common<--Catalina/Shared<--Webapp1/Webapp2
(1)这里的Bootstrap为Java虚拟机内嵌的类装载器与ExtClassLoader的总称,
负责加载Java核心包中的类,以及存放在<JAVA_HOME>/jre/lib/ext目录下的类。
(2)System即系统类装载器,通常情况下就是AppClassLoader,
负责加载CLASSPATH环境变量设置的目录中的类。包含如下两个Jar包:
<CATALINA_HOME>/bin/bootstrap.jar
<JAVA_HOME>/lib/tools.jar
(3)Common类加载器负责从<CATALINA_HOME>/common/classes中的.class类文件和
<CATALINA_HOME>/common/lib中的Jar包加载类。
(4)Catalina类装载器负责从<CATALINA_HOME>/server/classes中的.class类文件和
<CATALINA_HOME>/server/lib中的Jar包加载类。
(5)Shard类加载器负责从<CATALINA_HOME>/share/classes中的.class类文件和
<CATALINA_HOME>/share/lib中的Java包加载类。
(6)WebappX类装载器负责从当前Web应用程序的/WEB-INF/classes中的.class类文件和
/WEB-INF/lib中的Jar包加载类。 - 编写一个自动编译工具
set CLASSPATH=c:\tomcat\common\lib\servlet.jar;%CLASSPATH%
设置CLASSPATH
javac -d d:\myweb\WEB-INF\classes %1
%1表示传递给这个批处理文件的第一个参数,这里就是拖动到它上面的java源文件名。
pause
执行完编译命令后暂停,等待人们按任意键后才继续运行,便于查看编译结果。
三、Servlet的特点及运行过程
- Servlet的特点
Servlet引擎是一种容器程序,它负责管理和维护所有Servlet对象的声明周期,
因此也被称之为Servlet容器或Web容器。
Servlet的最常见应用在于读取Web浏览器传递给Web服务器的参数和
生成Web服务器返回给Web浏览器的动态网页文档内容。
Servlet程序的运行过程就是它与Servlet引擎的交互过程。
Servlet程序只与Servlet引擎打交道。 - Servlet的运行过程
1、接收到访问某个Servlet的HTTP请求。可走2和4两条路。
2、装载并创建Servlet的一个实例对象。
3、调用Servlet实例对象的init()方法,以便执行Servlet的一些初始化工作。
4、创建一个用于封装HTTP请求消息的HTTPServletRequest对象
和一个代表HTTP响应消息的HttpServletResponse对象,
然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
5、在一个Web应用程序被停止或重新启动之前,Servlet引擎将卸载其中运行的Servlet。
在卸载Servlet之前,Servlet引擎将调用Servlet的destroy()方法,
以便在这个方法中执行Servlet的一些清尾工作。
<load-on-startup>元素中的内容被设置为0或一个正整数,它指定该Servlet应该
在Web应用程序启动时就被实例化和调用它的init()方法,且这个数字越小,
Servlet被装载的时间也越早,相同数字的Servlet之间的装载顺序由Servlet引擎
自己决定。如果<load-on-startup>元素中的内容被设置成了一个负整数,
则由Servlet引擎自己决定在什么时候装载该Servlet。
在Servlet的整个生命周期内,它的init方法只被调用一次,但它的service方法可能被调用多次。
在<Tomcat安装主目录>/conf/server.xml文件中,可以使用<Context>元素来设置每个独立的Web
应用程序的配置信息,<Context>元素有一个reloadable属性,当它的设置值为true时,Tomcat
将监视该Web应用程序的/WEB-INF/classes和/WEB-INF/lib目录下的类是否发生了改变,然后自动
重新装载那些发生了改变的类,并在Tomcat所运行的命令行窗口中显示出重新装载的有关提示信息。 - Servlet的线程安全问题
Servlet API中定义了一个javax.servlet.SingleThreadModel接口,如果某个Servlet实现了
SingleThreadModel接口,那么Servlet引擎将以单线程模式(多实例)来调用其service方法。
真正意义上的多线程安全问题是指一个Servlet实例对象被多个线程同时调用的问题。
所以,如果多个并发的service方法调用有线程安全问题,最好是自己在service方法中
编写多线程同步控制代码,而不要采取单线程的运行模式。
四、ServletConfig接口
- ServletConfig
Servlet程序是发布到Web应用程序中运行的,此Web应用程序就称之为Servlet容器。
Servlet的init方法与getServletConfig方法的关系与作用
Servlet引擎负责读取配置文件,根据配置文件中的信息生成ServletConfig对象,
接着创建Servlet类的实例对象,然后调用该Servlet实例对象的init方法
把ServletConfig对象传递给该Servlet实例对象。 - getInitParameterNames方法
getInitParameterNames方法用于返回一个Enumeration集合对象,
该集合对象中包含在web.xml文件中为当前Servlet设置的所有初始化参数的名称。 - getInitParameter方法
getInitParameter方法用于返回在web.xml文件中为Servlet所设置的某个名称的初始化参数的值,
如果指定名称的初始化参数不存在,则返回值为NULL。 - getServletName方法
getServletName方法用于返回Servlet在web.xml文件中的注册名称。对于没有在web.xml
文件中注册的Servlet,getServletName方法返回的结果为该Servlet的类名。 - getServletContext方法
在Servlet程序中,每个Web应用程序(Servlet容器)都用一个各自的ServletContext
对象来表示,ServletConfig对象中包含了ServletContext对象的引用。 - GenericServlet类实现ServletConfig接口的目的
GenericServlet类还是提供了一些简化的手段。
GenericServlet类除了实现Servlet接口中的方法之外,它还实现了ServletConfig
接口中的方法,在实现的ServletConfig接口方法内部,它们调用ServletConfig对象的
同名方法。例如,GenericServlet类的getServletName方法的定义如下:
public String getServletName() {
return getServletConfig().getServletName();
}
五、GenericServlet与HttpServlet类
- HttpServlet是GenericServlet子类,其完整名称是javax.servlet.http.HttpServlet,
它提供了处理HTTP协议的基本架构。
在HttpServlet类及其子类中,除了可以调用HttpServlet类内部新定义的方法外,
还可以调用Servlet、ServletConfig接口和GenericServlet类中定义的一些方法。 - 区分回调方法与工具方法
对于用作组件或插件的类则需要编写一些供系统去调用的方法,这些专门用于
被系统调用的方法被称之为回调方法,也就是回过来被系统调用的方法。
GenericServlet和HttpServlet类中除了包含有回调方法外,
也包含有一些供Servlet编程人员调用的工具方法,
编程人员可以在程序代码中直接调用这些工具方法去完成某种任务。 - init方法
init方法在Servlet的声明周期中仅执行一次,
Servlet引擎创建Servlet实例对象后立即调用该方法。
init方法的调用位于构造方法之后。
Servlet引擎在调用init方法时,会传递一个包含Servlet的配置和运行环境信息的
ServletConfig对象,Servlet接口中定义的init方法的语法格式如下:
public void init(ServletConfig config) throws ServletException
GenericServlet实现的init(ServletConfig config)方法中调用了无参数的init()方法,
所以,对于继承GenericServlet类的Servlet程序,也可以覆盖这个无参数的init()方法
来编写初始化代码,并且覆盖这个无参数的init()方法还有一个好处,那就是省去了
覆盖init(ServletConfig config)方法时总是要编写super.init(config)语句的麻烦。 - service方法
service方法是Servlet的核心方法,每当针对某个Servlet的访问请求到达时,
Servlet引擎就会调用该Servlet实例对象的service方法来进行响应。
Servlet接口中定义的service方法的语法格式为:
public void service(ServletRequest req, ServletResponse res)
throws ServletException, java.io.Exception
GenericServlet类没有对这个方法进行实现,HttpServlet类实现了这个方法。
将请求和响应对象的类型分别转换成HttpServletRequest和HttpServletResponse;
再将它们作为参数传递给下面这个重载的service方法。
HttpServlet类实现的service方法内部调用了另外一个重载形式的service方法,
重载的service方法的定义语法为:
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, java.io.IOException
如果在子类中覆盖这个重载的service方法,其接收的参数类型即为
HttpServletRequest和HttpServletResponse,那么,
在子类覆盖的service方法中就不再需要对这两个参数进行类型转换。 - destroy方法
destroy方法在Web容器卸载Servlet之前被调用,显然,该方法在Servlet声明周期中
也仅执行一次,可以通过覆盖destroy方法来完成与init方法相反的功能。 - getServletConfig方法
getServletConfig方法用于返回Servlet引擎通过init方法传递进来的
那个ServletConfig对象的引用。 - getServletInfo方法
getServletInfo方法用于返回Servlet的描述信息,Servlet引擎要
获得某个Servlet的描述信息时将调用这个方法。 - doXxx方法
HttpServlet中重载的service方法根据客户端的请求方方式,分别调用与之对应的
doXxx方法来完成具体的处理和响应细节,并将它接收的两个参数传递给该doXxx方法。
下面是HttpServlet中定义的doXxx方法:
doGet 用于处理GET请求
doPost 用于处理POST请求
doHead 用于处理HEAD请求
doPut 用于处理PUT请求
doDelete用于处理DELETE请求
doTrace 用于处理TRACE请求
doOptions用于处理OPTIONS请求 - 浏览器缓存内幕与getLastModified方法
IE浏览器
工具-->Internet选项-->常规选项卡-->Internet临时文件-->设置-->Internet临时文件夹
可以查看浏览器保存的所有缓存页面内容的文件夹的完整目录名称。
检查所存网页的较新版本
每次访问此页时检查
每次启动Internet Explorer时检查
自动
不检查
在HttpServlet类中定义了一个getLastModified方法,getLastModified方法的返回值
可以影响浏览器如何处理和利用缓存内容,该方法的完整语法定义如下:
protected long getLastModified(HttpServletRequest req)
HttpServlet中重载的service方法在调用doGet方法之前,它还将先调用
getLastModified方法,并根据getLastModified方法的返回值来决定是否调用
doGet方法和在响应消息中是否生成Last-Modified头字段,具体规则如下:
当getLastModified方法返回一个负数时,不管请求消息中的情况怎样,
service方法都将直接调用doGet方法来生成响应内容,这正是
HttpServlet类中定义的getLastModified方法的行为;
当getLastModified方法返回一个正数,且请求消息中没有包含If-Modified-Since
请求头时(这往往出现在对某个资源的第一次访问时),或者请求消息中
包含的If-Modified-Since请求头中的时间值比getLastModified方法返回的
时间值旧时,service方法将根据getLastModified方法的返回值
生成一个Last-Modified头字段,然后调用doGet方法生成响应时间。
当getLastModified方法返回一个正数时,且请求消息中包含的If-Modified-Since
请求头中的时间值比getLastModified方法返回的时间值新或者与之相同,
service方法将不调用doGet方法,而是向浏览器返回一个304
(Not Modified)状态码来通知浏览器继续使用以前缓存的内容。
揭开浏览器缓存的奥秘
请求方式:
“后退”、“前进“、直接在浏览器地址栏中输入访问地址
单击超链接
浏览器窗口中刷新,刷新的作用就是让浏览器务必向服务器发出访问请求。
单击超链接操作的结论:
如果某个页面的响应消息中包含Last-Modifed头字段,则当通过其他网页文档中的
超链接来调用这个页面时,浏览器只在每次启动后的第一次访问这个页面时
才向服务器发出服务请求,对于在这次启动运行期间对该页面的后续访问,
浏览器将不在向服务器发出访问请求,而是直接调用缓存的内容。在访问一个
普通的HTML文件时,Tomcat的缺省Servlet都会产生一个Last-Modified头字段
来说明这个HTML文件的最新修改时间,因此,在浏览器的一次启动运行期间,
它只在对某个HTML文件进行第一次访问时才向服务器发出真正的访问请求。
如果某个页面的响应消息中没有包含Last-Modified头字段,则当通过
其他网页文档中的超链接来调用这个页面时,浏览器在整个启动运行期间
对该页的每次访问,都将向服务器发出访问请求,而不会调用已缓存的内容。
六、ServletContext接口
- ServletContext接口
每个Web应用程序都是一个独立的Servlet容器,每一个Web应用程序分别用一个
ServletContext对象来表示,ServletContext接口定义了ServletContext对象
需要对外提供的方法,Servlet程序通过这些方法与Servlet容器进行通讯。
在Servlet容器初始化Servlet对象时,ServletContext对象随着
ServletConfig对象提供给Servlet。 - 获取Web应用程序的初始化参数
如果要在server.xml文件中为某个Web应用程序设置初始化参数,需要在该Web
应用程序所对应的<Context>元素中增加<Parameter>子元素,如下所示:
<Context path="/com" docBase"d:\myweb" debug="0" reloadable="true">
<Parameter> name="companyName" value="com" override="false"/>
</Context>
override属性用于指定在Web应用程序的web.xml文件中设置的同名初始化参数
是否被覆盖这里的设置,默认值为true,即允许被覆盖。
如果要在Web应用程序的web.xml文件中设置初始化参数,
则需要在根元素<web-app>中增加<context-param>子元素。如下所示:
<context-param>
<param-name>companyName</param-name>
<param-value>com_new</param-value>
</context-param> - 记录日志
ServletContext接口中定义了两个重载的log方法来记录日志,它们的定义如下:
public void log(java.lang.String msg)
public void log(java.lang.String message, java.lang.Throwable t)
GenericServlet类中也定义了两个log方法,它们分别调用ServletContext对象中
对应的log方法,这样,在Servlet中就可以简化对log方法的调用。
在server.xml文件中,使用<logger>元素来设置日志文件的相关信息,如下所示:
<Logger className="org.apache.catalina.logger.FileLogger" directory="logs"
prefix="localhost_log." suffix=".txt" timestamp="true"/>
directory属性用于指定所创建的日志文件的存储目录,如果指定的是一个相对路径,
则其基准路径为$CATALINA_HOME环境变量所设置的目录,
directory的默认值为相对目录“logs”。
<logger>元素可以嵌套在<Engine>、<Host>和<Context>元素之中,如果里层元素中
没有单独设置<logger>元素,它将继承外层元素中设置的<logger>元素。
JDK中提供的日志记录模块
JDK中的日志记录模块的所有类都位于java.util.logging包中。
JDK中的日志记录模块将日志信息定义成了7个级别:
FINEST、FINER、FINE、CONFIG、INFO、WARNING、SEVERE
每个logger对象都有一个名称,其名称通常采用包名的形式,用点(.)对名称进行层次划分。
根据logger对象的名称,logger对象可以在逻辑上形成一种父子关系。
最顶级的logger对象称为根logger对象,用空字符串("")表示。
logger.getLogger方法内部首先调用LogManager.getLogManager()方法获取LoggerManager
实例对象,然后从中检索指定名称的logger对象。如果logManager对象中存在指定
名称的logger对象,logger.getLogger方法返回该logger对象;如果logManager
对象中不存在指定名称的logger对象,logger.getLogger方法内部则创建一个新的
logger对象,并以指定的名称将该logger对象注册到logManager对象中后返回。
要想将某个logger对象记录的日志信息写入到某种设备中去,需要把与设备对应的Handler对象
注册到该logger对象上,调用某个logger对象的addHandler方法可以完成这一任务。
还可以调用logger对象的setLevel方法,来指定把该logger对象生成的
哪个级别的日志信息交给handler去处理。
还可以通过属性文件来动态配置。属性文件可以通过两种方式指定:
一种方式是使用默认的<JRE_HOME>/lib/log.properties文件;
另一种方式则是为JVM设置java.util.logging.config.file系统属性,即采用如下方式:
java -Djava.util.loggin.config.file=<属性文件名> <类名>
其中,属性文件必须位于CLASSPATH环境变量包含的某个目录中。如果使用了
第二种方式,那么默认的<JRE_HOME>/lib/log.properties文件将不再起作用。
下面是一个简单的log.properties文件:
handlers=java.util.logging.ConsoleHandler
.level=INFO
org.com.xxx.level=FINER
java.util.logging.ConsoleHandler.level=CONFIG
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter - application域范围的属性
由于一个Web应用程序中的所有Servlet都共享同一个ServletContext对象,所以,
ServletContext对象被称之为application对象(Web应用程序对象)。
ServletContext接口中定义了4个分别用于增加、删除、访问application域范围的属性的方法。
getAttributeNames方法:用于返回一个Enumeration集合对象,
该Enumeration集合对象中包含了application对象中的所有属性的名称。
getAttribute方法:用于返回某个属性的值。
removeAttribute方法:用于删除某个属性。
setAttribute方法:用于增加一个属性,设置的属性名最好遵循与包名同样的命名习惯。
如果该名称的属性已经存在,则用新的设置值替换原来的设置值;
如果属性设置值为null,则等效于使用了removeAttribute方法。 - 访问资源文件
ServletContext接口中还定义了一些用于访问Web应用程序的内部资源文件的方法,这些资源文件
是指Web应用程序内部的各种形式的文件,包括WEB-INF目录中不能被外界访问的文件。
getResourcePaths(String str)方法
返回一个java.util.Set集合对象,该Set集合对象中包含某个资源目录中的
所有子目录和文件的路径名称,每个路径名称都以相对于整个Web应用程序的根目录的
形式表示,即都用“/”开头,其中的每个目录路径的最后也都是一个“/”结尾。
getResource方法
返回映射到某个资源上的URL对象,传递给getResource方法的参数必须是一个以“/”开头的
资源路径名,开头的“/”表示当前Web应用程序的根目录。
getResourceAsStream方法
返回连接到某个资源上的InputStream对象,这个方法实际上是打开了getResource方法
返回的URL的对象的输入流,并返回这个输入流对象供程序直接去读取数据,
它的参数传递规则与getResource方法完全一样。
为了简化程序的编写,Class类中也定义了几个访问资源文件的方法,
这些方法内部调用了ClassLoader类中的同名方法去完成响应的功能。
ClassLoader.getResourceAsStream方法也可以访问目录中的资源文件,
但是,该方法不能访问Web应用程序内的其他目录中的资源。
ServletContext类中的访问资源的方法是通过Servlet容器来获得资源文件的,
它使得Servlet程序可以访问Web应用程序内部的任意位置的文件。 - 获取虚拟路径所映射的本地路径
ServletContext接口中定义了一个getRealPath方法,用于返回某个虚拟路径所映射的
本地文件系统路径。要返回Web应用程序的根目录所映射的本地文件系统路径,
传递给getRealPath方法的路径字符串中可以只有一个“/”字符,也可以是一个空字符串。 - Web应用程序之间的访问
要实现这个功能,首先都要获得代表其他Web应用程序的ServletContext对象。
ServletContext接口中定义了一个getContext方法来获得某个URL所对应的ServletContext
对象,传递给getContext方法的路径字符串必须以“/”作为起始字符,这个“/”代表的
是整个Web服务器的根目录,而不是某个Web应用程序的根目录。
如果要让某个Web应用程序内部能够使用ServletContext.getContext方法返回代表其他
Web应用程序的servletContext对象,必须将<Tomcat安装主目录>/conf/server.xml
文件中与该Web应用程序对应的<Context>元素的crossContext属性设置为true。
<Context path="/com" docBase="d:\myweb" debug="0" reloadable="true"
crossContext="true">
crossContext属性的默认值为fasle,此时,ServletContext.getContext方法的
返回值为null。 - ServletContext接口中的其他方法
getMajorVersion方法
返回Servlet容器所支持的Servlet API的主要版本号。
getMinorVersion方法
返回Servlet容器所支持的Servlet API的次要版本号。
getMimeType方法
返回某个文件名所对应的MIME类型。
getServerInfo方法
返回Servlet容器的名称和版本信息。