| リクエスト オブジェクトとレスポンス オブジェクトのライフサイクル
1. HTTP サーバーは、ブラウザから送信された [HTTP リクエスト プロトコル パッケージ] を受信すると、現在の [HTTP リクエスト プロトコル パッケージ] に対する [リクエスト オブジェクト] と [応答オブジェクト] を自動的に生成します。
2. Http サーバーが doGet/doPost メソッドを呼び出すとき、doGet/doPost が正しく実行されるように、[リクエスト オブジェクト] と [応答オブジェクト] を実際のパラメーターとしてメソッドに渡す責任があります。
3. HTTP サーバーは、HTTP 応答プロトコル パッケージをプッシュする準備をする前に、この要求に関連付けられた [要求オブジェクト] と [応答オブジェクト] を破棄する責任があります。
4. [リクエスト オブジェクト] と [レスポンス オブジェクト] のライフサイクルは、リクエストの処理を通じて実行されます。
5. 視覚的に言うと、[リクエスト オブジェクト] と [レスポンス オブジェクト] はサーバー側のユーザーの代弁者に相当します。
| サーブレット間の相互呼び出し
サーブレット呼び出しの基本的な概要
-
ブラウザからの一部のリクエストでは、サーバー側で複数のサーブレットを調整して処理する必要があることがよくあります。
-
複数のサーブレット間で呼び出しを行う基本的な目的は、ユーザー エクスペリエンスを向上させることです。 ルール: このリクエストに含まれるサーブレットの数に関係なく、ユーザーはブラウザにリクエストを開始するよう [手動で] 通知するだけで済みます。
-
複数のサーブレット間の呼び出しルール: リダイレクト ソリューション、リクエスト転送ソリューション
サーブレット呼び出しをリダイレクトする
原理
-
初めて、ユーザーは [手動方法] で OneServlet にアクセスするようにブラウザに通知し、OneServlet の動作が完了したら、応答ヘッダーの location 属性に TwoServlet のアドレスを書き込みます。
302 ステータス コードをステータス ラインに書き込みます。ブラウザは 302 ステータスを確認した後、応答ヘッダー内の場所を探し、すぐにサーバーへの 2 番目のリクエストを自動的に開始します。
-
つまり、ブラウザは少なくとも 2 つのリクエストを送信しますが、最初のリクエストのみがユーザーによって手動で送信され、後続のリクエストはブラウザによって自動的に送信されます。
-
リダイレクト ソリューションでは、アドレス バーを介して次のリクエストを開始するようにブラウザに通知されるため、リダイレクト ソリューションを通じて呼び出されるリソース ファイルによって受信されるリクエスト メソッドは [GET] である必要があります。
-
短所: リダイレクト ソリューションではブラウザとサーバーの間で複数回の往復が必要となり、往復回数に多くの時間がかかり、サービスに対するユーザーの待ち時間が長くなります。
文法
response.sendRedirect("请求地址"); //将地址写入到响应包中响应头中location属性
-
リクエスト アドレスは次のとおりです: 外部 Web サイトの URL / サーバー内のサーブレット実装クラス オブジェクトのエイリアス (つまり、動的リソース) / 内部静的リソース
-
内部リソースの場合、URL の構成は次のようになります: /サイト名/サーブレット オブジェクトに対応するエイリアス
例
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="/web4/s1" method="post">
<input type="submit" value="重定向">
</form>
</body>
</html>
(Servlet1 と Servlet2 のコードはまったく同じですが、番号が異なります。ここでは Servlet1 のコードのみを示します)
public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//...
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8"); //设置content-Type中的字符规则为UTF-8,以保证显示到网页为中文
PrintWriter out = resp.getWriter(); //获取输出流
//提示S1的 POST被调用
System.out.println("Servlet1 POST 被调用");
//重定向到S2
System.out.println("重定向到 /web4/s2");
resp.sendRedirect("/web4/s2");
}
}
public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8"); //设置content-Type中的字符规则为UTF-8,以保证显示到网页为中文
PrintWriter out = resp.getWriter(); //获取输出流
//提示S2的 GET被调用
System.out.println("Servlet2 GET被调用");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//...
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--Servlet1实现类 注册-->
<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>Servlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet1</servlet-name>
<url-pattern>/s1</url-pattern>
</servlet-mapping>
<!--Servlet2实现类 注册-->
<servlet>
<servlet-name>servlet2</servlet-name>
<servlet-class>Servlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet2</servlet-name>
<url-pattern>/s2</url-pattern>
</servlet-mapping>
</web-app>
結論: リダイレクトによって自動的に開始されるリクエストはすべて GET タイプです~
サーブレット呼び出しの転送リクエスト
原理
-
初めてユーザーがブラウザに OneServlet へのアクセスを手動で要求したとき。OneServlet の作業が完了すると、ブラウザの代わりに現在のリクエスト オブジェクトが使用され Tomcat にリクエストが送信され、TwoServlet の呼び出しを申請します。
Tomcat はこのリクエストを受信すると、自動的に TwoServlet に入り、残りのタスクを完了します。
-
リクエスト転送ソリューションでは、ブラウザは 1 つの Http リクエスト プロトコル パケットのみを送信します。このリクエストに参加するすべてのサーブレットは同じリクエスト プロトコル パッケージを共有するため、これらのサーブレットが受信するリクエスト メソッドはブラウザが送信するリクエスト メソッドと一致します。
-
リクエストの数: リクエストの転送プロセス中に、ブラウザは 1 つのリクエストのみを送信します (このリクエストに含まれるサーブレットの数に関係なく、ユーザーはブラウザを通じて手動でリクエストを 1 つ送信するだけで済みます)。
-
利点: サーブレット間の呼び出しはサーバー コンピューター上で行われるため、サーバーとブラウザ間の往復回数が節約され、処理速度が向上します。
文法
RequestDispatcher report = request.getRequestDispatcher("/资源文件名"); //通过当前请求对象生成资源文件申请报告对象
report.forward(当前请求对象,当前响应对象); //将报告对象发送给Tomcat
-
リクエストの転送は Tomcat の内部スケジューリングであり、Tomcat には現在の Web サイト内のリソースに対するスケジューリング機能しかないため、リソース ファイル名はサーバー内の静的/動的リソースのみにすることができます。
-
リソース ファイル名を記述するときは、詳細に注意してください。
-
Tomcat によって内部的に呼び出されるため、それらはすべて同じデプロイされた Web サイト内にあるため、リソース ファイル名は [Web サイトのデプロイメント エイリアスを記述する必要はありません]! [アクセスが必要な静的/リソース名を直接記述する]。名前の前のスラッシュを省略しないでください: /
-
Web サイト名を記述すると、URL に 2 つの Web サイト名が含まれ、404 エラーが発生します。
-
例
-
web.xml の設定ファイルは、このセクションの「サーブレット呼び出しのリダイレクト」と一致しているため、ここでは表示されません。
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="/web4/s1" method="post">
<input type="submit" value="重定向">
</form>
<form action="/web4/s2" method="get">
<input type="submit" value="请求转发">
</form>
</body>
</html>
public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8"); //设置content-Type中的字符规则为UTF-8,以保证显示到网页为中文
PrintWriter out = resp.getWriter(); //获取输出流
//提示S1的 GET被调用
System.out.println("Servlet1 GET 被调用");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//...
}
}
public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8"); //设置content-Type中的字符规则为UTF-8,以保证显示到网页为中文
PrintWriter out = resp.getWriter(); //获取输出流
//提示S2的 GET被调用
System.out.println("Servlet2 GET被调用");
//请求转发到S1
System.out.println("请求转发到 /web4/s1");
//重定向中的URL无需写部署在Tomcat的网站名(因为本来就是内部调用了),只需要写资源名即可
RequestDispatcher report = req.getRequestDispatcher("/s1"); //通过当前请求对象生成资源文件申请报告对象
//RequestDispatcher report = req.getRequestDispatcher("/web4/s1"); //错误写法!不需要写网站部署名web4
report.forward(req,resp); //将报告对象发送给Tomcat
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//...
}
}
結論は:
リクエスト転送によって呼び出される他のサーブレットのリクエスト メソッドは GET です (リクエストとレスポンスのオブジェクトを共有するため)。
転送を要求する URL には /resource 名を記述するだけで済みます (同じ Web サイト内にあるため、Tomcat はデフォルトで URL に Web サイト展開エイリアスを書き込みます)
| サーブレット間のデータ共有
サーブレットデータ共有の基本的な概要
-
データ共有とは: OneServlet の作業が完了した後、生成されたデータは TwoServlet に渡されて使用されます。
-
4 つのデータ共有スキーム:
-
ServletContext インターフェース [グローバル スコープ オブジェクト]
-
クッキークラス
-
HttpSession インターフェイス [セッション スコープ オブジェクト]
-
HttpServletRequest インターフェース [リクエストスコープオブジェクト]
-
ServletContext インターフェースのデータ共有
基本的な紹介
-
ServletContext はサーブレット仕様のインターフェイスであり、その実装クラスは Http サーバーによって提供されます。
-
ServletContext実装クラスのオブジェクトは「グローバルスコープオブジェクト」と呼ばれます。
-
複数のサーブレットが同じ Web サイトに属している場合、この方法を使用してサーブレット データを共有できます。
原理の説明
-
各 Web サイトにはグローバル スコープ オブジェクトがあり、Web サイト内のすべてのサーブレットで共有されます。
例: OneServlet はグローバル スコープ オブジェクトにデータを保存でき、現在の Web サイト内の他のサーブレットは、この時点でグローバル スコープ オブジェクトからこのデータを取得して使用できます。
グローバル スコープ オブジェクトのライフサイクル
-
Tomcat の起動中に、現在の Web サイトのメモリ内にグローバル スコープ オブジェクトが自動的に作成されます。
-
Tomcat の実行中、Web サイトにはグローバル スコープ オブジェクトが 1 つだけあります。
-
Tomcat の実行中、グローバル スコープ オブジェクトは常に有効です(グローバル スコープ オブジェクトのライフ サイクルは、Web サイトの実行期間全体を通じて実行されます)。
-
Tomcat がシャットダウンしようとすると、現在の Web サイト内のグローバル スコープ オブジェクトを破棄する責任があります。
文法
-
K は文字列、V はオブジェクト
//通过【请求对象】向Tomcat索要当前网站中【全局作用域对象】
ServletContext application = request.getServletContext();
//将数据添加到全局作用域对象作为【共享数据】
application.setAttribute("key1",数据);
//从全局作用域对象获取之前添加的共享数据【注意一下数据类型默认是Object,需要转换】
Object 数据 = application.getAttribute("key1");
例
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="/web5/S1" method="get">
<input type="text" name="v1">
<input type="submit" value="发送数据v1到S1">
</form>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>S1</servlet-name>
<servlet-class>S1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>S1</servlet-name>
<url-pattern>/S1</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>S2</servlet-name>
<servlet-class>S2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>S2</servlet-name>
<url-pattern>/S2</url-pattern>
</servlet-mapping>
</web-app>
public class S1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String v1 = (String)req.getParameter("v1");
System.out.println("收到了来自index的参数 v1 = " + v1);
/*【把数据存入ServletContext】*/
ServletContext application = req.getServletContext(); //通过【请求对象】向Tomcat索要当前网站中【全局作用域对象】
application.setAttribute("key1",v1); //将数据添加到全局作用域对象作为【共享数据】
System.out.println("S1的数据成功存入全局作用域对象");
/*【请求转发跳转到S2】*/
System.out.println("正在从S1跳转到S2");
System.out.println("=========================================================");
RequestDispatcher report = req.getRequestDispatcher("/S2");
report.forward(req,resp);
}
}
public class S2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("跳转到了S2");
//从全局作用域对象拿到S1存入的值
ServletContext application = req.getServletContext();
String v2Fromv1 = (String)application.getAttribute("key1");
System.out.println("S2拿到了从S1存入的数据: v2Fromv1 = " + v2Fromv1);
}
}
Cookie クラスのデータ共有
基本的な紹介
-
これは、Tomcat によって提供される servlet-api.jar に存在するサーブレット仕様のツール クラスに由来します。
-
2 つのサーブレットが同じ Web サイトから来て、同じブラウザ/ユーザーにサービスを提供する場合は、データ共有に Cookie オブジェクトを使用することをお勧めします。
原理の説明
-
ユーザーはブラウザを通じて MyWeb Web サイトにリクエストを送信して、初めて OneServlet を申請します。OneServlet は操作中に Cookie を作成して、現在のユーザーに関連するデータを保存します。
OneServlet の作業完了後、[応答ヘッダーに Cookie が書き込まれ]て現在のブラウザに返されますブラウザは応答パケットを受信後、ブラウザのキャッシュに Cookie を保存します
一定の時間が経過した後、ユーザーが [同じブラウザ] を通じて TwoServlet を再度申請するリクエストを [myWeb Web サイト] に送信すると、
ブラウザは[myWeb Web サイトによって以前にプッシュされた Cookie を無条件にリクエスト ヘッダーに書き込み]、それを送信します。
このとき、TwoServlet が実行されている場合、リクエスト ヘッダーの Cookie の情報を読み取ることで、OneServlet が提供する共有データを取得できます。
ライフサイクル
-
デフォルトでは、Cookie オブジェクトはブラウザのキャッシュに保存されます。したがって、ブラウザが閉じている限り、Cookie オブジェクトは破棄されます。
-
手動設定の場合、ブラウザは受信したCookieをクライアントコンピュータのハードディスクに保存する必要があり、同時にハードディスク上でのCookieの生存期間を指定する必要があります。
生存時間の範囲内では、ブラウザを閉じたり、クライアント コンピュータを閉じたり、サーバーを閉じたりしても、Cookie は破棄されません。
有効期限に達すると、Cookie はハードディスクから自動的に削除されます。
cookie.setMaxAge(60); //cookie在客户端硬盘存活时间(单位:秒) 在此期间用户即使关闭浏览器,也不会导致Cookie销毁
文法
-
データの保存: Cookie オブジェクトを作成し、Cookie 構築メソッドを通じて共有データ (現在のユーザー データ) を保存します。
-
Cookie はマップに相当します。Cookie に保存できるキーと値のペアは 1 つだけです
-
K と V は両方とも文字列のみにすることができ、Key は中国語にすることはできませんが、V は中国語にすることができます
-
Cookie card = new Cookie("key1","V");
resp.addCookie(card); //将cookie写入到响应头,交给浏览器
他のサーブレットの Cookie データを取得する: リクエスト オブジェクトを呼び出して、ブラウザによって返された Cookie をリクエスト ヘッダーから取得します。
//1.调用请求对象从请求头得到浏览器返回的Cookie
Cookie cookieArray[] = request.getCookies();
//2.循环遍历数据得到每一个cookie的key 与 value
for(Cookie card:cookieArray){
String key = card.getName(); //读取key "key1"
String value = card.getValue(); //读取value "abc"
}
例
Indexとweb.xmlの構成は上記と同じなので省略します。
public class S1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie card = new Cookie("key1","S1的值1");
Cookie card2 = new Cookie("key2","S1的值2");
Cookie card3 = new Cookie("key3","S1的值3");
resp.addCookie(card); //将cookie写入到响应头,交给浏览器
resp.addCookie(card2);
resp.addCookie(card3);
resp.sendRedirect("/web5/S2"); //将地址写入到响应包中响应头中location属性
}
}
public class S2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("跳转到了S2");
//1.调用请求对象从请求头得到浏览器返回的Cookie
Cookie cookieArray[] = req.getCookies();
//2.循环遍历数据得到每一个cookie的key 与 value
int i = 1;
for(Cookie card:cookieArray){
String key = card.getName(); //读取key "key1"
String value = card.getValue(); //读取value "abc"
System.out.println("数据" + i++ + ":" + key + " = " + value);
}
}
}
HttpSession インターフェースのデータ共有
基本的な紹介
-
サーブレット仕様の次のインターフェースから。Tomcat の servlet-api.jar に存在し、その実装クラスは Http サーバーによって提供されます。
-
開発者は、HttpSession インターフェイスで変更されたオブジェクトを [セッション スコープ オブジェクト] と呼ぶことに慣れています。
-
2 つのサーブレットが同じ Web サイトから来て、同じブラウザ/ユーザーにサービスを提供する場合は、データ共有に HttpSession オブジェクトを使用することをお勧めします。
原理の説明
-
HttpSession と Cookie の違い
-
[保存場所が異なります] Cookie: クライアントコンピュータ (ブラウザのメモリ/ハードディスク) に保存; HttpSession: サーバーコンピュータのメモリに保存
-
[保存できるさまざまなデータ型] Cookie: K は英語の文字列のみ、V は文字列のみ、HttpSession: K の文字列には中国語を含めることができ、V は任意の種類の共有データ オブジェクトを保存できます
-
[データ量] Cookie オブジェクトは 1 つの共有データのみを保存できますが、HttpSession はマップ コレクションを使用して共有データを保存するため、任意の数の共有データを保存できます。
-
-
HttpSession はサーバー コンピューターのメモリに保存されますが、異なる HttpSession オブジェクトがどのユーザーに対応するかをどのようにして知るのでしょうか?
-
HttpSession は Cookie を通じてユーザーを HttpSession に関連付けます
-
ライフサイクル
-
ユーザーが HttpSession に関連付けられるときに使用される Cookie は、ブラウザーのキャッシュにのみ保存できます
-
ブラウザが閉じられると、ユーザーとその HttpSession との関係が切断されることを意味します。
-
Tomcat はブラウザが閉じられたことを検出できないため、ブラウザが閉じられたときに Tomcat がブラウザに関連付けられた HttpSession を破棄することはありません。
この問題を解決するために、Tomcat は各 HttpSession オブジェクトに[アイドル時間]を設定します。アイドル時間はデフォルトで 30 分です。
現在の HttpSession オブジェクトが30 分間アイドル状態である場合、Tomcat はユーザーが HttpSession を放棄したと判断し、Tomcat は HttpSession を破棄します。
-
HttpSession のアイドル時間を手動で変更します。
web.xmlに設定
<session-config><session-timeout>5</session-timeout></session-config>
(単位:分)
文法
データの追加
//1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
HttpSession session = request.getSession(); //如果当前用户还没有session对象,则服务端创建一个新的
HttpSession session = request.getSession(false); //如果当前用户还没有session对象,则服务端不会创建新的,会返回一个null
//2.将数据添加到用户私人储物柜
session.setAttribute("key1",共享数据)
データを取得する
//1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
HttpSession session = request.getSession();
HttpSession session = request.getSession(false); //如果当前用户还没有session对象,则服务端不会创建新的,会返回一个null
//2.从会话作用域对象得到OneServlet提供的共享数据
Object 共享数据 = session.getAttribute("key1");
例
public class S1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
HttpSession session = req.getSession(); //如果当前用户还没有session对象,则服务端创建一个新的
//2.将数据添加到用户私人储物柜
session.setAttribute("键1","值V1");
//转到Servlet1中
resp.sendRedirect("/web5/S2"); //将地址写入到响应包中响应头中location属性
}
}
public class S2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
HttpSession session = req.getSession();
//2.从会话作用域对象得到OneServlet提供的共享数据
Object o1 = session.getAttribute("键1");
System.out.println(o1);
}
}
HttpServletRequest インターフェースのデータ共有
基本的な紹介
-
同じ Web サイト内で、2 つのサーブレットが [リクエスト転送] を通じて呼び出される場合、それらは同じリクエスト プロトコル パッケージを互いに共有します。
また、リクエスト プロトコル パッケージは 1 つのリクエスト オブジェクトにのみ対応するため、サーブレットは同じリクエスト オブジェクトを共有します。
この時点で、このリクエスト オブジェクトを使用して 2 つのサーブレット間でデータを共有できます。
-
リクエストオブジェクトがサーブレット間のデータ共有機能を実装する場合、開発者はリクエストオブジェクトを「リクエストスコープオブジェクト」と呼びます。
文法
//将数据添加到【请求作用域对象】中attribute属性
req.setAttribute("key1",数据); //数据类型可以任意类型Object
//从当前请求对象得到OneServlet写入到共享数据【当前Servlet必须和之前的Servlet共用一个请求对象。即请求转发】
Object 数据 = req.getAttribute("key1");
例
public class S1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("键1","值V"); //数据类型可以任意类型Object
//请求转发
RequestDispatcher report = req.getRequestDispatcher("/S2"); //通过当前请求对象生成资源文件申请报告对象
report.forward(req,resp); //将报告对象发送给Tomcat
}
}
public class S2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("跳转到了S2");
Object o1 = req.getAttribute("键1");
System.out.println(o1);
}
}