读书人

Servlet课程(转)

发布时间: 2012-12-19 14:13:14 作者: rapoo

Servlet教程(转)
一、Servlet简介 Servlet是对支持Java的服务器的一般扩充。它最常见的用途是扩展Web服务器,提供非常安全的、可移植的、易于使用的CGI替代品。它是一种动态加载的模块,为来自Web服务器的请求提供服务。它完全运行在Java虚拟机上。由于它在服务器端运行,因此它不依赖于浏览器的兼容性。
servlet容器:
负责处理客户请求、把请求传送给servlet并把结果返回给客户。不同程序的容器实际实现可能有所变化,但容器与servlet之间的接口是由servlet API定义好的,这个接口定义了servlet容器在servlet上要调用的方法及传递给servlet的对象类。
servlet的生命周期:
1、servlet容器创建servlet的一个实例
2、容器调用该实例的init()方法
3、如果容器对该servlet有请求,则调用此实例的service()方法
4、容器在销毁本实例前调用它的destroy()方法
5、销毁并标记该实例以供作为垃圾收集
一旦请求了一个servlet,就没有办法阻止容器执行一个完整的生命周期。
容器在servlet首次被调用时创建它的一个实例,并保持该实例在内存中,让它对所有的请求进行处理。容器可以决定在任何时候把这个实例从内存中移走。在典型的模型中,容器为每个servlet创建一个单独的实例,容器并不会每接到一个请求就创建一个新线程,而是使用一个线程池来动态的将线程分配给到来的请求,但是这从servlet的观点来看,效果和为每个请求创建一个新线程的效果相同。
servlet API
servlet接口:
public interface Servlet
它的生命周期由javax.servlet.servlet接口定义。当你在写servlet的时候必须直接或间接的实现这个接口。一般趋向于间接实现:通过从javax.servlet.GenericServlet或javax.servlet.http.HttpServlet派生。在实现servlet接口时必须实现它的五个方法:
init():
public void init(ServletConfig config) throws ServletException
一旦对servlet实例化后,容器就调用此方法。容器把一个ServletConfig对象传统给此方法,这样servlet的实例就可以把与容器相关的配置数据保存起来供以后使用。如果此方法没有正常结束就会抛出一个ServletException。一旦抛出该异常,servlet就不再执行,而随后对它的调用会导致容器对它重新载入并再次运行此方法。接口规定对任何servlet实例,此方法只能被调用一次,在任何请求传递给servlet之前,此方法可以在不抛出异常的情况下运行完毕。
service():
public void service(ServletRequest req,ServletResponse res) throws ServletException,IOException
只有成功初始化后此方法才能被调用处理用户请求。前一个参数提供访问初始请求数据的方法和字段,后一个提供servlet构造响应的方法。
destroy():
public void destroy()
容器可以在任何时候终止servlet服务。容器调用此方法前必须给service()线程足够时间来结束执行,因此接口规定当service()正在执行时destroy()不被执行。
getServletConfig():
public ServletConfig getServletConfig()
在servlet初始化时,容器传递进来一个ServletConfig对象并保存在servlet实例中,该对象允许访问两项内容:初始化参数和ServletContext对象,前者通常由容器在文件中指定,允许在运行时向sevrlet传递有关调度信息,后者为servlet提供有关容器的信息。此方法可以让servlet在任何时候获得该对象及配置信息。
getServletInfo():
public String getServletInfo()
此方法返回一个String对象,该对象包含servlet的信息,例如开发者、创建日期、描述信息等。该方法也可用于容器。
GenericServlet类
Public abstract class GenericServlet implants Servlet,ServletConfig,Serializable
此类提供了servlet接口的基本实现部分,其service()方法被申明为abstract,因此需要被派生。init(ServletConfig conf)方法把servletConfig对象存储在一个private transient(私有临时)实例变量里,getServletConfig()方法返回指向本对象的指针,如果你重载此方法,将不能使用getServletConfig来获得ServletConfig对象,如果确实想重载,记住要包含对super.config的调用。2.1版的API提供一个重载的没有参数的init()方法。现在在init(ServletConfig)方法结束时有一个对init()的调用,尽管目前它是空的。2.1版API里面,此类实现了ServletConfig接口,这使得开发者不用获得ServletConfig对象情况下直接调用ServletConfig的方法,这些方法是:getInitParameter(),getInitParameterNames(),getServletContext。此类还包含两个写日志的方法,它们实际上调用的是ServletContext上的对应方法。log(String msg)方法将servlet的名称和msg参数写到容器的日志中,log(String msg,Throwable cause)除了包含servlet外还包含一个异常。
HttpServlet类
该类扩展了GenericServlet类并对servlet接口提供了与HTTP更相关的实现。
service():
protected void service(HttpServletRequest req,HttpServletResponse res) throws ServletException,IOException
public void service(HttpServletRequest req,HttpServletResponse res)throws ServletException,IOException
该方法作为HTTP请求的分发器,这个方法在任何时候都不能被重载。当请求到来时,service()方法决定请求的类型(GET,POST,HEAD,OPTIONS,DELETE,PUT,TRACE),并把请求分发给相应的处理方法(doGet(),doPost(),doHead(),doOptions(),doDelete(),doPut(),doTrace())每个do方法具有和第一个service()相同的形式。为了响应特定类型的HTTP请求,我们必须重载相应的do方法。如果servlet收到一个HTTP请求而你没有重载相应的do方法,它就返回一个说明此方法对本资源不可用的标准HTTP错误。
getLatModified():
protected long getLastModified(HttpServletRequest req)
该方法返回以毫秒为单位的的自GMT时间1970年1月1日0时0分0秒依赖的最近一次修改servlet的时间,缺省是返回一个负数表示时间未知。当处理GET请求时,调用此方法可以知道servlet的最近修改时间,服务器就可决定是否把结果从缓存中去掉。
HttpServletRequest接口
public interface HttpServletRequest extends ServletRequest
所有实现此接口的对象(例如从servlet容器传递的HTTP请求对象)都能让servlet通过自己的方法访问所有请求的数据。下面是一些用来获取表单数据的基本方法。
getParameter()
public String getParameter(String key)
此方法试图将根据查询串中的关键字定位对应的参数并返回其值。如果有多个值则返回列表中的第一个值。如果请求信息中没有指定参数,则返回null。
getParameterValues():
public String[] getParameterValues(String key)
如果一个参数可以返回多个值,比如复选框集合,则可以用此方法获得对应参数的所有值。如果请求信息中没有指定参数,则返回null。
GetParameterNames():
Public Enumeration getParameterNames()
此方法返回一个Enumeration对象,包含对应请求的所有参数名字列表。
HttpServletResponse接口
public interface HttpServletResponse extends servletResponse
servlet容器提供一个实现该接口的对象并通过service()方法将它传递给servlet。通过此对象及其方法,servlet可以修改响应头并返回结果。
setContentType():
public void setContentType(String type)
在给调用者发回响应前,必须用此方法来设置HTTP响应的MIME类型。可以是任何有效的MIME类型,当给浏览器返回HTML是就是”text/html”类型。
getWriter():
public PrintWriter getWriter()throws IOException
此方法将返回PrintWriter对象,把servlet的结果作为文本返回给调用者。PrintWriter对象自动把Java内部的UniCode编码字符转换成正确的编码以使客户端能够阅读。
getOutputStream():
public ServletOutputStream getOutputStream() throws IOException
此方法返回ServletOutputStream对象,它是java.io.OutputStream的一个子类。此对象向客户发送二进制数据。
setHeader():
public void setHeader(String name,String value)
此方法用来设置送回给客户的HTTP响应头。有一些快捷的方法用来改变某些常用的响应头,但有时也需要直接调用此方法。
编译条件
需要从http://java.sun.com/products/servlet/ 获得一份JSDK的拷贝,并把servlet.jar移动到JDK安装目录下的\jre\lib\ext目录下。如果是JDK1.1,则移动到\lib下,并在CLASSPATH中加入servlet.jar的绝对路径。
运行条件
需要Apache Jserv,Jrun Servlet Exec,Java Web Server,Weblogic,WebSphere,Tomcat,Resin等servlet服务器端程序。
简单范例


