前回はMVCモデルについて概略を学びました。
今回は本研修でコントローラーの役目を果たすServletについて学んでいきましょう。
1. Servletとは?
Java Servletとは、Javaで書かれたプログラムであり、サーバ上で動きます。以前はJava Appletというクライアント(ブラウザ)側で動くJavaプログラムがあり、Java Servletと対になっていたためこの名前があります。(現在では Java Appletはほとんど使われていません)
Servletの概念は下図の通りです。
ブラウザからアプリケーションサーバにリクエストが送られると、初回のみServletコンテナがJavaのクラスファイルを実行してServletのインスタンスを作り、レスポンスを返します。それ以降、Servletのインスタンスはアプリケーションサーバのメモリに常駐し、リクエストに対してレスポンスを返します。リクエストメソッドに応じてgetにはdoGet()メソッド、postにはdoPost()メソッドが呼び出されます。
1.1. ServletでHello World
ここでは、ひとまずServletを単体で実行してみることにします。JavaSEでも一番最初に学んだ「Hello World」をやってみましょう。
以下のようなHelloServlet1.javaだけを作成して実行してみてください。
package controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/Hello1")
public class Hello1Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("Hello World");
}
}
すると真っ白なブラウザの画面が表示されましたね。
1回目は先述の通りServletのインスタンスを作ったり、Tomcatが停止中であれば立ち上げから始めますので時間がかかりますが、2回目以降は早くなるはずです。
さて、「Hello World」 はどこに表示されているのでしょうか?
実は、下図のように「コンソール」というタブがあり、ログとして表示されているのでした。
コンソールではプリントデバッグを行うことができます。また、各種エラーが表示されるところですから今後も頻繁に目にすることになります。
ここからServletの中身の解説に入りますが、ひとまずServlet特有の決り文句は無視して、urlPatternsとdoGet()メソッドという2つの重要ポイントを解説します。
1.2. urlPatterns
まず注目すべきは、urlPatternsです。urlPatternsはこのServletがどのようなURLの指定で呼び出せるかを規定しています。
@WebServlet("/Hello1")
ブラウザのアドレスバーを見ると以下のようになっていますね。
「http://localhost:8080/05_Servlet/Hello1」
実は、 urlPatternはJavaのクラス名とは無関係に付けることができます。
しかし、当社の新人エンジニア研修では特段の理由がない限り、urlPatternは1つだけ、クラス名からServletを削除したものを用います。(例. Hello1Servlet → Hello1)
なお、同じプロジェクトの複数のServletの中に同じurlPatternを指定するとServletも、JSPもHTMLさえも実行できなくなることがあります。Servletのファイルをコピーして、うっかり urlPattern を書き換えるのを忘れていると起こります。(しかも、コピーした後 urlPattern を書き換えてもキャッシュに元の urlPattern が残ることがあります。その場合にはプロジェクトの「リフレッシュ」が必要になりますので方法は講師にお尋ねください)
2. コンテキストルート
urlPatternの先頭の“/”はこのServletがアプリケーションの直下(プロジェクト名の直下で当社の研修環境の場合はwebappフォルダの中)にできることを示しています。つまり、ServletのURLは以下になります。
この時、以下のポート番号までがサーバのドメインです。
「http://localhost:8080/」
また、以下の「プロジェクト名/」までをコンテキストルートといいます。
「http://localhost:8080/05_Servlet/」
【context】とは英語で文脈という意味です。文脈が変われば言葉の意味が変わるように、プロジェクトが変われば同じ urlPatternでも呼び出されるServletが変わります。
さらに、以下がHelloServlet1のURLです。
「http://localhost:8080/05_Servlet/」
なお、前章で見たように${pageContext.request.contextPath}というEL式を使い「/プロジェクト名」を取得することができます。つまりこの章の場合は「/03_JavaWeb03Servlet」です。プロジェクト名は変更になることもありますので直接記述するよりも賢い方法です。
また、オリジナルのCSSやJavaScriptを組み込む際にも以下のように記述する必要があります。
href="${pageContext.request.contextPath}/css/mystyle.css"
- ①最終課題でオリジナルのCSSやJavaScriptを組み込む予定はありますか?
チームの答え: |
3. Servletクラス
ServletはHttpServletクラスを継承します。HttpServletクラスに関して当社の新人エンジニア研修では特に深入りはしません。JavaSEのときのような詳細な説明が欲しい方はJakarta EE 8 仕様 APIを御覧ください。
3.1. doGet()メソッド
次にdoGet()メソッドを見ていきます。
doGetメソッドは HttpServletクラスのdoGetメソッドをオーバーライドしているため@Overrideアノテーションを付けています。このメソッド内で起きる可能性のある例外を呼び出し元に投げるためにthrowsキーワードが使われていますが、決り文句ですし、JavaSEでも詳しく学んだので今回は深入りはしません。
doGetメソッドの引数は2つです。HttpServletRequest型の変数名requestというインスタンスとHttpServletResponse型の変数名responseというインスタンスです。(本研修では単純にリクエストとレスポンスと呼ぶことにします)
それぞれ、リクエストとレスポンスでやり取りされるオブジェクトのフィールドやメソッドが含まれています。リクエストとレスポンスについては、今回の新人エンジニア研修で折に触れて紹介することになりますので、ひとまず先を急ぐことにします。
では先の文字列「Hello World」をブラウザに表示するにはどうすればよいでしょうか?
それには、JSPにデータを渡す方法とJSPのEL【Expression Language】を使って表示する方法を学ぶ必要があります。(本当はServlet単体でもHTMLの出力は可能ですが、MVCを学ぶという本研修の趣旨からは外れますので解説しません。)
3.2. リクエスト属性とは?
あるServletからJSPへデータを渡すには属性というアプリケーション・サーバーのデータ領域を使います。
そして属性にはスコープ【scope】という有効範囲があります。英語の【scope】には範囲という意味があるということを私達はJavaSEで学びました。
JavaEEにはデータの有効範囲の異なる4種類のスコープがあるのですが、今回はそのうちスコープが狭い方から2番めのリクエスト属性(Request Attributes)を使います。(本研修ではあともう一つセッション属性(Session Attributes)というものを「5.ログイン処理の実装とセッション属性」で学びます)
次のようなServletを作成して実行してみましょう。
package controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns = { "/Hello2" })
public class Hello2Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("message", "Hello World");
request.getRequestDispatcher("view/result.jsp").forward(request, response);
}
}
- ①「request.getRequestDispatcher("/view/result.jsp").forward(request, response)」のように複数のメソッドを“.”でつなぐ書き方を何といいましたか?
あなたの答え: |
ServletではrequestのsetAttributeメソッドを使いインスタンスを属性に保存します。 【Attribute】=属性を、【set】=セットする、という意味のメソッドです。
ポイントは以下の記述です。
request.setAttribute("message", "Hello World");
リクエスト属性という保存領域にmessageという名前で"Hello World"という文字列のインスタンスを格納しています。
このメソッド名は「属性をセットする」というそのままの意味でしたね。
第2引数はセッションに格納したいインスタンスです。Object型なのでJavaのインスタンスであれば何でも格納できます。
第1引数は名前です。変数名のようなもので JSPのEL式でこの名前で取り出すことができます。
このようなデータ構造をキーバリュー(Key-Value)と呼びます。文字通り、データを取り出す際のキーと値というわけです。
オブジェクトはリクエスト属性に複数保存できます。それぞれを区別するために違う名前が必要になるのですね。
下図のnameが名前、attributeがオブジェクトになります。
そして、requestのforward()メソッドを使って指定のJSPにフォワード処理をします。ちょうどサッカーのフォワードがボールを前に前に運ぶイメージでしょうか。
リクエスト属性は、その名の通り、1回のリクエストとレスポンスの間だけ有効な記憶領域(スコープ)です。レスポンスを返し終わると消えてしまう記憶領域ですのでメモリを圧迫しません。他のプログラミング言語ではリクエスト変数と呼ばれることもあります。
/
3.3. フォワードとは
フォワードとは、処理中のServletからJSP(やServlet)に処理を移す(画面を切り替える)ことです。JSPに画面表示の処理を任せてしまうのがフォワードです。
以下の1行でフォワードが成立します。
request.getRequestDispatcher("view/result.jsp").forward(request, response);
画面を切り替える方法としてあとの章でリダイレクトというものも出てきますので比較を通じて、おいおい理解いただければ大丈夫です。このメソッドの前半部分でrequestのgetRequestDispatcher()メソッドを使っています。
「ブラウザにデータを戻すのであれば、 request ではなく、response のメソッドを使うのではないか?」そう思った人もいるかも知れません。しかし上図「リクエスト属性のイメージ」をよく見ると、ServletからJSPにデータを渡してからレスポンスをしているのでこれで良いのですね。
このフォワードのメソッド名は【Request】=「リクエストを」【Dispatcher】= 「送るものを」【get】=「ゲットする」という程度の意味です。送り先のURLは引数として文字列で渡します。以下のように2通りの書き方があります。この研修ではフォワード先のパス指定は①通常の相対パスで統一したいと思います。
なぜなら、それが一番短くかける上に、後で学ぶリダイレクト処理でも同じ書き方ができるからです。
"view/result.jsp"
今回この処理はメソッドチェーンを使い1行で書いています。2行で書くこともできますが、シンプルですからこの書き方に慣れてください。なお、以下の部分は決り文句と考えていただいて結構です。
.forward(request, response)
初めてServletを学んだときに面食らうのがforward後のURLです。
「http://localhost:8080/03_JavaWeb03Servlet/Hello2」
となっています。JSPのURLは以下の通りですが、表示はServletのURLのままですね。
「http://localhost:8080/03_JavaWeb03Servlet/view/result.jsp」
したがって、もしもエラーが起きた場合に問題の切り分けが困難になることがあります。つまり、エラーの発生箇所がServletなのか、JSPなのかが直ぐには判断しづらいことがあります。
4. JSPにおけるELの記述方法
JSPでは、ELを使ってその値をリクエスト属性から取り出してHTMLを組み立てます。HTMLファイルがブラウザにレスポンスされて皆さんの画面に表示されます。
result.jspには、HTMLの定型文をすべて消して、ELだけを記述することにしました。論点を明確にするためです。
実は、下記のようにJSPのELは$で始めて波括弧の中にリクエスト属性に付けた名前だけを書けば表示されます。この例では”message"です。
${message}
ただし、この書き方ですとこの後セッション属性というものが出てきたときに区別できません。そこでリクエスト属性であることを明確化するために以下のように書くことにします。
${requestScope.message}
また、このとき、もちろんJSPだけを単体で実行しても何も表示されません。Servletを介さないと「Hello World」が表示されないことを確認してください。
なお、変数に$マークを付けるのはIT業界の古くからの習慣です。古くはBasic、そしてLinuxのシェルスクリプトやPHPでも$は変数の目印として使われます。さらにJavaScriptのテンプレートリテラルでは全く同じ表記をします。豆知識として覚えておいて損はありません。
今回はMVCモデルについて学びました。
次回は、「フォームから送ったデータをServletで受け取る方法」を学んでいきます。ブラウザからのデータをServletで受けて、JSPで表示する一連のMVCの処理が書けるようになります。
IT企業向け新人研修おすすめ資料 無料公開中 (saycon.co.jp)