转自http://www.cnblogs.com/goody9807/archive/2007/06/13/782519.html
现在的JSP书籍有的是直接讲述JSP的使用,然后再讲解SERVERLET的使用;也有书籍是先讲述SERVERLET的使用,然后讲解JSP使用.个人认为第二种相对好一些,至于原因大家可以在学习体会到!所以今天我们接着学习SERVERLET的使用!
好,废话少说,现在开始!
service
method package cn.dragon.servlet; //下面是导入相应的包 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; /** * 这是第一个Servlet的例子 * @author cn.dragon */ public class ServletDemoFirst extends HttpServlet { //用于处理客户端发送的GET请求 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=GB2312"); //这条语句指明了向客户端发送的内容格式和采用的字符编码. PrintWriter out = response.getWriter(); out.println(" 您好!"); //利用PrintWriter对象的方法将数据发送给客户端 out.close(); } //用于处理客户端发送的POST请求 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); //这条语句的作用是,当客户端发送POST请求时,调用doGet()方法进行处理 } } |
以下截取部分 <servlet>
【注意】 ① 上面的两个<servlet-name>必须相同
|
package cn.dragon.servlet; import java.io.IOException; import javax.servlet.ServletException; public class ServletDemoSecond extends HttpServlet {
web.xml文件 <?xml version="1.0" encoding="UTF-8"?> |
Servlet入门1
1.1 关于Servlets在servlet的lifecycle中, 编写一个thread-safe编码以卸载servlet是很重要的。
Servlet入门外2
Servlets 执行 javax.servlet.Servlet interface. 当servlet编写者可以通过直接implement interface开发servlet, 但这样通常没有必要. 因为大多数servlet是针对用HTTP协议的web服务器, 这样最通用开发servlet办法是用 javax.servlet.http.HttpServlet 内.
HttpServlet 类通过extend GenericServlet基类执行 Servlet interface, 提供了处理HTTP协议的功能. 他的service方法支持标准HTTP/1.1请求.
一般地, 用HttpServlet指定的类编写的servlets可以多线程地并发运行 service方法.
2.1 与客户端的交互性
Servlet编写者注意HttpServlet类有几个欠缺的方法,你可以自己定义方法中内容,但是必须使用这些方法名称以使servlet知道你想做什么,
doGet, 用于处理 GET、有条件的GET 和头部 HEAD请求
doPost, 用户处理 POST 请求
doPut, 用于处理 PUT 请求
doDelete, 用于处理 DELETE请求
HttpServlet的service方法, 一般地, 当它接收到一个OPTIONS请求时,会调用doOptions 方法, 当接收一个TRACE请求是调用doTrace . doOptions缺省执行方式是自动决定什么样的HTTP被选择并且返回哪个信息.
在你使用这些方法时,必须带两个阐述. 第一个包含来自客户端的数据 HttpServletRequest. 第二个参数包含客户端的响应HttpServletResponse. 在下例中是这样的情况.
一个HttpServletRequest对象提供到达HTTP 头部数据, 也允许你获取客户端的数据. 怎样获取这些数据取决于HTTP端请求方法.
不管任何HTTP方式, 你可以用 getParameterValues 方法, 这个用来返回特定名称的参数值. 对于用 HTTP GET 请求的方式, 这个 getQueryString 方法将会返回一个可以用来解剖分析的.
对于用HTTP POST, PUT, 和 DELETE请求的方式, 你有两种方法可以选择. 如果是文本数据,你能通过getReader方法用BufferedReader获取 ; 如果是二进制数据, 能通过getReader 方法用 ServletInputStream获取.
为了响应客户端, 一个HttpServletResponse对象提供返回数据给用户的两个方法. 你可以用getWriter 方法返回,或者 getOutputStream 方法以输出流返回. 你应该用getWriter返回文本数据,而用getOutputStream返回二进制数据.
在使用Writer 或 OutputStream之前, HTTP 头部应该先被设置. HttpServletResponse内提供这样一个方法,之后可以用writer 或 outputstream 将响应主体部分发回用户. 完成后要关闭 writer 或 output stream以便让服务器知道响应已经完毕.
2.2 一个HTTP Servlet处理GET和HEAD方法的例子
public class SimpleServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
// 首先设置头部
res.setContentType("text/html");
// 用 writer方法返回响应数据
PrintWriter out = res.getWriter();
out.println("<HEAD><TITLE> SimpleServlet Output</TITLE></HEAD><BODY>");
out.println("<h1> SimpleServlet Output </h1>");
out.println("<P>This is output is from SimpleServlet.");
out.println("</BODY>");
out.close();
}
public String getServletInfo() {
return "A simple servlet";
}
}
这个例子完整地现实了一个servlet.
2.3 一个HTTP Servlet处理POST方式的例子
这里是个用HTML带POST表单的例子:
<html>
<head><title>JdcSurvey</title></head>
<body>
<form action=http://demo:8080/servlet/survey method=POST>
<input type=hidden name=survey value=Survey01Results>
<BR><BR>How Many Employees in your Company?<BR>
<BR>1-100<input type=radio name=employee value=1-100>
<BR>100-200<input type=radio name=employee value=100-200>
<BR>200-300<input type=radio name=employee value=200-300>
<BR>300-400<input type=radio name=employee value=300-400>
<BR>500-more<input type=radio name=employee value=500-more>
<BR><BR>General Comments?<BR>
<BR><input type=text name=comment>
<BR><BR>What IDEs do you use?<BR>
<BR>JavaWorkShop<input type=checkbox name=ide value=JavaWorkShop>
<BR>J++<input type=checkbox name=ide value=J++>
<BR>Cafe'<input type=checkbox name=ide value=Cafe'>
<BR><BR><input type=submit><input type=reset>
</form>
</body>
</html>
这里的servlet将表单数据写入一个文件,并且用一个thank you信息响应用户. 这里servlet的方法,如下例:
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
// 首先设置响应的 "content type" 头部
res.setContentType("text/html");
//得到响应的 PrintWriter以返回文本给客户端.
PrintWriter toClient = res.getWriter();
try {
//打开一个文件写入Survey的结果.
String surveyName = req.getParameterValues("survey")[0];
FileWriter resultsFile = new FileWriter(resultsDir
+ System.getProperty("file.separator")
+ surveyName + ".txt", true);
PrintWriter toFile = new PrintWriter(resultsFile);
// 从客户端得到表单数据 & 存贮在这个文件中
toFile.println("");
Enumeration values = req.getParameterNames();
while(values.hasMoreElements()) {
String name = (String)values.nextElement();
String value = req.getParameterValues(name)[0];
if(name.compareTo("submit") != 0) {
toFile.println(name + ": " + value);
}
}
toFile.println("");
//关闭文件.
resultsFile.close();
// 用一个thank you返回客户端
toClient.println("");
toClient.println("");
toClient.println("Thank you for participating");
toClient.println("");
} catch(IOException e) {
e.printStackTrace();
toClient.println(
"A problem occured while recording your answers. "
+ "Please try again.");
}
// 关闭writer; 响应完成.
toClient.close();
}
这个doPost方法是用getParameterNames和getParameterValues方法来从表单中获取数据的. 因为它返回文本给客户端, doPost 将调用 getWriter 方法. 在写入响应主体部分之前,它设置了响应头部字段的设置, 但响应完成后,关闭.
Servlet入门3
Lifecycle 方法
3.1 重编Init 初始化方法
在初始化过程中, servlet应当准备好它要安排的一些资源, 以便这个servlet 能够接收请求,做到这些可以不用考虑多线程, 因为在servlet初始化是只能是单进程的。 一旦初始化方法完成, servlet就能接收客户端的请求。 当然如果初始化不能成功,这个方法会扔出throw UnavailableException解释的.
初始化方法使用ServletConfig 对象作为参数. 这个方法应该保存这个对象, 以便它能有方法getServletConfig返回. 最简单的办法是,搞出一个新类,他的初始化方法数调用super.init. 如果确实这样做, 你就应当自己保存ServletConfig 对象, 并且自己重编getServletConfig 方法以便它能从新的位置得到对象.
下面是个初始化方法的例子. 它是来自Survey Servlet的初始化方法, 从一个表单接收输入然后存储到文件中,为了存储survey信息, 它需要一个目录. 它以初始化参数接收这个目录.
public void init(ServletConfig config)
throws ServletException
{
super.init(config);
//获取目录
resultsDir = getInitParameter("resultsDir");
//如果没有目录, 不处理客户端
if (resultsDir == null) {
throw new UnavailableException (this,
"Not given a directory to write survey results!");
}
}
这里的初始化方法调用super.init 方法来管理安排ServletConfig对象. 这个初始化方法也设置了一个字段: resultsDir, 作为初始化参数提供的目录名. 如果没有目录名被提供, 这个 servlet扔出一个不适用的解释. 如果初始化 方法成功完成,servlet将能处理客户端请求
初始化参数
初始化参数的规定是一个服务器方面的规定。如果初始化参数被规定, 都可以用同样的方法得到: 用 getInitParameter方法. 这个方法将参数名作为自己的参数项.
3.2 重编Destroy 方法
当服务器卸载一个servlet, 它将调用servlet的destroy方法. 这个 destroy方法是与初始化方法相反,同时从内存中释放servlet.
并不是所有的调用了初始化init方法是也必须调用destroy方法.
对于大多数的servlets, 一些初始化的工作必须反做的. 如, 假设有一个servlet,它在初始化时打开一个数据库连接,他的destroy 方法如下显示:需要关闭这个连接的
/**
* 关闭数据库连接
*/
public void destroy() {
try {
con.close();
} catch (SQLException e) {
while(e != null) {
log("SQLException: " + e.getSQLState() + '\t' +
e.getMessage() + '\t' +
e.getErrorCode() + '\t');
e = e.getNextException();
}
} catch (Exception e) {
e.printStackTrace();
}
}
关于一个Servlet中断涉及的多线程
但一个服务器卸载一个servlet, 它会在所有的service已经完成后调用 destroy. 如果你的操作运行需要很长时间, 但destroy 被调用时还有线程在运行. 这个servlet编写者有责任确保所有的线程都已经完成;
长时间运行响应客户端请求的那些servlet应当保留当前有多少方法在运行的记录. 他的 long-running 方法应当周期性地轮询以确保他们能够继续运行下去. 如果servlet被destroy方法调用, 那么这个long-running 方法如果必要必须停止工作或清除.
举例, 变量serviceCounter用来统计有多少service方法在运行, 变量 shuttingDown显示这个servlet是否被destory. 每个变量有它自己的获取方法:
public ShutdownExample extends HttpServlet {
private int serviceCounter = 0;
private Boolean shuttingDown;
...
// serviceCounter
protected synchronized void enteringServiceMethod() {
serviceCounter++;
}
protected synchronized void leavingServiceMethod() {
serviceCounter--;
}
protected synchronized int numServices() {
return serviceCounter;
}
//shuttingDown
protected setShuttingDown(Boolean flag) {
shuttingDown = flag;
}
protected Boolean isShuttingDown() {
return shuttingDown;
}
}
这个service方法每次在它进入时要增加,而在它返回退出时要减少:
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
enteringServiceMethod();
try {
super.service(req, resp);
} finally {
leavingServiceMethod();
}
}
destroy方法应当检查serviceCounter, 如果存在长时间方式运行的话, 设置变量shuttingDown . 这个变量将会让那个正在处理请求的线程知道:该结束了,关闭吧! destroy 方法应当等待这几个service 方法完成, 这样就是一个清楚的关闭过程了.
public void destroy() {
/* 检查是否有线程在运行,如果存在,告诉他们stop. */
if (numServices() > 0) {
setShuttingDown(true);
}
/* 等待他们stop. */
while(numService() > 0) {
try {
thisThread.sleep(interval);
} catch (InterruptedException e) {
}
}
}
long-running 方法如必要应当检查这个变量,并且解释他们的工作:
public void doPost(...) {
...
for(i = 0; ((i < lotsOfStuffToDo) && !isShuttingDown()); i++) {
try {
partOfLongRunningOperation(i);
} catch (InterruptedException e) {
}
}
}
3.3 提供关于Servlet的信息
/**
* This is a simple example of an HTTP Servlet. It responds to the GET
* and HEAD methods of the HTTP protocol.
*/
public class SimpleServlet extends HttpServlet {
...
public String getServletInfo() {
return "A simple servlet";
}
}