<P>

Enter social security Number:

<P>

<INPUT TYPE="TEXT" NAME="SOCSEC"></INPUT>

<P>

Enter Multiplier:

<P>

<INPUT TYPE="TEXT" NAME="MULTIPLIER"></INPUT>

<P>

<INPUT TYPE="SUBMIT" VALUE="Submit">

<INPUT TYPE="RESET">

</FORM>

</BLOCKQUOTE>

</BODY>

</HTML>

  这个HTML文件有两个数据域,用户可以输入社会保险号和一个乘数。当用户单击了Submit按纽。BonusServlet就得到了终端用户的数据。然后寻找Session Bean。将用户数据传递给Session Bean。Session Bean计算出奖金,把结果返回给Servlet。Servlet再通过另一个HTML页面将奖金结果返回给用户。



创建Servlet:

例子假定BonusServlet.java文件是在C:\J2EE\Client-Code目录下面。在运行的时候,Servlet代码执行如下操作:


获得用户数据


查找Session Bean


将用户数据传递给Session Bean


在得到Session Bean的返回结果以后,创建一个HTML页面将结果返回给客户。


Servlet代码如下:

import javax.servlet.*;

import javax.servlet.http.*;

import java.io.*;

import javax.naming.*;

import javax.rmi.PortableRemoteObject;

