Servlet JSP和Spring MVC初学指南(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-15 09:22:05

点击下载

作者:加 Budi Kurniawan 克尼亚万 美 Paul Deck

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Servlet JSP和Spring MVC初学指南

Servlet JSP和Spring MVC初学指南试读:

前言

Java Servlet技术简称Servlet技术,是Java开发Web应用的底层技术。由Sun公司于1996年发布,用来代替CGI——当时生成Web动态内容的主流技术。CGI技术的主要问题是每个Web请求都需要新启动一个进程来处理。创建进程会消耗不少CPU周期,导致难以编写可扩展的CGI程序。而Servlet有着比CGI程序更好的性能,因为Servlet在创建后(处理第一个请求时)就一直保持在内存中。此后,SUN公司发布了JavaServer Pages(JSP)技术,以进一步简化servlet程序开发。

自从Servlet和JSP技术诞生后,涌现出大量的基于Java的Web框架来帮助开发人员快速编写Web应用。这些框架构建于Servlet和JSP之上,帮助开发人员更加关注业务逻辑,无须编写重复性(技术)代码。目前,Spring MVC是最为流行的可扩展Java Web应用开发框架。

Spring MVC又叫Spring Web MVC,是Spring框架的一个模块,用于快速开发Web应用。MVC代表Model-View-Controller,是一个广泛应用于GUI开发的设计模式。该模式不局限于Web开发,也广泛应用在桌面开发技术上,如Java Swing和JavaFX。

下面将简要介绍HTTP、基于Servlet和JSP的Web编程,以及本书的章节内容编排。注意

本书中所有示例代码基于Servlet 3.0、JSP 2.3以及Spring MVC 4。本书假定读者已有Java以及面向对象编程基础。对于Java新手,我们建议阅读由Budi Kurniawan编写的《Java : A Beginner’s Tutorial (Fourth Edition)》(ISBN 9780992133047)一书。Servlet/JSP应用架构

Servlet是一个Java程序,一个Servlet应用有一个或多个Servlet程序。JSP页面会被转换和编译成Servlet程序。

Servlet应用无法独立运行,必须运行在Servlet容器中。Servlet容器将用户的请求传递给Servlet应用,并将结果返回给用户。由于大部分Servlet应用都包含多个JSP页面,因此更准确地说是“Servlet/JSP应用”。

Web用户通过Web浏览器例如IE、Mozilla Firefox或者谷歌Chrome来访问Servlet应用。通常,Web浏览器又叫Web客户端。

图I.1展示了Servlet/JSP应用的架构。图I.1 Servlet/JSP应用架构

Web服务器和Web客户端间通过HTTP协议通信,因此Web服务器也叫HTTP服务器。下面会详细讨论HTTP协议。

Servlet/JSP容器是一个可以同时处理Servlet和静态内容的Web容器。过去,由于通常认为HTTP服务器比Servlet/JSP容器更加可靠,因此人们习惯将Servlet/JSP容器作为HTTP服务器如Apache HTTP服务器的一个模块。这种模式下,HTTP服务器用来处理静态资源,而Servlet/JSP容器则负责生成动态内容。如今,Servlet/JSP容器更加成熟可靠,并被广泛地独立部署。Apache Tomcat和Jetty是当前最流行的Servlet/JSP容器,并且它们是免费而且开源的。你可以访问http://tomcat.apache.org 以及http://www.eclipse.org/jetty 下载。

Servlet和JSP只是Java企业版中众多技术中的两个,其他Java EE技术还有Java消息服务,企业Java对象、JavaServer Faces以及Java持久化等,完整的Java EE技术列表可以访问如下地址:http://www.oracle.com/technetwork/java/javaee/tech/index.html

要运行Java EE应用,需要一个Java EE容器,例如GlassFish、JBoss、Oracle Weblogic或者IBM WebSphere。诚然,我们可以将一个Servlet/JSP应用部署到一个Java EE容器上,但一个Servlet/JSP容器就已经满足需要了,并且更加轻量。当然,Tomcat和Jetty不是Java EE容器,因此无法运行EJB或JMS技术。HTTP

HTTP协议使得Web服务器与浏览器之间可以通过互联网或内网进行数据交互。万维网联盟(W3C),作为一个制定标准的国际社区,负责和维护HTTP协议。HTTP第一版是0.9,之后是HTTP 1.0,当前最新版本是HTTP 1.1。HTTP 1.1版本的RFC编号是2616,下载地址为http://www.w3.org/Protocols/HTTP/1.1/rfc2616.pdf。按计划,HTTP的下一个版本是HTTP/2。

Web服务器7×24小时不间断运行,并等待HTTP客户端(通常是Web浏览器)来连接并请求资源。通常,由客户端发起一个连接,服务端不会主动连接客户端。注意:

2011年,标准化组织IETF发布了WebSocket协议,即RFC 6455规范。该协议允许一个HTTP连接升级为WebSocket连接,支持双向通信,这就使得服务端可以通过WebSocket协议主动发起同客户端的会话通信。

互联网用户需要通过点击或者输入一个URL链接或地址来访问一个资源,如下为两个示例:http://google.com/index.htmlhttp://facebook.com/index.html

URL的第一个部分是http,代表所采用的协议。除HTTP协议外,URL还可以采用其他类型的协议,如下为两个示例:mailto:joe@example.comftp://marketing@ftp.example.org

通常,HTTP的URL格式如下:protocol://[host.]domain[:port][/context][/resource][?query string]

或者protocol://IP address[:port][/context][/resource][?query string]

中括号中的内容是可选的,因此一个最简的URL是http://yahoo.ca 或者http://192.168.1.9 。

需要说明的是,除了输入http://google.com,你还可以用http://209.85.143.99来访问谷歌。可以用ping命令来获取域名所对应的IP地址:ping google.com

由于IP地址不容易记忆,实践中更倾向于使用域名。一台计算机可以托管不止一个域名,因此不同的域名可能指向同一个IP。另外,example.com或者example.org无法被注册,因为它们被保留作为各类文档手册举例使用。

URL中的Host部分用来表示在互联网或内网中一个唯一的地址,例如:http://yahoo.com(没有host)所访问的地址完全不同于http://mail.yahoo.com (有host)。多年以来,作为最受欢迎的主机名,www是默认的主机名,通常,http://www.domainName 会被映射到http://domainName 。

HTTP的默认端口是80端口。因此,对于采用80端口的Web服务器,可以无须输入端口号。但有时候,Web服务器并未运行在80端口上,此时必须输入相应的端口号。例如:Tomcat服务器的默认端口号是8080,为了能正确访问,必须提供输入端口号:http://localhost:8080

localhost作为一个保留关键字,用于指向本机。

URL中的context部分用来代表应用名称,该部分也是可选的。一台Web服务器可以运行多个上下文(应用),其中一个可以配置为默认上下文,对于访问默认上下文中的资源,可以跳过context部分。

最后,一个context可以有一个或多个默认资源(通常为index.html,index.htm或者default.htm)。一个没有带资源名称的URL通常指向默认资源。当存在多个默认资源时,其中最高优先级的资源将被返回给客户端。

在资源名之后可以有一个或多个查询语句或者路径参数。查询语句是一个Key/Value组,多个查询语句间用“&”符号分隔。路径参数类似于查询语句,但只有value部分,多个value部分用“/”符号分隔。HTTP请求

一个HTTP请求包含三部分内容:● 方法-URI-协议/版本● 请求头信息● 请求正文

如下为一个具体示例:POST /examples/default.jsp HTTP/1.1Accept: text/plain; text/htmlAccept-Language:en-gbConnection:Keep-AliveHost:localhostUser-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 ➥ (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36Content-Length:30Content-Type: application/x-www-form-urlencodedAccept-Encoding: gzip, deflate lastName=Blanks&firstName=Mike

请求的第一行即是:方法-URI-协议/版本POST /examples/default.jsp HTTP/1.1

请求方法为POST,URI为/examples/default.jsp,而协议/版本为HTTP/1.1。

HTTP 1.1规范定义了7种类型的方法,包括GET、POST、HEAD、OPTIONS、PUT、DELETE以及TRACE,其中GET和POST广泛应用于互联网应用。

URI定义了一个互联网资源,通常解析为服务器根目录的相对路径。因此,通常用/符号打头。另外URL是URI的一个具体类型。(详见http://www.ietf.org/rfc/rfc2396.txt。)

HTTP请求所包含的请求头信息包含关于客户端环境以及实体内容等非常有用的信息。例如,浏览器所设置的语言实体内容长度等。每个header用回车/换行(即CRLF)分隔。

HTTP请求头信息和请求正文用一行空行分隔,HTTP服务器据此判断请求正文的起始位置。因此在一些关于互联网的书籍中,CRLF作为HTTP请求的第四种组件。

在此前所举的例子中,请求正文如下行:lastName=Blanks&firstName=Mike

在正常的HTTP请求中,请求正文的内容不止如此。HTTP响应

同HTTP请求一样,HTTP响应包含三部分:● 协议—状态码—描述● 响应头信息● 响应正文

如下是一个HTTP响应实例:HTTP/1.1 200 OKServer: Apache-Coyote/1.1Date: Thu, 8 Jan 2015 13:13:33 GMTContent-Type: text/htmlLast-Modified: Wed, 7 Jan 2015 13:13:12 GMTContent-Length: 112 HTTP Response ExampleWelcome to Brainy Software

类似于HTTP请求报文,HTTP响应报文第一行说明了HTTP协议的版本是1.1,并且请求结果是成功的(状态代码200为响应成功)。

同HTTP请求报文头信息一样,HTTP响应报文头信息也包含了大量有用的信息。HTTP响应报文的响应正文是HTML文档。HTTP响应报文的头信息和响应正文也是用CRLF分隔的。

状态代码200表示Web服务器能正确响应所请求的资源。若一个请求的资源不能被找到或者理解,则Web服务器将返回不同的状态代码。例如:访问未授权的资源将返回401,而使用被禁用的请求方法将返回405。完整的HTTP响应状态代码列表详见如下网址:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html本书内容简介第一部分:Servlet和JSP

第1章:“Servlets”,介绍Servlet API,本章重点关注两个java包:javax.servlet 和javax.servlet.http packages。

第2章:“会话管理”,讨论了会话管理——在Web应用开发中非常重要的主题(因为HTTP是无状态的),本章比较了4种不同的状态保持技术:URL重写、隐藏域、Cookies和HTTPSession对象。

第3章:“JavaServer Pages(JSP)”,JSP是Servlet技术的补充完善,是Servlet技术的重要组成部分,本章包括了JSP语法、指令、脚本元素和动作。

第4章:“表达式语言”,本章介绍了JSP 2.0中最重要的特性“表达式语言”。该特性的目标是帮助开发人员编写无脚本的JSP页面,让JSP页面更加简洁而且有效。本章将帮助你学会通过EL来访问Java Bean和上下文对象。

第5章:“JSTL”,本章介绍了JSP技术中最重要的类库:标准标签库——一组帮助处理常见问题的标签。具体内容包括访问Map或集合对象、条件判断、XML处理,以及数据库访问和数据处理。

第6章:“自定义标签”,大多数时候,JSTL用于访问上下文对象并处理各种任务,但对于特定的任务,我们需要编写自定义标签,本章将介绍如何编写标签。

第7章:“标签文件”,本章介绍在JSP 2.0中引入的新特性——标签文件,标签文件可以简化自定义标签的编写。

第8章:“监听器”,本章介绍了Servlet中的事件驱动编程,展示了Servlet API中的事件类以及监控器接口,以及如何应用。

第9章:“Filters”,本章介绍了Filter API,包括Filter、FilterConfig和FilterChain接口,并展示了如何编写一个Filter实现。

第10章:“修饰Requests和Responses”,本章介绍如何用修饰器模式来包装Servlet请求和响应对象,并改变Servlet请求和响应的行为。

第11章:“异步处理”,本章主要讨论Servlet 3.0引入的新特性——异步处理。该特性非常适合于当Servlet应用负载较高且有一个或多个耗时操作。该特性允许由一个新线程来运行耗时操作,使得当前的Web请求处理线程可以处理新的Web请求。

第12章:“安全”,介绍了如何通过声明式以及编程式来保护Java Web应用,本章覆盖四个主题:认证、授权、加密和数据完整性。

第13章:“部署”,介绍了Servlet/JSP应用的部署流程,以及部署描述符。

第14章:“动态加载以及Servlet容器加载器”介绍了Servlet 3.0中的两个新特性,动态注册支持在无须重启Web应用的情况下注册新的Web对象,以及框架开发人员最关心的容器初始化。第二部分:Spring MVC

第15章:“Spring框架”,介绍了最流行的开源框架。

第16章:“模型2和MVC模式”,讨论了Spring MVC所实现的设计模式。

第17章:“Spring MVC介绍”,Spring MVC概述。本章编写了第一个Spring MVC应用。

第18章:“基于注解的控制器”,讨论了MVC模式中最重要的一个对象—控制器。本章,我们将学会如何编写基于注解的控制器,这是Spring MVC 2.5版本引入的方法。

第19章:“数据绑定和表单标签库”,讨论Spring MVC最强大的一个特性,并利用它来展示表单数据。

第20章:“转换器和格式化”,讨论了数据绑定的辅助对象类型。

第21章:“验证器”,本章将展示如何通过验证器来验证用户输入数据。

第22章:“国际化”,本章将展示如何用Spring MVC来构建多语言网站。

第23章:“上传文件”,介绍两种不同的方式来处理文件上传。

第24章:“下载文件”,介绍如何用编程方式向客户端传输一个资源。附录

附录A:“Tomcat”,介绍如何安装和配置Tomcat。

附录B:“Web Annotations”,列出所有可用配置Web对象,如Servlet、Listener或Filter的注解。这些来自Servlet 3.0规范的注解可以帮助减少部署描述配置。

附录C:“SSL证书”,介绍了如何用KeyTool工具生成公钥/私钥对,并生成数字证书。下载示例应用

本书所有的示例应用压缩包可以通过如下地址下载:http://books.brainysoftware.com/download第一部分Servlets和JSP第1章Servlets

Servlet API是开发Servlet的主要技术。掌握Servlet API是成为一名强大的Java web开发者的基本条件,你必须熟悉Servlet API中定义的核心接口和类。

本章介绍了Servlet API,并教你如何编写第一个Servlet。1.1 Servlet API概览

Servlet API有以下4个Java包:● javax.servlet,其中包含定义Servlet和Servlet容器之间契约的类

和接口。● javax.servlet.http,其中包含定义HTTP Servlet和Servlet容器之间

契约的类和接口。● javax.servlet.annotation,其中包含标注Servlet、Filter、Listener

的标注。它还为被标注元件定义元数据。● javax.servlet.descriptor,其中包含提供程序化登录web应用程序

的配置信息的类型。

本章主要关注javax.servlet和javax.servlet.http的成员。

图1.1中展示了javax.servlet中的主要类型。图1.1 javax.servlet中的主要类型

Servlet技术的核心是Servlet,它是所有Servlet类必须直接或间接实现的一个接口。在编写实现Servlet的Servlet类时,直接实现它。在扩展实现这个接口的类时,间接实现它。

Servlet接口定义了Servlet与Servlet容器之间的契约。这个契约归结起来就是,Servlet容器将Servlet类载入内存,并在Servlet实例上调用具体的方法。在一个应用程序中,每种Servlet类型只能有一个实例。

用户请求致使Servlet容器调用Servlet的Service方法,并传入一个ServletRequest实例和一个ServletResponse实例。ServletRequest中封装了当前的HTTP请求,因此,Servlet开发人员不必解析和操作原始的HTTP数据。ServletResponse表示当前用户的HTTP响应,使得将响应发回给用户变得十分容易。

对于每一个应用程序,Servlet容器还会创建一个ServletContext实例。这个对象中封装了上下文(应用程序)的环境详情。每个上下文只有一个ServletContext。每个Servlet实例也都有一个封装Servlet配置的ServletConfig。

下面来看Servlet接口。上面提到的其他接口,将在本章的其他小节中讲解。1.2 Servlet

Servlet接口中定义了以下5个方法:void init(ServletConfig config) throws ServletExceptionvoid service(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOExceptionvoid destroy()java.lang.String getServletInfo()ServletConfig getServletConfig()

注意,编写Java方法签名的惯例是,对于与包含该方法的类型不处于同一个包中的类型,要使用全类名。正因为如此,在Service方法javax.servlet.ServletException的签名中(与Servlet位于同一个包中)是没有包信息的,而java.io.Exception则是编写完整的名称。

init、service和destroy是生命周期方法。Servlet容器根据以下规则调用这3个方法:● init,当该Servlet第一次被请求时,Servlet容器会调用这个方

法。这个方法在后续请求中不会再被调用。我们可以利用这个方

法执行相应初始化工作。调用这个方法时,Servlet容器会传入一

个ServletConfig。一般来说,你会将ServletConfig赋给一个类级

变量,因此这个对象可以通过Servlet类的其他点来使用。● service,每当请求Servlet时,Servlet容器就会调用这个方法。编

写代码时,是假设Servlet要在这里被请求。第一次请求Servlet时,

Servlet容器调用init方法和Service方法。后续的请求将只调用

Service方法。● destroy,当要销毁Servlet时,Servlet容器就会调用这个方法。当

要卸载应用程序,或者当要关闭Servlet容器时,就会发生这种情

况。一般会在这个方法中编写清除代码。

Servlet中的另外两个方法是非生命周期方法,即getServletInfo和getServletConfig:● getServletInfo,这个方法会返回Servlet的描述。你可以返回有用

或为null的任意字符串。● getServletConfig,这个方法会返回由Servlet容器传给init方法的

ServletConfig。但是,为了让getServletConfig返回一个非null

值,必须将传给init方法的ServletConfig赋给一个类级变量。

ServletConfig将在本章的1.6节中讲解。

注意线程安全性。Servlet实例会被一个应用程序中的所有用户共享,因此不建议使用类级变量,除非它们是只读的,或者是java.util.concurrent.atomic包的成员。

1.3节将介绍如何编写Servlet实现。1.3 编写基础的Servlet应用程序

其实,编写Servlet应用程序出奇简单。只需要创建一个目录结构,并把Servlet类放在某个目录下。本节将教你如何编写一个名为app01a的Servlet应用程序。最初,它会包含一个Servlet,即MyServlet,其效果是向用户发出一条问候。

要运行Servlets,还需要一个Servlet容器。Tomcat是一个开源的Servlet容器,它是免费的,并且可以在任何能跑Java的平台上运行。如果你到现在都还没有安装Tomcat,就应该去看看附录A,并安装一个。1.3.1 编写和编译Servlet类

确定你的机器上有了Servlet容器后,下一步就要编写和编译一个Servlet类。本例中的Servlet类是MyServlet,如清单1.1所示。按照惯例,Servlet类的名称要以Servlet作为后缀。

清单1.1 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("" + "Hello from " + servletName + ""); } @Override public void destroy() { }}

看到清单1.1中的代码时,可能首先注意到的是下面这个标注:@WebServlet(name = "MyServlet", urlPatterns = { "/my" })

WebServlet标注类型用来声明一个Servlet。命名Servlet时,还可以暗示容器,是哪个URL调用这个Servlet。name属性是可选的,如有,通常用Servlet类的名称。重要的是urlPatterns属性,它也是可选的,但是一般都是有的。在MyServlet中,urlPatterns告诉容器,/my样式表示应该调用Servlet。

注意,URL样式必须用一个正斜杠开头。

Servlet的init方法只被调用一次,并将private transient变量ServletConfig设为传给该方法的ServletConfig对象:private transient ServletConfig servletConfig;@Overridepublic void init(ServletConfig servletConfig) throws ServletException { this.servletConfig = servletConfig;}

如果想通过Servlet内部使用ServletConfig,只需要将被传入的ServletConfig赋给一个类变量。

Service方法发送字符串“Hello from MyServlet”给浏览器。对于每一个针对Servlet进来的HTTP请求,都会调用Service方法。

为了编译Servlet,必须将Servlet API中的所有类型都放在你的类路径下。Tomcat中带有servlet-api.jar文件,其中包含了javax.servlet的成员,以及javax.servlet.http包。这个压缩文件放在Tomcat安装目录下的lib目录中。1.3.2 应用程序目录结构

Servlet应用程序必须在某一个目录结构下部署。图1.2展示了app01a的应用程序目录。图1.2 应用程序目录

这个目录结构最上面的 app01a 目录就是应用程序目录。在应用程序目录下,是WEB-INF目录。它有两个子目录:● classes。Servlet类及其他Java类必须放在这里面。类以下的目

录反映了类包的结构。在图1.2中,只部署了一个类:

app01a.MyServlet。● lib。Servlet应用程序所需的JAR文件要在这里部署。但Servlet

API的JAR文件不需要在这里部署,因为Servlet容器已经有它的

备份。在这个应用程序中,lib目录是空的。空的lib目录可以删除。

Servlet/JSP应用程序一般都有JSP页面、HTML文件、图片文件以及其他资料。这些应该放在应用程序目录下,并且经常放在子目录下。例如,所有的图片文件可以放在一个image目录下,所有的JSP页面可以放在jsp目录下,等等。

放在应用程序目录下的任何资源,用户只要输入资源URL,都可以直接访问到。如果想让某一个资源可以被Servlet访问,但不可以被用户访问,那么就要把它放在WEB-INF目录下。

现在,准备将应用程序部署到Tomcat。使用Tomcat时,一种部署方法是将应用程序目录复制到Tomcat安装目录下的webapps目录中。也可以通过在Tomcat的conf目录中编辑server.xml文件实现部署,或者单独部署一个XML文件,这样就不需要编辑server.xml了。其他的Servlet容器可能会有不同的部署规则。关于如何将Servlet/JSP应用程序部署到Tomcat的详细信息,请查阅附录A。

部署Servlet/JSP应用程序时,建议将它部署成一个WAR文件。WAR文件其实就是以.war作为扩展名的JAR文件。利用带有JDK或者类似WinZip工具的JAR软件,都可以创建WAR文件。然后,将WAR文件复制到Tomcat的webapps目录下。当开始启动Tomcat时,Tomcat就会自动解压这个war文件。部署成WAR文件在所有Servlet容器中都适用。我们将在第13章讨论更多关于部署的细节。1.3.3 调用Servlet

要测试这个Servlet,需要启动或者重启Tomcat,并在浏览器中打开下面的URL(假设Tomcat配置为监听端口8080,这是它的默认端口):http://localhost:8080/app01a/my

其输出结果应该类似于图1.3。图1.3 MyServlet的响应结果

恭喜,你已经成功编写了第一个Servlet应用程序!1.4 ServletRequest

对于每一个HTTP请求,Servlet容器都会创建一个ServletRequest实例,并将它传给Servlet的Service方法。ServletRequest封装了关于这个请求的信息。

ServletRequest接口中有一些方法。public int getContentLength()

返回请求主体的字节数。如果不知道字节长度,这个方法就会返回−1。public java.lang.String getContentType()

返回请求主体的MIME类型,如果不知道类型,则返回null。public java.lang.String getParameter(java.lang.String name)

返回指定请求参数的值。public java.lang.String getProtocol()

返回这个HTTP请求的协议名称和版本。

getParameter是在ServletRequest中最常用的方法。该方法通常用于返回HTML表单域的值。在本章后续的“处理表单”小节中,将会学到如何获取表单值。

getParameter也可以用于获取查询字符串的值。例如,利用下面的URI调用Servlet:http://domain/context/servletName?id=123

用下面这个语句,可以通过Servlet内部获取id值:String id = request.getParameter("id");

注意,如果该参数不存在,getParameter将返回null。

除了getParameter外,还可以使用getParameterNames、getParameterMap和getParameterValues获取表单域名、值以及查询字符串。这些方法的使用范例请参阅“Http Servlets”小节。1.5 ServletResponse

javax.servlet.ServletResponse接口表示一个Servlet响应。在调用Servlet的Service方法前,Servlet容器首先创建一个ServletResponse,并将它作为第二个参数传给Service方法。ServletResponse隐藏了向浏览器发送响应的复杂过程。

在ServletResponse中定义的方法之一是getWriter方法,它返回了一个可以向客户端发送文本的java.io.PrintWriter。默认情况下,PrintWriter对象使用ISO-8859-1编码。

在向客户端发送响应时,大多数时候是将它作为HTML发送。因此,你必须非常熟悉HTML。注意:

还有一个方法可以用来向浏览器发送输出,它就是getOutputStream。但这个方法是用于发送二进制数据的,因此,大多数情况使用的是getWriter,而不是getOutputStream。

在发送任何HTML标签前,应该先调用setContentType方法,设置响应的内容类型,并将“text/html”作为一个参数传入。这是在告诉浏览器,内容类型为HTML。在没有内容类型的情况下,大多数浏览器会默认将响应渲染成HTML。但是,如果没有设置响应内容类型,有些浏览器就会将HTML标签显示为普通文本。

在清单1.1的MyServlet中已经用过ServletResponse。在本章以及后续章节中,还会看到在其他应用程序中也使用它。1.6 ServletConfig

当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init方法传入一个ServletConfig。ServletConfig封装可以通过@WebServlet或者部署描述符传给Servlet的配置信息。这样传入的每一条信息就叫一个初始参数。一个初始参数有key和value两个元件。

为了从Servlet内部获取到初始参数的值,要在Servlet容器传给Servlet的init方法的ServletConfig中调用getInitParameter方法。getInitParameter的方法签名如下:java.lang.String getInitParameter(java.lang.String name)

此外,getInitParameterNames方法则是返回所有初始参数名称的一个Enumeration:java.util.Enumeration getInitParameterNames()

例如,为了获取contactName参数值,要使用下面的方法签名:String contactName = servletConfig.getInitParameter("contactName");

除getInitParameter和getInitParameterNames外,ServletConfig还提供了另一个很有用的方法:getServletContext。利用这个方法可以从Servlet内部获取ServletContext。关于这个对象的深入探讨,请查阅本章1.7节。

下面举一个ServletConfig的范例,在app01a中添加一个名为ServletConfigDemoServlet的Servlet。这个新的Servlet如清单1.7所示。

清单1.2 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("" + "Admin:" + admin + "
Email:" + email + ""); } @Override public String getServletInfo() { return "ServletConfig demo"; } @Override public void destroy() { }}

如清单1.2所示,在@WebServlet的initParams属性中,给Servlet传入了两个初始参数(admin和email):@WebServlet(name = "ServletConfigDemoServlet", urlPatterns = { "/servletConfigDemo" }, initParams = { @WebInitParam(name="admin", value="Harry Taciak"), @WebInitParam(name="email", value="admin@example.com") })

利用下面这个URL,可以调用ServletConfigDemoServlet:http://localhost:8080/app01a/servletConfigDemo

其结果类似于图1.4。图1.4 ServletConfigDemoServlet效果展示

另一种方法是,在部署描述符中传入初始参数。在这里使用部署描述符,比使用@WebServlet更容易,因为部署描述符是一个文本文件,不需要重新编译Servlet类,就可以对它进行编辑。

部署描述符将在1.11节以及第13章中详细讲解。1.7 ServletContext

ServletContext表示Servlet应用程序。每个Web应用程序只有一个上下文。在将一个应用程序同时部署到多个容器的分布式环境中,每台Java虚拟机上的Web应用都会有一个ServletContext对象。

通过在ServletConfig中调用getServletContext方法,可以获得ServletContext。

有了ServletContext,就可以共享从应用程序中的所有资料处访问到的信息,并且可以动态注册Web对象。前者将对象保存在ServletContext中的一个内部Map中。保存在ServletContext中的对象被称作属性。

ServletContext中的下列方法负责处理属性:java.lang.Object getAttribute(java.lang.String name)java.util.Enumeration getAttributeNames()void setAttribute(java.lang.String name, java.lang.Object object)void removeAttribute(java.lang.String name)1.8 GenericServlet

前面的例子中展示了如何通过实现Servlet接口来编写Servlet。但你注意到没有?它们必须给Servlet中的所有方法都提供实现,即便其中有一些根本就没有包含任何代码。此外,还需要将ServletConfig对象保存到类级变量中。

值得庆幸的是GenericServlet抽象类的出现。本着尽可能使代码简单的原则, GenericServlet实现了Servlet和ServletConfig接口,并完成以下任务:● 将init方法中的ServletConfig赋给一个类级变量,以便可以通过调

用getServletConfig获取。● 为Servlet接口中的所有方法提供默认的实现。● 提供方法,包围ServletConfig中的方法。

GenericServlet通过将ServletConfig赋给init方法中的类级变量servletConfig,来保存ServletConfig。下面就是GenericServlet中的init实现:public void init(ServletConfig servletConfig) throws ServletException { this.servletConfig = servletConfig; this.init();}

但是,如果在类中覆盖了这个方法,就会调用Servlet中的init方法,并且还必须调用super.init(servletConfig)来保存ServletConfig。为了避免上述麻烦,GenericServlet提供了第二个init方法,它不带参数。这个方法是在ServletConfig被赋给servletConfig后,由第一个init方法调用:public void init throws ServletException { this.servletConfig = servletConfig; this.init();}

这意味着,可以通过覆盖没有参数的init方法来编写初始化代码,ServletConfig则仍然由GenericServlet实例保存。

清单1.3中的GenericServletDemoServlet类是对清单1.2中ServletConfigDemoServlet类的改写。注意,这个新的Servlet扩展了GenericServlet,而不是实现Servlet。

清单1.3 GenericServletDemoServlet类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("" + "Admin:" + admin + "
Email:" + email + ""); }}

可见,通过扩展GenericServlet,就不需要覆盖没有计划改变的方法。因此,代码变得更加整洁。在清单 1.3 中,唯一被覆盖的方法是 Service 方法。而且,不必亲自保存ServletConfig。

利用下面这个URL调用Servlet,其结果应该与ServletConfigDemoServlet相似:http://localhost:8080/app01a/generic

即使GenericServlet是对Servlet一个很好的加强,但它也不常用,因为它毕竟不像HttpServlet那么高级。HttpServlet才是主角,在

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载