本文摘自O'REILLY出版的《Java Servlet编程》第二版,示例运行环境基于Tomcat 5.5服务器
第一章 简介
虽然servlet可以用来扩展任何允许Java的服务器功能,但它最常用的扩展Web服务器,为CGI脚本的提供强大高效的替代品。
servlet是普通服务器的扩展,即一个可被动态载入以提高服务器功能的Java类。servlet多用于Web服务器以替CGI脚本。
运行servlet,需要一个servlet runner(或称servlet容器,有时叫servlet引擎,如tomcat等)。
servlet的优势包括:可移植,功能强大,高效,耐久,安全,简洁,集成化,可扩展性,灵活性。
第二章 HTTP servlet基础
Hello World程序:
import java.io.*;
import java.text.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class HelloWorld extends HttpServlet { //扩展HttpServlet类
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException //重载doGet()方法
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello World</h1>");
out.println("</body>");
out.println("</html>");
}
}
HttpServletRequest代表了客户端请求。HttpServletResponse代表了servlet的响应。
PrintWriter将Java的Unicode字符转换为区域(locale)特有的编码。
运行HelloWorld.java
1.首先将源码放在server_root/web_apps/test/WEB-INF/classes目录下(server_roots是安装tomcat的目录)
2.用javac将其编译。首先得确保servlet API在目录中,有效的方法是在环境变量ClassPath中添加属性"server_root/common/lib/servlet-api.jar;"。
3.启动tomcat服务器。(默认根地址是:http://localhost:8080,8080为监听端口)
4.配置web.xml。在server_root/web_apps/test/WEB-INF目录下添加web.xml文件,此文件的内容为:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<servlet>
<servlet-name>HelloWorld</servlet-name>
<servlet-class>HelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
5.访问地址http://localhost:8080/test/hello,即能运行程序。
处理表单数据
例如:
HTML表单含有<INPUT TYPE=TEXT NAME="name">
在servlet中得到name的信息可以通过 String name = req.getParameter("name");
WEB-INF目录
WEB-INF目录很特殊。该目录中的文件不直接为客户端服务;它们为服务器保存Java类和配置信息。这个目录类似JAR文件的META-INF目录:包含存档文件内容信息。
web.xml文件十一个配置描述富。这个文件包含本地服务的配置信息。它的结构本身并不是重点。重点在于该文件可以在与服务器无关的方式下来进行配置信息的确定。
第三章 servlet的生命周期
servlet的选择
servlet容器唯一必须严格遵守的规则就是以下生命周期的约定:
1.生成并初始化servlet。
2.除了客户服务呼叫。
3.卸载servlet并进行无用存储单元收集。
实例的持续性
当servlet的代码被载入时,服务器生成一个实例,这个实例处理该servlet的所有请求。它在三个方面提高了性能:
1.它使内存消耗变少
2.它节省了生成一个servlet对象所需要的资源。
3.它能够保证持续性。
init和destory
服务器在构造完servlet实例和处理任何请求之前运行servlet的init()方法,而在servlet不用服务了或所有挂起的请求处理完毕或超时使调用destory()方法。
init()方法用于servlet的初始化:产生或载入servlet处理请求使需要用到的对象。一个servlet的初始化参数可以配置在web.xml中。
在配置描述符中设置初始化参数
<web-app>
<servlet>
<servlet-name>
counter
</servlet-name>
<servlet-class>
InitCounter
</servlet-class>
<init-param>
<param-name>
initial
</param-name>
<param-value>
1000
</param-value>
<description>
The initial value for the counter <!-- optional -->
</description>
</init-param>
</servlet>
<web-app>
在destroy()方法中,一个servlet应释放它所占有的无法回收的所有存储单元。destroy()方法也可用于写所有未保存的信息,或为了保持持续性而要写入init()方法中以供下次初始化时读入的信息。
一个带初始化参数的计数器示例
public void init() throws ServletException {
String initial = getInitParameter("initial");
try {
count = Integer.parseInt(initial);
}
catch (NumberFormatException e) {
count = 0;
}
}
单线程模式
根据Servlet API文档,一个载入了SingelThreadModel servlet的服务器必须保证在servlet的service方法中没有同时执行的两个线程。即每个线程使用池中的一个实例。
使用方法是:
public class SingleThreadConnection extends HttpServlet
implements SingleThreadModel
{ ... }
后台处理
任何一个由servlet开始的线程能在响应发送出去之后继续执行。
启动时载入
可以配置servlet的Web应用程序,使服务器一开始就载入该程序。这可以通过将<load-on-startup>标签添加到配置描述符中的<servlet>中来实现,例如
<servlet>
<servlet-name>
ps
</servlet-name>
<servlet-class>
PrimeSearcher
</servlet-class>
<load-on-startup/>
</servlet>
在<load-on-startup>中可以包含一个正整数,以表明这个servlet和其他servlet在载入是的顺序。servlet按数字从小到大被载入。带有负数或非整数的servlet可在启动的任何时刻被载入,取决于服务器规定的顺序。
第四章 获取信息
CGI环境变量和对应的servlet方法
---------------------------------------------------------------------------
CGI环境变量 | HTTP servlet方法
---------------------------------------------------------------------------
SERVER_NAME | req.getServerName()
---------------------------------------------------------------------------
SERVER_SOFTWARE | req.getServletContext().getServerInfo()
---------------------------------------------------------------------------
SERVER_PROTOCOL | req.getProtocol()
---------------------------------------------------------------------------
SERVER_PORT | req.getServerPort()
---------------------------------------------------------------------------
REQUEST_METHOD | req.getMethod()
---------------------------------------------------------------------------
PATH_INFO | req.getPathInfo()
---------------------------------------------------------------------------
PATH_TRANSLATED | req.getPathTranslated()
---------------------------------------------------------------------------
SCRIPT_NAME | req.getServletPath()
---------------------------------------------------------------------------
DOCUMENT_ROOT | req.getServletContext().getRealPath("/")
---------------------------------------------------------------------------
QUERY_STRING | req.getQueryString()
---------------------------------------------------------------------------
REMOTE_HOST | req.getRemoteHost()
---------------------------------------------------------------------------
REMOTE_ADDR | req.getRemoteAddr()
---------------------------------------------------------------------------
AUTH_TYPE | req.getAuthType()
---------------------------------------------------------------------------
REMOTE_USER | req.getRemoteUser()
---------------------------------------------------------------------------
CONTENT_TYPE | req.getContentType()
---------------------------------------------------------------------------
CONTENT_LENGTH | req.getContentLength()
---------------------------------------------------------------------------
HTTP_ACCEPT | req.getHeader("Accept")
---------------------------------------------------------------------------
HTTP_USER_AGENT | req.getHeader("User-Agent")
---------------------------------------------------------------------------
HTTP_REFERER | req.getHeader("Referer")
---------------------------------------------------------------------------
取得servlet初始化参数
public String servletConfig.getInitParameter(String name)
取得servlet初始化参数名
public Enumeration servletConfig.getInitParameterNames()
这个方法以列举字符串的方式返回servlet的所有初始化参数,如果没有参数则返回空队列。
取得servlet名称
public String ServletConfig.getServletName()
如果该servlet未注册,则该方法返回servlet类名。
确定servlet版本
public int ServletContext.getMajorVersion()
public int ServletContext.getMinorVersion()
如果版本是2.1,则MajorVersion返回2,MinorVersion返回1
第五章 发送HTML信息
发送自定义响应
设置响应的内容类型: public void ServletResponse.setContentType(String type)
重定向请求
res.setStatus(res.SC_MOVED_TEMPORARILY); 设置状态码以表示重定向开始
res.setHeader("Location",site); 给出了行的位置
也可以简化为
res.sendRedirect(site);
配置错误页
<web-app>
<error-page>
<error-code>
400
</error-code>
<location>
/400.html
</location>
</error-page>
<error-page>
<error-code>
404
</error-code>
<location>
/404.html
</location>
</error-page>
</web-app>
异常
servlet只能将IOException、ServletException、RuntimeException的子类中的错误传给服务器
ServletException
ServletException是专门为servlet设计的java.lang.Exception的子类。这个类在javax.servlet包中定义。这个异常由servlet抛出,表明一个通常的servlet错误。
javax.servlet.servletException()
javax.servlet.servletException(String msg)
ServletException可支持一个“根本原因”的Throwable对象。这使ServletException成为任何类型异常和错误的包装。
javax.servlet.servletException(Throwable rootCause)
javax.servlet.servletException(String msg, Throwable rootCause)
使用这样的功能可以传递任何底层的错误和异常:
try {
thread.sleep(60000);
}
catch (InterruptedException e) {
throw new servletException(e); //包括所有异常
}
服务器可以通过调用getRootCause()检索和检查底层异常、堆栈轨迹等:
public Throwable ServletException.getRootCause()
如果没有嵌套的异常返回null。
配置异常网页
<error-page>
<exception-type>
javax.servlet.ServletException
</exception-type>
<location>
/servlet/ErrorDisplay
</location>
</error-page>
第六章 会话跟踪
使用cookie
servlet API提供了javax.servlet.http.Cookie类来运行cookie。cookie的HTTP首部有关细节处理由Servlet API进行。可以用Cookie构造函数来生成一个cookie:
public Cookie(String name, String value)
servlet可通过把一个cookie对象传给HttpServletResponse的AddCookie()方法来向客户端发送一个cookie。
public void HttpServletResponse.addCookie(Cookie cookie)
例:
Cookie cookie = new Cookie("ID","123");
res.addCookie(cookie);
servlet通过调用HttpServletRequest()的getCookies()方法来检索cookie。
public Cookie[] HttpServletRequest.getCookies()
取得cookie的代码如下:
Cookie[] cookies = req.getCookies();
if(cookies != null) {
for(int i=0;i<cookies.length;i++)
{
String name = cookies[i].getName();
String value = cookies[i].getValue();
}
}
设置cookie的版本
public void Cookie.setVersion(int v)
指定区域限制模式
public void Cookie.setDomain(String pattern)
在cookie结束前以秒数指定最大寿命
public void Cookie.setMaxAge(int expiry)
指定cookie路径,这个路径应是cookie发送目标URL的子集
public void Cookie.setPath(String uri)
表示cookie是否通过安全通道发送,例如SSL,默认为false
public void Cookie.setSecure(boolean flag)
设置cookie的注释字段。版本0的cookie不支持这项内容
public void Cookie.setComment(String comment)
为cookie指定新值
public void Cookie.setValue(String newValue)
会话跟踪API
servlet使用它的请求对象的getSession()方法来检索现有的HttpSession对象:
public HttpSession HttpServletRequest.getSession(boolean create)
这个方法返回作出请求的用户关联的当前对话。
getSession()必须在响应发送前被调用
向HttpSession对象添加数据:
public void HttpSession.setAttribute(String name, Object value)
检索会话对象:
public Object HttpSession.getAttribute(String name)
取得绑定在会话上所有的对象名:
public Enumeration HttpSession.getAttributeNames()
从对话中删除某一对象:
public void HttpSession.removeAttribute(String name)
设定会话的超时值:
public void HttpSession.setMaxInactiveInterval(int secs)
返回当前超时值:
public int HttpSession.getMaxInactiveInterval()
判断是否为新会话:
public boolean HttpSession.isNew()
立即结束会话:
public void HttpSession.invalidate()
返回会话生成的时间:
public long HttpSession.getCreationTime()
返回客户端上次发送请求的时间:
public long HttpSession.getLastAccessedTime()
取得会话的ID:
public String HttpSession.getId()
第一章 简介
虽然servlet可以用来扩展任何允许Java的服务器功能,但它最常用的扩展Web服务器,为CGI脚本的提供强大高效的替代品。
servlet是普通服务器的扩展,即一个可被动态载入以提高服务器功能的Java类。servlet多用于Web服务器以替CGI脚本。
运行servlet,需要一个servlet runner(或称servlet容器,有时叫servlet引擎,如tomcat等)。
servlet的优势包括:可移植,功能强大,高效,耐久,安全,简洁,集成化,可扩展性,灵活性。
第二章 HTTP servlet基础
Hello World程序:
import java.io.*;
import java.text.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class HelloWorld extends HttpServlet { //扩展HttpServlet类
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException //重载doGet()方法
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello World</h1>");
out.println("</body>");
out.println("</html>");
}
}
HttpServletRequest代表了客户端请求。HttpServletResponse代表了servlet的响应。
PrintWriter将Java的Unicode字符转换为区域(locale)特有的编码。
运行HelloWorld.java
1.首先将源码放在server_root/web_apps/test/WEB-INF/classes目录下(server_roots是安装tomcat的目录)
2.用javac将其编译。首先得确保servlet API在目录中,有效的方法是在环境变量ClassPath中添加属性"server_root/common/lib/servlet-api.jar;"。
3.启动tomcat服务器。(默认根地址是:http://localhost:8080,8080为监听端口)
4.配置web.xml。在server_root/web_apps/test/WEB-INF目录下添加web.xml文件,此文件的内容为:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<servlet>
<servlet-name>HelloWorld</servlet-name>
<servlet-class>HelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
5.访问地址http://localhost:8080/test/hello,即能运行程序。
处理表单数据
例如:
HTML表单含有<INPUT TYPE=TEXT NAME="name">
在servlet中得到name的信息可以通过 String name = req.getParameter("name");
WEB-INF目录
WEB-INF目录很特殊。该目录中的文件不直接为客户端服务;它们为服务器保存Java类和配置信息。这个目录类似JAR文件的META-INF目录:包含存档文件内容信息。
web.xml文件十一个配置描述富。这个文件包含本地服务的配置信息。它的结构本身并不是重点。重点在于该文件可以在与服务器无关的方式下来进行配置信息的确定。
第三章 servlet的生命周期
servlet的选择
servlet容器唯一必须严格遵守的规则就是以下生命周期的约定:
1.生成并初始化servlet。
2.除了客户服务呼叫。
3.卸载servlet并进行无用存储单元收集。
实例的持续性
当servlet的代码被载入时,服务器生成一个实例,这个实例处理该servlet的所有请求。它在三个方面提高了性能:
1.它使内存消耗变少
2.它节省了生成一个servlet对象所需要的资源。
3.它能够保证持续性。
init和destory
服务器在构造完servlet实例和处理任何请求之前运行servlet的init()方法,而在servlet不用服务了或所有挂起的请求处理完毕或超时使调用destory()方法。
init()方法用于servlet的初始化:产生或载入servlet处理请求使需要用到的对象。一个servlet的初始化参数可以配置在web.xml中。
在配置描述符中设置初始化参数
<web-app>
<servlet>
<servlet-name>
counter
</servlet-name>
<servlet-class>
InitCounter
</servlet-class>
<init-param>
<param-name>
initial
</param-name>
<param-value>
1000
</param-value>
<description>
The initial value for the counter <!-- optional -->
</description>
</init-param>
</servlet>
<web-app>
在destroy()方法中,一个servlet应释放它所占有的无法回收的所有存储单元。destroy()方法也可用于写所有未保存的信息,或为了保持持续性而要写入init()方法中以供下次初始化时读入的信息。
一个带初始化参数的计数器示例
public void init() throws ServletException {
String initial = getInitParameter("initial");
try {
count = Integer.parseInt(initial);
}
catch (NumberFormatException e) {
count = 0;
}
}
单线程模式
根据Servlet API文档,一个载入了SingelThreadModel servlet的服务器必须保证在servlet的service方法中没有同时执行的两个线程。即每个线程使用池中的一个实例。
使用方法是:
public class SingleThreadConnection extends HttpServlet
implements SingleThreadModel
{ ... }
后台处理
任何一个由servlet开始的线程能在响应发送出去之后继续执行。
启动时载入
可以配置servlet的Web应用程序,使服务器一开始就载入该程序。这可以通过将<load-on-startup>标签添加到配置描述符中的<servlet>中来实现,例如
<servlet>
<servlet-name>
ps
</servlet-name>
<servlet-class>
PrimeSearcher
</servlet-class>
<load-on-startup/>
</servlet>
在<load-on-startup>中可以包含一个正整数,以表明这个servlet和其他servlet在载入是的顺序。servlet按数字从小到大被载入。带有负数或非整数的servlet可在启动的任何时刻被载入,取决于服务器规定的顺序。
第四章 获取信息
CGI环境变量和对应的servlet方法
---------------------------------------------------------------------------
CGI环境变量 | HTTP servlet方法
---------------------------------------------------------------------------
SERVER_NAME | req.getServerName()
---------------------------------------------------------------------------
SERVER_SOFTWARE | req.getServletContext().getServerInfo()
---------------------------------------------------------------------------
SERVER_PROTOCOL | req.getProtocol()
---------------------------------------------------------------------------
SERVER_PORT | req.getServerPort()
---------------------------------------------------------------------------
REQUEST_METHOD | req.getMethod()
---------------------------------------------------------------------------
PATH_INFO | req.getPathInfo()
---------------------------------------------------------------------------
PATH_TRANSLATED | req.getPathTranslated()
---------------------------------------------------------------------------
SCRIPT_NAME | req.getServletPath()
---------------------------------------------------------------------------
DOCUMENT_ROOT | req.getServletContext().getRealPath("/")
---------------------------------------------------------------------------
QUERY_STRING | req.getQueryString()
---------------------------------------------------------------------------
REMOTE_HOST | req.getRemoteHost()
---------------------------------------------------------------------------
REMOTE_ADDR | req.getRemoteAddr()
---------------------------------------------------------------------------
AUTH_TYPE | req.getAuthType()
---------------------------------------------------------------------------
REMOTE_USER | req.getRemoteUser()
---------------------------------------------------------------------------
CONTENT_TYPE | req.getContentType()
---------------------------------------------------------------------------
CONTENT_LENGTH | req.getContentLength()
---------------------------------------------------------------------------
HTTP_ACCEPT | req.getHeader("Accept")
---------------------------------------------------------------------------
HTTP_USER_AGENT | req.getHeader("User-Agent")
---------------------------------------------------------------------------
HTTP_REFERER | req.getHeader("Referer")
---------------------------------------------------------------------------
取得servlet初始化参数
public String servletConfig.getInitParameter(String name)
取得servlet初始化参数名
public Enumeration servletConfig.getInitParameterNames()
这个方法以列举字符串的方式返回servlet的所有初始化参数,如果没有参数则返回空队列。
取得servlet名称
public String ServletConfig.getServletName()
如果该servlet未注册,则该方法返回servlet类名。
确定servlet版本
public int ServletContext.getMajorVersion()
public int ServletContext.getMinorVersion()
如果版本是2.1,则MajorVersion返回2,MinorVersion返回1
第五章 发送HTML信息
发送自定义响应
设置响应的内容类型: public void ServletResponse.setContentType(String type)
重定向请求
res.setStatus(res.SC_MOVED_TEMPORARILY); 设置状态码以表示重定向开始
res.setHeader("Location",site); 给出了行的位置
也可以简化为
res.sendRedirect(site);
配置错误页
<web-app>
<error-page>
<error-code>
400
</error-code>
<location>
/400.html
</location>
</error-page>
<error-page>
<error-code>
404
</error-code>
<location>
/404.html
</location>
</error-page>
</web-app>
异常
servlet只能将IOException、ServletException、RuntimeException的子类中的错误传给服务器
ServletException
ServletException是专门为servlet设计的java.lang.Exception的子类。这个类在javax.servlet包中定义。这个异常由servlet抛出,表明一个通常的servlet错误。
javax.servlet.servletException()
javax.servlet.servletException(String msg)
ServletException可支持一个“根本原因”的Throwable对象。这使ServletException成为任何类型异常和错误的包装。
javax.servlet.servletException(Throwable rootCause)
javax.servlet.servletException(String msg, Throwable rootCause)
使用这样的功能可以传递任何底层的错误和异常:
try {
thread.sleep(60000);
}
catch (InterruptedException e) {
throw new servletException(e); //包括所有异常
}
服务器可以通过调用getRootCause()检索和检查底层异常、堆栈轨迹等:
public Throwable ServletException.getRootCause()
如果没有嵌套的异常返回null。
配置异常网页
<error-page>
<exception-type>
javax.servlet.ServletException
</exception-type>
<location>
/servlet/ErrorDisplay
</location>
</error-page>
第六章 会话跟踪
使用cookie
servlet API提供了javax.servlet.http.Cookie类来运行cookie。cookie的HTTP首部有关细节处理由Servlet API进行。可以用Cookie构造函数来生成一个cookie:
public Cookie(String name, String value)
servlet可通过把一个cookie对象传给HttpServletResponse的AddCookie()方法来向客户端发送一个cookie。
public void HttpServletResponse.addCookie(Cookie cookie)
例:
Cookie cookie = new Cookie("ID","123");
res.addCookie(cookie);
servlet通过调用HttpServletRequest()的getCookies()方法来检索cookie。
public Cookie[] HttpServletRequest.getCookies()
取得cookie的代码如下:
Cookie[] cookies = req.getCookies();
if(cookies != null) {
for(int i=0;i<cookies.length;i++)
{
String name = cookies[i].getName();
String value = cookies[i].getValue();
}
}
设置cookie的版本
public void Cookie.setVersion(int v)
指定区域限制模式
public void Cookie.setDomain(String pattern)
在cookie结束前以秒数指定最大寿命
public void Cookie.setMaxAge(int expiry)
指定cookie路径,这个路径应是cookie发送目标URL的子集
public void Cookie.setPath(String uri)
表示cookie是否通过安全通道发送,例如SSL,默认为false
public void Cookie.setSecure(boolean flag)
设置cookie的注释字段。版本0的cookie不支持这项内容
public void Cookie.setComment(String comment)
为cookie指定新值
public void Cookie.setValue(String newValue)
会话跟踪API
servlet使用它的请求对象的getSession()方法来检索现有的HttpSession对象:
public HttpSession HttpServletRequest.getSession(boolean create)
这个方法返回作出请求的用户关联的当前对话。
getSession()必须在响应发送前被调用
向HttpSession对象添加数据:
public void HttpSession.setAttribute(String name, Object value)
检索会话对象:
public Object HttpSession.getAttribute(String name)
取得绑定在会话上所有的对象名:
public Enumeration HttpSession.getAttributeNames()
从对话中删除某一对象:
public void HttpSession.removeAttribute(String name)
设定会话的超时值:
public void HttpSession.setMaxInactiveInterval(int secs)
返回当前超时值:
public int HttpSession.getMaxInactiveInterval()
判断是否为新会话:
public boolean HttpSession.isNew()
立即结束会话:
public void HttpSession.invalidate()
返回会话生成的时间:
public long HttpSession.getCreationTime()
返回客户端上次发送请求的时间:
public long HttpSession.getLastAccessedTime()
取得会话的ID:
public String HttpSession.getId()