第 3 章基本Servlet程序设计 JavaEE 建立在JavaSE 的基础上,为开发和部署企业应用程序提供 API 和服务。将JavaSE 与JavaEE 的服务以及API 结合起来,将有助于 开发独立于系统平台、基于Web的JavaEE 应用。Servlet属于JavaEE 应用中的Web组件,是JSP 技术的基础,而且大型的Web应用开发需要 Servlet与JSP 相互配合才能完成。 本章将介绍Servlet的基本概念、Web服务器与Web容器的关系、基 本Servlet结构,通过实例介绍在OracleJDeveloper10g环境下开发、部署 和运行Servlet的基本方法和步骤。 3.evet的基本概念 1 Srl Servlet是CGI 程序设计的Java解决方案,是一种用于服务器端程序 设计的JavaAPI 。Servlet自从1997 年诞生以来,由于具有平台无关性、可 扩展性以及能够提供比CGI 脚本程序更加优越的性能,因此它的应用量快 速的增长,其成为Java2 企业应用平台的一个关键组件。Servlet是一些 Java类,用于动态地处理请求以及构造响应信息。它们动态地生成 HTMLWeb页面作为对请求的响应,还可以向客户以其他格式发送数据。 例如,串行化Java对象———Applet和Java应用程序,以及XML 。这些 Servlet在一个Servlet容器中运行,并且可以访问由该容器提供的服务。 Servlet的客户可以是一个浏览器、Java应用程序,或者任何其他可以构造 一个请求并从中接收响应的客户。当然,正常情况下这些请求是Servlet 可以识别和响应的HTTP 请求。 在用Servlet和JavaEE 技术进行Java企业服务器端编程时,Web服 务器从客户机接收请求,并把该请求映射到适当的资源上。如果该请求是 一个静态资源,则它会简单地返回该资源给相关的客户机。请求的对象也 可以是一个JavaEE 组件(如Servlet)。在这种情形下,JavaEE 服务器会 提供一个Web容器给Web服务器,Web服务器接着把这个对容器组件的 28 Java Web 与JavaFX 应用开发———基于Oracle JDevelope、Oracle DB XE 与NetBeans 实现 请求转发给指定的容器,随后由该容器把请求转发给相应的组件,再由该组件处理请求并 且返回一条响应信息,其执行过程如图3-1所示。 图3- 1 Servlet的基本执行流程 中间层由Web服务器和JavaEE服务器组成。一个JavaEE服务器上有2个容器,即 Web容器和EJB容器。Web容器就是管理着一个Web应用的所有Servlet和JSP运行的 Java环境,它是一个JavaEE服务器的组成部分,它的请求来自Web服务器。它必须支持 HTTP,并且可以选择支持其他协议。它可以建立在一个JavaEE服务器中,也可以作为一 个组件插入Web服务器中。同时,它还负责管理Servlet和JSP实例的调用和生存周期。 EJB容器是包含业务规则或逻辑的业务组件,主要提供对JDBC等JavaEEAPI的 访问。EJB有两种类型:会话Bean是面向逻辑的,并处理客户机的请求,也进行数据逻 辑的处理;实体Bean与数据本身紧密耦合,并处理数据访问和持久性。在客户机端,应用 程序容器是由JavaEE提供的在客户机上运行的Java应用程序,它通常使用AWT 、 SwingAPI,以及JavaFX构造GUI 。Servlet不是用户直接调用的程序,而是由实施该 Servle的Web应用中的Web容器根据进入的HTTP请求调用的Servlet。当一个 Servlet被调用后,Web容器把进入的请求信息转发到该Servlet,这样Servlet就可以处 理它并且生成动态响应信息。Web容器通过接收Servlet的请求与Web服务器交互,并 且把响应信息回送到Web服务器。 3.基本Sevet结构 2 rl JaaSrltAPI2.eveaaEE和Jv veve3为以Srlt技术为基础的基于JvaaSE的Web应 用开发提供了成熟的技术。Seve3API包括jvx.eveaasrlt.h rlt2.aasrlt和jvx.evetp两个 包。第一个包包含所有的Servlet实现和扩展的通用接口和类;第二个包包含在HTTP 实现特定的Servlet时所需要的扩充类。 基本Serlt结构的核心部分是jaasrltSrlt接口,它提供了所有Sevet的 vevx.eve.everl 框架结构。Servlet接口提供了5种方法,其中3个最重要的方法是:init()方法对 Sevesrie() dsry() rlt进行初始化;evc方法负责接收和响应客户请求;eto方法执行清除对 象等收尾工作。所有的Servlet必须实现这个接口,实现的方式或者是直接地,或者是通 过继承的方式。 3.2.1 GenericServlet 与HttpServlet 在ServletAPI2.3中,两个主要的类是GenericServlet与HtpServlet,而 第3 章 基本Servlet 程序设计  29 HttpServlet类是从GenericServlet类继承而来的。开发Servlet时,通常的做法是继承这 两个类中的一个。Servlet中没有main()方法,这就是为什么所有的Servlet都必须实现 javax.servlet.Servlet接口的原因。每当Web服务器收到一个指向某个Servlet的请求 时,它总要调用Servlet的service()方法。 当用户的Servlet继承GenericServlet类时,必须实现service()方法。GenericServlet 类的service()方法是一个抽象方法,其定义如下。 publicabstractvoid service(ServletRequestreq,ServletResponseres)throws ServletException,IOException; ● ServletRequest———含有发送给Servlet的信息,用来保存客户机向服务器发出请 求的各种属性,如IP地址。 ● ServletResponse———保存返回给客户机的数据,如设置服务器如何对客户机进行响应。 与GenericServlet类不同,当用户的Servlet继承HttpServlet类时,不需要实现 service()方法,HttpServlet类已经为用户实现了。HttpServlet类的service()方法的定 义如下。 protected void service ( HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException; 当HttpServlet.service()方法被调用时,它将读取请求中存储的方法类型,然后基于 该值确定应该调用哪一个方法,这些方法是被强制执行的。如果方法的类型是GET, service()方法将调用doGet()方法;如果方法的类型是POST,service()方法将调用 doPost()方法。 3.2.2 Servlet 的生命周期 Servlet的生命周期如下。 (1)Servlet由Web容器初始化,然后再处理请求。 (2)Servlet组件从客户层接收请求。 (3)Servlet处理相应的请求; (4)一旦处理完毕,就会向客户层返回一条响应信息。 (5)最后,Web容器负责销毁自己生成的任何Servlet实例。 上述执行过程中的第一步和第五步只执行一次,第二、第三和第四步将循环多次,以 处理众多的请求。 javax.servlet.Servlet接口说明了Servlet生命周期的框架结构。这个接口定义了 Servlet生命周期的3个方法:init()、service()、destroy()。 1.init()方法 init()方法是Servlet生命周期的起点,一旦加载了某个Servlet,服务器立即调用它 的init()方法。在init()方法中,Servlet将创建和初始化它在处理请求时要用到的资源, 例如数据库连接。init()方法的定义如下。 public void init(ServletConfig config) throws ServletException; 30 Java Web 与JavaFX 应用开发———基于Oracle JDeveloper、Oracle DB XE 与NetBeans 实现 init()方法使用ServletConfig对象作为参数。用户应该保存这个对象,以便在后续 程序中引用。一般用如下的方式定义init()方法。 public void init(ServletConfig config) throws ServletException { super.init(config); ... } 2.service()方法 service()方法处理客户发出的所有请求。在init()方法执行之前,service()方法无法对 客户的请求提供服务。因此,它不能直接实现service()方法,除非继承了GenericServlet 抽象类。 3.destroy()方法 destroy()方法标志着Servlet生命周期的结束。当服务需要关闭时,Web容器调用 Servlet的destroy()方法。此时,在init()方法中创建的任何资源都将被清除和释放。例 如,如果有打开的数据库连接,就应当被关闭。destroy()方法的定义如下。 public void destroy(); 3.3 基于JDeveloper开发Servlet 本节通过一个实例介绍在OracleJDeveloper10g 环境下怎样创建一个基本的 Servlet。下面对生成的Servlet源代码进行分析,这是主要着眼于这个Servlet的每个组 成部分、Servlet的实现方法以及Servlet使用的对象。 3.3.1 创建基本的Servlet (1)启动OracleJDeveloper,创建一个新的工作区,如图3-2所示。 图3-2 创建一个新的工作区 第 3 章 基本Servlet 程序设计  31 (2)单击“确定”按钮,将显示如图3-3所示的对话框,让用户创建一个工程文件。输 入项目文件名为BasicServlet,然后单击“确定”按钮,则可以完成工作区和工程文件的 创建。 图3- 3 创建一个新的工程 (3)在创建的工程文件中增加一个Servlet对象。从IDE主菜单中选择File→New 命令,将显示如图3-4所示的对话框。选择WebTier→Servlets→HTTPServlet,单击 “确定”按钮,将会显示HTTPServletWizard,如图3-5所示。 图3- 4 增加一个Servlet对象 (4)单击“下一步”按钮,将会显示Web应用版本对话框,如图3-6所示。单击“下一 步”按钮,将会显示创建Servlet对话框,如图3-7所示。 (5)如图3-7所示,分别输入Clas 与Package域,勾选doGet()与doPost()复选框。 之后单击“下一步”按钮,将会显示Servlet的URL映射名字对话框,如图3-8所示。 (6)图3-8用来指定创建的Servlet的URL映射名字和URL前缀。这样,在浏览器 中运行该Servlet时,Web容器OC4J就知道这个Servlet的具体存放位置。 32 Java Web 与JavaFX 应用开发———基于Oracle JDeveloper、Oracle DB XE 与NetBeans 实现 图3- 5 HTTPServletWizard 图3- 6 Web应用版本对话框 图3- 7 创建Servlet对话框 第3 章 基本Servlet 程序设计  33 图3-8 Servlet的URL映射名字对话框 (7)单击“完成”按钮,就可以在CodeEditor窗口得到如下所示的BasicServlet.java 的源代码。 package basicServlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.*; import javax.servlet.http.*; public class BasicServlet extends HttpServlet { private static final String CONTENT_TYPE = "text/html; charset=GBK"; public void init(ServletConfig config) throws ServletException { super.init(config); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(CONTENT_TYPE); PrintWriter out = response.getWriter(); out.println(""); out.println("BasicServlet"); out.println(""); out.println("

这个servlet 接收一个GET 请求.

"); out.println(""); out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(CONTENT_TYPE); PrintWriter out = response.getWriter(); 34 Java Web 与JavaFX 应用开发———基于Oracle JDeveloper、Oracle DB XE 与NetBeans 实现 out.println(""); out.println("BasicServlet"); out.println(""); out.println("

The servlet has received a POST. This is the reply.

"); out.println(""); out.close(); } } (8)从IDE的主菜单中选择Run→RunBasicServlet.jpr,运行该工程。JDeveloper 首先启动内嵌在IDE中的OC4J,并常驻内存中,然后启动默认的IE浏览器,运行结果如 图3-9所示。 图3-9 BasicServlet.jpr的运行结果 3.3.2 分析BasicServlet 类 从上述开发过程可以看到,在OracleJDeveloper环境下开发Servlet给开发人员带 来了极大的便利。下面分析BasicServlet类的组成及使用方法。 1.BasicServlet类的基本组成结构 首先,BasicServlet类继承了HttpServlet类。HttpServlet是一个抽象类,简化了 HTTPServlet的编码工作。同时,HttpServlet类继承了GenericServlet类,提供了处理 HTTP特定请求的功能。 2.BasicServlet类继承的方法 BasicServlet类重写了它继承的3个方法,下面说明这3个方法的用法。 (1)init()方法 init()方法首先读取传递给它的ServletConfig对象,再把该对象传递给它的父init() 方法,否则将保存该对象以备以后使用。一个Servlet可以使用ServletConfig对象访问 其配置数据。init()方法如果不能正常完成,将抛出一个ServletException。 Servlet技术规范保证了init()方法只在Servlet的任何给定的实例上被调用一次, init()方法被允许在任何请求传递到该Servlet之前完成。 执行上述动作的代码如下。 super.init(config); 在init()方法中可以实现下列一些典型任务。 第3 章 基本Servlet 程序设计  35 ● 从配置文件中读取配置数据。 ● 使用ServletConfig对象读取初始化参数。 ● 初始化诸如注册一个数据库驱动程序、连接日志记录服务等这样的一次性活动。 BasicServlet在init()方法中没有创建任何资源,所以也就没有定义destroy()方法。 (2)doGet()和doPost()方法 这两个方法的唯一区别是它们的服务的请求类型不同。doGet()方法处理GET请求, doPost()方法处理POST请求。它们均接收HttpServletRequest和HttpServletResponse对 象,它们封装了HTTP请求/响应信息。HttpServletRequest对象包含客户机发出的信 息,而HttpServletResponse对象则包含回送给客户机的信息。在这两个方法中被执行 的第一条语句如下。 response.setContentType(CONTENT_TYPE); 这个语句用于设置响应的内容类型和字符编码,这个响应属性只能设置一次,在开始 向Writer或OutputStream 输出流输出信息之前,必须先设置这个属性。在BasicServlet 类中,正在使用的是PrintWriter,所以把响应类型设置为text/html。 下一步要做的就是创建PrintWriter的对象,以便通过输出流对象把HTML文本信 息输出到客户机的浏览器上。可以通过调用ServletResponse的getWriter()方法达到这 一目的。执行这个动作的语句如下。 PrintWriter out=response.getWriter(); 现在就有了一个输出流对象的引用,它允许输出HTML 文本,并回送给 HttpServletResponse对象所对应的客户机浏览器,下面的程序片段描述了这个过程。 out.println(""); out.println("BasicServlet"); out.println(""); out.println("

The servlet has received a GET. This is the reply.

"); out.println(""); out.close(); 上述程序片段是一个非常直观地把HTML文本回送给客户机浏览器的方法,需要 做的仅是把在响应中包含的HTML文本传递给PrintWriter对象的println()方法,然后 再关闭输出流。 通过上面内容的学习,读者对Servlet的组成有了一定程度的了解,也知道了编制自 己的Servlet的哪一部分需要符合ServletAPI的框架结构要求,即类与类、类与接口之间 的继承关系。因此,读者现在能够创建自己的基本Servlet了。 3.3.3 部署Web 应用 1.创建与OC4J的连接 (1)启动OC4J,启动命令以及启动后的提示信息如图3-10所示。 (2)连接Web 容器OC4J。在OracleJDeveloperIDE 的系统导航窗口展开 36 Java Web 与JavaFX 应用开发———基于Oracle JDeveloper、Oracle DB XE 与NetBeans 实现 图3-10 启动OC4J Connections节点,选择ApplicationServer对象,右击,在弹出的快捷菜单中选择New Connection命令,将显示如图3-11 所示的连接OC4J 向导窗口。 图3-11 连接OC4J 向导窗口 (3)单击“下一步”按钮,将会显示如图3-12 所示的对话框。在ConnectionName 域 输入Oe选择独立OC4J10g10.3,如图312 所示。 racleAS10g,ConnectionTyp1. 图3-12 确定连接名称与连接类型 第 3 章 基本Servlet 程序设计  (4)单击“下一步”按钮,将会显示如图3-13所示的对话框。Username域使用默认 值,Pasword域输入连接OC4J的密码,并勾选DeployPasword复选框。 图3-13 确定用户名与密码 (5)单击“下一步”按钮,将会显示如图3-14所示的对话框。这里,输入HostName 的值为Del(作者所使用计算机的默认机器名),URLPath可以省略。 图3-14 确定连接URL等值 (6)单击“下一步”按钮,将会显示如图3-15所示的对话框。单击TestConnection按 钮,如果显示Suces! 信息,则说明已经连接成功。单击“完成”按钮,完成与OC4J的 连接。 2.创建Web应用的部署描述文件 (1)在工程文件BasicServlet中添加一个Web对象。从IDEE的主菜单中选择File→ New命令,在所显示的如图3-16所示对话框的Categories区域选择General→ 38 Java Web 与JavaFX 应用开发———基于Oracle JDeveloper、Oracle DB XE 与NetBeans 实现 图3-15 测试连接是否成功 DeploymentProfiles,在Items 区域选择WARFile,单击“确定”按钮,将会显示如图3-17 所示的对话框。将FileName 域的文件名改为Bsceve.epoy。 aiSrltdl 图3-16 创建部署描述文件 (2)单击“确定”按钮,将会显示如图3-18 所示的Web应用的部署信息。单击“确定” 按钮,将完成Web应用的部署描述文件的创建工作。 3. 部署与运行Web应用 在系统导航窗口选择Bascervet.epo右击,从弹出的快捷菜单中选择DepoytOracleAS10g,如图3-19 所示 i 。 Sldly, lo 第 3 章 基本Servlet 程序设计  39 图3-17 确定部署描述文件的名称和路径 图3-18 Web应用的部署信息 图3-19 部署Web应用到Web容器 40 Java Web 与JavaFX 应用开发———基于Oracle JDeveloper、Oracle DB XE 与NetBeans 实现 此时,IDE 将根据用户的配置进行BasicServlet.jpr工程的部署工作。在部署过程 中,信息浏览工作区将不断显示Web应用的部署信息。如果用户的配置有错误,也会将 错误信息显示出来。如果最后显示如下信息,则说明Web应用的部署配置成功完成。 ---- Deployment started. ----2021-7-20 11:56:12 Target platform is 独立OC4J 10g 10.1.3 (OracleAS10g). Wrote WAR file to E: \JDevStudio1013\jdev \mywork \BasicServlet \BasicServlet \ deploy\BasicServlet.war Wrote EAR file to E: \JDevStudio1013\jdev \mywork \BasicServlet \BasicServlet \ deploy\BasicServlet.ear BasicServlet 的Application UnDeployer 开始。 ...... 初始化BasicServlet 开始… 初始化BasicServlet 结束… 已启动的应用程序: BasicServlet 将Web 应用程序绑定到站点default-web-site 开始… 将应用程序BasicServlet 的BasicServlet Web 模块绑定到上下文根BasicServlet - BasicServlet-context-root 下的站点default-web-site 将Web 应用程序绑定到站点default-web-site 结束… BasicServlet 的Application Deployer 完成。操作时间: 107 msecs Elapsed time for deployment: 15 seconds ---- Deployment finished. ----2021-7-20 11:56:27 在MS-DOS窗口,改变当前目录为E:\jdevstudio1013\J2EE\HOME\config,用IDE 或其他的文本编辑器打开default-web-site.xml文件。其文件内容如下。 1. 2. < web - sitexmlns: xsi =" http://www. w3. org/2001/XMLSchema - instance" xsi: noNamespaceSchemaLocation=" http://xmlns. oracle. com/oracleas/schema/web - site- 10_0.xsd"port="8888" display- name="OC4J 10g (10.1.3) Default Web Site" schema-major-version="10" schema-minor-version="0" > 3. 4. 5. < web - app application ="system" name ="dms0" root ="/dms0" access - log = "false" /> 6. < web - app application =" system " name =" JMXSoapAdapter - web " root = "/JMXSoapAdapter" /> 7. < web- app application="default" name="jmsrouter_web" load- on- startup= "true" root="/jmsrouter" /> 8. < web - app application ="ascontrol" name ="ascontrol" load - on - startup = "true" root="/em" ohs-routing="false" /> 9. 10. < web - app application =" BasicServlet" name =" BasicServlet" load - on - ........................................................................ 第3 章 基本Servlet 程序设计  41 startup="true"root="/ServletWS-BasicServlet -context-root" /> 11. <..ac..ce..s..s-..lo..g ..pa..th..="....../l..og../d..ef..a..ul..t-..we..b-..ac..ce..s..s...lo..g"..sp..l..it..="..da..y"../> 12. 在一个Web容器中,每个Web应用与一个上下文环境(Context)相关联,并且一个 Web应用中包含的所有资源都相对于其上下文环境而存在。一个Servlet上下文环境存 在于Web容器的一个已知路径中,这个路径提供了用户访问Web容器中存放的HTML 文件和Servlet/JSP等Web资源的URL值的前缀。 在Web容器中,default-web-site.xml文件提供了部署Web应用的上下文环境。 ● 从第3行开始,针对每一个已经部署的Web应用提供服务,包括每个Web应用的 名称和上下文环境(root),而这个root就是URL所指定的Servlet的映射地址的 前缀。即客户机浏览器访问URL的前缀。 ● 第10行处画了波浪线,就是部署的BasicServlet这个Web应用的上下文环境。因 此,可以确定URL值为: ■ 对于HTML 文档———http://dell:8888/ServletWS-BasicServlet-context-root/ HTML文档名 ■ 对于Servlet———http://dell:8888/ServletWS-BasicServlet-context-root/servlet/ BasicServlet 图3-20所示就是BasicServlet的运行结果。 图3-20 BasicServlet的运行结果 3.4 本章小结 本章首先介绍了JavaServlet的基础知识,并通过实例介绍了在OracleJDeveloper 10g环境下开发、部署和运行Servlet的基本方法和步骤,然后分析了一个基本Servlet的 组成,使读者对一个基本Servlet的组成有了一定的认识,也了解了开发Servlet的哪一部 分需要符合Servlet的框架结构要求;最后介绍了怎样确定一个Servlet的URL的值,以 及用户访问这个Servlet的URL值的方法。