import Beans.*;

public class BonusServlet extends HttpServlet {

CalcHome homecalc;

public void init(ServletConfig config)

throws ServletException{

//Look up home interface

try{

InitialContext ctx = new InitialContext();

Object objref = ctx.lookup("calcs");

homecalc =

(CalcHome)PortableRemoteObject.narrow(

objref,

CalcHome.class);

} catch (Exception NamingException) {

NamingException.printStackTrace();

}

}

public void doGet (HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException {

String socsec = null;

int multiplier = 0;

double calc = 0.0;

PrintWriter out;

response.setContentType("text/html");

String title = "EJB Example";

out = response.getWriter();

out.println("<HTML><HEAD><TITLE>");

out.println(title);

out.println("</TITLE></HEAD><BODY>");

try{

Calc theCalculation;

//Get Multiplier and Social Security Information

String strMult =

request.getParameter("MULTIPLIER");

Integer integerMult = new Integer(strMult);

multiplier = integerMult.intValue();

socsec = request.getParameter("SOCSEC");

//Calculate bonus.10 AUGUST 28, 2000

double bonus = 100.00;

theCalculation = homecalc.create();

calc =

theCalculation.calcBonus(multiplier, bonus);

} catch(Exception CreateException){

CreateException.printStackTrace();

}

//Display Data

out.println("<H1>Bonus Calculation</H1>");

out.println("<P>Soc Sec: " + socsec + "<P>");

out.println("<P>Multiplier: " +

multiplier + "<P>");

out.println("<P>Bonus Amount: " + calc + "<P>");

out.println("</BODY></HTML>");

out.close();

}

public void destroy() {

System.out.println("Destroy");

}

}


  在import子句中,javax.servlet包括了Servlet Class的协议。Java.io是系统输入输出包。Javax.naming里面包含了Java名字目录服务APIs。Javax.rmi是用来Session Bean的home接口和Remote对象的通信使用的。

  在BonusServlet.init方法中,查找Session Bean的home接口。并且产生它的实例。方法使用了JNDI在组件的组装中的指定的名字calcs。用它来得到home接口的reference。然后就把这个reference和home接口类传递给PortableRemoteObject.narrow方法。来保证把reference转化为CalcHome类型。

