第 7 章 Servlet 技术

102
第 7 第 Servlet 第第 7.1Servlet 第第 7.2Servlet 第第第第第第第 7.3 第第 HttpServlet 第第第第第第第 7.4 第第 Servlet 第第第第第 7.5Servlet 第第第 7.6 第 Servlet 第第第第第第

description

第 7 章 Servlet 技术. 7.1Servlet 介绍 7.2Servlet 常用接口的使用 7.3 使用 HttpServlet 处理客户端请求 7.4 获得 Servlet 初始化参数 7.5Servlet 的配置 7.6 用 Servlet 生成动态图片. 7.1servlet 介绍. Servlet 已经出现了很长一段时间,它先于 J2EE 平台出现。在过去的一段时间内, Servlet 曾经得到广泛的应用,如今它在 J2EE 项目开发中仍然广泛使用。 JSP 基于 Servlet 技术构架,可见 Servlet 功能的强大。. - PowerPoint PPT Presentation

Transcript of 第 7 章 Servlet 技术

Page 1: 第 7 章  Servlet 技术

第 7 章 Servlet 技术

7.1Servlet 介绍7.2Servlet 常用接口的使用7.3 使用 HttpServlet 处理客户端请求 7.4 获得 Servlet 初始化参数 7.5Servlet 的配置7.6 用 Servlet 生成动态图片

Page 2: 第 7 章  Servlet 技术

7.1servlet 介绍

   Servlet 已经出现了很长一段时间,它先于 J2EE 平台出现。在过去的一段时间内, Servlet 曾经得到广泛的应用,如今它在 J2EE 项目开发中仍然广泛使用。 JSP 基于 Servlet 技术构架,可见 Servlet 功能的强大。

Page 3: 第 7 章  Servlet 技术

7.1.1 什么是 Servlet

   Servlet(Java 服务器小程序 ) 是用 Java 编写的服务器程序,是由服务器调用和执行的,按照 Servlet自身规范编写的 Java 类。

Servlet 是使用 Java Servlet 应用程序设计接口 (API) 及相关类和方法的 Java 程序。除了 Java Servlet API,Servlet 还可以使用用于扩展和添加到 API 的 Java 类软件包。

  Servlet 本身就是 Java 语言的一个应用,具有 Java 语言的所有优势,能完成普通 Java 程序所能完成的所有功能。

Page 4: 第 7 章  Servlet 技术

Servlet 概念

•Servlet 是一个标准的 Java 类,它符合 Java 类的一般规则。和一般Java 类不同之处就在于 Servlet 可以处理 HTTP 请求。在 Servlet API中提供了大量的方法,可以在 Servlet 中调用。它是用 Java 语言的 ServletAPI 来编写的特殊的 Java 类。•当把这些 Java 类的的字节码文件(也称为二进制文件 ,.class 文件)放到 Servlet 容器(比如: tomcat )的相应目录中时,它们就可以接受客户端响应了。 Servlet 的优点很多,它是一种流行的 BS 结构编程技术,是 JSP 编程技术的核心。•JSP 是以另外一种方式实现的 Servlet , Servlet 是 JSP 的早期版本,在 JSP 中,更加注重页面的表现,而在 Servlet 中则更注重业务逻辑的实现。因此,当编写的页面显示效果比较复杂时,首选是 JSP 。或者在开发过程中, HTML 代码经常发生变化,而 Java 代码则相对比较固定时,可以选择 JSP 。而我们在处理业务逻辑时,首选则是 Servlet 。同时, JSP 只能处理浏览器的请求,而 Servlet 则可以处理一个客户端的应用程序请求。因此, Servlet 加强了 Web 服务器的功能。

Page 5: 第 7 章  Servlet 技术

7.1.2.Servlet 技术的特点

   Servlet 带给开发人员最大的好处是它可以处理客户端传来的 HTTP 请求,并返回一个响应。 Servlet 是一个 Java 的类, Java 语言能够实现的功能, Servlet 基本上都能实现(除了图形界面外)。   Servlet 是服务器端的 Java 小程序。用于响应客户机的请求。在默认情况下, Servlet 采用一种无状态的请求 - 响应处理方式。Servlet 代码的主要作用是为了增强 Java 服务器端功能。

Page 6: 第 7 章  Servlet 技术

 Servlet 的特点

   Servlet 是一个供其他 Java程序( Servlet引擎)调用的 Java类,它不能独立运行,它的运行完全由 Servlet引擎来控制和调度。

   Servlet引擎是一种容器程序,它负责管理和维护所有Servlet 对象的生命周期。 Servlet 的加载、执行流程、以及如何接收客户端发送的数据和如何将数据传输到客户端等具体的底层事务,都是由 Servlet引擎来实现的。 Servlet引擎负责将客户端的请求信息转交给 Servlet 和将 Servlet 生成的响应信息返回给客户端。

   Servlet属于一种插件,它是一个提供了一些约定方法供容器去调用的类,它只负责在自身的方法中接受并处理容器传递进来的数据,以及生成并返回给容器去使用的数据和状态信息。

Page 7: 第 7 章  Servlet 技术

Servlet 的最常见应用在于:

读取WEB浏览器传递给WEB服务器的参数;生成WEB服务器返回给WEB浏览器的动态网页文档内容;Serlvet 也能获取WEB浏览器发送的 HTTP请求消息中的各个请求头和请求行信息;

以及生成用于WEB服务器发送的 HTTP响应消息中的状态行和响应头信息;

Serlvet 还能获取WEB服务器和 Servlet引擎自身的一些环境和状态信息。

Page 8: 第 7 章  Servlet 技术

  Servlet 程序的运行过程就是它与 Servlet引擎的交互过程, Servlet 程序只与 Servlet引擎打交道,它并不与Web服务器和客户端进行任何直接的交互。

 Web服务器上可以布置多个功能各不相同的 Servlet ,每个 Servlet 都应宣称它可以处理何种样式的 URL,当符合样式的 URL请求到达时, Servlet引擎调用相应的 Servlet进行处理。

Page 9: 第 7 章  Servlet 技术

Servlet 的优势

a. 可移植 因为 Servlet 由 Java 开发并符合规范定义和广泛接收的 API ,它可以再不同的操作系统平台和不同的应用服务器平台下移植。b. 功能强大 Servlet 可以使用 Java API 核心的所有功能,这些功能包括Web 和 URL访问、图像处理、数据压缩、多线程、 JDBC、 RMI 和序列化对象等。c. 安全 有几个不同层次为 Servlet 的安全提供了保障。 首先,它是 Java 编写的,所以它可以使用 Java 的安全框架; 其次, ServletAPI被实现为类型安全的; 另外容器也会对 Servlet 的安全进行管理。 在 Servlet安全策略中,可以使用编程的安全也可以使用声明性的安全,声明性的安全由容器进行统一管理

Page 10: 第 7 章  Servlet 技术

