Java入門 – エンジニアの入り口 https://eng-entrance.com 「エンジニアの入り口」は、プログラミング入門やエンジニアリング入門の知識が満載の初心者のための勉強サイトです。プログラミングやサーバ、ネットワークの基礎知識や勉強方法を習得できます。 Fri, 10 May 2019 03:00:58 +0000 ja hourly 1 https://wordpress.org/?v=5.2.19 【Java & Tomcat】HttpServletResponseインターフェイスについて知ろう https://eng-entrance.com/java-servlet-httpservletresponse https://eng-entrance.com/java-servlet-httpservletresponse#respond Sun, 28 Apr 2019 08:55:09 +0000 https://eng-entrance.com/?p=7273 この記事ではサーブレットがクライアントにレスポンスを返す際に、そのレスポンスを格納するオブジェクトとそのオブジェクトにアクセスするためのインターフェイスについて解説する。

HttpServletResponseインターフェイスとは何か

最初に、クライアントに返すレスポンスの情報がどのようにWebコンテナによって処理されるか見てみよう。レスポンスの情報はHttpServletResponseオブジェクトに入れてサーブレットとWebコンテナの間で受け渡しされる。

HttpServletResponseインターフェイスとは、このHttpServletResponseオブジェクトに情報を入れたり出したりしてアクセスするためのインターフェイスである。

HttpServletResponseオブジェクトは、サーバーからクライアントへ戻されるすべての情報をオブジェクトの内部にカプセル化している。つまり、HttpServletResponseインターフェイスに定義されたメソッドを使ってのみアクセスできると言うことだ。HTTPプロトコルの中で、カプセル化された情報はサーバーからクライアントにレスポンスのHTTPヘッダーかメッセージのボディによって送信される。

HttpServletResponseオブジェクトへのインターフェイス

レスポンスを送信するためにHTTPに依存する機能を提供するためにServletResponseインターフェイスを拡張したのが、HttpServletResponseインターフェイスである。例えば、HTTPヘッダーやボディにアクセスするためのメソッドを持っている。

WebコンテナはHttpServletResponseオブジェクトを生成して、それをサービスメソッド(doGet, doPostなど)に引数として渡す。

サーブレットは、引数として渡されたHttpServletResponseオブジェクトに対してメソッドを介して情報を読んだり書き込んだりする。それぞれのメソッドの詳細は別の記事で見ることができる。

まとめ

HttpServletResponseインターフェイスは、レスポンスの送信に関して HTTP 独自の機能性を与えるためにServletResponse インタフェースを拡張したもの、という所がポイントだろう。アプリケーションによって生成されるWebページの構成がより自由に出来るということでもあるので覚えておきたい。

]]>
https://eng-entrance.com/java-servlet-httpservletresponse/feed 0
【Java & Tomcat】Webアプリケーションの設定(web.xmlの設定)※サンプルプログラム付き https://eng-entrance.com/servlet-web-xml https://eng-entrance.com/servlet-web-xml#respond Sun, 21 Apr 2019 01:52:42 +0000 https://eng-entrance.com/?p=7240 この記事ではJavaで作成したWebアプリケーションを動作させる際に使用する環境設定ファイルについて説明する。

Webアプリケーションの設定とは