  DoGet()方法有两个参数。一个是request对象,另一个是reponse对象。浏览器发送一个request对象给Servlet。而Servlet返回一个response对象给浏览器。方法访问request对象里面的信息,可以发现是谁在发出的请求、请求的数据在什么表单里面、是哪个HTTP头被发送。并使用reponse对象产生一个HTML页面来响应浏览器的请求。

  当方法处理请求的时候,如果产生输入输出错误,就抛出一个IOException异常。如果不能处理请求,就会抛出一个ServletException异常。为了计算奖金值,doGet()创建了一个home接口,调用它的calcBonus。


创建Session Bean:

  Session Bean代表了与客户的一个短暂的会话。如果服务或者客户有一方崩溃了。数据就消失了。相反,Entity Bean代表了数据库中一段持久的数据。如果服务或者客户又一方崩溃了,底层的服务保证数据能被保存下来。

  因为这个Enterprise Bean只是应BonusServlet的请求,执行了一个简单的计算。如果发生崩溃,可以重新初始化计算。这样,我们在本例子中就选择Session Bean来实现这个计算。

 在组装配置好以后,Servlet组件和Session Bean组件如何在一个J2EE应用程序中协同工作。容器是Session Bean和支持Session Bean的底层平台之间的接口。容器是在配置期间产生的。

  本例子假定CalcBean.java、Calc.java和CalcHome.java文件都放在C:\J2EE\Beans目录下面。CalcHome.java文件前面的Package名字 Beans和目录Beans的名字应该是一样的。当这些文件被编译的时候,是从Beans目录中编译,其名字是包的名字后面加一个斜线在加上类或者接口的名字。


 

CalcHome.java文件:

package Beans;

import java.rmi.RemoteException;

import javax.ejb.CreateException;

import javax.ejb.EJBHome;

public interface CalcHome extends EJBHome {

Calc create() throws CreateException, RemoteException;

}

  BonusServlet并不直接同Session Bean通信。而是通过产生一个CalcHome的实例。这个Home接口扩展了EJBHome接口。有一个Create()方法,用来在容器中产生一个Session Bean。如果无法产生Session Bean,将会抛出一个CreateException异常。如果不能与Session Bean的远程方法通信,就会抛出一个RemoteException异常。


Calc.java文件:

package Beans;

import javax.ejb.EJBObject;

import java.rmi.RemoteException;

public interface Calc extends EJBObject {

public double calcBonus(int multiplier,

double bonus)

throws RemoteException;

}

  产生一个Home接口以后,J2EE应用程序就创建一个Remote接口和一个Session Bean。Remote接口扩展了EJBObject接口。并且声明了一个calcBonus()方法来计算奖金值。方法需要抛出javax.rmi.RemoteException异常。方法的实现在CalcBean类里面。


CalcBean.java文件:

package Beans;

import java.rmi.RemoteException;

import javax.ejb.SessionBean;

import javax.ejb.SessionContext;

public class CalcBean implements SessionBean {

public double calcBonus(int multiplier,

double bonus) {

double calc = (multiplier*bonus);

return calc;

}

public void ejbCreate() { }

public void setSessionContext(

SessionContext ctx) { }

public void ejbRemove() { }

public void ejbActivate() { }

public void ejbPassivate() { }

public void ejbLoad() { }

public void ejbStore() { }

}

  本Session Bean类实现了SessionBean接口,提供了CalcBonus()方法的行为。在BonusServlet调用CalcHome的Create()方法以后,依次调用setSessionContext()方法和ejbCreate()方法。

  这些空的方法是从SessionBean中来的。由容器负责调用。除非在Bean的创建或者删除里面,你需要附加一些你自己的操作。否者,你并不需要提供这些方法的行为。

读书人网 >编程

热点推荐