d. 简洁 Servlet 代码面向对象,在封装方面具有先天的优势。e. 集成 Servlet 和服务器紧密集成,它们可以密切合作完成特定的任务。f. 模块化 每一个 Servlet 可以执行一个特定任务,并且可以将他们并在一起工作。 Servlet之间是可以相互交流的g. 扩展性和灵活性 Servlet 本身的接口设计得非常精简,使得它有很强的扩展性。需要指出的是, Servlet不等于 HttpServlet ,后者是前者的一个常见扩展。 h. 高效耐久 Servlet 一旦载入,它就驻留在内存中,这样加快了响应的速度。在服务器上仅有一个 Java虚拟机在运行,它的优势在于,当 Servlet被客户端发送的第一个请示激活,以后它将继续运行于后台,等待以后的请求。每个请求将生成一个线程而不是进程。

Page 11: 第 7 章  Servlet 技术

7.1.3Servlet 的生命周期Servlet部署在容器里,它的生命周期由容器管理。 Servlet 的生命周期概括为以下几个阶段: 1. 装载 Servlet 这项操作一般是动态执行的。有些服务提供了相应的管理功能,可以再启动的时候就装载 Servlet ,并能够初始化特定的 Servlet 。 2. 创建一个 Servlet 实例 3. 调用 Servlet 的 init() 方法 4. 服务 如果容器接收到对此 Servlet 的请求,那么它调用 Servlet 的 service() 方法 5. 销毁 实例被销毁,通过调用 Servlet 的 destory() 方法销毁 Servlet 。 在这几个阶段中,对外提供服务是最要的阶段, service() 方法是最关心的方法,因为它才是真正处理业务的方法。

Page 12: 第 7 章  Servlet 技术
Page 13: 第 7 章  Servlet 技术

服务器加载Servlet

服务器创建Servlet类

调用Servlet实例

收到请求

调用service方法

Servlet在服务器调用destroy()方法后被卸载

Service方法处理请求并将结果返回到客户端

Servlet等待下一个请求或者由服务器卸载

Page 14: 第 7 章  Servlet 技术

Java Servlet 的实现方法步骤:

1 ,编写 Servlet 文件 :创建一个继承自 javax.servlet.http.HttpServlet 的 Java 类 ;2 ,部署 Servlet 文件 : 在 web.xml里定义;3 ,编译 Servlet 文件;4 ,访问 Servlet 文件 :启动 WEB 服务器。通过浏览器访问。

Page 15: 第 7 章  Servlet 技术

