标签:
掌握Servlet API 是成为一名技术高超的JAVA Web开发者的基础.必须非常熟悉Servlet API中所定义的70多种类型.
本篇博客将介绍Servlet API,并教你编写第一个Servlet应用程序.
Servlet API中有4个Java包,包括:
Servlet技术的核心是Servlet接口,这是所有Servlet类都必须直接或者间接实现的一个接口.Servlet接口定义了Servlet与Servlet容器之间的一个契约,Servlet容器会把Servlet类加载到内存中,并在Servlet实例中调用特定的方法.每个Servlet类型只能有一个实例.
Servlet容器还为每个应用程序创建一个ServletContext实例.这个对象封装context(应用程序)的环境细节.每个context只有一个ServletContext.每个Servlet实例还有一个封装Servlet配置信息的ServletConfig.
Servlet接口中定义了以下5个方法:
public void init(ServletConfig servletConfig)throws ServletException
public void service(ServletRequest request,ServletResponse response) throws ServletException,IOException
public void destroy()
public ServletConfig getServletConfig()
public String getServletInfo()
编写Java方法签名的规则是:与包含该方法的类型不在同一个包中的类型,要使用全类名.
init() service() destroy()方法是Servlet的生命周期方法,调用规则如下:
- init(): 第一次请求Servlet时,Servlet容器会调用这个方法.在后续的请求中不会在调用.
- service(): 每次请求Servlet时都会调用此方法,必须在这里编写要Servlet完成的响应代码. 第一次调用Servlet时会调用init()和service()方法,之后请求只调用service()方法.
- destroy(): Servlet要销毁时调用此方法,通常发生在卸载应用程序,或者关闭Servlet容器的时候.
- getServletInfo(): 该方法返回Servlet的描述,可以是任意字符串,甚至为null.
- getServletConfig(): 该方法返回由Servlet容器传给init方法的ServletConfig.为了让getServletConfig返回非null值,应该为传给init方法的ServletConfig赋给一个类级变量.
必须注意线程安全.一个应用程序中的所有用户将共用一个Servlet实例,因此 不建议使用类级变量,除非它们是只读的,或者是java.util.concurrent.atomic包中的成员.
Servlet应用程序编写起来非常简单,只需要创建一个目录结果,并将Servlet类放在某一个目录下即可.
在本节中,将学习如何编写一个简单的Servlet应用程序,将它命名为app01a.最初它只包含一个Servlet:MyServlet,其会给用户发送一条问候信息.
package app01a;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
@WebServlet(name = "MyServlet", urlPatterns = { "/my" })
public class MyServlet implements Servlet {
private transient ServletConfig servletConfig;
@Override
public void init(ServletConfig servletConfig)
throws ServletException {
this.servletConfig = servletConfig;
}
@Override
public ServletConfig getServletConfig() {
return servletConfig;
}
@Override
public String getServletInfo() {
return "My Servlet";
}
@Override
public void service(ServletRequest request,
ServletResponse response) throws ServletException,
IOException {
String servletName = servletConfig.getServletName();
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.print("<html><head></head>"
+ "<body>Hello from " + servletName
+ "</body></html>");
}
@Override
public void destroy() {
}
}
查看代码首先会注意到下面这个注解:
@WebServlet(name = “MyServlet”, urlPatterns = { “/my” })
注解中:name属性是可选的,一般用来提供Servlet类的名字,关键是urlPatterns它也是可选的,在MyServlet中,urlPatterns告诉容器,/my模式应该调用这个Servlet.
- URL模式必须一条正斜线开头.
Servlet应用程序必须以特定目录结果进行部署,应用程序包含WEB-INF目录
它有两个子目录:
- classes目录:Servlet类和其他的Java类都必须放在这里.类下方的目录反映了类的包结构.
- lib目录:在这里部署Servlet应用程序所需要的Jar文件.
所有的图像文件可以放在一个image目录下,所有的JSP页面可以放在一个jsp目录下,以此类推.
放在应用程序目录下的任何资源,用户可以通过输入该资源的URL而直接进行访问.如果希望某个资源可以被Servlet访问,但是不能被用户访问,那么应该把它放在WEB-INF目录下面.
把应用程序部署到Tomcat中:
运行MyServlet应用程序,通过以下地址:
允许结果:
恭喜!你的第一个Servlet应用程序已经运行!
下面是ServletRequest接口中的部分方法:
public int getContentLength()
返回请求主体中的字节数,如果不知道字节长度,则返回-1;
public java.lang.String getContentType()
返回请求主体的MIME类型,如果不知道类型,则返回null;
public java.lang.String getProtocol()
返回这个HTTP请求的协议名称和版本号;
public java.lang.String getParameter(java.lang.String name)
返回指定请求参数的值,返回一个HTML表单域的值,获取查询字符串的值.如果不存在返回null;
利用getParameterNames getParameterMap和getParameterValues来获取表单域的名称和值,以及查询字符串.
ServletResponse中定义了getWriter()方法,它返回可以将文本传给客户端的java.io.PrintWriter.默认情况下,PrintWriter对象采用ISO-8859-1编码.
在发送任何HTML标签之前,先通过调用setContentType来设置响应的内容类型,比如:将text/html作为参数传递,告诉浏览器内容类型为HTML.
- getInitParameter(java.lang.String name)
从一个Servlet内部获取某个初始参数的值,由传入init方法的ServletConfig中调用getInitParameter.
- java.util.Enumeration getInitParameterNames()
返回所有初始参数名称的一个Enumeration.
- getServletContext()
从Servlet内部获取ServletContext.
举个ServletConfig的例子.添加一个ServletConfigDemoServlet:
package app01a;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
@WebServlet(name = "ServletConfigDemoServlet",
urlPatterns = { "/servletConfigDemo" },
initParams = {
@WebInitParam(name="admin", value="Harry Taciak"),
@WebInitParam(name="email", value="admin@example.com")
}
)
public class ServletConfigDemoServlet implements Servlet {
private transient ServletConfig servletConfig;
@Override
public ServletConfig getServletConfig() {
return servletConfig;
}
@Override
public void init(ServletConfig servletConfig)
throws ServletException {
this.servletConfig = servletConfig;
}
@Override
public void service(ServletRequest request,
ServletResponse response)
throws ServletException, IOException {
ServletConfig servletConfig = getServletConfig();
String admin = servletConfig.getInitParameter("admin");
String email = servletConfig.getInitParameter("email");
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.print("<html><head></head><body>" +
"Admin:" + admin +
"<br/>Email:" + email +
"</body></html>");
}
@Override
public String getServletInfo() {
return "ServletConfig demo";
}
@Override
public void destroy() {
}
}
ServletContext表示Servlet应用程序.每个Web应用程序只有一个context.
用ServletConfig中调用getServletContext方法可以获得ServletContext.
保存在ServletContext中的对象称作属性.
ServletContext中包含如下常用属性:
- getAttribute()
- getAttributeNames()
- setAttribute()
- removeAttribute()
通过Servlet接口编写Servlet很麻烦,需要把它的所有方法都实现及时不用的方法,所以,我们有GenericServlet抽象类,它实现了Servlet和ServletConfig,并做了以下工作:
- 将init方法中的ServletConfig赋给一个类级变量,使它可以通过调用getServletConfig来获取.
- 为Servlet接口中的所有方法提供默认实现.
- 提供方法来包装ServletConfig中的方法.
在类中如果覆盖了init()方法,则必须调用super.init(servletConfig)来保存ServletConfig.
可以通过覆盖无参的init方法来编写初始化代码,ServletConfig仍然由GenericServlet实例保存.
接下来举个继承GenericServlet的Servlet栗子:
package app01a;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.GenericServlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
@WebServlet(name = "GenericServletDemoServlet",
urlPatterns = { "/generic" },
initParams = {
@WebInitParam(name="admin", value="Harry Taciak"),
@WebInitParam(name="email", value="admin@example.com")
}
)
public class GenericServletDemoServlet extends GenericServlet {
private static final long serialVersionUID = 62500890L;
@Override
public void service(ServletRequest request,
ServletResponse response)
throws ServletException, IOException {
ServletConfig servletConfig = getServletConfig();
String admin = servletConfig.getInitParameter("admin");
String email = servletConfig.getInitParameter("email");
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.print("<html><head></head><body>" +
"Admin:" + admin +
"<br/>Email:" + email +
"</body></html>");
}
}
javax.servlet.http包是Servlet API中的第二个包,其包含了编写Servlet应用程序的类和接口.
HttpServlet类覆盖javax.servlet.GenericServlet类.
HttpServlet中有两项特性是GenericServlet所没有的:
- 不覆盖service方法,而是覆盖doGet doPost,或者两者都覆盖掉.在极少数情况下,还要覆盖以下某个方法:doHead() doPut() doTrace() doOptions()或doDelete().
- 将用HttpServletRequest和HttpServletResponse代替ServletRequest和ServletResponse.
HttpServletRequest表示HTTP环境中的Servlet请求.它继承java.servlet.ServletRequest接口,并增加了几个方法:
- String getContextPath()
返回表示请求context的请求URI部分.
- Cookie[] getCookies()
返回一个Cookie对象数组.
- String getHeader(String name)
返回指定HTTP标头的值.
- String getMethod()
返回发出这条请求的HTTP方法的名称.
- String getQueryString()
返回请求URL中的查询字符串.
- HttpSession getSession()
返回与这个请求有关的session对象.如果没有找到,则创建新的session对象.
- HttpSession getSession(boolean create)
返回与这个请求有关的session对象.如果没有找到,并且create参数为true,那么将创建新的session对象.
HttpServletResponse表示HTTP环境下的Servlet响应.
- void addCookie(Cookie cookie) 给这个响应对象添加cookie
- void addHeader(String name,String value) 给这个响应对象添加标头.
- void sendRedirect(String location) 发送响应代号,将浏览器重定向到指定的位置.
每个Web应用程序中几乎都会包含一个或者多个HTML表单,用来接收用户输入.可以轻松地将一个HTML表单从Serlet发送到浏览器.
HTML输入域或文本域中的值将被当作字符串发送到服务器.空白的输入域或文本域将发送一条空白的字符串,因此,带有一个输入域名称的ServletRequest.getParameter将永远不会返回null.
package app01b;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "FormServlet", urlPatterns = { "/form" })
public class FormServlet extends HttpServlet {
private static final long serialVersionUID = 54L;
private static final String TITLE = "Order Form";
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("<html>");
writer.println("<head>");
writer.println("<title>" + TITLE + "</title></head>");
writer.println("<body><h1>" + TITLE + "</h1>");
writer.println("<form method=‘post‘>");
writer.println("<table>");
writer.println("<tr>");
writer.println("<td>Name:</td>");
writer.println("<td><input name=‘name‘/></td>");
writer.println("</tr>");
writer.println("<tr>");
writer.println("<td>Address:</td>");
writer.println("<td><textarea name=‘address‘ "
+ "cols=‘40‘ rows=‘5‘></textarea></td>");
writer.println("</tr>");
writer.println("<tr>");
writer.println("<td>Country:</td>");
writer.println("<td><select name=‘country‘>");
writer.println("<option>United States</option>");
writer.println("<option>Canada</option>");
writer.println("</select></td>");
writer.println("</tr>");
writer.println("<tr>");
writer.println("<td>Delivery Method:</td>");
writer.println("<td><input type=‘radio‘ " +
"name=‘deliveryMethod‘"
+ " value=‘First Class‘/>First Class");
writer.println("<input type=‘radio‘ " +
"name=‘deliveryMethod‘ "
+ "value=‘Second Class‘/>Second Class</td>");
writer.println("</tr>");
writer.println("<tr>");
writer.println("<td>Shipping Instructions:</td>");
writer.println("<td><textarea name=‘instruction‘ "
+ "cols=‘40‘ rows=‘5‘></textarea></td>");
writer.println("</tr>");
writer.println("<tr>");
writer.println("<td> </td>");
writer.println("<td><textarea name=‘instruction‘ "
+ "cols=‘40‘ rows=‘5‘></textarea></td>");
writer.println("</tr>");
writer.println("<tr>");
writer.println("<td>Please send me the latest " +
"product catalog:</td>");
writer.println("<td><input type=‘checkbox‘ " +
"name=‘catalogRequest‘/></td>");
writer.println("</tr>");
writer.println("<tr>");
writer.println("<td> </td>");
writer.println("<td><input type=‘reset‘/>" +
"<input type=‘submit‘/></td>");
writer.println("</tr>");
writer.println("</table>");
writer.println("</form>");
writer.println("</body>");
writer.println("</html>");
}
@Override
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("<html>");
writer.println("<head>");
writer.println("<title>" + TITLE + "</title></head>");
writer.println("</head>");
writer.println("<body><h1>" + TITLE + "</h1>");
writer.println("<table>");
writer.println("<tr>");
writer.println("<td>Name:</td>");
writer.println("<td>" + request.getParameter("name")
+ "</td>");
writer.println("</tr>");
writer.println("<tr>");
writer.println("<td>Address:</td>");
writer.println("<td>" + request.getParameter("address")
+ "</td>");
writer.println("</tr>");
writer.println("<tr>");
writer.println("<td>Country:</td>");
writer.println("<td>" + request.getParameter("country")
+ "</td>");
writer.println("</tr>");
writer.println("<tr>");
writer.println("<td>Shipping Instructions:</td>");
writer.println("<td>");
String[] instructions = request
.getParameterValues("instruction");
if (instructions != null) {
for (String instruction : instructions) {
writer.println(instruction + "<br/>");
}
}
writer.println("</td>");
writer.println("</tr>");
writer.println("<tr>");
writer.println("<td>Delivery Method:</td>");
writer.println("<td>"
+ request.getParameter("deliveryMethod")
+ "</td>");
writer.println("</tr>");
writer.println("<tr>");
writer.println("<td>Catalog Request:</td>");
writer.println("<td>");
if (request.getParameter("catalogRequest") == null) {
writer.println("No");
} else {
writer.println("Yes");
}
writer.println("</td>");
writer.println("</tr>");
writer.println("</table>");
writer.println("<div style=‘border:1px solid #ddd;" +
"margin-top:40px;font-size:90%‘>");
writer.println("Debug Info<br/>");
Enumeration<String> parameterNames = request
.getParameterNames();
while (parameterNames.hasMoreElements()) {
String paramName = parameterNames.nextElement();
writer.println(paramName + ": ");
String[] paramValues = request
.getParameterValues(paramName);
for (String paramValue : paramValues) {
writer.println(paramValue + "<br/>");
}
}
writer.println("</div>");
writer.println("</body>");
writer.println("</html>");
}
}
使用部署描述符是配置Servlet应用程序的另一种方法,部署描述符总是命名为web.xml,并放在WEB-INF目录下.
栗子:有两个没有@WebServlet进行标注的Servlet:分别为:SimpleServlet和WelcomeServlet.以及部署描述符文件:web.xml:
package app01c;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SimpleServlet extends HttpServlet {
private static final long serialVersionUID = 8946L;
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.print("<html><head></head>" +
"<body>Simple Servlet</body></html");
}
}
package app01c;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class WelcomeServlet extends HttpServlet {
private static final long serialVersionUID = 27126L;
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.print("<html><head></head>"
+ "<body>Welcome</body></html>");
}
}
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app 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_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>SimpleServlet</servlet-name>
<servlet-class>app01c.SimpleServlet</servlet-class>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SimpleServlet</servlet-name>
<url-pattern>/simple</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>WelcomeServlet</servlet-name>
<servlet-class>app01c.WelcomeServlet</servlet-class>
<load-on-startup>20</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>WelcomeServlet</servlet-name>
<url-pattern>/welcome</url-pattern>
</servlet-mapping>
</web-app>
部署描述符的好处:
- 可以包含@WebServlet中没有的元素,如load-on-startup表示在应用程序启动时加载Servlet,而不是第一次调用Servlet时加载.
- 如果需要修改配置值,如Servlet路径,就不需要重新编译Servlet类.
- 可以将初始参数传给一个Servlet,并且不需要重新编译Servlet类就可以对它们进行编译.
- 部署描述符还允许覆盖Servlet注解中指定的值.可以在标注完Servlet之后,又在同一个应用程序的部署描述符中声明Servlet.
未完待续...
标签:
原文地址:http://blog.csdn.net/fang323619/article/details/51794528