第七章 服务器响应的生成:HTTP响应报头
1.任意响应报头的设置
public void setHeader(String headerName,
String headerValue)
– 设定任意的报头
public void setDateHeader(String name,
long millisecs)
– 将自1970年以来的毫秒数转换成GMT格式日期字符串
public void setIntHeader(String name,
int headerValue)
– 可以省去在调用setHeader之前将int转换成字符串的麻
烦
addHeader, addDateHeader, addIntHeader
– 增加新报头,而非替换已有的报头
2.普通响应报头的设置
setContentType
– 设定Content-Type报头。
– servlet几乎总会用到这个报头。
– 参见常见MIME类型的表格。
• setContentLength
– 设定Content-Length报头。
– 用于持续性HTTP连接。
– 参见Connection请求报头。
• addCookie
– 为Set-Cookie报头增加一个值。
– 参见介绍cookie的部分。
• sendRedirect
– 设定Location报头(以及改变状态代码)。
3.常见MIME类型
类型 含意
application/msword Microsoft Word document
application/octet-stream Unrecognized or binary data
application/pdf Acrobat (.pdf) file
application/postscript PostScript file
application/vnd.ms-excel Excel spreadsheet
application/vnd.ms-powerpoint Powerpoint presentation
application/x-gzip Gzip archive
application/x-java-archive JAR file
application/x-java-vm Java bytecode (.class) file
application/zip Zip archive
audio/basic S ound file in .au or .snd format
audio/x-aiff AIFF sound file
audio/x-wav Microsoft Windows sound file
audio/midi MIDI sound file
text/css HTML cascading style sheet
text/html HTML document
text/plain Plain text
text/xml XML document
image/gif GIF image
image/jpeg JPEG image
image/png PNG image
image/tiff TIFF image
video/mpeg MPEG video clip
video/quicktime QuickTime video clip
4.常见HTTP 1.1响应报头
• Cache-Control (1.1) 和Pragma (1.0)
– no-cache值阻止浏览器缓存页面。
• Content-Disposition
– 通过这个报头,可以请求浏览器询问用户将响应存储到磁盘上
给定名称的文件中。
Content-Disposition: attachment; filename=file-name
• Content-Encoding
– 文档的编码方式。参见之前压缩的例子。
• Content-Length
– 响应中的字节数。
– 参见前面幻灯片中的setContentLength。
– 使用ByteArrayOutputStream在发送文档前对文档进行缓冲,这
样才能够确定数据的大小。参见有关Connection请求报头的讨
论。
• Content-Type
– 返回文档时所采用的MIME类型。
– 使用setContentType设置这个报头。
• Expires
– 特定的一段时间,这段时间后应该将文档认作是过期
,不应该再继续缓存。
– 使用setDateHeader设置这个报头。
• Last-Modified
– 文档最后被改动的时间。
– 不要直接设置这个报头;而应该提供getLastModified
方法。参见书中的博彩数字的例子(第3章)。
• Location
– 浏览器应该重新连接到的URL。
– 不要直接设置这个报头,而要使用sendRedirect进行设
定。
• Refresh
– 多少秒后浏览器应该重新载入页面。同时还可以包括
应该连接到的URL。参见后面的例子。
• Set-Cookie
– 浏览器应该记下来的cookie。不要直接设置这个报头
;而应该使用addCookie。参见下一节。
• WWW-Authenticate
– 授权的类型和范围需要在Authorization报头中给出。
参见More Servlets & JSP 中有关安全的章节。
You use the shorthand
setContentType method to set the Content-Type header, and the MIME type
for Excel spreadsheets is application/vnd.ms-excel. So, to generate Excel
spreadsheets, just do:
response.setContentType("application/vnd.ms-excel");
PrintWriter out = response.getWriter();
package coreservlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
/** Servlet that creates Excel spreadsheet comparing
* apples and oranges.
*/
public class ApplesAndOranges extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/vnd.ms-excel");
PrintWriter out = response.getWriter();
out.println("\tQ1\tQ2\tQ3\tQ4\tTotal");
out.println("Apples\t78\t87\t92\t29\t=SUM(B2:E2)");
out.println("Oranges\t77\t86\t93\t30\t=SUM(B3:E3)");
}
}
处理长时间运行的servlet时我们需要下述内容:
• 不同请求间存储数据的方式。
– 对于不专门针对任意某个客户的数据,可以将它存储在servlet
的字段中(实例变量)。
– 对于专属于某个用户的数据,则要将它存储在HttpSession对象
中。
• 参见随后有关会话跟踪的课程。
– 对于需要为其他servlet或JSP页面访问的数据(和用户无关),
可将其存储到ServletContext中。
• 在响应发送给用户之后,保持计算继续运行的方法。
– 这项任何比较简单:启动一个线程。唯一要注意的是:将线程
的优先级设为比较低的值,这样才不会拖慢整个服务器的运行
。
• 在更新结果就绪后将它们发送给浏览器的方法。
– 使用Refresh报头告诉浏览器,让它请求更新。
使用servlet生成JPEG图像
1. 创建一个BufferedImage
2. 在BufferedImage上绘制内容
3. 设置Content-Type响应报头
response.setContentType("image/jpeg");
4. 获取输出流
OutputStream out = response.getOutputStream
5. 以JPEG格式将BufferedImage发送到输出流
try {
ImageIO.write(image, "jpg", out);
} catch(IOException ioe) {
System.err.println("Error writing JPEG file: "
+ ioe);
}
package coreservlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.awt.*;
/** Servlet that generates JPEG images representing
* a designated message with an oblique-shadowed
* version behind it.
*/
public class ShadowedText extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String wantsList = request.getParameter("showList");
if (wantsList != null) {
showFontList(response);
} else {
String message = request.getParameter("message");
if ((message == null) || (message.length() == 0)) {
message = "Missing 'message' parameter";
}
String fontName = request.getParameter("fontName");
if ((fontName == null) || (fontName.length() == 0)) {
fontName = "Serif";
}
String fontSizeString = request.getParameter("fontSize");
int fontSize;
try {
fontSize = Integer.parseInt(fontSizeString);
} catch(NumberFormatException nfe) {
fontSize = 90;
}
response.setContentType("image/jpeg");
MessageImage.writeJPEG
(MessageImage.makeMessageImage(message,
fontName,
fontSize),
response.getOutputStream());
}
}private void showFontList(HttpServletResponse response)
throws IOException {
PrintWriter out = response.getWriter();
String docType =
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " +
"Transitional//EN\">\n";
String title = "Fonts Available on Server";
out.println(docType +
"<HTML>\n" +
"<HEAD><TITLE>" + title + "</TITLE></HEAD>\n" +
"<BODY BGCOLOR=\"#FDF5E6\">\n" +
"<H1 ALIGN=CENTER>" + title + "</H1>\n" +
"<UL>");
String[] fontNames = MessageImage.getFontNames();
for(int i=0; i<fontNames.length; i++) {
out.println(" <LI>" + fontNames[i]);
}
out.println("</UL>\n" +
"</BODY></HTML>");
}
}
package coreservlets;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
/** Utilities for building images showing shadowed messages.
* <P>
* Requires JDK 1.4 since it uses the ImageIO class.
* JDK 1.4 is standard with J2EE-compliant app servers
* with servlets 2.4 and JSP 2.0. However, standalone
* servlet/JSP engines require only JDK 1.3 or later, and
* version 2.3 of the servlet spec requires only JDK
* 1.2 or later. So, although most servers run on JDK 1.4,
* this code is not necessarily portable across all servers.
*/
public class MessageImage {
/** Creates an Image of a string with an oblique
* shadow behind it. Used by the ShadowedText servlet.
*/
public static BufferedImage makeMessageImage(String message,
String fontName,
int fontSize) {
Font font = new Font(fontName, Font.PLAIN, fontSize);
FontMetrics metrics = getFontMetrics(font);
int messageWidth = metrics.stringWidth(message);
int baselineX = messageWidth/10;
int width = messageWidth+2*(baselineX + fontSize);
int height = fontSize*7/2;
int baselineY = height*8/10;
BufferedImage messageImage =
new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)messageImage.getGraphics();
g2d.setBackground(Color.white);
g2d.clearRect(0, 0, width, height);
g2d.setFont(font);
g2d.translate(baselineX, baselineY);
g2d.setPaint(Color.lightGray);
AffineTransform origTransform = g2d.getTransform();
g2d.shear(-0.95, 0);
g2d.scale(1, 3);
g2d.drawString(message, 0, 0);
g2d.setTransform(origTransform);
g2d.setPaint(Color.black);
g2d.drawString(message, 0, 0);
return(messageImage);
}
public static void writeJPEG(BufferedImage image,
OutputStream out) {
try {
ImageIO.write(image, "jpg", out);
} catch(IOException ioe) {
System.err.println("Error outputting JPEG: " + ioe);
}
}
public static void writeJPEG(BufferedImage image,
File file) {
try {
ImageIO.write(image, "jpg", file);
} catch(IOException ioe) {
System.err.println("Error writing JPEG file: " + ioe);
}
}
public static String[] getFontNames() {
GraphicsEnvironment env =
GraphicsEnvironment.getLocalGraphicsEnvironment();
return(env.getAvailableFontFamilyNames());
}
/** We need a Graphics object to get a FontMetrics object
* (an object that says how big strings are in given fonts).
* But, you need an image from which to derive the Graphics
* object. Since the size of the "real" image will depend on
* how big the string is, we create a very small temporary
* image first, get the FontMetrics, figure out how
* big the real image should be, then use a real image
* of that size.
*/
private static FontMetrics getFontMetrics(Font font) {
BufferedImage tempImage =
new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D)tempImage.getGraphics();
return(g2d.getFontMetrics(font));
}
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD><TITLE>JPEG Generation Service</TITLE></HEAD>
<BODY BGCOLOR="#FDF5E6">
<H1 ALIGN="CENTER">JPEG Generation Service</H1>
Welcome to the <I>free</I> trial edition of our JPEG
generation service. Enter a message, a font name,
and a font size below, then submit the form. You will
be returned a JPEG image showing the message in the
designated font, with an oblique "shadow" of the message
behind it. Once you get an image you are satisfied with,
right-click
on it (or click while holding down the SHIFT key) to save
it to your local disk.
<P>
The server is currently on Windows, so the font name must
be either a standard Java font name (e.g., Serif, SansSerif,
or Monospaced) or a Windows font name (e.g., Arial Black).
Unrecognized font names will revert to Serif. Press the
"Show Font List" button for a complete list.
<FORM ACTION="/servlet/coreservlets.ShadowedText">
<CENTER>
Message:
<INPUT TYPE="TEXT" NAME="message"><BR>
Font name:
<INPUT TYPE="TEXT" NAME="fontName" VALUE="Serif"><BR>
Font size:
<INPUT TYPE="TEXT" NAME="fontSize" VALUE="90"><P>
<INPUT TYPE="SUBMIT" VALUE="Build Image"><P>
<INPUT TYPE="SUBMIT" NAME="showList" VALUE="Show Font List">
</CENTER>
</FORM>
</BODY></HTML>
package coreservlets;
import java.io.*;
public class ImageTest {
public static void main(String[] args) {
String message = "Testing";
String font = "Arial";
if (args.length > 0) {
message = args[0];
}
if (args.length > 1) {
font = args[1];
}
MessageImage.writeJPEG
(MessageImage.makeMessageImage(message, font, 40),
new File("ImageTest.jpg"));
}
}