7.1.4 开发、部署一个简单的 Servlet 例程 7-1 入门的 ServletPackage com.jspdev.ch7 Import java.io.*;Import javax.servlet.*;Import javax.servlet.http.*;Public class HelloWorldServlet extends HttpServlet{Public void doGet(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{response.setContentType("text/html;charset=gb2312");PrintWriter out=response.getWriter();

包 javax.servlet 和 javax.servlet.http 提供了 servlet 接口和类。所有的servlet 都必须实现 servlet 接口,它定义了生命周期方法。

Page 16: 第 7 章  Servlet 技术

out.println("<html>"); out.println("<head>");out.println("<title>HelloWorld</title>");out.println("</head>");out.println("<body bgcolor=\"white\">");out.println("<hr>");out.println("Hello World!");out.println("</body></html>");}Public void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException,ServletException{doGet(request,response); } }

Page 17: 第 7 章  Servlet 技术

  这个 Servlet直接继承 HttpServlet , HttpServlet封装了编写基于 HTTP协议的 Servlet 的大部分功能。 HelloWorldServlet 中有两个方法:一个是 doGet ,它处理 HTTP GET 请求;另一个是 doPost ,它处理 HTTP POST 请求。在这里 doGet和 doPost 基本上一样的处理。不同之处在于 doGet会把用户的输入显示在 URL 中, doPost 比 doGet 的安全性强一点。首先对于客户端它是不可见的,另外服务器日志上会记录所有经过 URL 而 Post 出去的资料的内容。  在 doGet 方法中,首先设置响应的 MIME 类型和编码方式,然后获得输出流对象。这个输出流对象用 out 表示,这个 out对象和 JSP 中内建对象 out 是一样的,通过它可以把输出发送到客户端。

Page 18: 第 7 章  Servlet 技术

接下来就看看怎么部署。找到 WEB-INF\web.xml 。添加如下内容 例程 7-2 添加的内容<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"><display-name>Welcome to Tomcat</display-name> 对站台做出描述 .<description>ServletHelloWorld 实例 </description> 定义站台的名称 .<Servlet> <servlet-name>HelloWorldServlet</servlet-name> <servlet-class>com.jspdev.ch7.HelloWorldServlet </servlet-class> </Servlet> <servlet-mapping> <servlet-name>HelloWorldServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>

在上述内容中,首先声明 Servlet ,指定这个 Servlet 的名字和类,然后在后面为这个 Servlet做 URI映射。

Page 19: 第 7 章  Servlet 技术

Servlet 的注册与运行1.Servlet 程序必须通过 Servlet引擎来启动运行,并且储存目录有特殊要求,通常需要存储在 <WEB 应用程序目录 >\WEB-INF\classes\ 目录中。如果这个 Servlet 程序有包名,那么在这个目录下面还要有包名对应的目录结构。

2.Servlet 程序必须在 WEB 应用程序的 web.xml 文件中进行注册和映射其访问路径,才可以被 Servlet引擎加载和被外界访问。

3. 一个 <servlet>元素用于注册一个 Servlet ,它包含有两个主要的子元素: <servlet-name> 和 <servlet-class> ,分别用于设置 Servlet 的注册名称和 Servlet 的完整类名(包括包名)。

4. 一个 <servlet-mapping>元素用于映射一个已注册的Servlet 的一个对外访问路径,它包含有两个子元素: <servlet-name> 和 <url-pattern> ,分别用于指定 Servlet 的注册名称和 Servlet 的对外访问路径。

Page 20: 第 7 章  Servlet 技术

<web-app> ...... <servlet> <servlet-name>AnyName</servlet-name> <servlet-class>HelloServlet</servlet-class> </servlet> ...... <servlet-mapping> <servlet-name>AnyName</servlet-name>    第一个“ /”表示 <WEB应用程序目录 > <url-pattern>/demo/hello.html</url-pattern> </servlet-mapping> ......</web-app>这个 <servlet>和 <servlet-mapping>中的两个是对应的。两个

<servlet-name> 必须相同。当用户访问 /demo/hello.html 的时候,就会去调用 HelloServlet 这个 Servlet 程序, 同一个 Servlet 可以被映射到多个 URL上,即多个 <servlet-mapping> 元素的 <servlet-name> 子元素的设置值可以是同一个 Servlet 的注册名。

Page 21: 第 7 章  Servlet 技术

<servlet-name>

指定 Servlet 的名字,这个名字在同一个Web应用程序中必须是唯一的。

<servlet-class>

指定 Servlet 类的完整限定名。

Page 22: 第 7 章  Servlet 技术

7.2Servlet 常用接口的使用Servlet 的类接口可以从以下几个方面进行分类 1. Servlet 实现相关 定义了用于实现 Servlet 相关的类和方法 2. Servlet 配置相关 主要包括 ServletConfig 接口 3. Servlet异常相关 Servlet API 定义了两个异常,它们是 ServletException 和 UnavailableException 4. 请求和响应相关 用于接收客户端的请求,并且做出对应的响应。 5. 会话跟踪 用于跟踪和客户端的会话 6. Servlet 上下文 通过这个接口,可以再多个 Web 应用程序中共享数据 7. Servlet协作 主要是 RequestDispatcher 接口,用于进行视图派发 ,即把一个请求转发到另一个 Servlet 。 8. 过滤 定义了请求响应过滤的相关 API 和接口 9. 其他类 Cookie 和 HttpUtils 类

Page 23: 第 7 章  Servlet 技术

7.2.1Servlet 实现相关 1.Servlet 声明: public interface Servlet 这个接口是所有 Servlet必须直接或者间接实现的接口。它定义了以下的方法 a. init(ServletConfig config) 用于初始化 Servlet b. destory() 销毁 Servlet c. getServletInfo() 获得 Servlet 的信息 d. getServletConfig() 获得 Servlet 配置相关信息 e. service(ServletRequest request,ServeltResponse response) 运行应用程序逻辑的入口点。它接收两个参数, ServletRequest 表示客户端请求的信息, ServletResponse 表示对客户端的响应。

Page 24: 第 7 章  Servlet 技术

2. GenericServlet 声明: public abstract class GenericServlet implements Servlet,ServletConfig,java.io.Serializable

GenericServlet 提供了对 Servlet 接口的基本实现。它是一个抽象类,它的 service() 方法是一个抽象方法, GenericServlet 的派生类必须直接或者间接实现这个方法。

Page 25: 第 7 章  Servlet 技术

3. HttpServlet 声明: public abstract class HttpServlet extends GenericServlet implements java.io.Serializable

HttpServlet 类是针对使用 HTTP协议的 Web 服务器的 Servlet 类。 HttpServlet 类通过执行 Servlet 接口,能够提供 HTTP协议的功能。

Page 26: 第 7 章  Servlet 技术

HttpServlet 的子类必须实现以下方法中的一个 * doGet 如果 Servlet支持 HTTP GET 请求,用于 HTTP GET请求 * doPost 如果 Servlet支持 HTTP GET 请求,用于 HTTP POST 请求 * doPut 如果 Servlet支持 HTTP GET 请求,用于 HTTP PUT请求 * doDelete 如果 Servlet支持 HTTP GET 请求,用于 HTTP DELETE 请求 * init 和 destroy 管理 Servlet占用的资源。如果需要管理 Servlet生命周期内所持有资源可以重载这两个方法 * getServletInfo 获得 Servlet 自身的信息

Page 27: 第 7 章  Servlet 技术

7.2.2Servlet 配置相关   javax.servlet.ServletConfig 接口代表了 Servlet 的配

置, Servlet 配置包括 Servlet 的名字、 Servlet 的初始化参数和 Servlet 上下文。 例程 7-3 Servlet 的配置 <servlet>

<servlet-name>HelloWorldServlet</servlet-name> <servlet-class>HelloWorldExample<servlet-class> <init-param> <param-name>encoding</param-name> <param-value>gb2312</param-value> </init-param> </servlet>

Page 28: 第 7 章  Servlet 技术

<init-param>

定义 Servlet 的初始化参数。如果使用了 <init-param>元素,则必须包含 <param-name> 和 <param-value>元素,可以包含零个或多个 <description>元素。<description>

为初始化参数提供一个文本描述。 <param-name> 定义初始化参数的名字。

<param-value> 定义初始化参数的值。

Page 29: 第 7 章  Servlet 技术

ServletConfig 声明: public interface ServletConfig 这个接口的主要方法有以下几个 * getInitParameter(String name) 返回特定名字的初始化参数。 例如: HelloWorldExample 中如果有 getInitParameter("encoding") ,那么将返回 "gb2312" 字符串 * getInitParameterNames() 返回所有的初始化参数的名字 * getServletContext() 返回 Servlet 的上下文对象的引用

Page 30: 第 7 章  Servlet 技术

7.2.3Servlet异常相关1、 ServletException 声明: public class ServletException extends Exception 它包含几个构造方法和一个获得异常原因的方法,这个方法如下。 * getRootCause() 返回造成这个 ServletException 的原因 2、 UnavailableException 声明: public class UnavailableException extends ServletException 当 Servlet 或者 Filter暂时或者永久不能使用时,就会抛出这个异常。

Page 31: 第 7 章  Servlet 技术

7.2.4 Servlet 请求和响应 和请求响应相关的类和接口非常多,主要有: 1. ServletRequest 代表了 Servlet 的请求。它是一个高层的接口, HttpServletRequest 是它的子接口。 2. ServletResponse 代表了 Servlet 的响应。它是一个高层的接口, HttpServletResponse 是它的子接口 3. ServletInputStream Servlet 的输入流 4. ServletOutputStream Servlet 的输出流 5. ServletRequestWrapper 它是 ServletResquest 的实现 6. ServletResponseWrapper 它是 ServletResponse 的实现 7. HttpServletRequest 代表了 HTTP 的请求,继承了 ServletRequest 接口 8. HttpServletResponse 代表了 HTTP 的响应,继承了 ServletResponse 接口 9. HttpServletRequestWrapper HttpServletRequest 的实现 10.HttpServletResponseWrapper HttpServletResponse 的实现

Page 32: 第 7 章  Servlet 技术

下面主要看看 HttpServletRequest 和 HttpServletResponse这两个接口 :1. HttpServletRequest 声明: public interface HttpServletRequest extends ServletRequest   这个接口中最常用的方法就是获得请求中的参数,这个请求中的参数是客户端表单中的数据。 HttpServletRequest接口可以获取由客户端传送的阐述名称,也可以获取客户端正在使用的通信协议,可以获取产生请求并且接收请求的服务器远端主机和其 IP地址等一些信息 。   HttpServletRequest 接口提供获取数据流的 Servlet、 ServletInputStream 方法,这些数据是客户端引用 HTTP Post和 Put 方法递交的。一个 ServletRequest 的子类可以让 Servlet 获得更多的协议特性数据。例如: HttpServletRequest 包含获取头部信息的方法有 request.getMethod()、 request.getProtocol()、 request.getPathInfo()等

Page 33: 第 7 章  Servlet 技术

JSP 中的内建对象 request 是一个 HttpServletRequest 实例,如下一些重要方法 :1.getCookies() 获的客户端发送的 Cookie 。返回一个数组,该数组包含这个请求中当前所有 Cookie 。如果这个请求中没有 Cookie ,返回一个空数组 2.getSession() 返回和客户端关联的 Session 。如果没有给客户端分配 Session ,返回 null 3.getSession(boolean create) 和上一个方法类似,不同的是,如果没有给客户端分配 Session ,则创建一个新的 Session 并返回。 4. getParameter(java.lang.String name) 返回请求中名为 name的参数值。这个值往往是 checkbox 或者 select控件提交的,获得的值是一个 String 数组。

Page 34: 第 7 章  Servlet 技术

2.HttpServletResponse 声明: public interface HttpServletResponse extends ServletResponse   它代表了对客户端的 HTTP 响应。 HttpServletResponse 接口给出相应的客户端的 Servlet 方法。它允许 Servlet 设置内容长度和回应 MIME 类型,并且提供输出流 ServletOutputStream 。常用的方法有 : 1. addCookie(Cookie cookie) 在响应中增加一个 Cookie 2. encodeURL(java.lang.String.url) 使用 URL 和 SessionId 重写这个 URL 3. sendRedirect(java.lang.String location) 把响应发送到另一个页面或者 Servlet 进行处理 4. setContentType(java.lang.String.type) 设置响应的 MIME 类型

5. setCharacterEncoding(java.lang.String charset) 设置响应的字符编码类型 。

Page 35: 第 7 章  Servlet 技术

7.2.5Servlet会话跟踪

和会话跟踪相关的类和接口有: HttpSession HttpSession 声明: public interface HttpSession   这个接口被 Servlet引擎用来实现 HTTP 客户端和 HTTP会话两者之间的关联。这种关联可能在多处连接和请求中持续一段给定的时间。 Session 用来在无状态的 HTTP协议下越过多个请求页面来维持状态和识别用户。   一个 Session 可以通过 Cookie 或重写 URL 来维持。

Page 36: 第 7 章  Servlet 技术

它的常用方法有以下几种。 1. getCreateTimes() 返回创建 Session 的时间 2. getId() 返回分配给这个 Session 的标识符。一个 HTTP Session 的标志符是一个由服务器来建立和维护的唯一的字符串 3. getLastAccessedTime() 返回客户端最后一次发出与这个 Session 有关的请求的时间,如果这个 Session 是新建立的返回 -1

4. getMaxInactiveInterval() 返回一个秒数,这个秒数表示客户端在不发出请求时, Session被 Servlet引擎维持的最长时间。在这个时间之后, Session 可能被 Servlet引擎终止。如果这个Session不会被终止,这个方法返回 -1.

Page 37: 第 7 章  Servlet 技术

5. getValue(String name) 返回一个以给定的名字绑定在 Session 上的对象。如果不存在这样的绑定,返回空值 6. getValueNames() 以一个数组返回绑定到 Session 上的所有数据的名称。7. invalidate();public void invalidate() 这个方法终止这个 Session ,所有绑定在这个 Session 上的数据都会被清除。 8. isNew() 返回一个布尔值以判断这个 Session 是不是新的。如果一个 Session 已经被服务器建立但是还没有收到相应的客户端的请求,这个 Session将被认为是新的。这意味着,这个客户端还没有加入会话或没有被会话公认。在它发出下一个请求时还不能返回适当的 Session 认证信息。当 Session 无效后,再调用这个方法会抛出一个 IllegalStateException 。

Page 38: 第 7 章  Servlet 技术

9. putValue(String name ,Object value) 以给定的名字绑定给定的对象到 Session 中。已存在的同名的绑定会被重置,这时会调用 HttpSessionBindingListener 接口的 valueBound 方法 10. removeValue(String name) 取消给定名字的对象在 Session 上的绑定。如果未找到给定名字绑定的对象,这个方法什么也不做。这时则会调用 HttpSessionBindingListener 接口的 valueUnbound 方法 11. setMaxInactiveInterval(Int interval) 设置一个秒数,这个秒数表示客户端在不发出请求时, Session被 Servlet引擎维持的最长时间。

Page 39: 第 7 章  Servlet 技术

7.2.6   Servlet 上下文  和 Servlet 上下位相关的接口有 ServletContext ServletContext 声明: public interface ServletContext

  在服务器上使用 Session 对象维持与单个客户相关的状态,而当为多个用户 Web 应用维持一个状态时,则应使用 Servlet环境 (Context) 。   ServletContext 对象表示一组 Servlet共享的资源。在 Servlet API 的 1.0 和 2.0 的版本中 ServletContext 对象仅仅提供了访问有关 Servlet环境信息的方法。 例如:提供了访问服务器名称 MIME 类型映射等方法和可以将信息写入服务器日志文件的 log() 方法,大部分实现程序都会为一台主机中的所有 Servlet 或每一个虚拟机主机提供一个 Servlet环境。

Page 40: 第 7 章  Servlet 技术

它常用的方法有: 1.getAttribute(String name) 获得 ServletContext 中名称为 name 的属性 2.getContext(String uripath) 返回给定的 uripath 的应用的 Servlet 上下文,如 ServletContext test=getContext("/test"); 3. removeAttribute(String name) 删除名称为 name属性 4. setAttribute(String name , Object object) 在 ServletContext 中设置一个属性,这个属性的名字为 name ,值为 object对象。

Page 41: 第 7 章  Servlet 技术

7.2.7 Servlet协作

   Servlet协作主要是 RequestDispatcher 接口, RequestDispatcher 是一个 Web资源的包装器,它可以把一个请求转发到另一个 Servlet 。可以用来把当前 request 传递到该资源,或者把新的资源包括到当前响应中。 RequestDispathcer 声明: public interface RequestDispatcher

Page 42: 第 7 章  Servlet 技术

使用:   getRequestDispatcher(path)

String path="/index.jsp";// 这是当前应用中一个绝对路径的 url   

servlet: RequestDispatcher dispatcher=getServletContext().getRequestDispatcher(path);   jsp: RequestDispatcher dispatcher=application.getRequestDispatcher(path);

Page 43: 第 7 章  Servlet 技术

它包含两个方法: 1. forword(ServletRequest request,ServletResponse response)把请求转发到服务器上的另一个资源 (Servlet,JSP,HTML) 2. include(ServletRequest request,ServletResponse response)把服务器上的另一个资源 (Servlet、 JSP、 HTML) 包含到响应中。

dispatcher.forward();//转到 path 这个页面(不可以在这之前或之后有其它输出) dispatcher.include();//向浏览器输出 path 这个页面的执行结果(可以在这之前或之后有其它输出)

Page 44: 第 7 章  Servlet 技术

1、 ServletRequest.getRequestDispatcher(String path) path 可是绝对路径也可以是相对路径

2、 ServletContext.getRequestDispatcher(String path)

path必须以“ /” 开头,代表 context root

3、另一个方法 ServletContext.getNameDispatcher(String name) 参数并不是路径,而是其名称,如果有多个 Servlet名称一样的,在 web.xml 进行配置区别 。

以上方法回传一个 RequestDispatcher 对象,接着 forward() 或 include()

Page 45: 第 7 章  Servlet 技术

forward() 和 include()区别:

   include() 方法将 HTTP 请求转送给其他 Servlet 或 jsp后,这个 Servlet 或 jsp虽然可以处理请求,但是主导权还是原来的 Servlet 或 jsp ,就是被调用的 Servlet 或 jsp 如果产生任何 HTTP 回应,将会并入原来的 HttpResponse 对象

Page 46: 第 7 章  Servlet 技术

7.2.8 过滤   在 web 应用中实施过滤是我们常使用的技术。通过过滤,可以对请求进行统一编码、对请求进行认证等。每个Filter 可能只担任很少的任务,多个 Filter 可以互相协作,通过这种协作,可以完成一个复杂的功能。

1. Filter 声明: public interface Filter 它是 Filter必须实现的接口,包括:•init(FilterConfig filterConfig) 这个方法初始化 Filter•doFilter(ServletRequest request , ServletResponse response , FilterChain chain)Filter 的业务方法就是这里实现。•destroy() 释放 Filter占用的资源

Page 47: 第 7 章  Servlet 技术

2.FilterChain 声明: public interface FilterChain 它是代码的过滤链,通过这个接口把过滤的任务在不同的 Filter之间转换。 它包含了一个方法: doFilter(ServletRequest request、 ServletResponse response) 通过这个方法来调用下一个 Filter 。如果没有下一个 Filter ,那么将调用目标的资源 。

Page 48: 第 7 章  Servlet 技术

3.FilterConfig 声明: public interface FilterConfig 它代表了 Filter 的配置。和 Servlet 一样, Filter 也有一些配置信息,比如 Filter 的名字和初始化参数等 。它包含了以下方法 :1. getFilterName() 返回 Filter 的名字 2. getInitPatameter(String name) 获得名称为 name 的初始参数 3.getServletContext() 返回这个 Filter 所在的 Servlet 上下文对象 4. getInitParameterNames() 获得 Filter 配置中的所有初始化参数的名字。

Page 49: 第 7 章  Servlet 技术

访问方式 :

在 JSP 程序中, Servlet作为一个 Java 类可以有多种方式访问。直接在地址栏中通过 URL访问; HelloWorldServlet.java web.xml 通过 JSP 程序提交表单访问; LoginServlet.java Login.jsp web.xml 通过超级链接访问 。 DoRequest.java xian.jsp web.xml

Page 50: 第 7 章  Servlet 技术

通过 JSP 程序提交表单访问 LoginServlet.java

package test;import java.io.*;import javax.servlet.*;import javax.servlet.http.*;public class LoginServlet extends HttpServlet{ public void init(ServletConfig config) throws ServletException { super.init(config); }public void destroy(){}

Page 51: 第 7 章  Servlet 技术

public void service(HttpServletRequest request,HttpServletResponse response) throws IOException { // 获得一个向客户发送数据的输出流: response.setContentType(“text/html;charset=GB2312”); PrintWriter out=response.getWriter(); String name=request.getParameter("name1"); String pwd=request.getParameter("name2"); if(name.trim().equals("admin") && pwd.equals("admin")){ out.println("<HTML> <BODY>"); out.println(" 用户成功登录 "); out.println("</body> </html>"); } else{ out.println("<HTML> <BODY>"); out.println(" 用户登录失败 "); out.println("</body> </html>"); } } }

Page 52: 第 7 章  Servlet 技术

Login.jsp

<%@ page language="java" pageEncoding="gb2312"%><html><body bgcolor=#e3e4e8><center><h3>登录页面 </h3><form method="post" name="form1" action="LoginServlet" ><P> 用户昵称: <INPUT type="text" name="name1"></P><P> 用户密码: <INPUT type="password" name="name2"></P><P><INPUT type="submit" value=" 提交 ">

<INPUT type="reset" value=" 重置 " ></form></html>

Page 53: 第 7 章  Servlet 技术

通过超级链接访问DoRequest.javapackage test;import javax.servlet.*;import javax.servlet.http.*;import java.io.*;import java.util.*;public class DoRequest extends HttpServlet { public void init() throws ServletException {} public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {…… } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }public void destroy() {} //清除资源 }

Page 54: 第 7 章  Servlet 技术

xian.jsp

<%@ page contentType="text/html;charset=GB2312" %><MHML><BODY><center><a href="Req">访问 Servlet 并显示服务器信息 </a></center></BODY></HTML>

Page 55: 第 7 章  Servlet 技术

7.3 使用 HttpServlet 处理客户端请求

   Servlet被设计成请求驱动的。 Servlet 的请求可能包含多个数据项。当 Web 容器接收到某个对 Servlet 的请求时,它把它封装成一个 HttpServletRequest 对象,然后把此对象传给 Servlet 的对应的服务方法。服务方法通常是 doGet() 和 doPost() 方法。另外 HttpServlet 也提供了一些高级的处理方法,它们有 doPut、 doTrace 和 doDelete 。   在 HttpServlet抽象类中的 service() 方法一般不需要被重写,它会自动调用和用户请求对应的 doGet() 和 doPost()方法。

Page 56: 第 7 章  Servlet 技术

1.doGet    Get 调用用于获取服务器信息,并将其作为响应返回给客户端。当经由 Web 浏览器,或者通过 HTML、 JSP直接访问Servlet 的 URL 时,一般使用 Get 调用。 Get 调用在 URL里显示正传送给 Servlet 的数据,这在系统的安全方面可能带来一些问题。比如说用户登录时,表单里的用户名和密码需要发送到服务器端,如果使用 Get 调用,就会在浏览器的 URL里显示用户名和密码。   下面给出一个例子。使用 doGet 调用,那么在客户端的 Form 中必须指定调用的类型为 get 。如:<form action="/test/doget_servlet" method="get"> ........ <input type="type" name="name"> .......... </form>

Page 57: 第 7 章  Servlet 技术

那么 Servlet 代码如下 例程 7-4 测试 doGet 方法 (ch7\WEB-INF\classes\DoGetTestServlet.java)

public class DoGetTestServlet extends HttpServlet { public void doGet(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{ request.setCharacterEncoding("gb2312"); response.setContentType("text/html;charset=gb2312"); PrintWtriter out=response.getWriter(); out.println(" 获得了以下的参数值: name=<br>"+request.getParameter("name")); out.flush(); } }

Page 58: 第 7 章  Servlet 技术

  在 doGetTestServlet 中,通过 request.getParameter()方法获得请求中的参数。部署时,在 web.xml 中正确描述这个 Servlet ,并且指定 URI映射为 /doget_servlet, 即: <servlet> <servlet-name>DoGetTestServlet</servlet-name> <servlet-class>com.jspdev.ch7.DoGetTestServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DoGetTestServlet</servlet-name> <url-pattern>/doget_servlet.html<url-pattern> </servlet-mapping>   在浏览器中输入: http://127.0.0.1:8080/ch7/doget_servlet.html,填写信息后提交,测试结果见图 7-3 。

Page 59: 第 7 章  Servlet 技术

2.doPost    doPost 用于客户端把数据传送到服务器端,它会有副作用。但是使用它的好处是可以隐藏发送给服务器端的任何数据。 Post适合于发送大量的数据。

例如: <form action="/test/dopost_servlet" method="post"> ...... <textarea name="des" cols="50" rows="10"></textarea> .... </form>

  上例使用了 textarea控件,客户端可以发送大量的数据。下面看看 Servlet 代码。

Page 60: 第 7 章  Servlet 技术

例程 7-5 测试 doPost 方法 (ch7\WEB-INF\classes\DoPostTestServlet.java)

public class DoPostTestServlet extends HttpServlet{ public void doPost(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{ request.setCharacterEncoding("gb2312"); response.setContentType("text/html;chatset=gb2312"); PrintWiter out=response.getWriter(); out.println(" 获得以下的参数值: des=<br>"+request.getParameter("des")); out.flush(); } }   在处理 Post 请求的 Servlet 服务器时,它需要覆盖 HttpServlet 的 doPost 方法, doPost 方法中的代码几乎和 DoGetTestServlet 中的 doGet 代码一样。

Page 61: 第 7 章  Servlet 技术

3.doPut Put 的调用和 Post 相似,它允许客户端把真正的文件存放在服务器上,而不仅仅是传送数据。

4.doDelete 它与 Put 调用相似,它允许客户端删除服务器端的文件或者 Web 页面。它的使用也非常少。

5.doTrace 由容器调用以使此 Servlet 能够处理 Trace 请求。这个方法主要用于调试,它是不可以覆盖的方法。

Page 62: 第 7 章  Servlet 技术

6.doHead 它用于处理客户端的 Head 调用,并且返回一个 Response 。当客户端只需要知道响应的 Header 时,它就发出一个 Header请求。在这种请求下客户端往往关心响应的长度和响应的 MIME 类型。

7.doOptions 它用于处理客户端的 Options 调用。通过这个调用,客户端可以获得此 Servlet支持的方法,如某个 Servlet覆盖了 doPost 方法,那么将返回: Allow:POST,TRACE,OPTIONS,HEAD 在一般情况下不需要覆盖这个方法。

Page 63: 第 7 章  Servlet 技术

doGet :参数显示传递doPost :参数隐式传递doPut :文件传递doDelete :删除指令传递doTrace :由容器调用doHead :客户端仅需要获取 Head信息即响

应长度和 MIME 类型时调用。doOptions :获取 Servlet支持的方法。

Page 64: 第 7 章  Servlet 技术

7.4 获得 Servlet 初始化参数

   Servlet 可以配置一些初始化参数,我们可以在 Servlet中获得这些初始化的参数。下面用一个例子:   编写一个使用 JDBC连接数据库的 Servlet 程序,为了保证这个 Servlet 的通用性,我们可以把它的驱动程序、连接数据库的 URL、用户名和密码配置到 web.xml 文件中。当 Servlet 执行操作时,通过 ServletConfig 获得初始化的参数以连接数据库。 例程 7-6 获得 Servlet 的初始参数 (JDBCServlet.java)

例程 7-7Servlet 的初始配置 (ch7\WEB-INF\web.xml部分描述 )

Page 65: 第 7 章  Servlet 技术

7.5Servlet 的配置   Servlet 配置包含 Servlet 的名字、 Servlet 的类 ( 如果是 JSP ,那么就指定 JSP 文件 )、初始化参数、启动装入的优先级、 Servlet 的映射和运行的安全设置。 Servlet 配置的 DTD (文档类型定义)如下 :<!EKENENT servlet(icon?,servlet-name,display-name?,description?, (servlet-class|jsp-file),init-param*,load-on-startup?,run-as?,security-role-ref*)>

下面结合一个实例例程7-8 一个简单的Servlet (ch7\WEB-INF\classes\Counter

Servlet.java)

Page 66: 第 7 章  Servlet 技术

7.5.1Servlet 的名字、类和其他杂项

  在配置 Servlet 时,首先必须指定 Servlet 的名字、Servlet 的类 ( 如果是 JSP ,必须指定 JSP 文件的位置 ) 。另外,可以选择性地给 Servlet 增加一定的描述,并且指定它在部署时显示的名字和部署时显示的 Icon 。

Page 67: 第 7 章  Servlet 技术

CounterServlet 是这样被配置的如下 例程 7-9 CounterServlet 的部分配置<servlet>      <description>Servlet 配置 </description>      <display-name>TestServletConfig</display-name>      <servlet-name>CounterServlet</servlet-name>      <servlet-class>com.jspdev.ch7.CounterServlet</servlet-class>     .........   

<description> 为 Servlet指定一个文本描述。

<display-name>

为 Servlet指定一个简短的名字,这个名字可以被某些工具所显示。

Page 68: 第 7 章  Servlet 技术

如果要配置的 Servlet 是一个 JSP 文件,那么可以这样设置 <servlet>    <servlet-name>NewUserServlet</servlet-name>    <jsp-file>newUser.jsp</jsp-file>  </servlet>  

<jsp-file>

指定在Web应用程序中的 JSP文件的完整路径,该路径以斜杠( /)开始。如果要对一个 JSP文件做URL映射,就会用到这个元素。

Page 69: 第 7 章  Servlet 技术

7.5.2 初始化参数

<servlet>     <init-param>         <param-name>counter</param-name>         <param-value>10000</param-value>     </init-param>  </servlet>  在这个配置中,指定 counter 的参数值为 10000

Page 70: 第 7 章  Servlet 技术

<init-param>

定义 Servlet 的初始化参数。如果使用了 <init-param>元素,则必须包含 <param-name> 和 <param-value>元素,可以包含零个或多个 <description>元素。<description>

为初始化参数提供一个文本描述。 <param-name> 定义初始化参数的名字。

<param-value> 定义初始化参数的值。

Page 71: 第 7 章  Servlet 技术

7.5.3启动装入优先级 启动装入优先级通过 <load-on-startup> 配置,例如 例程 7-10 启动优先级描述<servlet>    <servlet-name>NewUserServlet</servlet-name>    <jsp-file>newUser.jsp</jsp-file>    <load-on-startup>10</load-on-starup>  </servlet>  <servlet>    <servlet-name>HelloWorldServlet</servlet-name>    <servlet-class>com.test.HelloWorldServlet</servlet-class>    <load-on-startup>30</load-on-starup>  </servlet>  <servlet>    <servlet-name>PrintServlet</servlet-name>    <servlet-class>com.test.HelloWorldServlet2</servlet-class>    <load-on-startup>AnyTime</load-on-starup>  </servlet>  

Page 72: 第 7 章  Servlet 技术

  指定当 Web 应用程序启动时, Servlet被加载的次序。元素的内容必须是一个整数,如果这个值是一个负数,或者没有设定这个元素, Servlet 容器将在客户端首次请求这个 Servlet 时加载它;如果这个值是正数或 0 ,容器将在 Web 应用程序部署时加载和初始化这个 Servlet ,并且先加载数值小的 Servlet ,后加载数值大的 Servlet 。如果某个 Servlet需要在其他 Servlet被加载之前加载,可以在部署描述符中使用这个元素。如果 <servlet>元素包含了 <jsp-file>元素和<load-on-startup>元素,则 JSP 文件将被预编译并加载。   那么可以保证 NewUseServlet 在 HelloWorldServlet之前被载入, PrintServlet 可以在服务启动后的任何时候载入。

   <load-on-startup>< 参数 ></load-on-startup>  启动时按“参数”由小到大的顺序加载,参数是” AntTime” 时可在服务启动后任何时候载入。

<load-on-startup>

Page 73: 第 7 章  Servlet 技术

7.5.4Servlet 的映射 可以给一个 Servlet做多个映射,这样,我们可以通过不同的方式访问这个 Servlet 。例如 例程 7-11 CounterServlet 的映射配置<servlet-mapping>     <servlet-name>CounterServlet</servlet-name>     <url-pattern>/count_servlet</url-pattern>  </servlet-mapping>   <servlet-mapping>     <servlet-name>CounterServlet</servlet-name>     <url-pattern>/count/*</url-pattern>  第一个“ /” 表示 <WEB 应用程序目录 >

Page 74: 第 7 章  Servlet 技术

  通过这些配置,我们可以使用不同的方式访问这个 Servlet 。有趣的是,对于第二种映射方式,可以通过 /count 开头,都能访问这个 Servlet 。 http://localhost:8028/ch7/count/count

http://localhost:8028/ch7/count/count/lskdjf

Page 75: 第 7 章  Servlet 技术

   <servlet-mapping>元素在 Servlet 和 URL样式之间定义一个映射。它包含了两个子元素 <servlet- name> 和 <url-pattern> , <servlet-name>元素给出的 Servlet名字必须是在<servlet>元素中声明过的 Servlet 的名字。 <url-pattern>元素指定对应于 Servlet 的 URL路径,该路径是相对于 Web应用程序上下文根的路径。    Servlet 2.5 规范允许 <servlet-mapping> 的 <url-pattern>子元素出现多次,之前的规范只允许一个 <servlet-mapping>元素包含一个 <url-pattern>子元素。   在配置了 Servlet与 URL样式之间的映射后,当 Servlet容器接收到一个请求,它首先确定该请求应该由哪一个 Web应用程序来响应。并且在找到第一个成功的匹配后,不再进行下一个匹配。

Page 76: 第 7 章  Servlet 技术

不同的 pattern 可以映射到同一个 servlet ,但同一个 pattern不能映射到不同的 servlet 。

<servlet-mapping><servlet-name>getStatus</servlet-name><url-pattern>/status/*</url-pattern></servlet-mapping><servlet-mapping><servlet-name>getStatus</servlet-name><url-pattern>/briefStatus/*</url-pattern></servlet-mapping>

如果同一 web.xml 文件中一个 url-pattern映射到不同的 servlet ,容器就无法保证对一个 request 调用哪个 servlet 。

Page 77: 第 7 章  Servlet 技术

URL Pattern 语法 : 一个 URL Pattern 中的每个字符必须和 URL pat

h 中的严格一致。 有两个例外,在一个 Pattern末尾, /* 匹配从此

点以后的任何字符; *. 扩展名 则匹配任何有此扩展名的文件名。

Page 78: 第 7 章  Servlet 技术

在 Servlet映射到的 URL中也可以使用 *通配符,但是只能有两种固定的格式:一种格式是“ *.扩展名”,另一种格式是以正斜杠( /)开头并以“ /*”结尾。

<servlet-mapping> <servlet-name> AnyName   </servlet-name> <url-pattern> *.do </url-pattern></servlet-mapping>表示当客户访问以“ .do”为后缀的 url 的时候,都调

用 <servlet-name>为 AnyName 的 Servlet 程序。

<servlet-mapping> <servlet-name>AnyName</servlet-name> <url-pattern> /action/* </url-pattern></servlet-mapping>当前web站点下所有 action 子路径下面的所有 url 都匹

配 <servlet-name>为 AnyName 的 Servlet 程序。

Page 79: 第 7 章  Servlet 技术

例如:服务器 example.com 的路径 /examples 下的匹配模式<url-pattern>/status/*</url-pattern> 可有如下匹配 :

http ://example.com/examples/status/synopsis

http ://example.com/examples/status/complete?date=today

http ://example.com/examples/status

服务器 example.com 的路径 /examples 下的匹配模式 <url-pattern>*.map</url-pattern> 可有如下匹配 :

http ://example.com/examples/US/Oregon/Portland.map

http ://example.com/examples/US/Washington/Seattle.map

http ://example.com/examples/Paris.France.map

Page 80: 第 7 章  Servlet 技术

一个 url-pattern不能映射到不同的 servlet ,对于可用部分一致的 url-pattern ( /* 或 *.do ),调用哪个 Servlet 由匹配过程决定: 1〉严格匹配优先于带 * 的匹配; 2〉最长 pattern 优先于其他 pattern; 3〉路径匹配优先于文件类型匹配; 4〉 pattern <url-pattern>/</url-pattern> 匹配没

有其他 pattern匹配的 request 。

Page 81: 第 7 章  Servlet 技术

缺省 Servlet

如果某个 Servlet 的映射路径仅仅为一个正斜杠( / ),那么这个 Servlet 就成为当前Web 应用程序的缺省 Servlet即“默认映射”。

凡是在 web.xml 文件中找不到匹配的 <servlet-mapping>元素的 URL ,它们的访问请求都将交给缺省 Servlet 处理,也就是说,缺省 Servlet 用于处理所有其他 Servlet 都不处理的访问请求。

Page 82: 第 7 章  Servlet 技术

默认映射一般到一个应用的第一页。显式提供一个默认映射保证了不正确的 URL requests 被映射到可由应用所处理的 return而不是给出一个 return error 。 如下的 <servlet-mapping>元素将默认映射映射

到 Welcome servlet 实例:<servlet-mapping>

<servlet-name>Welcome</servlet-name>

<url-pattern>/</url-pattern>

</servlet-mapping>

Page 83: 第 7 章  Servlet 技术

7.5.5运行安全设置 关于 Web 应用的安全配置,这里先给出一个简单的例子:CounterServlet 的安全配置 例程 7-12 CounterServlet 的安全配置<servlet>     <run-as>        <role-name>admin</role-name>    </run-as>     <security-role-ref>        <role-name>admin</role-name>        <role-link>admin</role-link>     </security-role-ref>  </servlet>  

Page 84: 第 7 章  Servlet 技术

<run-as>

  指定用于执行组件的角色。如果使用了 <run-as> 元素,可以包含零个或多个 <description> 元素,必须包含 <role-name> 元素。

<description> 指定一个文本描述。

<role-name> 指定用于执行组件的角色名。

Page 85: 第 7 章  Servlet 技术

<security-role-ref>

声明在组件或部署的组件的代码中的安全角色引用。如果使用了 <security-role-ref> 元素,则必须包含 <role-name> 元素,可以包含零个或多个 <description> 元素,零个或一个 <role-link> 元素。

<description> 为安全角色引用提供一个文本描述。

<role-name>

指定在代码中使用的安全角色的名字。

<role-link> 指定到一个安全角色的引用。

Page 86: 第 7 章  Servlet 技术

7.6 用 Servlet 生成动态图片

   Servlet 比 JSP 强大之处在于后台处理,它不仅可以生成动态的 HTML 内容,也可以动态生成图片。   在许多请求下,我们需要使用这种技术,比如显示邮箱的利用率、生成动态的年度报表等。   这些编程的思路是首先获得绘画的一些必要参数,然后利用这些参数使用 Java.awt.image、 java.awt.*等 Java 图形编程类库进行动态生成。

例程7-13 可以动态生成图形的Servlet

(ch7\WEB-INF\classes\CreatImageServlet.java)

Page 87: 第 7 章  Servlet 技术

java.awt.Image 抽象类 Image 是表示图形图像的所有类的超类。 java.awt.image.BufferedImage Image 的子类,描述具有可访问图像数据缓冲区的 Image 。  在 Web 应用中,经常需要动态生成图片,比如实时股市行情,各种统计图等等,这种情况下,图片只能在服务器内存中动态生成并发送给用户,然后在浏览器中显示出来。

import java.io.*;   import java.awt.*;   import java.awt.image.*;     import javax.servlet.*;   import javax.servlet.http.*;    

import com.sun.image.codec.jpeg.*;

Page 88: 第 7 章  Servlet 技术

 在 Java 中, java.awt 和 java.awt.image 包提供了基本的绘制图像的能力,我们可以在内存中绘制好需要的图形,然后编码成 jpeg 或其他图像格式,最后发送相应给浏览器即可。下面是使用 Servlet 动态创建图像的详细步骤:   1.创建 BufferedImage对象,该对象存在内存中,负责保存绘制的图像;   2.创建 Graphics2D对象,该对象负责绘制所需的图像;

   3.当绘制完成后,调用 com.sun.image.codec.jpeg 包的 JPEG 编码器对其编码;   4.最后将编码后的数据输出至 HttpResponse即可。

  注意 com.sun.image.codec.jpeg 包位于 JDK 目录的 rt.jar包中,它不是公开的 API ,需要将 rt.jar 复制到 web 应用程序的 WEB-INF/lib 下。

Page 89: 第 7 章  Servlet 技术

我们先创建一个最简单的 Servlet:

public class CreateImageServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("image/jpeg");  // 设置了 response 的 contentType 为 image/jpeg ,这样浏览器就可以正确识别  createImage(response.getOutputStream());   // 返回客户端的输出流对象 }}

Page 90: 第 7 章  Servlet 技术

  我们首先设置了 response 的 contentType 为 image/jpeg ,这样浏览器就可以正确识别。  本质上,浏览器向服务器请求静态图片如 jpeg 时,服务器返回的仍然是标准的 http 响应,只不过 http头的 contentType不是 text/html ,而是 image/jpeg 而已,因此,我们在 Servlet 中只要设置好 contentType ,然后发送图像的数据流,浏览器就能正确解析并显示出图片。

Page 91: 第 7 章  Servlet 技术

然后,创建一个大小为 100x100的 BufferedImage对象,准备绘图:

private void createImage(OutputStream out){   

int width = 100;int height = 100;BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);//创建一个 BufferedImage绘制动态图像;// 描述具有可访问图像数据缓冲区的 Image,//第3个参数表示所创建图像的类型, TYPE_INT_BGR  一

个具有 8 位 RGB 颜色分量的图像

Page 92: 第 7 章  Servlet 技术

Graphics2D g = bi.createGraphics();

// 创建 Graphics2D 对象,可以将它绘制到此 BufferedImage 中。// BufferedImage对象中得到图形环境进行绘制,一个 Graphics或者 Graphics2D 对象

接着, BufferedImage 对象中获取 Graphics2D 对象.

Page 93: 第 7 章  Servlet 技术

绘图:

g.setBackground(Color.BLUE); // 填充背景色g.clearRect(0, 0, width, height); g.setColor(Color.RED); // 设置前景色g.drawLine(0, 0, 99, 99); // 开始绘图 ,绘制一条直线// 绘图完成,释放资源g.dispose();bi.flush();

Page 94: 第 7 章  Servlet 技术

然后,对 BufferedImage进行 JPEG编码:

JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);// 创建可用来编码 JPEG 数据流的 JPEGImageDecoder 实例// JPEGCodec 类是实现 JPEG 图像 Decoder/Encoder(解码器 /编码器)的工厂类。// JPEGImageEncoder 将图像缓冲数据编码为 JPEG 数据流

JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bi);// getDefaultJPEGEncodeParam(BufferedImage bi) //          创建 JPEGEncodeParam 对象

param.setQuality(1.0f, false);  //创建替代当前已建量化表的新量化表//压缩比低但质量很好 (1.0); forceBaseline - 强制基准量化表

Page 95: 第 7 章  Servlet 技术

然后,对 BufferedImage进行 JPEG编码:encoder.setJPEGEncodeParam(param);// 设置 JPEGEncodeParam 对象,用于将来的编码操作。//编码后的 JPEG图像直接输出到了 out对象中,我们只要传入 //response. getOutputStream()就可以直接输出到 HttpResponse中try { encoder.encode(bi); //进行编码}catch(IOException ioe) { ioe.printStackTrace();}

  编码后的 JPEG 图像直接输出到了 out 对象中,我们只要传入 response. getOutputStream() 就可以直接输出到 HttpResponse 中。

Page 96: 第 7 章  Servlet 技术

下面修改 web.xml 添加 Servlet映射  <servlet>     <servlet-name>CreateImageServlet</servlet-name>     <servlet-class>com.test.ch8.CreateImageServlet  </servlet-class>  </servlet>  <servlet-mapping>     <servlet-name>GreateImageServlet</servlet-name>     <url-pattern>/CreateImage</url-pattern>  </servlet-mapping>   结果见图 7-4

Page 97: 第 7 章  Servlet 技术

  BufferedImage 是在内存中的,通常在 BufferedImage 中进行修改等工作,然后再将 BufferedImage 显示出来。   这样做是为了防止直接在显示的图片上修改会出现的图片闪烁等问题。

java.awt.image.BufferedImage

返 回

Page 98: 第 7 章  Servlet 技术

  为了够将实现类和它们的生成过程完全分割开,而引进这个概念,工厂类就是隐藏类的实现过程的类,使得调用者不必知道实现类的任何信息。  一个调用原始类接口的类,有利于原始类的封装,相对于直接的构造器方式更节省资源,选择不同的工厂类就会有不同的处理方法。工厂类实际上是一个标准设计模式,你可以根据需要自行修改。

工厂类

返 回

Page 99: 第 7 章  Servlet 技术

java.awt.Graphics    java.awt.Graphics2D

   Graphics 类是所有图形上下文的抽象基类,允许应用程序可以在组件(已经在各种设备上实现),进行绘制。

   Graphics2D 类扩展了 Graphics 类,提供了对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制。它是用于在 Java(tm) 平台上呈现二维形状、文本和图像的基础类。

返 回

Page 100: 第 7 章  Servlet 技术

com.sun.image.codec.jpeg.JPEGCodec

   com.sun.image.codec.jpeg 包中的类并不属于核心 Java API 。它们属于 Sun 公司发布的 JDK 和 JRE 产品的一部分。 createJPEGEncoder(OutputStream dest)       创建可用来将图像数据编码为 JPEG 数据流的 JPEGImageEncoder 实例。createJPEGDecoder(InputStream src)       创建可用来解码 JPEG 数据流的 JPEGImageDecoder 实例。

返 回

Page 101: 第 7 章  Servlet 技术

接口 JPEGImageEncoder   JPEGImageEncoder 将图像缓冲数据编码为 JPEG 数据流。该接口的用户应在 BufferedImage 中提供图像数据,在 JPEGEncodeParams 对象中设置必要的参数,并成功地打开 OutputStream (编码 JPEG 流的目的流)。 JPEGImageEncoder 接口可将图像数据编码为互换的缩略 JPEG 数据流,该数据流将写入提供给编码器的 OutputStream 中。

getDefaultJPEGEncodeParam(BufferedImage bi)   创建 JPEGEncodeParam 对象的工厂方法。返回的对象对给定 BufferedImage 所做的编码工作将是可靠的。setJPEGEncodeParam(JPEGEncodeParam jep)   设置 JPEGEncodeParam 对象,用于将来的编码操作。 jep - 以后编码要用到的 JPEGEncodeParam 对象。

返 回

Page 102: 第 7 章  Servlet 技术

接口 JPEGEncodeParam

   JPEGEncodeParam 封装了控制编码 JPEG 数据流所必需的表和选项。参数可以由应用程序显式设置,也可以从 JPEG 头读取。setQuality (float quality, boolean forceBaseline)   创建替代当前已建量化表的新量化表。   根据质量参数的不同,创建的量化表介于压缩比很高但质量很差 (0.0) 与压缩比低但质量很好 (1.0) 之间。在 1.0 的质量水平,表的值将都是 1 。这样就不会由于量化而丢失数据。 返 回