最初にWebアプリケーションがどのように動いているかを簡単に説明しよう。ユーザがブラウザの画面に表示された絵や文章とリンクしたURL (http://www.linuxacademy.ne.jp/servlet など)を選ぶか、直接ブラウザにURLを入力すると、選んだリンク先の画面がブラウザに表示される。この時、何が起きているかと言うと、ブラウザからWebサーバーに送られてきたリクエストに対してレスポンスを返すよう設定されたサーブレットが起動されている。そして、そのサーブレットが返すレスポンスによって、次の画面が表示される。このリクエストとサーブレットの関係を設定することを「Webアプリケーションの設定」と呼んでいる。

Webアプリケーションを動かすためには、ただサーブレットクラスを作成するだけでは足りない。クライアントからのリクエストに対応するサーブレットを設定するとことをマッピング(紐付け)と呼ぶ。

このマッピングのために必要な基本的な情報は次の通りである。

  • URLパス:サーブレットを起動するためのパス

例: http://www.linuxacademy.ne.jp/servlet

  • コンテキストルート(Context-root):;サーブレットやHTMLやWebアプリケーションの設定などが入っている一番上位のディレクトリ

例: C:\WebApplication

  • サーブレットの完全修飾名:パッケージ名とクラス名の両方を持つクラス名

例: sample.Servlet

クライアントがリクエストにURLパスを指定してWebサーバーに送ると、WebサーバーにあるWebコンテナが対応するサーブレットにリクエストを渡してくれる。この時、URLパスの中のurl-patternからサーブレットへのマッピングは、web.xml(ディプロイメント・デスクリプタとも呼ばれる)にアプリケーション設定情報として登録されている。次の図はリクエストのURLパスからどのように、サーブレットへマッピングされるかを示している。

web.xmlの設定の仕方

web.xmlとは、Webアプリケーションを動かすために関係する環境(サーブレット、HTMLファイルなど)を設定するためのファイルである。Java EEの最新のバージョンでは、web.xmlを使わなくても替わりにアノテーションを使うことができる。web.xmlを使うかどうかは選択できる。

その基本的な設定の仕方を見てみよう。

次の図は、どのようにurl-patternがサーブレットにマッピング情報として登録されているかを示している。url-patternがservlet-nameにマッピングされ、そのservlet-nameからservlet-classへとマッピングされる。

例えば、

  • リクエストのurl-patternがApplication1であれば
  • url-pattern:Application1が一致するのは<servlet-mapping>の<url-pattern>:Application1である。
  • <url-pattern>:Application1に<servlet-name >のservlet1の名前が付けられている。
  • <servlet-name>のservlet1が<servlet>の<servlet-name>:servlet1にマッピングされている。
  • <servlet-name>のservlet1に<servlet-class>ApplicationServlet1がサーブレットとして割り当てられる。

バージョン

このドキュメントを書くために使用した各コンポーネントのバージョンを示す。次のセクションの「名前空間宣言とスキーマロケーション」などは、このバージョンに対応して定義されているので注意が必要である。

構成要素 バージョン
Servlet 3.1.
Apache Tomcat 8.5.
JRE 1.8

名前空間宣言とスキーマロケーション

web.xmlファイルの先頭に「名前空間宣言とスキーマロケーション」を必ず記述しなければならない。

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">

サーブレット<servlet>

サーブレット<servlet>要素は、サーブレットについて名前やクラスなのどのデータを、必要に応じ宣言できる。以下にそれらのデータを扱うための要素をあげる。

要素 必須 内容
<servlet-name> サーブレットの標準的な名前で、web.xml(ディプロイメント・デスクリプタ)の中でサーブレットの定義を参照するために用いられる名前を定義する。
<display-name> GUIツールによって表示するための短い名前。
<description> サーブレットのテキスによる説明。
<servlet-class> サーブレットの完全修飾名。

Servlet 3.0以降、<servlet-class> と<jsp-file>はオプションである。<servlet-class> と<jsp-file>なしの環境設定は、予備とみなされている;プログラムで動的にサーブレットを登録するためのサーブレットAPIを使用すべきである。その他は、配置が失敗する。

<jsp-file> Webアプリケーション内のJSPファイルへのフルパス、つまりWebアプリケーションのルートに対する相対ディレクトリである。

Servlet 3.0以降、<servlet-class> と<jsp-file>はオプションである。<servlet-class> と<jsp-file>なしの環境設定は、予備とみなされている;プログラムで動的にサーブレットを登録するためのサーブレットAPIを使用すべきである。その他は、配置が失敗する。

<init-param> サーブレットの初期属性の名前と値のペアーを含む。

各属性のための<init-param>タグのセットをセパレータに使ってください。

<load-on-startup> WebLogicサーバーはWebLogicサーバーが立ち上がったとき、サーブレットを初期化する。要素のオプションである値は、サーブレットがロードされる順番を表す正の整数でなければならない。低い整数値が高い整数値よりも先にロードされる。もし、値が特定できないか、またはもし値が正の整数値でなければ、WebLogicサーバーはアプリケーションが立ち上がっている間にサーブレットをなんらかの順番でロードする。
<run-as>   アプリケーション実行のために使用されるrun-as認証として指定される。
<security-role-ref>   サーブレットロジックの中に直接コードで書かれた代替ロール名に<security-role>によって定義されたセキュリティロール名をリンクするために使われる。抽象的に拡張されたレイヤーはサーブレットにサーブレットのコードの変更なしに配置を構成することを許す。

必須項目の「-」:オプションの意味である。

サーブレット・マッピング<servlet-mapping>

サーブレット・マッピング<servlet-mapping>要素はサーブレットとURLパターンの紐付けを行う。以下にそのマッピングを行うための要素をあげる。

要素 内容
<servlet-name> servletの<servlet-name>と同じ。
<url-pattern> URLを解決するために用いるパターンを記述する。

「http://host:port + WebAppName」に続く部分はWebLogic Server によって<url-pattern>と比較される、もしパターンが一致すれば、サーブレットはこの要素に紐付けされたサーブレットが呼び出される。

 

パターンの例:

/soda/grape/*,  /foo/* ,  /contents,  *.foo

 

URLはサーブレット3.0仕様に規定された規則に従わなければならない。サーブレット・マッピングの付加的な例は、サーブレット・マッピングを参照してください。

シンプルなweb.xmlのサンプルプログラム

このサンプルプログラムは、シンプルなweb.xmlを使ったものだ。クライアントからのリクエストがサーブレットクラスを呼び出す。そのサーブレットは「Hello World!」を表示するレスポンスを返す。その手順とレスポンスによって表示される画面は実行結果で確認できる。

web.xmlの定義

URLパスよって呼び出されるサーブレットクラスの場所は次の図の通りである。また、URLパスとサーブレットのマッピングはweb.xmlに定義されている。

これが、web.xmlである。ひとつのサーブレットがマッピングされている。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <servlet>
    <servlet-name>helloworld</servlet-name>
    <servlet-class>HelloWorld</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>helloworld</servlet-name>
    <url-pattern>/HelloWorld</url-pattern>
  </servlet-mapping>
</web-app>

サンプルプログラム

次のプログラムは、HttpServletクラスを継承して作成されたサーブレットクラスである。リクエストメソッドはGETに対応したdoGet()メソッドのみが実装されている。

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloWorld extends HttpServlet {//[]1]
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
           throws ServletException, IOException {//[2]
        response.setContentType("text/html");//[3]
        PrintWriter out = response.getWriter();//[4]
        out.println("<html><head></head><body>");//[5]
        out.println("<p>Simple Application</p>");//[6]
        out.println("<p>Hello World!</p>");//[7]
        out.println("</body></html>");//[8]
    }
}

実行結果

コンテキストルートはServletSimpleXMLなので、クライアントからのパスは以下のようになる。

http://localhost:8080/ServletSimpleXML/HelloWorld

次の画面は、web.xmlの設定に対してパスをIEのアドレスに入力した結果である。

サンプルプログラムの説明

それでは簡単にプログラムの解説をしていこう。

  • [1] HttpServletを継承して、HelloWorldクラスを定義する。
  • [2] doGet()メソッドをオーバーライドして定義する。
  • [3] Content Typeに「text/html」を設定する。
  • [4] HTMLを出力するためのoutオブジェクトを取得する。
  • [5]-[8] outオブジェクトに「Simple Application」と「Hello World!」を表示するHTMLコードを出力する。

パッケージに入ったサーブレットのweb.xml

前のセクションのサンプルプログラムは、サーブレットがパッケージ入っていないシンプルなweb.xmlファイルだった。今度は、そのサーブレットが次のように「sample」というパッケージに入っている。この場合は、パッケージ名も含めた完全修飾名でサーブレットを定義しなければならない。

これがweb.xmlの定義の中の完全修飾名でサーブレットが定義されている部分だ。

<servlet>
    <servlet-name>helloworld</servlet-name>
    <servlet-class>sample.HelloWorld</servlet-class>
  </servlet>

では、web.xmlの全体を見てみよう。

web.xmlの定義

URLパスよって呼び出されるサーブレットクラスの場所は次の図の通りである。また、URLパスとサーブレットのマッピングはweb.xmlに定義されている。

これが、web.xmlである。パッケージの名前が付いたサーブレットがマッピングされている。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <servlet>
    <servlet-name>helloworld</servlet-name>
    <servlet-class>sample.HelloWorld</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>helloworld</servlet-name>
    <url-pattern>/HelloWorld</url-pattern>
  </servlet-mapping>
</web-app>

サンプルプログラム

サンプルプログラムのコードは、基本的に「シンプルなweb.xmlのサンプルプログラム」と同じである。違いは、最初の行にパッケージの宣言があるだけだ。

package sample;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloWorld extends HttpServlet {//[]1]
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {//[2]
        response.setContentType("text/html");//[3]
        PrintWriter out = response.getWriter();//[4]
        out.println("<html><head></head><body>");//[5]
        out.println("<p>Simple Application</p>");//[6]
        out.println("<p>Hello World!</p>");//[7]
        out.println("</body></html>");//[8]
    }
}

実行結果

コンテキストルートはServletPackageXMLなので、クライアントからのパスは以下のようになる。

http://localhost:8080/ServletPackageXML/HelloWorld

レスポンス画面は、「シンプルなweb.xmlのサンプルプログラム」に同じになる。

サンプルプログラムの説明

プログラムのコードも、パッケージの宣言を除いて「シンプルなweb.xmlのサンプルプログラム」に同じである。

web.xmlの<init-param>による初期設定

このサンプルプログラムは、web.xmlの<servlet>要素に<init-param>要素を追加して、サーブレットに初期属性を渡している。サーブレットは、その初期属性を使って「Hello World!」に続いて都市と国を表示するレスポンスを返す。そのレスポンスによって初期属性が表示される画面を実行結果のセクションで確認できる。

web.xmlの定義

URLパスによって呼び出されるサーブレットクラスの場所は次の図の通りである。また、URLパスとサーブレットのマッピングはweb.xmlに定義されている。

これが、web.xmlである。サーブレットの初期属性が<init-param>要素の<param-name>要素と<param-value>要素のペアーに設定されている。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <servlet>
    <servlet-name>helloworld</servlet-name>
    <servlet-class>HelloWorld</servlet-class>
    <init-param>
      <param-name>country</param-name>
      <param-value>Japan</param-value>
    </init-param>
    <init-param>
      <param-name>city</param-name>
      <param-value>Tokyo</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>helloworld</servlet-name>
    <url-pattern>/HelloWorld</url-pattern>
  </servlet-mapping>
</web-app>

サンプルプログラム

このプログラムは、HttpServletクラスを継承して作成されたサーブレットクラスである。リクエストメソッドはGETに対応したdoGet()メソッドのみが実装されている。web.xmlで設定された初期属性をgetInitParameter()メソッドで取得して、レスポンスの中で表示している。

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloWorld extends HttpServlet {//[]1]
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {//[2]
        String country = getInitParameter("country");//[3]
        String city = getInitParameter("city");//[4]

        response.setContentType("text/html");//[5]
        PrintWriter out = response.getWriter();//[6]
        out.println("<html><head></head><body>");//[7]
        out.println("<p>Simple Application</p>");//[8]
        out.println("<p>Hello World! from " + city + " " + country + ".</p>");//[9]
        out.println("</body></html>");//[10]
    }
}

実行結果

コンテキストルートはServletInitParamXMLなので、クライアントからのパスは以下のようになる。

http://localhost:8080/ServletInitParamXML/HelloWorld

次の画面は、web.xmlの設定に対してパスをIEのアドレスに入力した結果である。

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] HttpServletを継承して、HelloWorldクラスを定義する。
  • [2] doGet()メソッドをオーバーライドして定義する。
  • [3] Content Typeに「text/html」を設定する。
  • [4] getInitParameter()メソッドでパラメータ名:countryを取得し、変数countryに代入する。
  • [5] getInitParameter()メソッドでパラメータ名:cityを取得し、変数cityに代入する。
  • [6] HTMLを出力するためのoutオブジェクトを取得する。
  • [7]-[10] outオブジェクトに「Simple Application」と「Hello World! from + (都市名:変数city) + (国名:変数country)」を表示するHTMLコードを出力する。

デフォルトサーブレット

このサンプルプログラムは、デフォルトサーブレットのweb.xml宣言を示すものである。デフォルトサーブレットは、WebコンテナがURLパターンからサーブレットを選択しようとしてサーブレットが見つからないときに呼び出される。

web.xmlの定義

URLパスよって呼び出されるサーブレットクラスの場所は次の図の通りである。また、URLパスとサーブレットのマッピングはweb.xmlに定義されている。

これが、web.xmlである。HelloWorldとDefaultServletのふたつが定義されている。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <servlet>
    <servlet-name>helloworld</servlet-name>
    <servlet-class>HelloWorld</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>defaultservlet</servlet-name>
    <servlet-class>DefaultServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>helloworld</servlet-name>
    <url-pattern>/HelloWorld</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>defaultservlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

サンプルプログラム

サンプルプログラムのHelloWorldは、「シンプルなweb.xmlのサンプルプログラム」と同じである。またDefaultServletも、基本的に「シンプルなweb.xmlのサンプルプログラム」と同じである。違いは、クラスの名前と画面の表示だけである。

ここでは、DefaultServletのコードだけを掲載する。HelloWorldは「シンプルなweb.xmlのサンプルプログラム」のセクションを参照してください。

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DefaultServlet extends HttpServlet {//[1]
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {//[2]
        response.setContentType("text/html");//[3]
                       PrintWriter out = response.getWriter();//[4]
                       out.println("<html><head></head><body>");//[5]
                       out.println("<p>Servlet not found.</p>");//[6]
                       out.println("<p>Default Servlet</p>");//[7]
                       out.println("</body></html>");//[8]
                   }
}

実行結果

コンテキストルートはServletDefaultXMLなので、HelloWorldを呼び出すクライアントからのパスは以下のようになる。

http://localhost:8080/ServletDefaultXML/HelloWorld

次の画面は、このパスをIEのアドレスに入力した結果である。

コンテキストルートはServletDefaultなので、存在しないURLパターンHelloXXXXXを呼び出すクライアントからのパスは以下のようになる。

http://localhost:8080/ServletDefaultXML/HelloXXXXX

次の画面は、このパスをIEのアドレスに入力した結果である。

サンプルプログラムの説明

それでは簡単にデフォルトサーブレットのプログラムの解説をしてゆこう。

  • [1] HttpServletを継承して、HelloWorldクラスを定義する。
  • [2] doGet()メソッドをオーバーライドして定義する。
  • [3] Content Typeに「text/html」を設定する。
  • [4] HTMLを出力するためのoutオブジェクトを取得する。
  • [5]-[8] outオブジェクトに「DefaultServlet」を表示するHTMLコードを出力する。

まとめ

この記事では環境設定用にweb.xmlファイルを作成してWebアプリケーションを動作させる、という手法について説明した。実際にサンプルプログラムを動作させながら仕組みについて理解を深めよう。

]]>
https://eng-entrance.com/servlet-web-xml/feed 0
【Java & Tomcat】Webアプリケーションの設定(マッピング)※サンプルプログラム付き https://eng-entrance.com/java-servlet-mapping https://eng-entrance.com/java-servlet-mapping#respond Sun, 31 Mar 2019 09:36:01 +0000 https://eng-entrance.com/?p=7258 この記事ではJavaで作成したWebアプリケーションを動作させる際に、URLパスと実ファイルを結びつける「マッピング」というものについて説明する。

マッピングとは

マッピングとは、Webコンテナがサーブレットを選んでクライアントのリクエストを渡すためのものである。

下の図が示すように、クライアントのリクエストは、URLパスを含んでいる。さらに、このURLパスは、コンテキストルートとURLパターンを持っている。この二つの情報からサーブレットは選択され、クライアントからのリクエストが渡される。

サーブレット選択のためのURLパスの使用

どのようにWebコンテナがURLパスからサーブレットを選ぶかを見ていこう。まず、コンテキストルートを選択するところから始まる。サーブレットが配置されているディレクトリの一番上にあるのがコンテキストルートである。

このコンテキストルートが見つかったら、次に以下の順序でWebコンテナはURLパターンからサーブレットを選ぶ。

  1. URLパターンが正確に一致する。
  2. URLパターンがパスマッピングで一致する。
  3. URLパターンが拡張子マッピングで一致する。
  4. どのURLパターンにも一致しない。

Webコンテナは、大文字と小文字を区別してマッチングのための文字列比較を行う。この時、どのようにそのURLパスの中のURLパターンとサーブレットのURLパターンが比較されるかを、サーブレットを選ぶ順序で見ていこう。

これからの説明で使われるサンプルに登場するサーブレットは次の配置になっている。

URLパターンの正確な一致

URLパターンが正確に一致するとは、URLパスの中のURLパターンとサーブレットのURLパターンの一文字一文字が正確に一致しているということである。

例を見てみよう。URLパスが次のようであれば、URLパターンは「/juice」となる。

http://localhost:8080/Servlet/juice

このURLパターンに一致するのは「/juice」だけである。他のどんな文字列も不一致となる。

URLパスのURLパターン サーブレットのURLパターン 一致 選択
/juice /juice
/JuiCe × ×
/juice以外のすべてのパターン × ×

URLパスの「/juice」と正確に一致するURLパターンをアノテーションとweb.xmlで宣言すると次のようになる。

アノテーション

このコードがサーブレットのためのアノテーションである。サーブレットのクラス宣言の直前に書くことによってURLパターン「/juice」がマッピングされる。

@WebServlet("/juice")

web.xml

web.xmlによる定義は、サーブレットクラスが一度サーブレット名に紐付けされ、さらにサーブレット名がURLパターンに紐付けされる。このURLパターンがサーブレットのURLパターンとなる。

URLパターン

<url-pattern>

サーブレット名

<servlet-name>

サーブレットクラス

<servlet-class>

/juice servlet1 Servlet1

この関係を定義したweb.xmlを次に示す。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <servlet>
    <servlet-name>servlet1</servlet-name>
    <servlet-class>Servlet1</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>servlet1</servlet-name>
    <url-pattern>/juice</url-pattern>
  </servlet-mapping>
</web-app>

サンプルプログラム

このプログラムが、URLパターン「/juice」からマッピングされるサーブレットのクラスである。ここでは、アノテーション@WebServlet()を用いてURLパターンの宣言を行ったが、web.xmlによる宣言を行う時はアノテーションの宣言は不要である。

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("/juice")//[1]
public class Servlet1 extends HttpServlet {//[2]
                   protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                                        throws ServletException, IOException {//[3]
                       PrintWriter out = response.getWriter();//[4]
                       out.println("[5] Servlet1");
                   }
}

実行結果

ブラウザにURLパス:http://localhost:8080/Servlet/juice  を入力し、Enterを押す。

表示されるブラウザ画面:

ブラウザにURLパス:http://localhost:8080/Servlet/JuiCeを入力し、Enterを押す。

表示されるブラウザ画面:サーブレットが選択できなかったことを示す画面が表示される。

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションによりURLパターン「/juice」を宣言する。
  • [2] HttpServletを継承して、Servlet1クラスを定義する。
  • [3] doGet()メソッドをオーバーライドして定義する。
  • [4] HTMLを出力するためのoutオブジェクトを取得する。
  • [5] outオブジェクトに「Servlet1」を出力する。

URLパターンのパスマッピング

パスマッピングとは、サーブレットに紐つけられたURLパターンとして、「/water/*」のような「/」で始まり「/*」の末尾で終わる文字列を使って一致するURLパターンを探すものだ。この「/」で始まり「/*」の末尾で終わる文字列をパス・プレフィックス(接頭辞)という。パスマッピングで「/*」は、「/*」以降の文字列がどんな文字列にも当てはまるものとされる。

Webコンテナは最も長いパス・プレフィックスと一致するパスを見つけようとする。例えば、URLパスのURLパターンが「/soda/grape/index.html」ならば、サーブレットのURLパターンはパス・プレフィックス「/soda/*」と「/soda/grape/*」の両方に一致する。この時、Webコンテナは「/」文字をセパレータとして、パスツリーを先頭のディレクトリから比較し、次のディレクトリというようにひとつずつ降りながら比較する。こうしてサーブレットのURLパターンの中で最も長い一致を選択する。それで、この場合は2番目のディレクトリも一致する「/soda/grape/*」が選択されることになる。

例を見てみよう。

URLパス:http://localhost:8080/Servlet/soda/grape/index.html

このURLパターン「/soda/grape/index.html」から選択されるのは、先に説明したように「/soda/*」より長い一致を持つパス・プレフィックス「/soda/grape/*」である。

URLパスのURLパターン サーブレットのURLパターン 一致 選択
/soda/grape/index.html /soda/grape/*
/soda/* ×
/water/* × ×

URLパス:http://localhost:8080/Servlet/soda/grape/index.bop

このURLパターン「/soda/grape/index.bop」からは、前と同じようにより長い「/soda/grape/*」が選択される。

URLパスのURLパターン サーブレットのURLパターン 一致 選択
/soda/grape/index. bop /soda/grape/*
/soda/* ×
/water/* × ×

URLパス:http://localhost:8080/Servlet/soda/index.html

このURLパターン「soda/index.html」は「/soda/*」には一致するものの「/soda/grape/*」には一致しないので、このURLパターンから選択されるのは、「/soda/*」となる。

URLパスのURLパターン サーブレットのURLパターン 一致 選択
/soda/grape/index.html /soda/grape/* × ×
/soda/*
/water/* × ×

URLパス:http://localhost:8080/Servlet/water/*

このURLパターン「/water/*」は「/water/*」に一致し、他のパターンには一致しないので、このURLパターンから選択されるのは、「/water/*」となる。

URLパスのURLパターン サーブレットのURLパターン 一致 選択
/soda/grape/index.html /soda/grape/* × ×
/soda/* × ×
/water/*

URLパス:http://localhost:8080/Servlet/water/index.html

このURLパターン「/water/index.html」は「/water/*」に一致し、このURLパターンから選択されるのは、「/water/*」となる。

URLパスのURLパターン サーブレットのURLパターン 一致 選択
/soda/grape/index.html /soda/grape/* × ×
/soda/* × ×
/water/*

アノテーション

このコードがサーブレットのためのアノテーションである。サーブレットのクラス宣言の直前に書くことによってURLパターンがサーブレットへ次のようにマッピングされる。

  • /soda/grape/* → Servlet2
  • /water/* → Servlet3
  • / soda /* → Servlet4

実際のコードの宣言部分は次のようになる。

@WebServlet("/soda/grape/*")
public class Servlet2 extends HttpServlet {
              …..
}
@WebServlet("/soda/*")
public class Servlet3 extends HttpServlet {
              …..
}
@WebServlet("/water/*")
public class Servlet4 extends HttpServlet {
              …..
}

web.xml

web.xmlによる定義は、サーブレットクラスが一度サーブレット名に紐付けされ、さらにサーブレット名がURLパターンに紐付けされている。このURLパターンがサーブレットのURLパターンとなる。

URLパターン

<url-pattern>

サーブレット名

<servlet-name>

サーブレットクラス

<servlet-class>

/soda/grape/* servlet2 Servlet2
/soda/* servlet3 Servlet3
/water/* servlet4 Servlet4

この関係を定義したweb.xmlを次に示す。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <servlet>
    <servlet-name>servlet4</servlet-name>
    <servlet-class>Servlet4</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>servlet3</servlet-name>
    <servlet-class>Servlet3</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>servlet2</servlet-name>
    <servlet-class>Servlet2</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>servlet4</servlet-name>
    <url-pattern>/water/*</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>servlet3</servlet-name>
    <url-pattern>/soda/*</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>servlet2</servlet-name>
    <url-pattern>/soda/grape/*</url-pattern>
  </servlet-mapping>
</web-app>

サンプルプログラム

このプログラムが、URLパターン「/juice」からマッピングされるサーブレットのクラスである。ここでは、アノテーション@WebServlet()を用いてURLパターンの宣言を行ったが、web.xmlによる宣言を行う時はアノテーションの宣言は不要である。

(import は全てServlet1と同じ)
@WebServlet("/soda/grape/*")//[1]
public class Servlet2 extends HttpServlet {//[2]
                   protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                                        throws ServletException, IOException {//[3]
                       PrintWriter out = response.getWriter();//[4]
                       out.println("[5] Servlet2");
                   }
}

 

(import は全てServlet1と同じ)
@WebServlet("/soda/*")//[1]
public class Servlet3 extends HttpServlet {//[2]
                   protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                                        throws ServletException, IOException {//[3]
                       PrintWriter out = response.getWriter();//[4]
                       out.println("[5] Servlet3");
                   }
}

 

(import は全てServlet1と同じ)
@WebServlet("/water/*")//[1]
public class Servlet4 extends HttpServlet {//[2]
                   protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                                        throws ServletException, IOException {//[3]
                       PrintWriter out = response.getWriter();//[4]
                       out.println("[5] Servlet4");
                   }
}

 

実行結果

ブラウザにURLパス:http://localhost:8080/Servlet/soda/grape/index.htmlを入力し、Enterを押す。

表示されるブラウザ画面:

ブラウザにURLパス:http://localhost:8080/Servlet/soda/grape/index.bopを入力し、Enterを押す。

表示されるブラウザ画面:

ブラウザにURLパス:http://localhost:8080/Servlet/soda/index.htmlを入力し、Enterを押す。

表示されるブラウザ画面:

ブラウザにURLパス:http://localhost:8080/Servlet/grape/ water/*を入力し、Enterを押す。

表示されるブラウザ画面:

ブラウザにURLパス:http://localhost:8080/Servlet/water/index.htmlを入力し、Enterを押す。

表示されるブラウザ画面:

サンプルプログラムの説明

どのサーブレットも、URLパターンと表示するサーブレットの番号が異なるだけで、それ以外は「URLパターンの正確な一致」のセクションのServlet1と同じコードになっている。

URLパターンの拡張子マッピング

URLパス最後の部分が拡張子(例:.jspなど)を含んでいたならば、コンテナは、その拡張子のためのリクエストを処理するサーブレットを見つけようとする。拡張子は、「.」文字の後の部分として定義されている。

サーブレットに紐付けされたURLパターンが「*.」で始まるならば、拡張子マッピングのために使われる。

URLパス:http://localhost:8080/Servlet/juice/orange.jsp

URLパス:http://localhost:8080/Servlet/index.jsp

これらのURLパターン「/juice/orange.jsp」と「/index.jsp」は、拡張子が「jsp」なので、このURLパターンから選択されるのは、「*.jsp」となる。

URLパスのURLパターン サーブレットのURLパターン 一致 選択
/juice/orange.jsp *.jsp
*.xxx × ×
/index.jsp *.jsp
*.xxx × ×

アノテーション

このコードがサーブレットのためのアノテーションである。サーブレットのクラス宣言の直前に書くことによってURLパターン「*.jsp」がマッピングされる。

@WebServlet("*.jsp")

web.xml

web.xmlによる定義は、サーブレットクラスが一度サーブレット名に紐付けされ、さらにサーブレット名がURLパターンに紐付けされている。このURLパターンがサーブレットのURLパターンとなる。

URLパターン

<url-pattern>

サーブレット名

<servlet-name>

サーブレットクラス

<servlet-class>

*.jsp servlet5 Servlet5

この関係を定義したweb.xmlを次に示す。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <servlet>
    <servlet-name>servlet5</servlet-name>
    <servlet-class>Servlet5</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>servlet5</servlet-name>
    <url-pattern>*.jsp</url-pattern>
  </servlet-mapping>
</web-app>

サンプルプログラム

このプログラムが、URLパターン「*.jsp」からマッピングされるサーブレットのクラスである。ここでは、アノテーション@WebServlet()を用いてURLパターンの宣言を行ったが、web.xmlによる宣言を行う時はアノテーションの宣言は不要である。

(import は全てServlet1と同じ)
@WebServlet("*.jsp")//[1]
public class Servlet5 extends HttpServlet {//[2]
                   protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                                        throws ServletException, IOException {//[3]
                       PrintWriter out = response.getWriter();//[4]
                       out.println("[5] Servlet5");
                   }
}

実行結果

ブラウザにURLパス:http://localhost:8080/Servlet/*.jspを入力し、Enterを押す。

表示されるブラウザ画面:

ブラウザにURLパス:http://localhost:8080/Servlet/index.jspを入力し、Enterを押す。

表示されるブラウザ画面:

サンプルプログラムの説明

どのサーブレットも、URLパターンと表示するサーブレットの番号が異なるだけで、それ以外は「URLパターンの正確な一致」のセクションのServlet1と同じコードになっている。

どのURLパターンにも一致しない

もしサーブレットの選択において前の3つの規則(正確な一致、パスマッピング、拡張子マッピング)のどれにも当てはまらなかったなら、Webコンテナは要求されたものに替わる適切なコンテンツを使おうとする。もし、アプリケーションのためにデフォルトサーブレットが定義されていたならば、それが使われる。多くのWebコンテナが供給されているコンテンツのためにデフォルトサーブレットを提供している。

サーブレットに紐付けされたURLパターンが文字「/」だけならば、デフォルトサーブレットを定義していることになる。このため、どのURLパターンにも一致しない場合は、このデフォルトサーブレットが選択される。

デフォルトサーブレットは、「Webアプリケーションの設定(アノテーション)」か「Webアプリケーションの設定(web.xmlの設定)」の記事で説明しているので参考にできる。

まとめ

この記事では入力されたURLによってマッピングされたそれぞれ別のサーブレットによる出力が出てくる事を確認した。実際にサンプルプログラムを動作させながら仕組みについて理解を深めよう。

]]>
https://eng-entrance.com/java-servlet-mapping/feed 0
【Java & Tomcat】コンテンツタイプの設定(setContentType)※サンプルプログラム付き https://eng-entrance.com/java-servlet-content-type https://eng-entrance.com/java-servlet-content-type#respond Sun, 24 Mar 2019 09:38:00 +0000 https://eng-entrance.com/?p=7278 この記事ではWebアプリケーションの出力結果に影響する「コンテンツタイプ」の設定について説明する。

コンテンツタイプの設定の仕方

コンテンツタイプの設定とは、クライアントサーバー間のコンテンツの種類を設定することである。コンテンツの種類には次のようなものがある。実際に設定する時は、MIMEタイプを使用して設定を行う。

コンテンツの種類

MIMEタイプ

HTML文章

text/html

JPEG画像

image/jpeg

PDF文書

application/pdf

このコンテンツタイプは、HttpServletResponse.オブジェクトのメソッドを呼び出すことにより設定できる。

書き方の基本は簡単だ。

HttpServletResponseオブジェクト.setContentType(java.lang.String type);

実際のコードはこうなる。

response.setContentType("text/html");

また、コンテンツの中で使われる文字コード(Shift_JISやUTF-8など)も、日本語を表示させる場合に設定する。

response.setContentType("text/html; charset=Shift_JIS");

文字コードをsetCharacterEncoding()メソッドで単独で設定するとこともできる。

HttpServletResponseオブジェクト. setCharacterEncoding (java.lang.String type);

注意点として、サーブレットは、レスポンスのgetWriterメソッドを呼び出す前に、また、レスポンスをコミットする前にsetContentTypeメソッドを呼び出さなければならない。そうしないとsetContentTypeメソッドによる設定は無効になってしまう。

setContentTypeのAPI仕様

setContentTypeのAPI仕様をここに示しておこう。

setContentType(java.lang.String type)

戻り値の型

void

内容

もしレスポンスがまだコミットされていないならば、クライアントに送るレスポンスのコンテンツタイプを設定する。

与えられたコンテンツタイプは、設定をコード化する文字列、例えば、「text/html; charset=UTF-8」といった文字列を含むかもしれない。getWriterメソッドが呼び出される前にこのメソッドが呼び出された時だけ、レスポンスの文字コードは与えられたコンテンツタイプに設定される。

このメソッドは、コンテンツタイプと文字コードを変えるために繰り返し呼び出されるかもしれない。もしレスポンスがコミットされた後に呼び出されるならば、このメソッドは無効になる。 もし、getWriterメソッドが呼び出された後かもしくはレスポンスがコミットされた後に、呼び出されるならば、それはレスポンスの文字コードを設定しない。

もしプロトコルがそうする方法を提供するなら、コンテナはサーブレットのレスポンスのライターのために使われるコンテンツタイプと文字コードを、クライアントへ知らせなければならない。HTTPの場合は、コンテンツタイプヘッダーが使われる。

 

引数:type - コンテンツのMIMEタイプを指定する文字列

 

参照:setLocale(java.util.Locale), setCharacterEncoding(java.lang.String),

getOutputStream(), getWriter()

setContentTypeを使用しないサンプルプログラム

このサンプルプログラムは、setContentTypeを使わずに半角英数字と日本語を表示する。この場合、文字コードが設定されていないので、日本語が正しく表示されない。

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("/NotSetContentType")//[1]
public class NotSetContentType extends HttpServlet {//[2]
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {//[3]
        PrintWriter out = response.getWriter();//[4]
        out.println("<html><head></head><body>");//[5]
        out.println("<p>abcdefABCDEF</p>");//[6]
        out.println("<p>あいうえおかきくけこ</p>");//[7]
        out.println("</body></html>");//[8]
    }
}

実行結果

ブラウザにURL:http://localhost:8080/Servlet/NotSetContentTypeを入力し、Enterを押す。

表示されるブラウザ画面:

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] HttpServletを継承して、NotSetContentTypeクラスを定義する。
  • [3] doGet()メソッドをオーバーライドして定義する。
  • [4] HTMLを出力するためのPrintWriterオブジェクトを取得する。
  • [5]-[8] PrintWriterオブジェクトに「abcdefABCDEF」と「あいうえおかきくけこ」を表示するHTMLコードを出力する。

setContentTypeを使用したサンプルプログラム

このサンプルプログラムは、setContentTypeを使ってMIMEタイプと文字コードの設定を行い、半角英数字と日本語を表示する。この設定は、レスポンスのgetWriterメソッドを呼び出す前に行われている。この場合、日本語も正しく表示される。

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("/SetContentType")//[1]
public class SetContentType extends HttpServlet {//[2]
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {//[3]
        response.setContentType("text/html; charset=Shift_JIS");//[4]
        PrintWriter out = response.getWriter();//[5]
        out.println("<html><head></head><body>");//[6]
        out.println("<p>abcdefABCDEF</p>");//[7]
        out.println("<p>あいうえおかきくけこ</p>");//[8]
        out.println("</body></html>");//[9]
    }
}

実行結果

ブラウザにURL:http://localhost:8080/Servlet/SetContentTypeを入力し、Enterを押す。

表示されるブラウザ画面:

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] HttpServletを継承して、SetContentTypeクラスを定義する。
  • [3] doGet()メソッドをオーバーライドして定義する。
  • [4] Content Typeを設定する。
  • [5] HTMLを出力するためのPrintWriterオブジェクトを取得する。
  • [6]-[9] PrintWriterオブジェクトに「abcdefABCDEF」と「あいうえおかきくけこ」を表示するHTMLコードを出力する。

まとめ

この記事では実際にsetContentTypeを使用するか、しないかで出力結果が大きく異なることを確認した。サンプルプログラムを実際に動作させて確かめてみよう。

]]>
https://eng-entrance.com/java-servlet-content-type/feed 0
【Java & Tomcat】サーブレットのライフサイクル ※サンプルプログラム付き https://eng-entrance.com/servlet-lifecycle https://eng-entrance.com/servlet-lifecycle#respond Sat, 16 Mar 2019 06:12:58 +0000 https://eng-entrance.com/?p=7210 この記事ではサーブレットのライフサイクルについて説明する。

ライフサイクルとは何か

サーブレット(Servlet)のライフサイクル(Servlet Life Cycle)とは、Webコンテナの中でサーブレットが生成されてから消去されるまでの過程である。サーブレットはJavaのクラスがそうであるようにインスタンスが生成され、そのインスタンスが要求されたサービスを実行する。そして、必要なくなったときに削除される。この過程がサーブレットのライフサイクルである。

この図は、サーブレットのライフサイクルを表したものである。

その詳細をはじまりから見てみよう。

はじまり

Javaで書かれたコードがコンパイルされてクラスファイルになる。そして、Webコンテナに配置されたところからサーブレットのライフサイクルが始まる。Webコンテナに配置されたサーブレットは、Webコンテナによってコントロールされる。そして、リクエストがサーブレットに割り当てられた時、Webコンテナは次のステップを実行する。

ステップ1:インスタンスの生成と初期化

もし、サーブレットのインスタンスが存在しなかったなら、Webコンテナは

  1. Servletクラスをロードする。
  2. Servletクラスのインスタンスを生成する。
  3. サーブレットのinit()メソッドを呼び出すことにより、サーブレットのインスタンスを初期化する。

ステップ2:リクエストによるサービスメソッド呼び出し

Webコンテナは、リクエストとレスポンス・オブジェクトを引数として渡すservive()メソッドを起動する。

インスタンスの削除:destroy()メソッド

もしインスタンスを削除することが必要であれば、Webコンテナはdestroy()メソッドを呼び出すことによりサーブレットを終了させる。

ライフサイクルイベント

サーブレットにはライフサイクルイベントを活用する仕組みがあり、サーブレットの状態を知ることができる。ライフサイクルイベントが発生した時、リスナーオブジェクトに呼び出されるメソッドを定義することによって、イベントをモニターしたり、対応した処理をしたりすることができる。

ライフサイクルイベントして活用できる主なものを以下に示す。コンテキストとは、実行情報のことである。

オブジェクト

イベントの詳細

Webコンテキスト

イベント:初期化と消滅。

Webアプリケーションのサーブレットコンテキスト(実行)の変化について通知するためのイベントである。

リスナークラス:javax.servlet.ServletContextListener
イベントクラス:javax.servlet.ServletContextEvent

セッション

イベント:生成、無効、有効、パッシベーション、タイムアウト

Webアプリケーション内のセッションの変化について通知するためのイベントである。

リスナークラス:
javax.servlet.http.HttpSessionListener, javax.servlet.http.HttpSessionActivationListener,

イベントクラス:
javax.servlet.http.HttpSessionEvent

リクエスト

イベント:サーブレトリクエストがWebコンポーネントによって処理されることが始まった。

 

リスナークラス:javax.servlet.ServletRequestListener

イベントクラス:javax.servlet. ServletRequestEvent

どのように活用できるのかを、サンプルプログラムで見てみよう。

ServletContextListenerの仕様

ServletContextListenerクラスにある二つのメソッドのAPI仕様を示す。

contextInitialized(ServletContextEvent sce)

戻り値の型

void

内容

ウェブアプリケーションの初期化のプロセスが始まっている通知である。すべてのサーブレットコンテキストのリスナーは、Webアプリケーションのどんなフィルターもしくはサーブレットでも、初期化される前にコンテキストの初期化を知らされている。

引数:
sce -初期化された サーブレットコンテキストについての情報

contextDestroyed(ServletContextEvent sce)

戻り値の型

void

内容

サーブレットコンテキストがシャットダウンされようとしている通知である。サーブレットコンテキストリスナーがコンテキストの破壊について知らされる前に、すべてのサーブレットとフィルターは破壊されてしまっている。

引数:sce - 破壊されたサーブレットコンテキストについての情報

HttpSessionListenerの仕様

HttpSessionListenerクラスにある二つのメソッドのAPI仕様を示す。

sessionCreated(HttpSessionEvent se)

戻り値の型

void

内容

セッションが生成されたことを通知。

引数:se – 通知イベント。

sessionDestroyed(HttpSessionEvent se)

戻り値の型

void

内容

セッションが無効になることを通知。

引数:se – 通知イベント。

ServletRequestListenerの仕様

ServletRequestListenerクラスにある二つのメソッドのAPI仕様を示す。

sessionCreated(HttpSessionEvent se)

戻り値の型

void

内容

Webアプリケーションのスコープから入ることを通知。

引数:sre – リクエストについての情報。

requestDestroyed(ServletRequestEvent sre)

戻り値の型

void

内容

Webアプリケーションのスコープから出ることを通知。

引数:sre – リクエストについての情報。

 

コンテキストイベントのサンプルプログラム

ライフサイクルイベントを受け取るためには、ListenerクラスにListenerインターフェースを実装することによって定義できる。このサンプルプログラムでは、コンテキストイベントをListenerクラスで受け取っている。その結果はログとして出力される。

このサンプルプログラムを実行させるために、Webサーバーを起動し、しばらく待ってWebサーバーを終了している。この手順で、下記の実行結果が得られる。

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener()//[1]
public class ContextEventListener  implements ServletContextListener {//[2]
    public void contextInitialized(ServletContextEvent event) {//[3]
        ServletContext context = event.getServletContext();//[4]
        context.log("[5]コンテキスト:開始");
    }
    public void contextDestroyed(ServletContextEvent event) {//[6]
        ServletContext context = event.getServletContext();//[7]
        context.log("コンテキスト:終了");//[8]
    }
}

実行結果

1 07, 2017 11:41:21 午後 org.apache.catalina.core.ApplicationContext log
情報: [5] コンテキスト:開始
1 07, 2017 11:41:29 午後 org.apache.catalina.core.ApplicationContext log
情報: [8] コンテキスト:終了

 

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] ServletContextListenerを継承して、ContextEventListenerクラスを提起する。
  • [3] 修飾子publicでメソッドcontextInitialized ()を宣言する。
  • [4] eventオブジェクトからコンテキストを取得する。
  • [5] 「コンテキスト:開始」をコンテキストのログに出力する。
  • [6] 修飾子publicでメソッドcontextDestroyed ()を宣言する。
  • [7] eventオブジェクトからコンテキストを取得する。
  • [8] 「コンテキスト:終了」をコンテキストのログに出力する。

セッションイベントのサンプルプログラム

ライフサイクルイベントを受け取るためには、ListenerクラスにListenerインターフェースを実装することによって定義できる。

import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent ;
import javax.servlet.http.HttpSessionListener;

@WebListener()//[1]
public class SessionEventListener  implements HttpSessionListener {//[2]
    public void sessionCreated(HttpSessionEvent  event) {//[3]
               HttpSession session = event.getSession();//[4]
        ServletContext context = session.getServletContext();//[5]
        context.log("[6] セッション開始: ID = " + session.getId());
    }
    public void sessionDestroyed(HttpSessionEvent event) {//[7]
               HttpSession session = event.getSession();//[8]
        ServletContext context = session.getServletContext();//[9]
        context.log("[10] セッション終了:ID = " + session.getId());
    }
}

実行結果

1 09, 2017 9:55:57 午前 org.apache.catalina.core.ApplicationContext log
情報: [6] セッション開始: ID = DF2FA0C602123211CF6FE75860B5836E
1 09, 2017 9:55:58 午前 org.apache.catalina.core.ApplicationContext log
情報: [10] セッション終了:ID = DF2FA0C602123211CF6FE75860B5836E

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] HttpSessionListenerを継承して、SessionEventListenerクラスを定義する。
  • [3] 修飾子publicでメソッドsessionCreated ()を宣言する。
  • [4] eventオブジェクトからセッションを取得する。
  • [5] sessionオブジェクトからコンテキストを取得する。
  • [6] 「セッション開始: ID =(セッションIDを取得)」をコンテキストのログに出力する。
  • [7] 修飾子publicでメソッドsessionDestroyed ()を宣言する。
  • [8] eventオブジェクトからリクエストを取得する。
  • [9] eventオブジェクトからコンテキストを取得する。
  • [10] 「セッション終了: ID =(セッションIDを取得)」をコンテキストのログに出力する。

リクエストイベントのサンプルプログラム

ライフサイクルイベントを受け取るためには、ListenerクラスにListenerインターフェースを実装することによって定義できる。

import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;

@WebListener()//[1]
public class RequestEventListener  implements ServletRequestListener {//[2]
    public void requestInitialized(ServletRequestEvent event) {//[3]
        ServletRequest request = event.getServletRequest();//[4]
        ServletContext context = event.getServletContext();//[5]
        context.log("[6] " + request.getRemoteAddr() + "のリクエストがスコープに入る");
    }
    public void requestDestroyed(ServletRequestEvent event) {//[7]
        ServletRequest request = event.getServletRequest();//[8]
        ServletContext context = event.getServletContext();//[9]
        context.log("[10] " + request.getRemoteAddr() + "のリクエストがスコープから出る");
    }
}

実行結果

1 08, 2017 1:26:16 午後 org.apache.catalina.core.ApplicationContext log
情報: [6] 0:0:0:0:0:0:0:1のリクエストがスコープに入る
1 08, 2017 1:26:16 午後 org.apache.catalina.core.ApplicationContext log
情報: [10] 0:0:0:0:0:0:0:1のリクエストがスコープから出る

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] ServletRequestListenerを継承して、RequestEventListenerクラスを定義する。
  • [3] 修飾子publicでメソッドrequestInitialized ()を宣言する。
  • [4] eventオブジェクトからリクエストを取得する。
  • [5] eventオブジェクトからコンテキストを取得する。
  • [6] 「(リクエストを出したクライアントのアドレス)のリクエストがスコープに入る」をコンテキストのログに出力する。
  • [7] 修飾子publicでメソッドrequestDestroyed ()を宣言する。
  • [8] eventオブジェクトからリクエストを取得する。
  • [9] eventオブジェクトからコンテキストを取得する。
  • [10] 「(リクエストを出したクライアントのアドレス)のリクエストがスコープから出る」をコンテキストのログに出力する。

イベント発生させたサーブレットプログラム

ライフサイクルイベントを受け取るためには、ListenerクラスにListenerインターフェースを実装することによって定義できる。

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 javax.servlet.http.HttpSession;

@WebServlet("/EventTest")//[1]
public class ServleEventTest extends HttpServlet {//[2]
                   public void init() throws ServletException{//[3]
                                     log("[4] init()");
                   }
                   protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                                        throws ServletException, IOException {//[5]
                                     PrintWriter out = response.getWriter();//[6]
                                     out.write("[7] Event Test Servlet => ");
                                    
                                     HttpSession session = request.getSession(false);//[8]
                                     if (session == null){//[9]
                                                        session = request.getSession(true);//[10]
                                                        out.write("[11] Session has started");
                                                        return;//[12]
                                     }
                                     out.write("[13] Session has closed");
                                     session.invalidate();//[14]
                   }
                   public void destroy(){//[15]
                                     log("[16] destroy()");
                   }
}

実行結果

手順1)Webサーバーを起動する。

ログ:

1 09, 2017 11:13:04 午前 org.apache.catalina.core.StandardService startInternal
情報: サービス Catalina を起動します
1 09, 2017 11:13:04 午前 org.apache.catalina.core.StandardEngine startInternal
情報: Starting Servlet Engine: Apache Tomcat/7.0.73
1 09, 2017 11:13:05 午前 org.apache.catalina.core.ApplicationContext log
情報: [5] コンテキスト:開始

手順2)ブラウザにURL: http://localhost:8080/Servlet/EventTest と入力し、Enterを押す。

ブラウザ画面:

ログ:

1 09, 2017 11:13:14 午前 org.apache.catalina.core.ApplicationContext log
情報: [6] 0:0:0:0:0:0:0:1のリクエストがスコープに入る
1 09, 2017 11:13:14 午前 org.apache.catalina.core.ApplicationContext log
情報: lifecycleevent.ServleEventTest: [4] init()
1 09, 2017 11:13:14 午前 org.apache.catalina.core.ApplicationContext log
情報: [6] セッション開始: ID = A30AA242438DEE29A6B075B366BEC09B

手順3)ブラウザの更新ボタンを押す。

ブラウザ画面:

ログ:

1 09, 2017 11:15:08 午前 org.apache.catalina.core.ApplicationContext log
情報: [6] 0:0:0:0:0:0:0:1のリクエストがスコープに入る
1 09, 2017 11:15:08 午前 org.apache.catalina.core.ApplicationContext log
情報: [10] セッション終了:ID = A30AA242438DEE29A6B075B366BEC09B
1 09, 2017 11:15:08 午前 org.apache.catalina.core.ApplicationContext log
情報: [10] 0:0:0:0:0:0:0:1のリクエストがスコープから出る

手順4)Webサーバーを停止する。

ログ:

1 09, 2017 11:16:01 午前 org.apache.catalina.core.StandardService stopInternal
情報: サービス Catalina を停止します
1 09, 2017 11:16:01 午前 org.apache.catalina.core.ApplicationContext log
情報: lifecycleevent.ServleEventTest: [16] destroy()
1 09, 2017 11:16:01 午前 org.apache.catalina.core.ApplicationContext log
情報: [8] コンテキスト:終了

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] HttpServletを継承して、ServleEventTestクラスを定義する。
  • [3] 修飾子publicでメソッドServletException ()を宣言する。
  • [4] 「init()」をコンテキストのログに出力する。
  • [5] 修飾子publicでメソッドdoGet ()をオーバーライドする。
  • [6] HTMLを出力するためのoutオブジェクトを取得する。
  • [7] outオブジェクトに「Event Test Servlet => 」を出力する。
  • [8] セッションsessionオブジェクトを取得する。
  • [9][10] セッションが開始されていない時、セッションを開始する。
  • [11][12] outオブジェクトに「Session has started」を出力し、処理を終了する。
  • [13] outオブジェクトに「Session has closed」を出力する。
  • [14] セッションを終了する。

ライフサイクルの詳細

サーブレットの生成と初期化

@WebServletアノテーションを使ってWebアプリケーションのサーブレット・コンポーネントの定義を行う。このアノテーションはクラスの仕様に含められ、宣言されたサーブレットについての属性情報を含んでいる。アノテーションが付いているサーブレットは少なくともひとつのURLパターンを属性情報として含んでいなければならない。これは、アノテーションのurlPatternsまたはvalue 属性によって特定される。他の全ての属性はオプションで、指定されなければデフォルト設定となる。アノテーションの属性がURLパターンの時だけは、value属性を使用してください。他方、他の属性が使われている時は、urlPatternsを使用してください。

例えば、次のコードの抜粋は、URLパターン「/report」を持つサーブレットを定義する。@WebServletでアノテーションを付加されたクラスはjavax.servlet.http.HttpServletを継承していなければならない。

@WebServlet("/report")public class MoodServlet extends HttpServlet {    ...

Webコンテナは、サーブレットクラスがローディグされ初期化された後、クライアントから送られたリクエストが来る前に初期化しなければならない。永続的な構成データを読むこと、リソースを初期化すること、その他の一度だけのアクティビティを実行することをサーブレットに許可してこのプロセスをカスタマイズするために、サーブレットのinit()メソッドをオーバーライドするか、@WebServletアノテーションのinitParams属性を指定することができる。initParams属性は、@WebInitParamアノテーションを含んでいる。もし初期化プロセスを完了できない時は、サーブレットはUnavailableException例外を発生させる。特定のサーブレットによって必要とされるデータを提供するために初期化パラメータを使用してください。対照的に、コンテキスト属性はWebアプリケーションのすべてのコンポーネントに有効なデータを提供する。

サービスメソッド

サーブレットによって提供されるサービスは、GenericServletのserviceメソッドの中、httpServletオブジェクトのdoMethods(Methodの部分は、Get, Delete, Options, Post, Put, or Trace置き換えられる)の中、またはサーブレットインターフェースを実装したクラスによって定義された他のプロトコルに依存したメソッドの中に実装したものである。serviceメソッドという言葉は、クライアントにサービスを提供するサーブレットクラスの中にあるどんなメソッドのために使われる。

サービス(serviceメソッドのための一般的なパターンは、リクエストから情報を抽出すること、そしてその情報に基づいて外部リソースにアクセスすること、そしてレスポンスに反映させる。HTTPサーブレットのために、レスポンスに反映させるための正しい手順は、次の通りです。

  1. レスポンスから出力ストリームを取り出す。
  2. レスポンスヘッダーに書き込む。
  3. 出力ストリームにすべてのコンテンツ本体を書き込む。

レスポンスがコミットされる前に、レスポンスヘッダーは設定されなければならない。レスポンスがコミットされた後に設定または追加されたどんな試みも、Webコンテナは無視する。

まとめ

この記事では、サーブレットのライフサイクルについて紹介した。サンプルプログラムを実際に動作させるなどして、仕組みを理解しよう。

 

]]>
https://eng-entrance.com/servlet-lifecycle/feed 0
【Java & Tomcat】文字出力用のストリームの取得(getWriter)※サンプルプログラム付き https://eng-entrance.com/java-servlet-getwriter https://eng-entrance.com/java-servlet-getwriter#respond Sun, 10 Mar 2019 01:05:50 +0000 https://eng-entrance.com/?p=7284 サーブレットの処理結果としてなんらかの文字を出力するにはgetWriterという名称のメソッドを使用する必要がある。ここではその仕組みについて説明する。

文字出力用のストリームの取得の仕方

文字出力用のストリームの取得とは、HttpServletResponseオブジェクトから文字を出力する入れ物を取り出すことである。ストリームというのは文字が順番に連続して並んでいる入れ物のことである。取り出したストリームへ文字を書き出すと、それがクライアントに送られ、画面に表示される。

書き方の基本は簡単だ。

PrintWriterストリームの参照変数 = HttpServletResponseオブジェクト. getWriter();

実際のコードはこうなる。

PrintWriter out = response.getWriter();

ストリームを取り出したら、次に行うことはストリームに文字列を書き込むことである。取り出したストリームに書き込むためにPrintWriterクラスのメソッドが準備されている。

代表的なのがprintlnメソッドである。boolean型、char型、char[]型、int型、long型、float型、double型、String型の値を文字列としてストリームに出力する。その後、文字を出力した行を終了する。

書き方はこうである。

ストリームの参照変数.println(値);

実際のコードはこうなる。

out.println("ABCD");

もし、一行をいくつかに分けて出力する必要があるときは、最後の出力以外のメソッドをprintにすればよい。こうすれば行は終了しない。

ストリームの参照変数.print(値);

もし、上のABCDを連続して書いたprintlnのコードをふたつに分けて書いたとするとコードはこうなる。

out.print("AB");

out.println("CD");

他にも必要に応じて使えるメソッドがある。主要なメソッドとその特徴を挙げておく。詳細はPrintWriterクラスの仕様を参照してください。

文字列出用メソッド

説明

append(値);

Char型の文字かCharSequence型の文字列の値を、現在の文字列の後に追加する。

append(値、開始位置、終了位置);

CharSequence型の文字列の値の開始位置から終了位置までを、現在の文字列の後に追加する。

printf(フォーマット、引数);

値をフォーマットに従って文字列として出力する。

getWriterのAPI仕様

getWriter()

戻り値の型

java.io.PrintWriter

内容

文字テキストをクライアントに送ることができるPrintWriterオブジェクトを戻す。PrintWriterは、getCharacterEncoding()メソッドによって戻される文字コードを使用する。もしレスポンスの文字コードが、getCharacterEncodingメソッドの仕様に従って指定されていないならば(すなわち、メソッドはデフォルト値ISO-8859-1だけを戻す)、getWriterメソッドはそれをISO-8859-1へと変更する。

PrintWriterのflush()メソッドと呼ばれるメソッドはレスポンスをコミットする。

このgetWriter()メソッドかgetOutputStream()メソッドのどちらかが、ボディを書くために呼び出されるかもしれないが、両方は呼び出されることはない。

戻り値:文字データをクライアントに戻すことができるPrintWriterオブジェクト

例外:

java.io.UnsupportedEncodingException -もしgetCharacterEncoding()メソッドによって戻される文字コードが使用できないならば。

java.lang.IllegalStateException -もしgetOutputStreamメソッドが、このレスポンスオブジェクトのためにすでに呼び出されているならば。

java.io.IOException -もしインプットもしくはアウトプットの例外が起こるならば。

参照:

getOutputStream(), setCharacterEncoding(java.lang.String)

サンプルプログラム

このサンプルプログラムは、getWriterを使って文字出力用のストリームを取得し、そのストリームに様々なメソッドを使って値を出力する。

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("/GetWriter")//[1]
public class ServletGetWriter extends HttpServlet {//[2]
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {//[3]
              
        boolean booleanValue = true;//[4]
        char charValue = 'A';//[5]
        char[] charValues = {'B', 'C', 'D'};//[6]
        int intValue = 21;//[7]
        long longValue = 41L;//[8]
        double floatValue = 12.8f;//[9]
        double doubleValue = 56.78;//[10
        String stringValue = "EFGHIJ";//[11]
        CharSequence charSequenceValue = stringValue;//[12]

        response.setContentType("text/html; charset=Shift_JIS");//[13]
        PrintWriter out = response.getWriter();//[14]
        out.println("<html><head></head><body>");//[15]

        out.println("<p>");//[16]
        out.print("append(char型の値) = ");//[17]
        out.append(charValue);//[18]
        out.println("<br>");//[19]
        out.print("append(CharSequence型の値) = ");//[20]
        out.append(charSequenceValue, 1, 3);//[21]
        out.println("</p>");//[22]

        out.println("<p>");//[23]
        out.print("printf(\"intValue = %d\", intValue) => ");//[24]
        out.printf("intValue = %d", intValue);//[25]
        out.println("</p>");//[26]

        out.println("<p>");//[27]
        out.print("print(booleanValue) = ");//[28]
        out.print(booleanValue);//[29]
        out.println("<br>");//[30]
        out.print("print(charValue) = ");//[31]
        out.print(charValue);//[32]
        out.println("<br>");//[33]
        out.print("print(charValues) = ");//[34]
        out.print(charValues);//[35]
        out.println("<br>");//[36]
        out.print("print(intValue) = ");//[37]
        out.print(intValue);//[38]
        out.println("<br>");//[39]
        out.print("print(longValue) = ");//[40]
        out.print(longValue);//[41]
        out.println("<br>");//[42]
        out.print("print(floatValue) = ");//[43]
        out.print(floatValue);//[44]
        out.println("<br>");//[45]
        out.print("print(doubleValue) = ");//[46]
        out.print(doubleValue);//[47]
        out.println("</p>");//[48]

        out.println("</body></html>");//[49]
    }
}

実行結果

ブラウザにURL:http://localhost:8080/Servlet/GetWriterを入力し、Enterを押す。

表示されるブラウザ画面:

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] HttpServletを継承して、HelloWorldクラスを定義する。
  • [3] doGet()メソッドをオーバーライドして定義する。
  • [4]-[12] 表示するために様々な型の変数を宣言する。
  • [13] Content Typeを設定する。
  • [14] 文字列出力用のストリームを出力するためにPrintWriterオブジェクトを取得する。
  • [15] HTMLの画面の開始を宣言する。
  • [16]-[22] appendメソッドを使って値を出力する。
  • [23]-[26] printfメソッドを使って値を出力する。
  • [27]-[48] printメソッドを使って値を出力する。
  • [49] HTML画面終了を宣言する。

まとめ

この記事では実際にgetWiter()を使用して様々な文字出力が出来ることを確認した。サンプルプログラムを実際に動作させて確かめてみよう。また、サンプルプログラムを自由に書き換えてそれが出力結果にどう影響するかを確認してみよう。

]]>
https://eng-entrance.com/java-servlet-getwriter/feed 0
【Java & Tomcat】リダイレクトの設定(sendRedirect)※サンプルプログラム付き https://eng-entrance.com/java-servlet-sendredirect https://eng-entrance.com/java-servlet-sendredirect#respond Sun, 03 Mar 2019 12:06:23 +0000 https://eng-entrance.com/?p=7355 この記事ではサーブレットによって特定のWebページへジャンプさせるための「リダイレクト」について説明する。

リダイレクトの設定の仕方

リダイレクトの設定とは、異なるURLにクライアントのあて先を変更するために適切なヘッダーとコンテンツを設定することである。sendRedirectメソッドを使ってURLパスを指定する。この時相対URLパスを使ってメソッドを呼ぶことも可能である。コンテナが相対パスを完全なURLパスに変換してくれる。

例えば下の図にあるように、リダイレクトを使えばサーブレットが別のWebページ(ここではGoogle検索)を呼び出すことが可能になる。

書き方の基本は簡単だ。

HttpServletResponseオブジェクト. sendRedirect (URLパス);

実際のコードはこうなる。

response.sendRedirect("http://www.google.com");

リダイレクトの設定API仕様

void sendRedirect(java.lang.String location)

戻り値の型

void

内容

指定されたリダイレクトロケーションURLを使用してクライアントに一時的なリダイレクトレスポンスを送る。このメソッドは、相対的なURLを受け取ることができる;サーブレットコンテナは、レスポンスをクライアントに送る前に、相対的なURLを絶対的なURLに変えなければならない。

もしロケーションの先頭に「/」がないならば、コンテナはそれを現在のリクエストURLに相対的なものとして解釈する。

もしロケーションの先頭に「/」があるならば、コンテナはサーブレットコンテナルートに相対的なものとして解釈する。

もしレスポンスがすでにコミットされているならば、このメソッドはIllegalStateException例外を発生させる。このメソッドを使用した後に、レスポンスはコミットされたとみなされるべきであり、書き込まれるべきではない。

引数:location - リダイレクトロケーションURL

例外:

java.io.IOException - もし、インプットもしくはアウトプットの例外が起こるならば。

java.lang.IllegalStateException – もし、レスポンスがコミットされたか、もしくは、URLの一部が与えられて、正しいURLに変換できなければ。

sendRedirectを使用したサンプルプログラム

このサンプルプログラムは、水曜日を英語で入力することを要求する。もし正しく英単語が入力されると、「正しく入力されました」が表示される。もし、間違っているとGoogle検索画面を表示する。このGoogle検索画面を表示する時にリダイレクトの設定を使っている。

サーブレットの配置とプログラムのコードは次のようになっている。

最初に単語を入力するHTMLで書かれた入力画面redirect.htmlのコードを示す。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<title>リダイレクトサンプル</title>
</head>
<body>
<p>水曜日を英語で入力してください。間違えるとGoogle検索が表示されます。</p>
<form action="/Servlet/ServletRedirect" method="get">
    <p>言葉:<input type="text" name="word"></p>
    <p><input type="submit" value="検索" style="WIDTH: 200px; HEIGHT: 20px"></p>
</form>
</body>
</html>

次に、HTML画面からリクエストを受け取るサーブレットのコードを示す。

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("/ServletRedirect")//[1]
public class ServletRedirect extends HttpServlet {//[2]
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {//[3]
        response.setContentType("text/html; charset=UTF-8");//[4]
        String word = request.getParameter("word");//[5]
        if (!checkWord(word)) {//[6]
            response.sendRedirect("http://www.google.com");//[7]
           return;//[8]
        }
        PrintWriter out = response.getWriter();//[9]
        out.println("<html><head></head><body>");//[10]
        out.println("<p>正しく入力されました。</p>");//[11]
        out.println("<p>水曜日は英語でWednesdayです。</p>");//[12]
        out.println("</body></html>");//[13]
    }
    boolean checkWord(String word) {//[20]
        if (word == null)//[21]
            return false;//[22]
        if (word.equals("Wednesday"))//[23]
           return true;//[24]
        if (word.equals("wednesday"))//[25]
           return true;//[26]
        return false;//[27]
    }
}

実行結果

ブラウザにURL:http://localhost:8080/Servlet/redirect.htmlを入力し、Enterを押す。

表示されるブラウザ画面:

「Wednesday」と正しく入力し、検索ボタンを押す。

表示されるブラウザ画面:

それ以外の間違った単語を入力し、検索ボタンを押す。

表示されるブラウザ画面:

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] HttpServletを継承して、ServletRedirectクラスを定義する。
  • [3] doGet()メソッドをオーバーライドして定義する。
  • [4] Content Typeを設定する。
  • [5] 入力された単語を取得し、変数wordに代入する。
  • [6] 単語をチェックするメソッドcheckWordを呼び出す。
  • [7]-[8] もし、チェックがNGならば、メソッドsendRedirectによってGoogle検索を呼び出す。そして、処理を終了する。
  • [9] HTMLを出力するためのPrintWriterオブジェクトを取得する。
  • [10]-[13] PrintWriterオブジェクトに「正しく入力されました。」と「水曜日は英語でWednesdayです。」を表示するHTMLコードを出力する。

 

  • [20] メソッドcheckWordを定義する。
  • [21]-[22] 引数wordがnullならば、戻り値falseで終了する。
  • [23]-[24] 引数wordがWednesdayならば、戻り値trueで終了する。
  • [25]-[26] 引数wordがwednesdayならば、戻り値trueで終了する。
  • [27] 戻り値trueで終了する。

まとめ

リダイレクトの動作自体は単純なものだが、例えば様々なURLを行き来するための分岐に利用することもできる。まずはサンプルプログラム内のリダイレクト先URLを変更したり、様々な改造にトライしてみよう。

 

]]>
https://eng-entrance.com/java-servlet-sendredirect/feed 0
【Java & Tomcat】サーブレットからフォームデータを取得する(サンプルコード付き) https://eng-entrance.com/java-servlet-get-formdata https://eng-entrance.com/java-servlet-get-formdata#respond Sun, 24 Feb 2019 10:07:12 +0000 https://eng-entrance.com/?p=7292 Webアプリケーションを作成するにあたり、ブラウザへの出力ばかりではなく、フォームを使ってユーザー側からの入力を取得する場合がある。ここではその方法について説明する。

フォームデータの取得の仕方

フォームデータとは、Webページに入力されたデータのことである。このデータには様々なものがある。テキストを入力するテキストフィールド、ラジオボタンの選択、リストからの選択データなどである。

テキスト入力フィールドの例を考えてみよう。

サーブレットが入力されたフォームデータを取得するために、クライアントからリクエスト情報が入っているHttpServletRequestオブジェクトに対してgetParameterメソッドを使う。ラジオボタンのデータはリクエスト情報の中にパラメータとして含まれている。このメソッドにテキスト入力フィールドのパラメータの名前(name)を引数として与えることによって入力されたテキスト入力フィールドのデータを取得することができる。

書き方の基本は簡単だ。

HttpServletRequestオブジェクト. getParameter (パラメータの名前);

実際のHTML画面のフォームデータ入力のコードはこうなる。

<input type="text" name="item1">

その値を取得するサーブレット側のコードはこうなる。

String item1 = request.getParameter("item1");

パラメータを取得するAPI仕様

getParameter(java.lang.String name)

戻り値の型

java.lang.String

内容

リクエストのパラメータの値を文字列として戻す。もしパラメータがなければnullを戻す。リクエストパラメータはリクエストともに送られる付加的な情報である。HTTPサーブレットのために、パラメータが参照文字列か送信されたフォームデータに含まれている。

パラメータがただひとつだけの値を持っていることを確かめた時に、このメソッドを使うべきである。もしパラメータがひとつ以上の値を持っているならば、getParameterValues(java.lang.String)を使うべきである。

もし、複数のパラメータで使うならば、戻される値はgetParameterValuesによって返される配列の最初の値である。(更なる詳細は、仕様を参照してください)

引数:指定されたパラメータの名前

戻り値:パラメータのひとつの値を表す文字列。

参照:getParameterValues(java.lang.String)

フォームデータを取得するサンプルプログラム

このサンプルプログラムは、フォームデータとしてふたつの項目を入力する。そのデータを取得したサーブレットは、入力項目をそのまま項目1と項目2としてレスポンスの画面に表示する。

サーブレットの配置とプログラムのコードは次のようになっている。

最初にHTMLで書かれたフォームデータ入力画面のコードを示す。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html lang="ja">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
</head>
<title>フォームデータの取得サンプル</title>
</head>
<body>
<p>ふたつの項目を入力してください。</p>
<form action="/Servlet/ServletGetParameters" method="get">
    <p>項目1:<input type="text" name="item1"></p>
    <p>項目2:<input type="text" name="item2"></p>
    <p><input type="submit" value="入力実行" style="WIDTH: 200px; HEIGHT: 20px"></p>
</form>
<p>
</body>
</html>

次に、HTML画面からリクエストを受け取るサーブレットのコードを示す。

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("/ServletFormData")//[1]
public class ServletFormData extends HttpServlet {//[2]
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {//[3]
        response.setContentType("text/html; charset=Shift_JIS");//[4]

        String item1 = request.getParameter("item1");//[5]
        String item2 = request.getParameter("item2");//[6]
        PrintWriter out = response.getWriter();//[7]
        out.println("<html><head></head><body>");//[8]
        out.println("<p>入力された項目を表示します。</p>");//[9]
        out.println("<p>入力項目1:" + item1 + "</p>");//[10]
        out.println("<p>入力項目2:" + item2 + "</p>");//[11]
        out.println("</body></html>");//[12]
    }
}

実行結果

ブラウザにURL:http://localhost:8080/Servlet/formdata.htmlを入力し、Enterを押す。

表示されるブラウザ画面:

項目1に「aaa」項目2に「bbb」と入力し、入力実行ボタンを押す。

表示されるブラウザ画面:

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] HttpServletを継承して、ServletFormDataクラスを定義する。
  • [3] doGet()メソッドをオーバーライドして定義する。
  • [4] Content Typeを設定する。
  • [5] 入力されたフォームデータの項目1を取得し、変数item1に代入する。
  • [6] 入力されたフォームデータの項目2を取得し、変数item2に代入する。
  • [7] HTMLを出力するためのPrintWriterオブジェクトを取得する。
  • [8]-[12] PrintWriterオブジェクトに「入力された項目を表示します。」と表示し、続いて項目1の値(変数item1)と項目2(変数item2)の値を表示するHTMLコードを出力する。

まとめ

サンプルプログラムをご覧頂いてもわかる通り、フォームを使って入力されたデータを元に様々な処理を行う事ができる。HTMLとして出力している部分を中心に、自分なりに色々と変更してみよう。

]]>
https://eng-entrance.com/java-servlet-get-formdata/feed 0
【Java & Tomcat】サーブレット開発をEclipseでするための初期設定を画像付きで分かりやすく解説 https://eng-entrance.com/java-servlet-eclipse https://eng-entrance.com/java-servlet-eclipse#respond Sun, 17 Feb 2019 01:46:11 +0000 https://eng-entrance.com/?p=7326 サーブレット開発を行うにあたり、まず必要となるのがベースとなる開発環境である。この記事ではその開発環境の立ち上げと初期設定について紹介する。

Eclipseでサーブレットの作成をする

Eclipseには色々な開発環境が準備されている。そのなかのPleiades All in One Eclipseを使うと難しい設定をしたり、基本的なコードを書いたりしないでも、オプションを選択するだけで簡単にサーブレットを作成することができる。この環境があれば、作成だけでなく実行も簡単だ。

その手順は、次のようになっている。

  • Eclipseのインストール
  • 立ち上げ
  • パースペクティブの設定
  • プロジェクトの作成
  • サーブレット作成
  • サーブレットの実行

では、インストールからサーブレットの実行までの手順を追って説明する。

なお、当ブログではEclipseのインストールについて過去何度か取り上げているため、その時点で導入したものがあればそちらを使用しても問題はない。新規にプロジェクトを作成し、後に登場する「パースペクティブの設定」辺りから始めるのがよいだろう。

Eclipseのインストール

Eclipseの「Pleiades All in One Eclipseダウンロード(http://mergedoc.osdn.jp/)」というサイトに行くと次のような表示がされる。その中のJava→Full EditionをインストールするコンピュータのOSに合わせてダウンロードする。(今回の例ではPleiades4.6というバージョンを使っているが、その時点での最新のバージョンで問題はない)

ここからは、Windowsの場合を例に説明を続ける。ダウンロードが終わったら、zipファイルをディレクトリに展開する。「pleiades-4.6.2-java-win-64bit-jre_20161221」といzipファイルをC:\eclipseのディレクトに展開している。

展開したフォルダのpleiades-4.6.2→eclipseにeclipse.exeという実行ファイルがある。これをクリックすれば、Eclipseが立ち上がる。すばやく立ち上げるためにショートカットを作成してホーム画面に置いておくこともできる。

立ち上げ

eclipse.exe実行すると、Eclipseが立ち上がっていることを示す次のような画面が表示される。

しばらく待つと、今度はワークスペースを設定するための画面が表示される。

あらかじめ作成しておいたEclipse用のワークスペース(C:\workspace)を指定する。このワークスペースにこれから作成するサーブレットに関係するJavaのプログラムや設定ファイルがプロジェクトごとに保存される。OKボタンを押す。そうすると、いよいよEclipseの画面が表示される。

これが最初のEclipseの画面である。

パースペクティブの設定

サーブレットを開発するためはTomcatなどサーバーを動かすことが必要だが、この画面にはそれがない。サーバー管理などのサポートがあるサーブレットに適したパースペクティブ(画面の構成)が必要なのだ。それが、Java EE(Java Platform, Enterprise Edition)のためのパースペクティブである。

画面右上にあるパースペクティブのアイコンをクリックして。「パースペクティブを開く」の画面からJave EEを選択する。そして、OKボタンを押す。

画面の構成が変わって、Java EEのパースペクティブで画面が表示される。画面の中央は、プログラムを開発するためのエディタである。画面の中央下のところにサーバーのタブがある。これがサーバーの管理を行うところだ。サーブレット開発には、この両方が必要である。

プロジェクトの作成

サーブレットを含む開発に関係するもの入れるためにプロジェクトを作成する。そのために、メニューからファイル→新規→プロジェクトを選択する。

新規プロジェクト画面が開く。

その画面からWeb→動的Webプロジェクトを選択し、次へのボタンを押す。新規動的Webプロジェクト画面が開く。これがサーブレットを開発するための必要な構成情報を設定する画面である。

プロジェクト名を入力し、ターゲット・ランタイムを選択する。ターゲット・ランタイムを選択すると、下のふたつの項目が自動的に選ばれる。必要なら、動的モジュールバージョンや構成も選択する。動的Webモジュールバージョンとの組み合わせで、動作しない場合がある。注意が必要だ。

完了ボタンを押すと、プロジェクトが作成される。

これで、サーブレットを作成するための準備が整った。では、サーブレットの作成を始めよう。

サーブレット作成

サーブレットを作成するために、Javaソース→srcを選択する。srcを右クリックして、さらに新規→サーブレットと選ぶ。

サーブレット作成画面が表示される。

表示されたサーブレット作成画面にJavaパッケージ名:sample、クラス名:ServletSampleと入力する。完了ボタンを押す。

実行可能なサーブレットの基本的なコード自動生成される。これを修正して目的のサーブレットを作成することができる。次のセクションでは、このコードをそのまま実行している。

これで、サーブレットの基本的なコードができた。簡単だ。

サーブレットの実行

サーブレットの実行を行うためには、サーバーを立ち上げる必要がある。サーバータブをクリックする。「使用可能なサーバーがありません。このリンクをクリックして新規サーバーを作成してください」と表示されるので、そのリンクをクリックする。

新規サーバー画面が表示される。

新規サーバー画面で、サーバー(ここではTomcat V8.0)を選択し、完了ボタンを押す。サーバーが追加される。

画面下のサーバータブを見ると、追加されたサーバーが停止状態であることが分かる。次に、サーバーを右クリックして、追加及び除去を選択する。

追加および除去画面が表示される。これは、サーバーにプロジェクトを追加したり、除去したりするための画面である。

追加および除去画面でプロジェクトWebSampleを選択して、追加ボタンを押す。WebSampleが構成済みに追加されたら、完了ボタンを押す。

元の画面に戻る。

サーバーにプロジェクトのリソースを公開するために、サーバーを選択し、右クリックして公開を選択する。これによって、プロジェクトの成果物がサーバー内に公開(配置)される。

サーバーをスタートさせるために、サーバーを選択し、右クリックして開始を選択する。

サーバーが立ち上がり、状態が始動開始済みになる。

プロジェクトが公開され、サーバーが起動したら、準備が完了したことになる。次にURLを指定してサーブレットを呼び出す。この時のURLは、以下のような形式になっている。

http://localhost:8080/[Project名]/[URLパターン]

Eclipseのプロジェクト名は、WebSampleであり、URLパターンはサーブレットのクラス定義の直前に@WebServlet()の引数として定義されているServletSampleとなる。

@WebServlet("/ServletSample")
public class ServletSample extends HttpServlet {
……
}

それで、ブラウザにURL:http://localhost:8080/WebSample/ServletSample と入力し、Enterを押す。

表示されるブラウザ画面:

これが、表示されればサーバーでサーブレットが正しく動作したことになる。

まとめ

サーブレット開発の基盤となるツールはEclipse以外にも色々とあるが、開発にあたって必要なツールが最初から全て揃っており、ネット上での資料も豊富なことから、まず取っ掛かりとしてはEclipseがおすすめである。実際に導入して動かしてみよう。

]]>
https://eng-entrance.com/java-servlet-eclipse/feed 0
【Java & Tomcat】GETリクエストの処理 (doGet)※サンプルコード付き https://eng-entrance.com/java-servlet-doget https://eng-entrance.com/java-servlet-doget#respond Sun, 10 Feb 2019 12:20:00 +0000 https://eng-entrance.com/?p=7364 クライアントから発せられたリクエストには様々なものがあるが、その中で今回はGETというリクエストが来た際の処理について説明する。

サーブレットのGETリクエスト処理

クライアントからのリクエストはサーブレットに渡され、そのサーブレットがリクエストの中にあるメソッドに対応した処理を行う。リクエストに含まれるメソッドには、次の図が示すようにGET、POSTなどいくつかの種類がある。そのひとつがGETリクエストである。

GETリクエストは、HttpServletクラスを継承したサーブレットクラスで処理される。このサーブレットクラスで、GETリクエストに対応したHttpServletクラスのメソッドdoGet()をオーバーライドして、要求にあった処理をさせる。

この例では、サービスメソッドのdoGet()をオーバーライドしている。このdoGet()メソッドの中に、レスポンスとしてクライアントに返すデータの処理や表示する画面をHTMLで記述することになる。

@WebServlet("/ServletGetRequest")//[1]
public class ServletGet extends HttpServlet {//[2]
    static int accessCountInDatabase = 0;//[3]
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {//[4]
….
}
}

doGet()の処理の流れ

ここでは、GETリクエストに対応したメソッド:doGet()を取り上げている。そのAPI仕様を見る前に、doGet()の処理の流れを大まかに見てみよう。

GETメソッドを処理するdoGet()だが、基本的にサーバーにあるデータベースなどの情報を読むだけで、情報の変更を行わない処理のために使われる。また、クライアントから送られてくる画面入力情報が外部に公開されるので、クレジット番号などの入力には使えない。処理の流れは次のようになっている。

そのAPI仕様を見てみよう。

doGet()メソッドのAPI仕様

doGet(HttpServletRequest req, HttpServletResponse resp)

戻り値の型

protected void

内容

サーブレットにGETリクエストを処理させるためにサーバー によって呼び出される。

GET リクエストをサポートするために、このメソッドをオーバーライドすることは、また自動的にHTTP HEADリクエストをサポートする。HEAD リクエストはリクエストヘッダーフィールドだけで、返信の中にBODYがないGETリクエストである。

このメソッドをオーバーライドする時、リクエストデータを読み、返信ヘッダーを書き、返信のためのライターまたは出力ストリームオブジェクトを取得して、そして最後に、レスポンスデータを書く。Content TypeとEncodingを含むことがベストである。レスポンスを返すためにプリントライターオブジェクトを使う時、プリントライターオブジェクトにアクセスする前にContent Typeを設定する。

(さらなる詳細は、API仕様書を参照してください。)

 

引数:

req -クライアントが生成するサーブレットへのリクエストを含む HttpServletRequestオブジェクト

resp -サーブレットがクライアントに送る返信を含む HttpServletResponseオブジェクト

例外:

java.io.IOException - もし、サーブレットがGET リクエストを操作する時に、入力もしくは出力エラーが検出されるならば。

ServletException - もし、GETリクエストのための処理できなかったならば。

では、実際のサーブレットの作成をサンプルプログラムで見てみよう。

GETリクエストを処理するサンプルプログラム

このサンプルプログラムラムでは、GETリクエストの処理をdoGet()メソッドで実装している。サーブレットは、この時、GETリクエストなので、データベースに見立てたアクセスカウンタの表示処理を行っている。カウンタの更新処理は行わない。

サーブレットの配置とプログラムのコードは次のようになっている。

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("/ServletGetRequest")//[1]
public class ServletGet extends HttpServlet {//[2]
    static int accessCountInDatabase = 0;//[3]
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {//[4]

        response.setContentType("text/html; charset=Shift_JIS");//[5]
        PrintWriter out = response.getWriter();//[6]
        out.println("<html><head></head><body>");//[7]
        out.println("<p>GETリクエストを受信</p>");//[8]
        out.println("<p>アクセス回数:" + loadAccessCountInDatabase() + "回</p>");//[9]
        out.println("</body></html>");//[10]
    }
    int loadAccessCountInDatabase() {//[20]
        return accessCountInDatabase;//[21]
    }
}

実行結果

ブラウザにURL:http://localhost:8080/Servlet/ServletGetRequest を入力し、Enterを押す。

表示されるブラウザ画面:

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] HttpServletを継承して、ServletGetクラスを定義する。
  • [3] データベースにある情報に見立てた変数accessCountInDatabaseを定義する。
  • [4] doGet()メソッドをオーバーライドして定義する。
  • [5] Content Typeを設定する。
  • [6] HTMLを出力するためのoutオブジェクトを取得する。
  • [7]-[10] outオブジェクトに「GETリクエストを受信」と「アクセス回数」を表示するHTMLコードを出力する。
  • [20][21] 変数accessCountInDatabaseの値を戻すメソッドloadAccessCountInDatabase()を定義する。

HTML画面でリクエストを指定するサンプルプログラム

このサンプルプログラムは、前のセクションのサーブレットにHTMLで書かれた画面からGETリクエストとPOSTリクエストを選んで送信することができるようになっている。

サーブレットの配置とプログラムのコードは次のようになっている。

GETリクエストかPOSTリクエストの送信を選択するHTML画面表示のためのコードがservletget.htmlである。GETリクエストの送信は次のようなコードになっている。

<form action="/Servlet/ServletGetRequest" method="get">

また、POSTリクエストの場合は、この「method=」の部分が「"post"」となっている。全てのコードを次に示す。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html lang="ja">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
</head>
<title>GETリクエストサンプル</title>
</head>
<body>
<p>リクエストを送信する</p>
<form action="/Servlet/ServletGetRequest" method="get">
<input type="submit" value="GETリクエスト送信" style="WIDTH: 200px; HEIGHT: 20px">
</form>
<p></p>
<form action="/Servlet/ServletGetRequest" method="post">
<input type="submit" value="POSTリクエスト送信" style="WIDTH: 200px; HEIGHT: 20px">
</form>
</body>
</html>

入力画面からGETリクエストを受け取ったサーブレットは、doGet()メソッドの中でレスポンスを返す処理を行う。

実行結果

ブラウザにURL:http://localhost:8080/Servlet/servletget.htmlを入力し、Enterを押す。

表示されるブラウザ画面:

GETリクエスト送信ボタンを押す。この時は、サーブレットのdoGet()処理が実行されて、GETリクエストが正常に処理されたことをレスポンスとして表示する。

表示されるブラウザ画面:

もし、GETリクエストではなく、POSTリクエストを送信するとどうなるかというと、エラー画面が表示される。表示内容を見るとPOSTリクエストをサポートしていないことが分かる。

表示されるブラウザ画面:

まとめ

クライアントからの要求に応じて様々な処理結果をブラウザ上に出力できることがわかるだろう。サンプルプログラムを使って処理結果を自分なりに変えてみるなど、色々とやってみよう。

]]>
https://eng-entrance.com/java-servlet-doget/feed 0