1. Servlet介绍
1.1. 百度百科
Servlet是在服务器上运行的小程序。这个词是在Java applet的环境中创造的,Java applet是一种当作单独文件跟网页一起发送的小程序,它通常用于在客户端运行,结果得到为用户进行运算或者根据用户互作用定位图形等服务。
服务器上需要一些程序,常常是根据用户输入访问数据库的程序。这些通常是使用公共网关接口(CGI(Common Gateway Interface))应用程序完成的。然而,在服务器上运行Java,这种程序可使用Java编程语言实现。在通信量大的服务器上,Javaservlet的优点在于它们的执行速度更快于CGI程序。各个用户请求被激活成单个程序中的一个线程,而无需创建单独的进程,这意味着服务器端处理请求的系统开销将明显降低。
1.2. 维基百科
Servlet(Server Applet),全称Java Servlet,未有中文译文。是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
最早支持Servlet标准的是JavaSoft的Java Web Server。此后,一些其它的基于Java的Web服务器开始支持标准的Servlet。
1.3. 什么是Servlet
Servlet是JavaEE三大组件之一,是使用Java语言编写服务器端的程序,主要用来处理Web应用程序中的请求-响应。Servlet并没有main之类的执行方法,当用户访问服务器的时候,Tomcat是通过调用Servlet的某些方法来完成整个处理过程的。Servlet是运行在Tomcat服务器提供的Servlet容器中的,所以Servlet是不用程序指定调用的。
1.4. Tomcat与JavaEE
JavaEE的版本与Tomcat服务器的版本是存在一种对应关系的,在开发Web应用程序的时候,需要注意对应版本关系,不然可能引起Web程序报错。
JavaEE与Tomcat服务器的版本对应关系如下表:
Tomcat服务器版本 |
Servlet\JSP版本 |
JavaEE版本 |
Java运行环境 |
Tomcat 4.1 |
Servlet 2.3\JSP 1.2 |
JavaEE 1.3 |
JDK 1.3 |
Tomcat 5.0 |
Servlet 2.4\JSP 2.0 |
JavaEE 1.4 |
JDK 1.4 |
Tomcat 5.5\6.0 |
Servlet 2.5\JSP 2.1 |
JavaEE 5.0 |
JDK 5.0 |
Tomcat 7.0 |
Servlet 3.0\JSP 2.2 |
JavaEE 6.0 |
JDK 6.0 |
如果使用Tomcat服务器的高版本时,可以向下兼容Servlet\JSP、JavaEE及Java运行环境的版本。目前我们学习研究Servlet,主要是以2.5版本为主,所以使用的JavaEE版本可以是JavaEE 5.0版本。
在Tomcat服务器与JavaEE中,分别提供了有关Servlet的帮助文档信息。如果在Tomcat服务器中查看Servlet的相关信息在Tomcat服务器的安装目录中,webapps目录中的docs目录中名为servletapi文件夹中查看。如果在JavaEE中查看有关Servlet的相关信息,需要下载对应JavaEE版本的API帮助文档。
需要注意的是,Servlet 3.0版本在Tomcat服务器和JavaEE都提供帮助文档,但Servlet 2.5版本只有在JavaEE提供了帮助文档,Tomcat并没有提供Servlet 2.5版本的帮助文档。
2. 编写一个Servlet
2.1. 通过Eclipse创建Servlet
开发工具Eclipse或MyEclipse本身提供了创建Servlet的功能,下面我们首先利用开发工具来创建一个Servlet,具体步骤如下:
- 首先,我们创建一个Web工程。
- 在Web工程的src目录下,鼠标右键点击“New”选项,选择“Servlet”选项。
- 弹出创建Servlet的界面窗口,具体内容如下:
- 输入Servlet的包名、名称及相关方法后,点击“Next”按钮进行下一步操作。
该界面是配置Servlet在web.xml文件中的相关信息,具体内容如下:
-
- Servlet/JSP Class Name:Servlet的完整路径。
- Servlet/JSP Name:Servlet的名称。
- Servlet/JSP Mapping URL:配置Servlet拦截的路径,客户端通过该路径访问Servlet。
- File Path of web.xml:当前工程的web.xml配置文件保存路径。
- Display Name:显示名称。
- Description:描述名称。
- 配置完毕之后,点击“Finish”按钮,完成Servlet的创建工作。
创建完成之后,当前Web工程的变化是在src目录下多了一个Servlet的Java文件,在WEB-INF目录中的web.xml文件中多了Servlet相关配置信息。
创建的Servlet的Java文件内容:
public class FirstServlet extends HttpServlet { public void init() throws ServletException {} public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE HTML >"); out.println("<HTML>"); out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>"); out.println(" <BODY>"); out.println (" This is "+ this.getClass()+", using the GET method"); out.println(" </BODY>"); out.println("</HTML>"); out.flush(); out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE HTML >"); out.println("<HTML>"); out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>"); out.println(" <BODY>"); out.println (" This is "+ this.getClass()+", using the GET method"); out.println(" </BODY>"); out.println("</HTML>"); out.flush(); out.close(); } public void destroy() {} }
Web工程的配置文件web.xml内容:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name></display-name> <servlet> <description>This is the description of my J2EE component</description> <display-name>This is the display name of my J2EE component</display-name> <servlet-name>FirstServlet</servlet-name> <servlet-class>app.java.servlet.FirstServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FirstServlet</servlet-name> <url-pattern>/servlet/FirstServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
将当前Web应用程序发布到Tomcat服务器,并启动Tomcat服务器运行测试当前创建的Servlet内容。
- 通过Eclipse或MyEclipse将当前Web工程发布到Tomcat服务器,并启动Tomcat服务器。
- 打开浏览器,在地址栏中输入http://localhost:8080/08_servlet/servlet/FirstServlet,访问服务器端的Servlet内容。
2.2. 手动编写一个Servlet
通过Eclipse或MyEclipse创建Servlet虽然简单,但我们并不知道相关代码是什么含义。所以,下面我们需要研究一下生成出来的代码。
首先, 我们来研究一下创建的Servlet文件源代码,会发现如下内容:
- 是继承于HttpServlet类。
- 包含init()、doGet()、doPost()和destroy()方法。
根据上述内容,我们可以手动创建一个Servlet的Java文件,如下面的代码所示:
public class SecondServlet extends HttpServlet { @Override public void init() throws ServletException { System.out.println("这是init()方法..."); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("这是doGet()方法..."); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("这是doPost()方法..."); } @Override public void destroy() { System.out.println("这是destroy()方法..."); } }
其次,web.xml配置文件增加的内容:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name></display-name> <!-- servlet标签:用于配置Servlet的名称和完整路径. * servlet-name标签:用于为对应的Servlet设置名称. * servlet-class标签:用于设置对应的Servlet的完整路径. --> <servlet> <servlet-name>SecondServlet</servlet-name> <servlet-class>app.java.servlet.SecondServlet</servlet-class> </servlet> <!-- servlet-mapping标签:用于配置Servlet拦截客户端请求路径. * servlet-name标签:用于设置对应使用的Servlet名称. * url-pattern标签:用于设置客户端请求的拦截路径. * 相对路径:/servlet/FirstServlet * 绝对路径:http://localhost:8080/08_servlet/servlet/FirstServlet --> <servlet-mapping> <servlet-name>SecondServlet</servlet-name> <url-pattern>/servlet/SecondServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
将当前Web应用程序发布到Tomcat服务器,并启动Tomcat服务器运行测试当前创建的Servlet内容。
- 通过Eclipse或MyEclipse将当前Web工程发布到Tomcat服务器,并启动Tomcat服务器。
- 打开浏览器,在地址栏中输入http://localhost:8080/08_servlet/servlet/SecondServlet,访问服务器端的Servlet内容。
2.3. Servlet的继承链
通过创建Servlet的Java文件中的代码内容,可以发现创建的Servlet是继承于HttpServlet类,查看JavaEE帮助文档中的HttpServlet内容。
Method Summary |
|
protected void |
doGet(HttpServletRequest req, HttpServletResponse resp) |
protected void |
doPost(HttpServletRequest req, HttpServletResponse resp) |
protected void |
service(HttpServletRequest req, HttpServletResponse resp) |
void |
service(ServletRequest req, ServletResponse res) |
通过帮助文档提供的内容,我们可以知道创建Servlet中的doGet和doPost方法是继承于HttpServlet提供的,但还有init和destroy方法没有找到。我们发现HttpServlet是继承于GenericServlet,查看JavaEE帮助文档中的GenericServlet内容。
Method Summary |
|
void |
destroy() |
void |
init() |
abstract void |
service(ServletRequest req, ServletResponse res) |
通过帮助文档提供的内容,我们可以知道init和destroy方法是源于GenericServlet。但是其实GenericServlet都实现了Servlet接口。
Method Summary |
|
void |
destroy() |
getServletConfig() |
|
getServletInfo() |
|
void |
init(ServletConfig config) |
void |
service(ServletRequest req, ServletResponse res) |
所以,init和destroy方法是Servlet接口提供的方法。通过上述的查找,我们已经很清晰的知道了Servlet的继承关系,具体如下图:
2.4. Servlet工作流程
利用Servlet完成的Web应用的实际工作流程是通过Tomcat服务器发布服务,客户端与服务器端之间的交互遵循Http协议完成的。具体工作流程如下:
- 客户端浏览器向服务器端发送请求。
- 服务器端由Tomcat服务器提供的Servlet容器解析接收到的请求。
- 通过Web应用程序的配置文件web.xml,解析到对应执行的Servlet。
- Servlet完成客户端发送的请求逻辑,并完成向客户端发送的响应内容。
- 由Tomcat服务器提供的Servlet容器向客户端浏览器进行响应。
我们也可以通过下面的图来理解Servlet具体的工作流程。
2.5. Servlet注意事项
值得注意的是Servlet内容是属于JavaEE内容,和使用JavaSE内容一样,都是需要引入JAR包的。使用Eclipse或MyEclipse创建Web应用程序的时候,会发现已经导入了JavaEE所需要的JAR包。其中javaee.jar包中包含了使用Servlet的所有内容。
但是,当把Web应用程序发布到Tomcat服务器的时候,发现对应的目录中并没有javaee.jar包。我们知道无论是编译还是运行都是需要这些JAR包的,这说明Tomcat服务器本身提供了Servlet运行所需要的环境。在Tomcat服务器的安装目录中的lib目录中可以找到servlet-api.jar包,该JAR包也提供了Servlet运行所需的环境。
我们如果想要手动编译Servlet的话,需要做以下及步:
- 在Tomcat安装目录中的webapps目录创建Web工程名称及目录结构。
- 在命令行中利用命令编译Servlet文件。
javac -classpath C:\Tools\apache-tomcat-7.0.55\lib\servlet-api.jar -d . Servlet.java
- 在对应Web工程目录的WEB-INF目录中的web.xml进行配置。
3. 深入掌握Servlet
3.1. Servlet的生命周期
一般情况下,自定义Servlet都是继承HttpServlet。但通过HttpServlet的继承链,我们知道HttpServlet是实现了Servlet接口,下面列表是Servlet接口提供的所有方法。
Method Summary |
|
void |
destroy() |
getServletConfig() |
|
getServletInfo() |
|
void |
init(ServletConfig config) |
void |
service(ServletRequest req, ServletResponse res) |
上述所有方法中,init()、service()和destroy()方法叫做Servlet的生命周期。下面我们分别讨论一下有关生命周期的三个方法:
- init()方法
- 在Servlet实例化之后,Servlet容器会调用init()方法,主要是用来完成处理客户端请求之前的初始化工作。
- init()方法在Servlet的生命周期中只被执行一次。
- service()方法
- Servlet容器调用service()方法来处理客户端发送的请求。在service()方法被调用之前,必须保证init()方法被正确执行。
- service()方法在每次客户端发送请求之后,会被执行一次。
- destroy()方法
- 当Servlet容器检测到当前Servlet实例被移除时,会调用destroy()方法,以便让Servlet实例可以释放所使用的所有资源。
- destroy()方法在Servlet的生命周期中也只被执行一次。
下面我们通过实际操作来讨论关于Servlet的生命周期是怎么样的:
- 首先,创建一个Servlet文件,具体如下。
public class LifeServlet implements Servlet { public LifeServlet(){ System.out.println("这里创建了一个Servlet实例对象..."); } public void init(ServletConfig config) throws ServletException { System.out.println("这是init()方法..."); } public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.println("这是service()方法..."); } public void destroy() { System.out.println("这是destroy()方法..."); } public ServletConfig getServletConfig() { return null; } public String getServletInfo() { return null; } }
- 在web.xml文件中,配置有关Servlet信息。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>LifeServlet</servlet-name> <servlet-class>com.servlet.LifeServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LifeServlet</servlet-name> <url-pattern>/servlet/LifeServlet</url-pattern> </servlet-mapping> </web-app>
- 将Web应用程序发布到Tomcat服务器,并启动Tomcat服务器。
- 启动Tomcat服务器之后,我们可以查看Tomcat服务器启动的日志内容,并没有有关Servlet信息。
十一月 20, 2017 1:22:48 下午 org.apache.catalina.core.AprLifecycleListener init INFO: Loaded APR based Apache Tomcat Native library 1.2.12. 十一月 20, 2017 1:22:48 下午 org.apache.catalina.core.AprLifecycleListener init INFO: APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true]. 十一月 20, 2017 1:22:49 下午 org.apache.coyote.AbstractProtocol init INFO: Initializing ProtocolHandler ["http-apr-8080"] 十一月 20, 2017 1:22:49 下午 org.apache.coyote.AbstractProtocol init INFO: Initializing ProtocolHandler ["ajp-apr-8009"] 十一月 20, 2017 1:22:49 下午 org.apache.catalina.startup.Catalina load INFO: Initialization processed in 1914 ms 十一月 20, 2017 1:22:49 下午 org.apache.catalina.core.StandardService startInternal INFO: Starting service Catalina 十一月 20, 2017 1:22:49 下午 org.apache.catalina.core.StandardEngine startInternal INFO: Starting Servlet Engine: Apache Tomcat/7.0.27 十一月 20, 2017 1:22:49 下午 org.apache.catalina.startup.HostConfig deployDirectory INFO: Deploying web application directory E:\apache-tomcat-7.0.27\webapps\08_servlet 十一月 20, 2017 1:22:50 下午 com.sun.faces.config.ConfigureListener contextInitialized INFO: 初始化上下文 '/08_servlet' 的 Mojarra 2.0.3 (FCS b03) 十一月 20, 2017 1:22:51 下午 com.sun.faces.spi.InjectionProviderFactory createInstance INFO: JSF1048:有 PostConstruct/PreDestroy 注释。标有这些注释的 ManagedBeans 方法将表示注释已处理。 十一月 20, 2017 1:22:51 下午 org.apache.catalina.startup.HostConfig deployDirectory INFO: Deploying web application directory E:\apache-tomcat-7.0.27\webapps\docs 十一月 20, 2017 1:22:51 下午 org.apache.catalina.startup.HostConfig deployDirectory INFO: Deploying web application directory E:\apache-tomcat-7.0.27\webapps\examples 十一月 20, 2017 1:22:51 下午 org.apache.catalina.core.ApplicationContext log INFO: ContextListener: contextInitialized() 十一月 20, 2017 1:22:51 下午 org.apache.catalina.core.ApplicationContext log INFO: SessionListener: contextInitialized() 十一月 20, 2017 1:22:51 下午 org.apache.catalina.core.ApplicationContext log INFO: ContextListener: attributeAdded('org.apache.jasper.compiler.TldLocationsCache', 'org.apache.jasper.compiler.TldLocationsCache@526509bf') 十一月 20, 2017 1:22:51 下午 org.apache.catalina.startup.HostConfig deployDirectory INFO: Deploying web application directory E:\apache-tomcat-7.0.27\webapps\host-manager 十一月 20, 2017 1:22:51 下午 org.apache.catalina.startup.HostConfig deployDirectory INFO: Deploying web application directory E:\apache-tomcat-7.0.27\webapps\manager 十一月 20, 2017 1:22:51 下午 org.apache.catalina.startup.HostConfig deployDirectory INFO: Deploying web application directory E:\apache-tomcat-7.0.27\webapps\ROOT 十一月 20, 2017 1:22:52 下午 org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["http-apr-8080"] 十一月 20, 2017 1:22:52 下午 org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["ajp-apr-8009"] 十一月 20, 2017 1:22:52 下午 org.apache.catalina.startup.Catalina start INFO: Server startup in 2333 ms
- 打开浏览器,在地址栏中输入http://localhost:8080/08_servlet/servlet/LifeServlet,并查看控制台信息。
- 重新刷新页面,再次发送请求,调用Servlet内容。
- 停止Tomcat服务器,并查看控制台信息。
通过上述操作,我们可以发现:在第一次向Servlet发送请求时,Tomcat服务器的Servlet容器首先创建Servlet实例对象,再进行Servlet初始化工作,最后调用service()方法来处理请求。第二次向Servlet发送请求时,只调用了service()方法,并没有执行Servlet的构造方法和init()方法。在停止Tomcat服务器时,Servlet的destroy()方法被调用,释放所使用的资源。
3.2. Servlet的线程安全
在Servlet的整个生命周期中,构造方法只被执行一次。也就是说,在Servlet的整个生命周期中,只存在一个Servlet实例对象。这说明Servlet是单例多线程的,可能会引起线程安全问题。
所谓线程安全就是一个Servlet实例对象会同时处理多个请求,这样的Servlet工作效率的确很高。但如果Servlet中包含成员变量的话,可能一个线程对该成员变量进行写操作,而另一个线程对该成员变量进行读操作。所以,单例多线程的Servlet不能创建成员变量。
3.3. 服务器启动创建Servlet
通过之前的测试操作,我们发现Servlet并不是在Tomcat服务器启动时创建实例对象,而是在第一次请求之后才一并创建实例对象、初始化并处理逻辑的。Servlet又是单例的,在整个生命周期中只创建一个Servlet实例对象。如果可以在Tomcat服务器启动时,进行创建实例对象并完成初始化工作,在请求之后只调用service()方法处理请求逻辑即可。
可以在web.xml配置文件增加相关配置即可,具体增加内容如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>LifeServlet</servlet-name> <servlet-class>app.java.servlet.LifeServlet</servlet-class> <!-- load-on-startup标签:配置当前Servlet在启动时创建实例对象 * 标签中的数字,表示级别(0-9级),一般设置为0即可. --> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>LifeServlet</servlet-name> <url-pattern>/servlet/LifeServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
增加配置信息之后,重新启动Tomcat服务器,查看控制台信息
通过查看控制台打印的信息,可以看出在启动Tomcat服务器时,已经创建并初始化了Servlet实例对象。
3.4. url-pattern的三种配置
在web.xml配置文件中配置有关Servlet的时候,<url-pattern>标签是用于配置当前Servlet拦截的路径,也就是说,客户端浏览器访问<url-pattern>标签配置的路径才能访问对应Servlet内容。
关于拦截路径的配置方式其实有三种方式:
- 完全路径匹配:是以“/”开始,路径中间不能包含通配符“*”,例如:/firstServclet,表示访问路径为http://localhost:8080/08_servlet/firstServlet。
- 目录匹配:是以“/”开始,以“/*”结尾的,例如:/firstServlet/*,表示访问路径为http://localhost:8080/08_servlet/firstServlet路径下任意内容。
- 扩展名匹配:是以“*”开始,不能以“/”开始,以“.xxx”结尾,例如:*.do,表示访问路径为所有扩展名为“.do”的路径。
值得注意的问题:
- 在一个<servlet-mapping>标签中,可以配置多个<url-pattern>标签。也就是说,一个Servlet可以拦截多个不同路径的访问。
- 上述三种配置路径方式具有优先级:完全路径匹配 -> 目录匹配 -> 扩展名匹配。
下面通过一些测试,来看看路径配置的三种方式:
如下有一些映射关系:
- Servlet1 映射到 /abc/*
- Servlet2 映射到 /*
- Servlet3 映射到 /abc
- Servlet4 映射到 *.do
问题:
- 当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应?Servlet1
- 当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应?Servlet3
- 当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应?Servlet1
- 当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应?Servlet2
- 当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应?Servlet2
如果客户端浏览器请求的路径是错误时,页面会显示404错误内容。这是因为所有发布到Tomcat服务器的Web应用程序的web.xml文件都继承了Tomcat服务器安装目录中conf目录中的web.xml文件。当访问路径是错误的,或者对应Servlet没有配置,实际上会执行Tomcat服务器中的web.xml的相关配置,具体内容如下:
<servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
3.5. 相对路径与绝对路径
之前我们开发的Servlet,在客户端浏览器中都是直接在地址栏中输入路径来访问的。如果创建一个页面来访问Servlet应该怎么样呢?下面我们来看一看:
- 在Web工程中的WebRoot目录下,创建一个新目录名为“html”,然后在该目录下创建一个新的HTML页面。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>01.html</title> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="this is my page"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> </head> <body> <h1>相对路径访问Servlet</h1><br> <a href="">相对路径访问Servlet</a> <h1>绝对路径访问Servlet</h1><br> <a href="">绝对路径访问Servlet</a> </body> </html>
- 在Web工程中的WebRoot目录下,创建一个新的HTML页面。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>02.html</title> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="this is my page"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> </head> <body> <h1>相对路径访问Servlet</h1><br> <a href="">相对路径访问Servlet</a> <h1>绝对路径访问Servlet</h1><br> <a href="">绝对路径访问Servlet</a> </body> </html>
- 在Web工程中创建一个Servlet。
public class PathServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("成功访问到Servlet..."); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
- 配置Web工程的web.xml文件
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>PathServlet</servlet-name> <servlet-class>app.java.servlet.PathServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>PathServlet</servlet-name> <url-pattern>/pathServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
- 将当前Web工程发布到Tomcat服务器,并启动Tomcat服务器。
- 打开浏览器,分别访问01.html、02.html和PathServlet。
- 访问01.html的路径:http://localhost:8080/08_servlet/html/01.html。
- 访问02.html的路径:http://localhost:8080/08_servlet/02.html。
- 访问PathServlet的路径:http://localhost:8080/08_servlet/pathServlet。
- 根据上述的访问路径,可以知道在01.html和02.html页面中,通过绝对路径访问PathServlet是相同的。
- 在01.html和02.html页面中,通过相对路径访问PathServlet是不同的。
- 在01.html页面中利用相对路径访问PathServlet应该是../pathServlet。原因是pathServlet是在01.html页面的父级目录中。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>01.html</title> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="this is my page"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> </head> <body> <h1>相对路径访问Servlet</h1><br> <a href="../pathServlet">相对路径访问Servlet</a> <h1>绝对路径访问Servlet</h1><br> <a href="http://localhost:8080/08_servlet/pathServlet">绝对路径访问Servlet</a> </body> </html>
-
- 在01.html页面中利用相对路径访问PathServlet应该是./pathServlet或直接访问拦截名称pathServlet。原因是pathServlet与02.html页面处在同一级别的目录中。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>02.html</title> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="this is my page"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> </head> <body> <h1>相对路径访问Servlet</h1><br> <a href="pathServlet">相对路径访问Servlet</a> <h1>绝对路径访问Servlet</h1><br> <h1>绝对路径访问Servlet</h1><br> <a href="http://localhost:8080/08_servlet/pathServlet">绝对路径访问Servlet</a> </body> </html>
什么是绝对路径与相对路径:
- 绝对路径:就是无论当前资源在什么位置,都能通过当前资源访问到目标资源。
- 相对路径:就是判断当前资源与目标资源的相对位置,找出相对当前资源可以访问到目标资源的路径。
4. 研究掌握HttpServlet
4.1. HttpServlet概述
在大多数的Web应用程序中,客户端都是通过Http协议去访问服务器端的资源,而我们编写的Servlet主要是用于Http协议的请求和响应处理。为了快速开发应用于Http协议的Servlet类,Sun公司在javax.servlet.http包中提供了一个抽象类HttpServlet,它继承于GenericServlet,用于创建适合基于Http协议的Web Servlet。
public abstract class HttpServlet extends GenericServlet {}
下列表中罗列了HttpServlet的所有方法:
Method Summary |
|
protected void |
doDelete(HttpServletRequest req, HttpServletResponse resp) |
protected void |
doGet(HttpServletRequest req, HttpServletResponse resp) |
protected void |
doHead(HttpServletRequest req, HttpServletResponse resp) |
protected void |
doOptions(HttpServletRequest req, HttpServletResponse resp) |
protected void |
doPost(HttpServletRequest req, HttpServletResponse resp) |
protected void |
doPut(HttpServletRequest req, HttpServletResponse resp) |
protected void |
doTrace(HttpServletRequest req, HttpServletResponse resp) |
protected long |
getLastModified(HttpServletRequest req) |
protected void |
service(HttpServletRequest req, HttpServletResponse resp) |
void |
service(ServletRequest req, ServletResponse res) |
下面我们就针对HttpServlet抽象类中提供的各个方法进行讨论。
4.2. 重写的service()方法
在HttpServlet类中提供了两种重载的service()方法:
public abstract class HttpServlet extends GenericServlet { @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest) req; response = (HttpServletResponse) res; } catch (ClassCastException e) { throw new ServletException("non-HTTP request or response"); } service(request, response); } protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doGet(req, resp); } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } } }
通过查看HttpServlet的源代码我们可以知道,第一个service()方法是GenericServlet类中的Service()方法的实现。在该service()方法中将ServletRequest和ServletResponse对象转换成HttpServletRequest(继承于ServletRequest接口)和HttpServletResponse(继承于ServletResponse接口),然后调用了第二个service()方法,对客户端的请求进行处理。
在第二个service()方法中,针对Http 1.1协议中定义的7种请求方式Get、Post、Head、Put、Delete、Trace和Options提供了7种处理方法。这7种方法的参数类型及异常抛出类型与HttpServlet类中的第二个service()方法是一致的。当Servlet容器接收到一个针对HttpServlet对象的请求时,调用该对象的方法顺序如下:
- 调用公用service()方法,将参数类型转换成HttpServletRequest和HttpServletResponse,然后调用受保护的service()方法。
- 在受保护的service()方法中,获取Http请求方法的名字,然后根据请求方法的类型,调用响应的doXXX()方法。
因此,我们在自定义Servlet继承于HttpServlet的时候,通常不需要重写service()方法,只需重写响应的doXXX()方法即可。
4.3. 七种请求处理方法
在HttpServlet抽象类中提供了针对Http 1.1协议中定义的7种请求方式Get、Post、Head、Put、Delete、Trace和Options提供了7种处理方法:
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
这7种处理请求的方法中,HttpServlet类对Trace和Options方法做了适当的实现,因此我们不需要重写doTrace()和doOptions()方法。而对于其他的5种请求处理方法,HttpServlet类提供的实现都是返回Http错误。对于Http 1.0的客户端请求,这些方法返回的状态码为400,表示客户端发送的请求在语法上是错误的。对于Http 1.1的客户端请求,这些方法返回的状态码为405,表示对于指定资源的请求方法不被允许。
而对于Http协议的实际应用来讲,我们最常用的是Get和Post,所以在自定义Servlet时,常重写doGet()和doPost()两个请求处理方法。其中doGet()方法用来处理Get方式的请求,doPost()方法用来处理Post方式的请求,下面我们通过一个案例来看一看:
- 创建一个HTML页面用于发送客户端请求。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>index.html</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> </head> <body> <h1>GET方式请求</h1> <form id="userinfo" method="get" action="threeServlet"> 用户名:<input type="text" id="username" name="username"> <input type="submit" id="submit" value="提交"> </form> <h1>POST方式请求</h1> <form id="userinfo" method="post" action="threeServlet"> 用户名:<input type="text" id="username" name="username"> <input type="submit" id="submit" value="提交"> </form> </body> </html>
- 创建一个Servlet用于处理请求。
public class ThreeServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("这是GET方式发送的请求,Servlet使用doGet()方法来处理."); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("这是POST方式发送的请求,Servlet使用doPost()方法来处理."); } }
- 配置web.xml文件。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>ThreeServlet</servlet-name> <servlet-class>app.java.servlet.ThreeServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ThreeServlet</servlet-name> <url-pattern>/threeServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
- 将Web工程发布到Tomcat服务器,并启动Tomcat服务器。
- 打开浏览器,在地址栏中输入http://localhost:8080/08_servlet/index.html
利用GET方式发送请求,控制台会打印doGet()方法的内容。利用POST方式发送请求,控制台会打印doPost()方法的内容。
4.4. Request与Response
HttpServlet提供的service()方法与7种处理请求的方法都接收两个参数,一个是HttpServletRequest继承于ServletRequest,是用于处理Http协议中的请求,一个是HttpServletResponse继承于ServletResponse,是用于处理Http协议中的响应。
关于HttpServletRequest和HttpServletResponse的具体内容,我们会在后面的知识中学到。
5. 研究掌握GenericServlet
5.1. GenericServlet概述
如果我们直接通过实现Servlet接口来编写一个Servlet类,就需要实现Servlet接口定义的5种方法,为了简化Servlet的编写,在javax.servlet包中提供了一个抽象类GenericServlet,该类提供了除service()方法外的其他4种方法的简单实现。GenericServlet类定义了一个通用的、不依赖于具体协议的Servlet,它实现了Servlet接口和ServletConfig接口。
public abstract class GenericServlet implements Servlet, ServletConfig
下列表中罗列了GenericServlet的所有方法:
Method Summary |
|
void |
destroy() |
getServletConfig() |
|
getServletContext() |
|
void |
init() |
void |
init(ServletConfig config) |
abstract void |
service(ServletRequest req, ServletResponse res) |
5.2. 重写的init()方法
如果我们要自定义一个通用的Servlet,只需要从GenericServlet类继承,并实现其中的抽象方法service()方法。
在GenericServlet类中,提供了两种重载的init()方法:
- public void init(ServletConfig config) throws ServletException
- public void init() throws ServletException
第一种init()方法是Servlet接口中init()方法的实现。在这种方法中,首先将ServletConfig对象保存在一个transient实例变量中,然后调用第二种不带参数的init()方法。
通常我们在编写继承于GenericServlet的自定义Serlvet时,只需要重写第二中不带参数的init()方法就可以了。
5.3. ServletConfig对象
在javax.servlet包中,定义了ServletConfig接口。Servlet容器使用ServletConfig对象在Servlet初始化时向其传递配置信息。
所谓的Serlvet配置信息,就是在Web应用程序中web.xml文件中配置有关Servlet的内容。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name></display-name> <servlet> <description>This is the description of my J2EE component</description> <display-name>This is the display name of my J2EE component</display-name> <servlet-name>FirstServlet</servlet-name> <servlet-class>app.java.servlet.FirstServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FirstServlet</servlet-name> <url-pattern>/servlet/FirstServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
要想从ServletConfig对象获取有关Servlet的配置信息,首先需要获得ServletConfig对象,方式有以下几种:
- 通过继承GenericServlet,并重写init(ServletConfig config)方法来获取ServletConfig对象。
public class ConfigServlet extends GenericServlet { private ServletConfig config; @Override public void init(ServletConfig config) throws ServletException { this.config = config; } @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { } }
- 通过继承GenericServlet,并调用getServletConfig()方法来获取ServletConfig对象。
ServletConfig servletConfig = getServletConfig();
ServletConfig接口提供了以下方法供使用:
Method Summary |
|
getInitParameter(String name) |
|
getInitParameterNames() |
|
getServletContext() |
|
getServletName() |
下面我们一一来讨论上述方法的作用:
- getServletName()方法:获取web.xml文件中配置的Servlet名称。
<servlet> <servlet-name>ConfigServlet</servlet-name> <servlet-class>app.java.servlet.ConfigServlet</servlet-class> </servlet>
我们通过获取到的ServletConfig对象调用getServletName()方法来验证。
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { ServletConfig servletConfig = getServletConfig(); String servletName = servletConfig.getServletName(); System.out.println(servletName); }
运行Web应用程序,在控制台中打印“ConfigServlet”。
- getInitParameter(String name)方法:返回指定名称的初始化参数的值,如果参数不存在则返回null值。
首先,我们需要在web.xml文件中有关Servlet配置信息中,增加初始化参数的内容。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>ConfigServlet</servlet-name> <servlet-class>app.java.servlet.ConfigServlet</servlet-class> <init-param> <param-name>name</param-name> <param-value>123</param-value> </init-param> <init-param> <param-name>baidu</param-name> <param-value>http://www.baidu.com</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>ConfigServlet</servlet-name> <url-pattern>/servlet/ConfigServlet</url-pattern> </servlet-mapping> </web-app>
然后,我们在自定义Servlet的service()方法中获取对应初始化参数。
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { ServletConfig servletConfig = getServletConfig(); String name = servletConfig.getInitParameter("name"); String blog = servletConfig.getInitParameter("baidu"); System.out.println(name + baidu); }
运行Web应用程序,在控制台中打印“123 http://www.baidu.com”。
- getInitParameterNames()方法:返回Servlet配置的所有初始化参数名称的枚举集合。
- Enumeration是Iterator的前身,用法与Iterator一致。
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { ServletConfig servletConfig = getServletConfig(); Enumeration enumeration = servletConfig.getInitParameterNames(); while (enumeration.hasMoreElements()) { String element = (String) enumeration.nextElement(); String value = servletConfig.getInitParameter(element); System.out.println(element + ": " + value); } }
运行Web应用程序,在控制台中打印:
name: 123
blog: http://www.baidu.com
- getServletContext()方法:返回一个ServletContext对象,后面具体学习。
ServletConfig有哪些实际作用呢?在struts 1 框架中就运行了ServletConfig内容。
<!-- Standard Action Servlet Configuration (with debugging) --> <servlet> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value> /WEB-INF/struts-config.xml, /WEB-INF/struts-config-Wildcard.xml </param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <!-- Standard Action Servlet Mapping --> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
6. ServletContext对象
6.1. ServletContext概述
ServletContext对象是Servlet三大域对象之一,每个Web应用程序都拥有一个ServletContext对象,该对象是Web应用程序的全局对象或者上下文。Tomcat服务器在启动时,会自动创建一个ServletContext对象,在关闭时,会自动销毁这个ServletContext对象。每个Web应用程序只拥有一个ServletContext对象,ServletContext对象可以在整个Web应用中共享数据资源。
下列是ServletContext提供的方法列表:
Method Summary |
|
getAttribute(String name) |
|
getAttributeNames() |
|
getInitParameter(String name) |
|
getInitParameterNames() |
|
getMimeType(String file) |
|
getRealPath(String path) |
|
getServletContextName() |
|
getServletNames() |
|
void |
log(String msg) |
void |
removeAttribute(String name) |
void |
setAttribute(String name, Object object) |
6.2. 获取ServletContext对象
在自定义Servlet中有以下几种方式获取到ServletContext对象:
- 通过ServletConfig对象的getServletContext()方法获取。
- 通过继承GenericServlet类或HttpServlet类,调用GenericServlet类或HttpServlet类的getServletContext()方法获取。
我们通过一个案例来讨论一下。
- 首先,创建一个自定义Servlet,用来获取ServletContext对象。
public class AServlet extends GenericServlet { @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { ServletConfig config = getServletConfig(); ServletContext context1 = config.getServletContext(); context1.log("这是通过ServletConfig对象获取到的ServletContext对象."); ServletContext context2 = getServletContext(); context2.log("这是通过继承GenericServlet类获取到的ServletContext对象."); } }
- 在web.xml文件中配置Servlet相关信息。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>AServlet</servlet-name> <servlet-class>app.java.context.AServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>AServlet</servlet-name> <url-pattern>/servlet/AServlet</url-pattern> </servlet-mapping> </web-app>
- 将Web应用程序发布到Tomcat服务器,并启动Tomcat服务器。
- 打开浏览器,在地址栏中输入http://localhost:8080/08_servlet/servlet/AServlet,在控制台打印相关信息。
通过ServletContext对象的log(Stirng msg)方法,可以向控制台打印信息。
6.3. 配置全局初始化参数
在web.xml文件中,使用<init-param>定义的初始化参数,只能在当前Servlet中使用,而其他Servlet是无权限访问当前Servlet下配置的初始化参数的。而可以使用ServletContext在web.xml文件中配置全局初始化参数,这样当前Web应用程序中的所有Servlet都可以访问。
- 在web.xml文件中使用<context-param>来定义全局初始化参数。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <context-param> <param-name>weixin</param-name> <param-value>longestory</param-value> </context-param> <servlet> <servlet-name>AServlet</servlet-name> <servlet-class>app.java.context.AServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>AServlet</servlet-name> <url-pattern>/servlet/AServlet</url-pattern> </servlet-mapping> <servlet> <servlet-name>BServlet</servlet-name> <servlet-class>app.java.context.BServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>BServlet</servlet-name> <url-pattern>/servlet/BServlet</url-pattern> </servlet-mapping> </web-app>
- 在两个自定义Servlet中,分别利用ServletContext对象获取全局初始化参数。
public class BServlet extends GenericServlet { @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { ServletContext context = getServletContext(); String weixin = context.getInitParameter("weixin"); System.out.println(weixin); } }
- 将Web应用程序发布到Tomcat服务器,并启动Tomcat服务器。
- 打开浏览器,在地址栏中分别输入http://localhost:8080/08_servlet/servlet/AServlet和http://localhost:8080/08_servlet/servlet/BServlet,在控制台打印相关信息。
在自定义Servlet中,可以通过ServletContext对象的getInitParameter(String name)方法获取对应参数名称的全局初始化参数值,也可以通过ServletContext对象的getInitParameterNames()方法获取所有全局初始化参数的名称。
还可以通过ServletContext对象的getMineType(String file)方法根据文件扩展名获取文件MIME类型。
public class BServlet extends GenericServlet { @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { ServletContext context = getServletContext(); String html = context.getMimeType("1.html"); String css = context.getMimeType("2.css"); String javascript = context.getMimeType("3.js"); System.out.println("HTML的文件类型为"+html+", CSS的文件类型为"+css+", javascript的文件类型为"+javascript); } }
发布Web应用程序,并启动Tomcat服务器,在控制台中打印:
HTML的扩展名为text/html, CSS的扩展名为text/css, javascript的扩展名为application/javascript
ServletContext对象的getMineType(String file)方法会自动读取Tomcat安装目录中conf目录中的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <mime-mapping> <extension>html</extension> <mime-type>text/html</mime-type> </mime-mapping> <mime-mapping> <extension>css</extension> <mime-type>text/css</mime-type> </mime-mapping> <mime-mapping> <extension>js</extension> <mime-type>application/javascript</mime-type> </mime-mapping> </web-app>
6.4. 多个Servlet共享数据
在同一个Web应用程序中,多个Servlet之间可以共享ServletContext对象中的数据信息。主要是通过ServletContext对象的setAttribute(String name, Object object)方法和getAttribute(String name)方法完成,下面我们来实现统计网站访问次数的案例。
- 创建一个VisitServlet用来获取访问次数,并存储在ServletContext对象中。
public class VisitServlet extends HttpServlet { @Override public void init() throws ServletException { ServletContext context = getServletContext(); context.setAttribute("times", 0); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext context = getServletContext(); int times = (Integer)context.getAttribute("times"); times ++; context.setAttribute("times", times); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
- 创建一个ShowTimeServlet用来显示访问次数。
public class ShowTimeServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext context = getServletContext(); int times = (Integer)context.getAttribute("times"); response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("<h1>VisitServlet共被访问了"+times+"次</h1>"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
- 配置web.xml文件中有关Servlet信息。
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>VisitServlet</servlet-name> <servlet-class>app.java.context.VisitServlet</servlet-class> </servlet> <servlet> <servlet-name>ShowTimeServlet</servlet-name> <servlet-class>app.java.context.ShowTimeServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>VisitServlet</servlet-name> <url-pattern>/visit</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>ShowTimeServlet</servlet-name> <url-pattern>/show</url-pattern> </servlet-mapping> </web-app>
- 发布Web应用程序到Tomcat服务器,并启动Tomcat服务器。
- 打开浏览器,在地址栏输入http://localhost:8080/08_servlet/visit,访问VisitServlet。
- 再新打开浏览器,在地址栏输入http://localhost:8080/08_servlet/show,显示访问次数。
6.5. 读取Web工程中资源文件
读取工程中的资源文件,Java中的IO流其实就可以完成,下面使用Java中的IO流完成读取资源文件。
- 首先在Web工程中,创建四个资源文件。
- 在Web工程的根目录下创建1.txt。
- 在Web工程的WebRoot目录下创建2.txt。
- 在Web工程的WebRoot目录的WEB-INF目录下创建3.txt。
- 在Web工程的src目录下创建4.txt。
- 创建一个Java文件用于读取上述的四个资源文件。
public class ReaderFileTest { // 编写readfile()方法完成资源文件的读取工作. public static void readfile(String fileName) throws Exception{ BufferedReader reader = new BufferedReader(new FileReader(fileName)); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } reader.close(); } public static void main(String[] args) throws Exception { // 读取1.txt String filename1 = "1.txt"; readfile(filename1); // 读取2.txt String filename2 = "WebRoot/2.txt"; readfile(filename2); // 读取3.txt String filename3 = "WebRoot/WEB-INF/3.txt"; readfile(filename3); // 读取4.txt String filename4 = "src/4.txt"; readfile(filename4); } }
- 运行该Java文件会在控制台打印响应信息。
如果要想利用Servlet API的内容来读取Web工程中的资源文件,又要如何来做呢?ServletContext对象的getRealPath()方法可以来完成此项工作。
- 创建一个自定义Servlet,使用ServletContext对象的getRealPath()方法来完成读取资源文件。
public class ReadFileServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); OutputStream out = response.getOutputStream(); /* * 读取1.txt * * 因为1.txt资源文件在Web工程的根目录. * * Web工程的WebRoot目录发布到Tomcat服务器. * * 所以,1.txt资源文件是不会发布到Tomcat服务器的,Servlet无法读取. */ // 读取2.txt String filename2 = getServletContext().getRealPath("/2.txt"); InputStream in2 = new FileInputStream(new File(filename2)); IOUtils.copy(in2, out); // 读取3.txt String filename3 = getServletContext().getRealPath("/WEB-INF/3.txt"); InputStream in3 = new FileInputStream(new File(filename3)); IOUtils.copy(in3, out); // 读取4.txt String filename4 = getServletContext().getRealPath("/WEB-INF/classes/4.txt"); InputStream in4 = new FileInputStream(new File(filename4)); IOUtils.copy(in4, out); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
- 发布Web应用程序到Tomcat服务器,并启动Tomcat服务器。
- 打开浏览器,在地址栏中分别输入http://localhost:8080/08_servlet/read,在控制台打印相关信息。
除了可以使用ServletContext对象的getRealPath()方法之外,还可以使用ServletContext对象的getResourceAsStream()方法来完成读取资源文件的工作。
public class ReadFileServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { InputStream in = getServletContext().getResourceAsStream("/WEB-INF/classes/4.txt"); IOUtils.copy(in, out); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
还有一种通用的方法:利用Class类的getResource()方法也可以完成读取资源文件的工作。
public class ReadFileServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 利用类加载器读取Web工程的资源文件 String filename = ReadFileServlet.class.getResource("/4.txt").getFile(); InputStream in = new FileInputStream(new File(filename)); IOUtils.copy(in, out); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
来源:https://www.cnblogs.com/aaron911/p/7849591.html