【絶対に挫折しないJava超入門】これ以上簡単に教えるのは無理②【サポート付き】
どうも、エンジニアの陽翔です。
【絶対に挫折しないJava超入門】の第2回です。Java EEの中核技術であるServletの超入門です。
第1回ではこのnoteの目的や使い方も書いてあるので、読んでない方は是非ご覧ください。
1.前回の宿題の答え合わせ
さて、では前回の宿題の答え合わせから。
1-1.宿題
以下のJSPアプリを作成してみましょう。名前とTwitterアカウントはあなたのものでやってみましょう。
URL
http://localhost:8080/HelloYourName/HelloYourName.jsp
1-2.答えの例
では答え合わせをしましょう。
①コンテキストルート
Tomcatの「webapps」に下に「HelloYourName」フォルダを作るのが正解です。
②JSP
「HelloYourName」フォルダの下に「HelloYourName.jsp」ファイルを作成します。
「HelloYourName.jsp」のコーディング例です。
<%@page contentType="text/html" pageEncoding="UTF-8" session="false" %>
<html>
<body>
<table border='1' width='600' >
<tr>
<td width='300'>Your Name</td>
<td width='300'>陽翔</td>
</tr>
<tr>
<td>Twitter</td>
<td><a href='https://twitter.com/engineer_yosho' target=_blank>@engineer_yosho</a></td>
</tr>
</table>
</body>
</html>
1-3.スマホからアクセスする方法
Twitterでも書いたのですがURLを少し変更すれば、PCと同一ネットワークにあるスマホからでも見る事が出来ます。この動画のような感じです。
私の環境の場合はURLを下記のように指定しただけです。
http://192.168.0.12:8080/HelloYourName/HelloYourName.jsp
localhost:8080
↓
192.168.0.12:8080
「192.168.0.12」とはTomcatを動かしているPCのIPアドレスです。
答え合わせでどうしても分からない点があった方はツイッターもしくはインスタグラムからお問い合わせください。
2.ServletでHello Worldアプリを開発
さて、では第2回のテーマは「Servlet(サーブレット)」です。ServletはJSPと並びJavaのWebアプリケーション中核技術となりますのでとても重要です。
今回もまずは手を動かして行きますよ。
2-1.コンテキストルートを作成
コンテキストルートは第1回で解説したので大丈夫ですね。今回は「HelloServlet」というコンテキストルートを作ります。
そして、ここからが前回とは違います。「HelloServlet」の下に「WEB-INF」更にその下に「classes」をというフォルダ作成します。
2-2.Servletをコーディング
さて、ここからは少し難易度が上がるかもしれません。丁寧にやっていきますので、皆さん全員付いてきてください。挫折するくらいならDM下さいね。
①開発用のフォルダを作る
今回は「C:\DEV\src\HelloServlet」としましょう。ソースを置いておくフィルなので実際はどこでも良いです。
そしてHelloServlet.javaというファイルを作成します。
②HelloServlet.javaをコーディングする
import java.io.IOException;
import java.io.PrintWriter;
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("/HELLO")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<br><br>");
out.println("<b>Hello World!!</b><br>");
out.println("by Servlet<br>");
out.println("</body>");
out.println("</html>");
}
}
今回は割りとがっつりコーディングしてもらいます。後で解説しますので、まずは丸コピしちゃいましょう。
③コンパイル
HelloServlet.javaをコンパイルします。詳しくは後ほど解説しますが、.javaファイルをコンパイルして.classファイルというものを作ります。この.classファイルはバイトコードと呼ばれるもので、実際にJVM上で動くのはこのバイトコードです。
HelloServlet.java
↓
(コンパイル)
↓
HelloServlet.class
因みにJSPは少し特殊でコンパイルを明示的に行う必要はないのです。(実際には実行時に自動でコンパイルされています。)
分からなくてOKですので、どんどん手を動かしましょう。
コンパイルにはJDKに含まれるコンパイラーを使います。コマンドプロンプトを起動してください。
c:\>cd DEV\src\HelloServlet
c:\DEV\src\HelloServlet>javac -cp "C:\apache-tomcat-9.0.36\lib\servlet-api.jar" -d "C:\apache-tomcat-9.0.36\webapps\HelloServlet\WEB-INF\classes" HelloServlet.java
コマンドプロンプトでこのようにコマンドを打ち込んでください。エラー無く終了すればコンパイルは成功です。
ここでエラーがでたら何かが間違っているので、1つ1つ見直してやり直してください。必ずできますよ。絶対大丈夫。
「WEB-INF」の下の「classes」の中に「HelloServlet.class」が出来上がっているはずです。これがバイトコードです。
ここまで問題なく出来たでしょうか?
2-3.Servletアプリケーションへアクセス
さて、今開発したばかりのWebアプリケーションへアクセスしてみましょう。
ブラウザを開きこのURLへアクセス。
http://localhost:8080/HelloServlet/HELLO
この画面が表示されたら成功です。JSPに続きServletの実装もできましたね!!
Webアプリケーションマネージャ画面でも確認してみましょう。
http://localhost:8080/manager/html
「/HelloServlet」が出来ていますね。ここは第1回でやったのでもう大丈夫ですね。
さて、最初のServletの実装はこれで終了です。
3.ここまでにやってきた事の理屈を解説
今回もやってきました。「理屈の理解」の時間です。
今回動かしたServletの理屈をJava EEとセットで解説していきます。丁寧に解説したのでかなりのボリュームになっていますが、気負いせず着いてきてください。途中、理解できない事があってもあまり深追いせずに、イメージだけつかむ程度でもOKです。
3-1.Java EEとJava SEについて
Java EEとJava SEについては第1回で解説するか悩みましたが、Servletを動かした後の方が良いと思ったので今回にしました。
さて、Javaには3つのエディションがあります。
・Java SE(Java Platform, Standard Edition)
・Java EE(Java Platform, Enterprise Edition)
・Java ME(Java Platform, Micro Edition)
実はこの3つのエディションというが分かりづらくて、私は最初は勘違いして「何かが3つ横並びで存在している」って思っていましたが、そうではありません。
wikipediaから拾ってきた説明だとこんな感じ。
Java SE
Javaの基本機能のみを定めたもの
Java EE
Javaで実装されたアプリケーションサーバーの標準規格及びそのAPIを定めたもの。Java SEの拡張機能の形で提供
Java ME
携帯電話、PDA、テレビのようなリソースが制限されたデバイスにおけるJavaの小型セット
(※組み込み系での利用を想定しています。本noteでは説明対象外)
多くの入門書でも大体同じような説明が書かれているんだけど、結局は「良く分からん」ってなるんです。だから、この超入門ではもっと分かりやすく、まずはイメージ図をお見せします。
こうです。
このイメージ図を見つつ、下記の解説を読んでもらうと分かりやすいかなと思います。
Java SE
Javaアプリケーションの実行環境であるJVM + 標準的なAPI(Java SE API)をセットにしたモノ。これがないとJavaは動かない。JREもしくはJDKという実装で提供される。
Java EE
JavaのWebアプリケーションを実現する上で必要な機能の標準規格。具体的には「Servlet」、「JSP」、「JDBC」等の機能と、これらの機能をWebアプリケーションから利用する為のAPIの標準規格。この標準規格を満たした実装が「Webアプリケーションサーバー」であり、商用やOSSなど多くのWebアプリケーションサーバーが存在している。当然、どのWebアプリケーションサーバーでもJava EEアプリを稼動させる事が可能。Java SEの拡張機能になるのでJava SEへ依存しており、Java SE(つまり、JVM)がないと動かない。
「標準規格」って何やねん。ってずっと思っていました。
元々Javaはオープンソースの世界で育ってきた経緯もあって、Java EEの仕様は「標準規格」として公開されています。当然、Oracle社もWebアプリケーションサーバーを開発・提供していますが、他の会社や団体からも商用やOSSでWebアプリケーションサーバーは多く提供されています。だから「標準規格」という分かりずらい言い方になってるんです。
Java EEは標準規格であり、その規格に準拠して実装されたものが「Webアプリケーションサーバー」です。まぁ、ざっくり言うと「Java EE ≒ Webアプリケーションサーバー」ですね。
メジャーなWebアプリケーションサーバーを一覧にしました。
・Oracle
Oracle Weblogic Server
Oracle Application Server(OAS)
GlassFish Server
・IBM
IBM WebShphere Application Server
・RedHat
JBoss Enterprise Application Platform
・Apache
Tomcat
分かりやすく書いたつもりですが、ちょっとよく分からないという方も、現時点で理解できなくてもいいです。ざっくりイメージとして、こう理解してください。
・Java SE ≒ JRE/JDK
・Java EE ≒ Webアプリケーションサーバー
イメージ図ももう一回掲載しておきます。
余談:覚えなくてもいい話①
このnoteでは今後もJava EEと表現しますが、厳密には2017年以降のバージョンは「Jakarta EE」という呼び方が正しいです。理由をざっくり言うと、Java EEの開発・保守がOracle社からOSSのEclipse財団へ移管されたから。Java EEという商標は引き続きOracle社が持っているので使えなくなり、Jakarta EEと名乗る事になったのです。
余談:覚えなくてもいい話②
実はJava 11からはJREの提供はなくなりました。Javaの実行環境はJREであり「JVM + Java SE APIのセット」で、Javaプログラムを動かすにはJREのインストールが必須と説明してきました。しかし今後はJREをアプリケーションの一部として組み込む流れがあるようです。第1回でJDKのダウンロードページ(https://www.oracle.com/java/technologies/javase-downloads.html)を見てもらいましたが、確かに、Java 14はJDKしか提供されていません。
3-2.コンパイルとバイトコード
ソースコード(.javaファイル)を、実際のJVM上で稼動する形式であるバイトコード(.classファイル)へ変換する作業をコンパイルと言い、JDKにて提供される開発ツールの1つであるコンパイラーにて行います。
✓ポイント
コンパイル時にはJavaの構文のエラーチェックや、参照しているクラスとの整合性もチェックを行っています。
コンパイラーは、「Javac」というコマンドで起動します。コマンドの実体はこれで、JDKインストール時に一緒にインストールされます。
今回、コンパイルはこのようにコマンドを打ちました。
c:\>cd DEV\src\HelloServlet
c:\DEV\src\HelloServlet>javac -cp "C:\apache-tomcat-9.0.36\lib\servlet-api.jar" -d "C:\apache-tomcat-9.0.36\webapps\HelloServlet\WEB-INF\classes" HelloServlet.java
分解して解説します。
javac
「javac」でコンパイラを呼び出します。下記の「-cp」や「-d」はオプションと呼ばれ、コンパイラに対して指示を出していると考えて下さい。それぞれのオプションについて解説します。
-cp "C:\apache-tomcat-9.0.36\lib\servlet-api.jar"
「-cp」というオプションはクラスパスの指定です。クラスパスというのは、コンパイル時に参照するクラスファイルのパスを指定します。
ん??
このあたりから難しくなってきますよね。大丈夫です。丁寧に解説していきます。
まず、これを見てください。今回コーディングしたHelloServlet.javaの最初の部分の抜粋です。
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
2行目に「java.io.PrintWriter」という記載がありますね。これは「PrintWriter」というクラスを使うという意味です。5行目に「javax.servlet.http.HttpServlet」という記載もありますね。同じく「HttpServlet」というクラスを利用するという意味です。
クラスについては第3回以降で解説いたします。ここでは外部のAPI(機能)と理解しておいてください。
さて、コンパイルする際にエラーのチェックを行うと言いましたが、これらの外部のクラスとの整合性もチェックします。ですのでコンパイラーに外部クラスのパス(=クラスパス)を教える必要があります。
クラスのパスとは、バイトコード(.class)のパスです。つまり「PrintWirter.class」や「HttpServlet.class」のパスを教える必要があります。
そんなのどこにあるか分からないですよね?
そうですね。自分で実装したクラスであればまだしも、知らないクラスがどこにあるかなんか分かるはずもない。と言うかそもそも「PrintWirter.class」も「HttpServlet.class」って何?って話ですよね?
「PrintWriter.class」というのは、簡単に言うと画面に文字列を出力する機能を提供するクラスです。このクラスは「Java SE」で提供されるAPIです。
「HttpServlet.class」は、Servletを実装する上で必須となるクラスなのですが、「Java SE」ではなく「Java EE」で提供されるAPIです。
さっきの図にふきだしを付けると、こういう感じです。
JavacコマンドはJDKに含まれるコマンドなので、Java SEのAPIのクラスパスは把握していますから、教えてあげる必要はありません。ですが、Java EEのAPIについては把握していないので、APIの場所(=クラスパス)を教えてあげる必要があります。
つまり「HttpServlet.class」のクラスパスは教えてあげる必要があるという意味です。
ここまでは分かった。でも「HttpServlet.class」がどこにあるかなんて分からん、って話ですよね。
ちょっと前の話を思い出してください。Java EEのAPIはWebアプリケーションサーバーが提供していますよ。つまり、今回で言えばTomcatが提供してくれています。
ちょっと調べてみましょう。-cpオプションでこのように指定していたので、
-cp "C:\apache-tomcat-9.0.36\lib\servlet-api.jar"
実際にそのパスを確かめてみると、確かに「servlet-api.jar」というファイルがありました。
「.jar」ファイルというのは、簡単に言えば複数の「.class」ファイルをまとめて1つのフォルダに入れて圧縮したモノです。
実はzipファイルと同じ形式での圧縮なので、Windowsのエクスプローラーで解凍して中身を見る事ができます。(どっかにコピーしてservlet-api.jar.zipとリネームすると中身がみれますよ)
そしてやっと見つけました。「HttpServlet.class」がありましたね。
ちょっと長くなりましたが、クラスパスの指定についてOKでしょうか?
次に行きましょう。
-d "C:\apache-tomcat-9.0.36\webapps\HelloServlet\WEB-INF\classes"
「-d」というオプションはコンパイル後のバイトコードをどこに出力するかの指定です。自由に指定していいのですが、今回はTomcatの配下のclassesを指定しています。ここに配置するとTomcatはバイトコードを認識できるからです。
因みに、本来は「バイトコードを配置する」という作業が必要で、この配置作業を「デプロイ」と言います。実際のJava開発では必ず必要になるものなので、第3回で解説いたします。
HelloServlet.java
コンパイルする.javaファイルを指定します。
Javacコマンドの前にcdコマンドで.javaファイルを格納しているフォルダに移動しているので、フルパスの指定は不要です。ファイル名だけでOKです。
c:\>cd DEV\src\HelloServlet
ちょっと長かったですね。ここで一息入れて下さい。実はここからが本題ですよ。
3-3.Servlet解説
ServletはJava EEの中核技術です。Servletを使っていないJavaのWebアプリなんて存在していません。それくらい重要です。
ここから先も1つ1つ丁寧に解説しますよ。
まず、今回コーディングしたHelloServlet.javaの全体がこちら。
import java.io.IOException;
import java.io.PrintWriter;
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("/HELLO")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<br><br>");
out.println("<b>Hello World!!</b><br>");
out.println("by Servlet<br>");
out.println("</body>");
out.println("</html>");
}
}
まず、大前提なのですがHelloServlet.javaでは、「HelloServlet」という1つのクラスを宣言(コーディング)しています。そしてコンパイルする事で「HelloServlet.class」という1つのバイトコードを生成する事ができます。
基本は、
1つのjavaファイル = 1つのクラス=1つのclassファイル(バイトコード)
と理解しておいて下さい。
もちろん、例外もあって1つのjavaファイルに複数のクラスをコーディングする事もできますが、ここでは忘れてもらっていいです。
さて、このあたりでそもそも「クラス」ってなんだろう?って疑問が沸いているのではないでしょうか?
✓ポイント
オブジェクト指向を理解する上で、「クラス」や「インスタンス」が、まず最初につまづくポイントですね。このnoteでは敢えてここについて言及する事を避けてきました。ここでもまだ解説しません。もっと実装を進めてから解説します。Javaでコーディングしたものは全てクラスです。これだけは覚えておいて下さい。
では、分解して解説します。
3-3-1.import構文
まず、先ほどもちょっと触れた、最初のこの部分。
import java.io.IOException;
import java.io.PrintWriter;
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 xxxxxxx;
と、外部クラスファイルを指定する事で、利用する外部クラスを指定します。今回は7行で7つのクラスを指定しています。
例えば、先ほどの「HttpServlet」はこのように指定します。
import javax.servlet.http.HttpServlet;
単純に「HttpServlet」ではなく「javax.servlet.http.HttpServlet」ってなんでしょうね?
これは「パッケージ」と呼ばれる概念です。簡単に言うと、多くのクラスファイルをフォルダーで整理しているものです。
先ほどjarファイルの中身を覗いた時に、このようにフォルダーで階層的に整理されていたと思います。パッケージとはこのフォルダーでの整理そのものです。難しく考える必要はありません。
因みにimport構文で宣言する事で、その後で利用する際にはパッケージ名を省略して使う事ができます。(省略しなくてもいいのですが、普通は省略します。)
3-3-2.クラス宣言
次にこの部分です。やや難しいかもしれませんが着いてきてくださいね。
@WebServlet("/HELLO")
public class HelloServlet extends HttpServlet {
・・・(中略)・・・
}
ここは重要です。クラスの宣言は必ずこのような構文になります。ここにこれからクラスを書くよ!という意味です。
public class <クラス名> {
・・・(中略)・・・
}
先ほど「1つのjava=1つのクラス」と言いましたね。つまり、1つのjavaファイルには、このクラスの宣言は1つしか書きませんよ。
そして、ここでもJavaのつまづくポイントである「継承」という概念が出てきます。ソース上でいうと「extends HttpServlet」 の部分です。
public class HelloServlet extends HttpServlet {
・・・(中略)・・・
}
「継承」というのは簡単に言うと、あるクラスの機能を引き継ぎつつ、ちょっと拡張もして別のクラスをコーディングするという意味です。
ここでは「extends」の後に指定した「HttpServlet」クラスを継承して、「HelloServlet」クラスを作りますよ、という事を宣言しています。
「HttpServlet」クラスは、前に既に解説したとおりで、Java EEが提供するAPI(=クラス)の1つです。Servletをコーディングする場合、必ず「HttpServlet」を継承する必要があります。必ずです。おまじない的に必ず書くものと覚えましょう。
なお、継承されるクラスをスーパークラス、継承するクラスをサブクラスと言います。これは覚えておいてもいいです。
今回で言うと、こうですね。
・HttpServletクラス ⇒ スーパークラス(継承される側)
・HelloServletクラス ⇒ サブクラス(継承する側)
少しだけ突っ込んだ解説をすると、Servletというのは、Webアプリの超基本的な機能である、HTTPに関する制御を実装するモノです。HTTPリクエストを処理したり、HTTPレスポンスを返したりなどです。
しかし、プログラマーがいちいちそんな超基本的な事をコーディングしなくても良いように、Webアプリケーションサーバーが「HttpServlet」クラスとして提供してくれています。我々は開発したいアプリケーションに特化した部分のみをコーディングすれば良いのです。
✓ポイント
「Java EEがWebアプリケーションに必要な機能を提供してくれている」、「JavaのWebアプリケーションは、Webアプリケーションサーバーがないと動かない」という説明をしてきましたが、Webアプリケーションサーバーを利用する事で、この「HttpServlet」を始めとした、Webアプリの開発で必要となる基礎的な機能をあらかじめ実装して準備してくれている、と解釈すると理解が早いかなと思います。
3-3-3.@WebServletアノテーション
次にこの1行についてです。
@WebServlet("/HELLO")
これもJavaの分かりずらい概念の1つ「アノテーション」というものですが、非常に重要な要素です。(重要ばっかりですいません)
まず、そもそもアノテーションとは何ぞや?ですよね。
✓ポイント
アノテーションというのは、クラスなどに「機能を付け足す、意味を付加する」機能です。「@XXXXX」もしくは「@XXXXX(XXXX)」と記載します。記載が任意の場合もあり、その場合は機能や意味が付与されません。
説明しても分かりずらいで有名なんですよ、アノテーションは・・・。
今回の例で具体的に説明しましょう。
今回の
@WebServlet("/HELLO")
は、ServletのURLを指定する機能で、「HelloServlet」のURLを「/HELLO」と指定しています。
思い出してください。今回のWebアプリのURLはこうでしたよね。
http://localhost:8080/HelloServlet/HELLO
こういう事です。
ServletというのはHTTPを制御する機能ですので、URLと紐づいているんです。
コンテキストルートは説明したとおりで、アプリケーションルートです。そしてその後の「/HELLO」という部分が、このHelloServletと紐づいています。
その紐づきを定義しているのが、今回の「@WebServlet("/HELLO")」というアノテーションなのです。
@WebServlet("/HELLO")
public class HelloServlet extends HttpServlet {
・・・(中略)・・・
}
どうですか?すっきりしましたか?
そして、@WebServletアノテーションは、記載は必須ではありません。しかし、その場合はweb.xmlファイルという別のファイルにURLとServletのマッピングを定義する事になります。従来の方法はこのweb.xmlにて定義、なのですが、@WebServletアノテーションの方が楽なんですよ。
アノテーションは便利機能として提供される事が多いので、必須ではないのですが、使った方がコーディングが楽になる事が多いです。
3-3-4.メソッド宣言(触りだけ)
「メソッド」について触りだけ解説します。
メソッドというのは、Javaの世界ではクラスの「振る舞い」と説明されている事が多いと思います。「振る舞い」というか「処理」です。そのクラスが実装する「処理」が「メソッド」です。
今回のコードで言えばこの部分です。「doGet」という名のメソッドです。
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<br><br>");
out.println("<b>Hello World!!</b><br>");
out.println("by Servlet<br>");
out.println("</body>");
out.println("</html>");
}
メソッドの書き方はこんな感じなのですが、今回は触りだけですので「メソッド」を1から10までは解説しません。メソッドは覚える事がたくさんあるので、こんなところでつまづいて欲しくないからです。
<アクセス修飾子> <戻り値のクラス> <クラス名>(<パラメータークラス> <パラメーター名>,・・・) throws <スローする例外のクラス> {
・・・(中略)・・・
}
次の章で今回のソースにフォーカスして解説していきます。
3-3-5.継承と@Overrideアノテーション
Servletの実装を行う上で避けて通れないのが、先ほど解説した「継承」、そして今回説明する「オーバーライド」です。
あと、既に気づいたかもしれませんが、ここにもアノテーションが登場します。「@Override」という記載がアノテーションです。
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
・・・(中略)・・・
}
「@Override」アノテーションは、「オーバーライドしているメソッドだよ」という意味を付加するモノです。
さて、ここで「オーバーライド」という概念を解説します。これは先ほど説明した「継承」に深く関連します。
オーバーライドとは、サブクラスがスーパークラスのメソッドを上書きして定義する事です。
一応、図も描いてみたんですが、
・・・やっぱり分かりづらいですよね。正直私がJavaの勉強を始めた時に分からなかった事のトップ3に入ります。
私の脳内のつぶやきはこんな感じでした。
「継承」というのは何となく分かった。あるクラスを機能拡張して別のクラスを作る事。HttpServletクラスはHTTPに関する基礎的な機能を実装していて、我々プログラマーは、HttpServletを継承して個別の処理のServletを実装すれば良い。ここまでは理解した。ただ「オーバーライド」が分からない。スーパークラス側のdoGetメソッドを、自分がコーディングするサブクラスのdoGetメソッドで上書きするって何?
doGetをオーバーライドしてサブクラスで実装するというのが「Servletのお決まり」なのですが、理解する上でこう考えましょう。
↓↓↓
「Servlet」とはHTTPを制御する機能を実装するもの。今回で言えば「http://localhost:8080/HelloServlet/HELLO」というURLにアクセスがあった時の処理を実装するのが「HelloServletクラス」という「Servlet」である。
HTTPの基礎的な説明は省略しますが、ブラウザのアドレス欄に「http://localhost:8080/HelloServlet/HELLO」と打ってアクセスされた場合、それは「HTTPのGetメソッド」でのアクセスという事になります。
「http://localhost:8080/HelloServlet/HELLO」に「HTTPのGetメソッド」でアクセスされた時に、下記のような画面を表示するというのが「HelloServletクラス」の「処理」という事になります。
この機能を実現する為には、「HTTPのGetメソッド」でアクセスされた場合に動く「処理」を「HelloServletクラス」にコーディングする必要があります。実際にコーディングすべきメソッドが「doGet」になります。
✓ポイント
「HTTPのGetメソッド」でアクセスされた場合に動く「処理」が、doGetメソッドです。
これはServletで定められたメソッド名です。自分で好き勝手に名前を付ける事はできません。
正確に言うとメソッド名だけでなく、
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
・・・(中略)・・・
}
「public void」とか「HttpServletRequest request」や「ServletException」など、名前以外だけでなくメソッド全体の宣言がきっちり定められています。
因みに、HTTPのPostメソッドを処理する為に「doPost」メソッドというものも用意されています。
「doGet」も「doPost」もスーパークラスである「HttpServletクラス」で宣言されていますが、スーパークラスでは処理の中身は実質何もやっていません。それはそうです。この「doGet」や「doPost」の実装は、URLへアクセスされた時の処理をコーディングするメソッドですから、当然、サブクラス側でコーディングする必要があるからです。
サブクラス側でスーパークラスの「doGet」や「doPost」を「オーバーライド」して、スーパークラス側の実質何もやっていない処理を上書きする事で、それぞれのURLのHTTP制御を実現するしている、という風に理解しましょう。
最後に「@Override」アノテーションについて説明。
このアノテーションを付けた場合、メソッド名を含むメソッドの宣言の全体が、スーパークラスの宣言と完全に一致しているかをチェックしてくれます。このチェックはコンパイル時に走るようになっていて、何かが間違っていたらコンパイルでエラーとなります。
これは非常に便利な機能で、もしメソッド宣言が1ミリでも間違っていた場合、オーバーライドメソッドではなく、ただのメソッドとして扱われてしまい、「HTTPのGetメソッドを処理する」という役割を果たしません。
もし、doGetメソッドの宣言をミスった場合、きっとURLにアクセスした時にエラーになってしまいます。それをコンパイル時にチェックしてくれるので、@Overrideアノテーションは積極的に使った方がいいです。
因みに、@Overrideアノテーションを付けなくても、正しく「doGet」メソッドをオーバーライドできていれば待って全く問題ありません。つまり@Overrideアノテーションは、コンパイル時のチェック機能を付加してくれているに過ぎません。このアノテーションは必須ではないのです。余力があれば、試しに@Overrideという1行を削除してコンパイルし、動かしてみてください。問題なく動きます。
3-3-6.doGetメソッドの実装解説
やっとdoGetメソッドの実装、つまりコーディングのついての解説です。ここまで長かったですね。しかし、ここまでの解説を何となくでも理解できていれば、doGetメソッドがどういう役割のものなのかが見えているかと思います。その上で中身のコーディングの解説を聞いた方が理解できるはずです。
さあ、ではやっていきましょう。
改めてdoGetメソッドのコードです。
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<br><br>");
out.println("<b>Hello World!!</b><br>");
out.println("by Servlet<br>");
out.println("</body>");
out.println("</html>");
}
散々解説した通りServletとして定められている通りにメソッド定義してオーバーライドしています。
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
・・・(中略)・・・
}
そして、「doGet(HttpServletRequest request,
HttpServletResponse response)」という宣言について。
HttpServletRequest request
と
HttpServletResponse response
は、このdoGetメソッドの「パラーメーター」もしくは「引数(ひきすう)」と呼ばれるものです。パラメーターとは、メソッドが呼び出される際に渡されるモノです。
そして、それぞれのパラメーターは下記のような意味があります。
・HttpServletRequest ⇒ HTTPリクエスを表すモノ
・HttpServletResponse ⇒ HTTPレスポンスを表すモノ
HttpServletRequest request
⇒「HttpServletReques」クラスの「request」という名前のパラメーター
HttpServletResponse response
⇒「HttpServletResponse」クラスの「response」という名前のパラメーター
何言ってるのか分からないですよね?
でも敢えて解説を続けます。
次にこの部分。
response.setContentType("text/html");
「response」とはHTTPレスポンスを表すモノだといいました。HTTPレスポンスはつまり、誤解を恐れずざっくり言うと「ブラウザに返す内容」です。
この1行でレスポンスは「text/html」だよ、と設定しています。つまり、テキストかHTMLだと言っています。
そしてこの1行。
PrintWriter out = response.getWriter();
「respnse」のメソッド「getWriter()」を呼び出して、PrintWriterクラスのインスタンスである「out」を得ています。が、ここでは理解しなくていいです。沼にはまらないでください。
最後にこの部分です。
out.println("<html>");
out.println("<body>");
out.println("<br><br>");
out.println("<b>Hello World!!</b><br>");
out.println("by Servlet<br>");
out.println("</body>");
out.println("</html>");
PrintWriterクラスのprintlnメソッドを呼び出しています。
HTMLっぽい感じがしますね。さっき、「ブラウザに返す内容はテキストかHTMLだよ」って設定しましたが、実際にブラウザに返すHTMLの内容をここでコーディングしています。
雰囲気で分かったとは思いますが、実際にブラウザにレスポンスされたHTMLはこちらです。
<html>
<body>
<br><br>
<b>Hello World!!</b><br>
by Servlet<br>
</body>
</html>
ちょっと実際に「http://localhost:8080/HelloServlet/HELLO」で表示された画面のHTMLを見てみましょう。
↓ 思ったとおりでした。
さて、全然大丈夫です。私も全く理解できませんでしたから。
再び私の脳内のつぶやきをご覧下さい。
「doGet」がメソッドであれば、ではこの「doGet」を呼び出しているのはそもそも誰なんだろう?そして、パラメーターとして渡されるHTTPリクエストとHTTPレスポンスって一旦何なんだろ?そもそもHTTPレスポンスからPrintWriterというインスタンスが得られるとかもよく分からないし、このPrintWriterのPrintlnメソッドにHTMLを渡すと、それがブラウザにHTMLとしてレスポンスされるのはなぜだろう?
皆さんも近しい疑問を持っているのではないでしょうか?
この難しさは、まずServletが少々特殊という事が1つの原因です。最初は完全に理解するというよりも、「Servletとはそういうモノだ」と考える方が良いですよ。
まず「doGet」を呼び出しているのはそもそも誰か?についてですが、そのあたりはWebアプリケーションサーバーがやってくれています。WebアプリケーションサーバーはWebアプリが必要する基礎的な機能を提供していると説明した通りです。
ブラウザにURLが入力されてHTTPリクストを受け取ってから、プログラマーが実装したServletクラス、今回で言えば「HelloServletクラス」のdoGetメソッドやdoPostメソッドが呼び出されるまでの過程は、Webアプリケーションサーバー側で全部引き受けてくれているんです。
HTTPレスポンスもWebアプリケーションサーバーがやってくれています。プログラマーは、「HTTPレスポンスから得たPrintWriterクラスのprintlnメソッドにHTMLを渡す」だけでよくて、その後の過程(おそらくprintlntメソッドで渡したHTMLを、HTTPレスポンスとして組み立ててブラウザへ返す)は、Webアプリケーションサーバーがやってくれるのでプログラマーが意識しなくていいのです。
さて、今回の解説はかなりの量になってしまいました。
このnoteはあくまで超入門ですので、Servletを理解する上で最低限必要な事に絞って解説していますし、現時点では理解できなくて良い点はそのように述べました。
最後までついてきていただけたでしょうか?ついてこれなくても現時点では問題ありません。
まだまだ、頭の中で繋がらない点が多々あり、ちゃんと理解できるだろうか?と不安になるかもしれませんが、大丈夫ですよ。その手元で動いているWebアプリケーションで、改変や機能追加などを実際に手を動かしながら色々やっていきます。その中で、点と点が繋がる瞬間が必ずやってきます。
4.宿題
今回も最後に宿題の時間です。今日、手を動かした事、そして理屈の解説で学んだ事を応用してWebアプリケーションを作成して下さい。
宿題
今回作成した「/HelloServlet」以下のServletを追加してみましょう。
URL
http://localhost:8080/HelloServlet/NAVY
画面イメージ
Hello World!!を「font color=navy」としています。
答えは第3回で解説いたします。ちょっと簡単かもしれませんが、是非やってみてください。
このnoteが役に立ったと思って頂けれたら、Twitterでフォローいただけるとうれしいです。続編をリリースした際にお知らせいたします。
繰り返しになりますが、フォロワーさん限定で、このnote内容についてのサポートをいたしますので、ぜひぜひご活用ください。
では、今日はここまでです。
さようなら。また会いましょう。
この記事が気に入ったらサポートをしてみませんか?