記事ディレクトリ
背景
前回の記事ではJavaのhttpモジュールのリクエストオブジェクトについて詳しく説明しましたが、今回はサーバーがクライアントに応答するために必要なオブジェクトであるレスポンスオブジェクトについて見ていきます。
HTTPプロトコルの知識
- リクエストメッセージ: クライアントからサーバーに送信されるデータ
- データ形式:
- リクエストライン
- リクエストヘッダー
- 空白行をリクエストする
- リクエストボディ
- データ形式:
- 応答メッセージ: サーバーからクライアントに送信されるデータ
-
データ形式:
-
応答ライン
- 構成: プロトコル/バージョン応答ステータス コードステータス コードの説明
- 応答ステータス コード: サーバーはクライアント ブラウザにこの要求と応答のステータスを伝えます。
- ステータスコードはすべて3桁です
- 分類:
- 1xx: サーバーはクライアントからメッセージを受信しましたが、受け入れが完了していないため、一定時間待機した後、1xx マルチステータス コードを送信します
- 2xx: 成功。参加者: 200
- 3xx: リダイレクト。代表:302(リダイレクト)、304(アクセスキャッシュ)
- 4xx: クライアントエラー。
- 代表する:
- 404 (リクエスト パスに対応するリソースがありません)
- 405: リクエスト メソッドには対応する doXxx メソッドがありません
- 代表する:
- 5xx: サーバー側のエラー。代表値:500(サーバー内で例外が発生しました)
-
応答ヘッダー:
- 形式: ヘッダー名: 値
- 一般的な応答ヘッダー:
- Content-Type: サーバーはクライアントに応答本文のデータ形式とエンコード形式を伝えます。
- Content-disposition: サーバーはクライアントに応答本文データをどの形式で開くかを指示します。
- 価値:
- インライン: デフォルト値、現在のページで開きます
- Attachment;filename=xxx: 応答本文を添付ファイルとして開きます。ドキュメントをダウンロード
- 価値:
-
応答空行
-
レスポンスボディ: 送信されたデータ
-
-
応答文字列形式
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 101
Date: Wed, 06 Jun 2018 07:08:42 GMT
-
応答オブジェクト
応答オブジェクトには、応答ステータス コード、応答ヘッダー、応答本文など、サーバーの応答に関する情報が含まれています。
- 応答行を設定する
- 形式: HTTP/1.1 200 ok
- ステータス コードを設定します: setStatus(int): 200、404、500 など。
- Content-Type (コンテンツ タイプ) や Cache-Control (キャッシュ コントロール) などの応答ヘッダーを設定します: setHeader(String name, String value)。
- 応答本文を設定します。
- 使用手順:
-
出力ストリームを取得する
- 文字出力ストリーム: PrintWriter getWriter()
- バイト出力ストリーム: ServletOutputStream getOutputStream()
-
出力ストリームを使用してデータをクライアント ブラウザに出力します。
-
- 使用手順:
ケース: リダイレクト
コード:
//1. 设置状态码为302
response.setStatus(302);
//2.设置响应头location
response.setHeader("location","/day15/responseDemo2");
或者
//简单的重定向方法
response.sendRedirect("/day15/responseDemo2");
responseDemo1 は responseDemo2 にリダイレクトされます
package cn.xxx.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 重定向
*/
@WebServlet("/responseDemo1")
public class ResponseDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo1........");
//访问/responseDemo1,会自动跳转到/responseDemo2资源
/* //1. 设置状态码为302
response.setStatus(302);
//2.设置响应头location
response.setHeader("location","/day15/responseDemo2");*/
request.setAttribute("msg","response");
//动态获取虚拟目录
String contextPath = request.getContextPath();
//简单的重定向方法
response.sendRedirect(contextPath+"/responseDemo2");
//response.sendRedirect("http://www.itcast.cn");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
package cn.itcast.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/responseDemo2")
public class ResponseDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo2222222........");
Object msg = request.getAttribute("msg");
System.out.println(msg);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
フォワード
package cn.itcast.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/responseDemo3")
public class ResponseDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//转发
request.getRequestDispatcher("/responseDemo2").forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
絶対パスと相対パスの使用シナリオ:
- クライアント ブラウザの場合: 仮想ディレクトリ (プロジェクトのアクセス パス) を追加する必要があります
* 仮想ディレクトリを動的に取得することをお勧めします: request.getContextPath()
*<a> , <form>
リダイレクト...
* サーバー使用の場合: 仮想ディレクトリを追加する必要はありません
* 転送パス
リダイレクトと転送の違い
- リダイレクト機能: リダイレクト
- アドレスバーの変更
- リダイレクトにより他のサイト (サーバー) 上のリソースにアクセスできる
- リダイレクトは 2 つのリクエストです。リクエスト オブジェクトを使用してデータを共有することはできません
- 転送特性: 転送
- 転送アドレスバーのパスは変更されません。
- 転送は現在のサーバー下のリソースにのみアクセスできます
- 転送はリクエストです。リクエスト オブジェクトを使用してデータを共有できます。
ケース:サーバーがブラウザに文字データを出力する
-
ステップ:
- 文字出力ストリームを取得する
- 出力データ
-
知らせ:
-
文字化けの問題:
- PrintWriter pw = response.getWriter(); 取得したストリームのデフォルトのエンコードは ISO-8859-1 です
- このストリームのデフォルトのエンコーディングを設定します
- ブラウザに応答本文に使用するエンコーディングを指示します。
//エンコーディングを設定する簡単な形式は、ストリームを取得する前に
response.setContentType("text/html;charset=utf-8");を設定することです。
-
package cn.itcast.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/responseDemo4")
public class ResponseDemo4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取流对象之前,设置流的默认编码:ISO-8859-1 设置为:GBK
// response.setCharacterEncoding("utf-8");
//告诉浏览器,服务器发送的消息体数据的编码。建议浏览器使用该编码解码
//response.setHeader("content-type","text/html;charset=utf-8");
//简单的形式,设置编码
response.setContentType("text/html;charset=utf-8");
//1.获取字符输出流
PrintWriter pw = response.getWriter();
//2.输出数据
//pw.write("<h1>hello response</h1>");
pw.write("你好啊啊啊 response");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
ケース: サーバーがバイトデータをブラウザに出力する
- バイト出力ストリームを取得する
- 出力データ
package cn.itcast.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/responseDemo5")
public class ResponseDemo5 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//1.获取字节输出流
ServletOutputStream sos = response.getOutputStream();
//2.输出数据
sos.write("你好".getBytes("utf-8"));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
ケース: 単純な確認コード
本質: 画像
目的: 悪意のあるフォーム登録の防止
package cn.itcast.web.servlet;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int width = 100;
int height = 50;
//1.创建一对象,在内存中图片(验证码图片对象)
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//2.美化图片
//2.1 填充背景色
Graphics g = image.getGraphics();//画笔对象
g.setColor(Color.PINK);//设置画笔颜色
g.fillRect(0,0,width,height);
//2.2画边框
g.setColor(Color.BLUE);
g.drawRect(0,0,width - 1,height - 1);
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789";
//生成随机角标
Random ran = new Random();
for (int i = 1; i <= 4; i++) {
int index = ran.nextInt(str.length());
//获取字符
char ch = str.charAt(index);//随机字符
//2.3写验证码
g.drawString(ch+"",width/5*i,height/2);
}
//2.4画干扰线
g.setColor(Color.GREEN);
//随机生成坐标点
for (int i = 0; i < 10; i++) {
int x1 = ran.nextInt(width);
int x2 = ran.nextInt(width);
int y1 = ran.nextInt(height);
int y2 = ran.nextInt(height);
g.drawLine(x1,y1,x2,y2);
}
//3.将图片输出到页面展示
ImageIO.write(image,"jpg",response.getOutputStream());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
ServletContext オブジェクト
- 概念: Web アプリケーション全体を表し、プログラム コンテナ (サーバー) と通信できます。
- 得る:
- リクエストオブジェクトを通じて
request.getServletContext()を取得します。 - HttpServlet を通じて
this.getServletContext() を取得します。
- リクエストオブジェクトを通じて
- 関数:
-
MIME タイプを取得します。
-
MIME タイプ: インターネット通信プロセスで定義されたファイルのデータ型
- 形式:大文字/小文字テキスト/html画像/jpeg
-
取得: String getMimeType(文字列ファイル)
-
-
ドメインオブジェクト: 共有データ
- setAttribute(文字列名,オブジェクト値)
- getAttribute(文字列名)
- RemoveAttribute(文字列名)
- ServletContext オブジェクトのスコープ: すべてのユーザーによって要求されたすべてのデータ
-
ファイルの実際の (サーバー) パスを取得します。
-
メソッド: String getRealPath(String path)
String b = context.getRealPath(“/b.txt”);//Web ディレクトリのリソース アクセス
System.out.println(b);String c = context.getRealPath(“/WEB-INF/c.txt”);//WEB-INF ディレクトリ下のリソース アクセス
System.out.println©;String a = context.getRealPath(“/WEB-INF/classes/a.txt”);//src ディレクトリ下のリソース アクセス
System.out.println(a);
-
-
package cn.itcast.web.servletcontext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/servletContextDemo1")
public class ServletContextDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
ServletContext对象获取:
1. 通过request对象获取
request.getServletContext();
2. 通过HttpServlet获取
this.getServletContext();
*/
//1. 通过request对象获取
ServletContext context1 = request.getServletContext();
//2. 通过HttpServlet获取
ServletContext context2 = this.getServletContext();
System.out.println(context1);
System.out.println(context2);
System.out.println(context1 == context2);//true
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
package cn.itcast.web.servletcontext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/servletContextDemo2")
public class ServletContextDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
ServletContext功能:
1. 获取MIME类型:
* MIME类型:在互联网通信过程中定义的一种文件数据类型
* 格式: 大类型/小类型 text/html image/jpeg
* 获取:String getMimeType(String file)
2. 域对象:共享数据
3. 获取文件的真实(服务器)路径
*/
//2. 通过HttpServlet获取
ServletContext context = this.getServletContext();
//3. 定义文件名称
String filename = "a.jpg";//image/jpeg
//4.获取MIME类型
String mimeType = context.getMimeType(filename);
System.out.println(mimeType);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
package cn.itcast.web.servletcontext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/servletContextDemo3")
public class ServletContextDemo3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
ServletContext功能:
1. 获取MIME类型:
2. 域对象:共享数据
3. 获取文件的真实(服务器)路径
*/
//2. 通过HttpServlet获取
ServletContext context = this.getServletContext();
//设置数据
context.setAttribute("msg","haha");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
package cn.itcast.web.servletcontext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/servletContextDemo4")
public class ServletContextDemo4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
ServletContext功能:
1. 获取MIME类型:
2. 域对象:共享数据
3. 获取文件的真实(服务器)路径
*/
//2. 通过HttpServlet获取
ServletContext context = this.getServletContext();
//获取数据
Object msg = context.getAttribute("msg");
System.out.println(msg);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
package cn.itcast.web.servletcontext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
@WebServlet("/servletContextDemo5")
public class ServletContextDemo5 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
ServletContext功能:
1. 获取MIME类型:
2. 域对象:共享数据
3. 获取文件的真实(服务器)路径
*/
// 通过HttpServlet获取
ServletContext context = this.getServletContext();
// 获取文件的服务器路径
String b = context.getRealPath("/b.txt");//web目录下资源访问
System.out.println(b);
// File file = new File(realPath);
String c = context.getRealPath("/WEB-INF/c.txt");//WEB-INF目录下的资源访问
System.out.println(c);
String a = context.getRealPath("/WEB-INF/classes/a.txt");//src目录下的资源访问
System.out.println(a);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
ケース: ファイルのダウンロード
-
ファイルのダウンロード要件:
- ページ表示のハイパーリンク
- ハイパーリンクをクリックすると、ダウンロード プロンプト ボックスがポップアップ表示されます
- 画像ファイルのダウンロードを完了する
-
分析します:
- ハイパーリンクが指すリソースがブラウザで解析できる場合はブラウザに表示されますが、解析できない場合はダウンロード プロンプト ボックスがポップアップ表示されます。ニーズを満たしていない
- すべてのリソースはダウンロード プロンプト ボックスをポップアップ表示する必要があります
- 応答ヘッダーを使用して、リソースを開く方法を設定します。
- コンテンツの性質:添付ファイル;ファイル名=xxx
-
ステップ:
- ページを定義し、ハイパーリンクの href 属性を編集し、サーブレットをポイントし、リソース名ファイル名を渡します。
- サーブレットの定義
- ファイル名を取得する
- バイト入力ストリームを使用してファイルをメモリにロードする
- 応答の応答ヘッダーを指定します: content-disposition:attachment;filename=xxx
- 応答出力ストリームにデータを書き出す
-
質問:
- 中国語ファイルの問題
- 解決策:
- クライアントが使用するブラウザのバージョン情報を取得する
- バージョン情報の違いにより、設定ファイル名のエンコード方法が異なります
- 解決策:
- 中国語ファイルの問題
package cn.itcast.web.utils;
import sun.misc.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class DownLoadUtils {
public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
}
package cn.itcast.web.download;
import cn.itcast.web.utils.DownLoadUtils;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取请求参数,文件名称
String filename = request.getParameter("filename");
//2.使用字节输入流加载文件进内存
//2.1找到文件服务器路径
ServletContext servletContext = this.getServletContext();
String realPath = servletContext.getRealPath("/img/" + filename);
//2.2用字节流关联
FileInputStream fis = new FileInputStream(realPath);
//3.设置response的响应头
//3.1设置响应头类型:content-type
String mimeType = servletContext.getMimeType(filename);//获取文件的mime类型
response.setHeader("content-type",mimeType);
//3.2设置响应头打开方式:content-disposition
//解决中文文件名问题
//1.获取user-agent请求头、
String agent = request.getHeader("user-agent");
//2.使用工具类方法编码文件名即可
filename = DownLoadUtils.getFileName(agent, filename);
response.setHeader("content-disposition","attachment;filename="+filename);
//4.将输入流的数据写出到输出流中
ServletOutputStream sos = response.getOutputStream();
byte[] buff = new byte[1024 * 8];
int len = 0;
while((len = fis.read(buff)) != -1){
sos.write(buff,0,len);
}
fis.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}