Powered by SmartDoc

Servlet

Servlet の基本

Servletは、JSPと同じく、Webブラウザからの要求を処理して動的なページを作成するためのものです。また、JSPと同様にTomcatなどのWebコンテナの内部で動きます。

Servletは、HttpServletというクラスを継承して、必要なメソッドをオーバーライドしたクラスになります。CGIと同じように、ServletからHTMLを出力できます。

JSPのところで、サンプル1,サンプル2, ...サンプル5のような出力をするloop.jspというサンプルプログラムを示しました。ここでは、同じ働きをするServletのプログラムを見てみましょう。

LoopServlet.java
// LoopServlet
//   サンプル1, サンプル2, ... サンプル5
//   とブラウザに表示する Servlet

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class LoopServlet extends HttpServlet {

    // HttpServlet で定義されているメソッド
    // HTTP の GET メソッドに対応する
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
                      throws ServletException, IOException {
        doIt(request, response);
    }

    // HttpServlet で定義されているメソッド
    // HTTP の POST メソッドに対応する
    public void doPost(HttpServletRequest request,
                       HttpServletResponse response)
                       throws ServletException, IOException {
        doIt(request, response);
    }

    private void doIt(HttpServletRequest request,
                      HttpServletResponse response)
                      throws ServletException, IOException {

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

        // HttpServletResponse 型のインスタンスから Writer を取り出し
        // Writer に HTML を書き出す
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>LoopServlet</title>");
        out.println("</head>");
        out.println("<body>");

        for (int i = 1; i <= 5; i++) {
            out.print("<p>サンプル");
            out.println(i);
            out.print("</p>");
        }

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

Servletのメソッドは、HTTPのリクエストメソッドと深く関係しています。HTTPのGETメソッドに対してはServletのdoGetメソッドが呼び出され、POSTメソッドに対してはServletのdoPostメソッドが呼び出されます。いずれのメソッドにも、ブラウザからの要求を表すHttpServletRequest型のオブジェクトと、Servletからの応答を表すHttpServletResponse型のオブジェクトが引数に含まれています。このServletでは、いずれのメソッドも、doIt(request, response)というメソッドに処理をまかせています。

またHTMLの出力は、次の手順になります。まず、HttpServletResponse型のオブジェクトであるresponseからPrintWriterオブジェクトを取り出します。次に、そのオブジェクトのprintln()メソッド、あるいはprint()メソッドを実行して、HTMLを書き出します。HTTPでは応答によってHTMLを返すので、応答を処理するHttpServletResponseを使うのです。

        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>LoopServlet</title>");

次の部分で、サンプル1,サンプル2, ...サンプル5と出力しています。

        for (int i = 1; i <= 5; i++) {
            out.print("<p>サンプル");
            out.println(i);
            out.print("</p>");
        }

もう1つのサンプルプログラムを見てみましょう。現在日時を表示するServletである、DateServlet.javaです。df.format()メソッドを実行することによって、現在の日時を出力しています。

DateServlet.java
// DateServlet
//   現在の日時をブラウザに表示する Servlet

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Date;
import java.text.DateFormat;

public class DateServlet extends HttpServlet {

    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
                      throws ServletException, IOException {
        doIt(request, response);
    }

    public void doPost(HttpServletRequest request,
                       HttpServletResponse response)
                       throws ServletException, IOException {
        doIt(request, response);
    }

    private void doIt(HttpServletRequest request,
                      HttpServletResponse response)
                      throws ServletException, IOException {

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

        Date d = new Date();
        DateFormat df = DateFormat.getDateTimeInstance();

        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>DateServlet</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<p>");
        out.println("いまは");
        out.println("<br />");
        out.println(df.format(d));
        out.println("<br />");
        out.println("です。");
        out.println("<br />");
        out.println("</body>");
        out.println("</html>");
    }
}

Servletでの要求・応答の処理

HttpServletRequest と HttpServletResponse

次のサンプルは、要求のヘッダ情報をブラウザに表示するServletです。

PrintHeadersServlet.java
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Enumeration;

public class PrintHeadersServlet extends HttpServlet {

    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
                      throws ServletException, IOException {
        doIt(request, response);
    }

    public void doPost(HttpServletRequest request,
                       HttpServletResponse response)
                       throws ServletException, IOException {
        doIt(request, response);
    }

    private void doIt(HttpServletRequest request,
                      HttpServletResponse response)
                      throws ServletException, IOException {

        Enumeration enum = request.getHeaderNames();

        response.setContentType("text/html; charset=Shift_JIS");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>ヘッダの一覧</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<ul>");

        while (enum.hasMoreElements()) {
            out.print("<li>");
            String name = (String)enum.nextElement();
            out.print(name + ": ");
            out.print(request.getHeader(name));
            out.println("</li>");
        }

        out.println("</ul>");
        out.println("</body>");
        out.println("</html>");
    }
}

このサンプルでは、HttpServletRequest型のオブジェクトrequestから、要求のヘッダ名のリストを取得しています。HTTPの要求を処理するのがHttpServletRequestであるのがポイントです。

        Enumeration enum = request.getHeaderNames();

また、HttpServletResponse型のオブジェクトからPrintWriterを取得し、そのPrintWriterに対してHTMLを出力しています。HTTPでは応答によってHTMLを返すので、応答を処理するHttpServletResponseを使うのです。

        PrintWriter out = response.getWriter();
        out.println("<html>");

このサンプルは、次のような出力になります。

    * host: localhost:8080
* user-agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:0.9.2) \
    Gecko/20010726 Netscape6/6.1
* accept: text/xml, application/xml, application/xhtml+xml, \
    text/html;q=0.9, image/png, image/jpeg, image/gif;q=0.2, \
    text/plain;q=0.8, text/css, */*;q=0.1
    * accept-language: ja
    * accept-encoding: gzip,deflate,compress,identity
    * accept-charset: Shift_JIS, utf-8;q=0.66, *;q=0.66
    * keep-alive: 300
    * connection: keep-alive

クエリーの処理

Servletでは、HttpServletRequestを使ってクエリーを処理します。

NameServlet.java
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class NameServlet extends HttpServlet {

    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
                      throws ServletException, IOException {
        doIt(request, response);
    }

    public void doPost(HttpServletRequest request,
                       HttpServletResponse response)
                       throws ServletException, IOException {
        doIt(request, response);
    }

    private void doIt(HttpServletRequest request,
                      HttpServletResponse response)
                      throws ServletException, IOException {
        request.setCharacterEncoding("Shift_JIS");

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

        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>入力された名前について</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<p>");
        out.println("姓: ");
        out.println(request.getParameter("familyName"));
        out.println("</p>");
        out.println("<p>");
        out.println("名: ");
        out.println(request.getParameter("givenName"));
        out.println("</p>");
        out.println("</body>");
        out.println("</html>");
    }
}

JSPと同じように、request.getParameter()というメソッドを使って、familyNameパラメータの値を出力しています。

        out.println(request.getParameter("familyName"));

Tomcat で Servlet を動かす

Servlet のコンパイル

Servletのプログラムに含まれている次の2つのパッケージは、J2SEには含まれていません。

そこで、Tomcatに含まれているライブラリをclasspathに含めてコンパイルする必要があります。

Windowsでは、次のようにしてコンパイルを実行します。

javac -classpath "%CATALINA_HOME%\common\lib\servlet-api.jar" \
    LoopServlet.java

classpathの値が""で囲われているのが不思議に思えるかもしれません。

"%CATALINA_HOME%\common\lib\servlet-api.jar"

これは、%CATALINA_HOME%の値にスペースが入っている時のための対策です。筆者の環境ではCATALINA_HOMEの値は次のようにスペースが入っているので、""で囲うことが必要になります。

C:\>echo %CATALINA_HOME%
C:\Program Files\Apache Group\Tomcat 4.1

Tomcat への配置

%CATALINA_HOME%\testというフォルダがあったとすると、その中のWEB-INF/classesフォルダにServletを置きます。Servletは、コンパイル済みのクラスファイルを配置します。

先のサンプルのServletを追加したときの、WEB-INFフォルダ以下の構成を示します。

WEB-INF/ --- web.xml
          |- classes/ --- LoopServlet.class
                       |- DateServlet.class
          |- lib/

WEB-INF フォルダと web.xml

Servletを使うときには、WEB-INFフォルダの中にあるweb.xmlを編集して、Servletに関する情報を記述する必要があります。JSPの場合は、web.xmlを編集する必要はありませんが、このファイルそのものが無ければ動作しません。

web.xml
<?xml version='1.0' encoding='UTF-8'?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd"
    version="2.4">

  <display-name>Servlet_and_JSP_Samples</display-name>
  <description>
     Servlet and JSP Samples
  </description>

  <servlet>
    <servlet-name>loop</servlet-name>
    <servlet-class>LoopServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>date</servlet-name>
    <servlet-class>DateServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>loop</servlet-name>
    <url-pattern>/loop</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>date</servlet-name>
    <url-pattern>/date</url-pattern>
  </servlet-mapping>

</web-app>

Servletに関する記述の例として、LoopServletに関する部分を抜き出してみましょう。

  <servlet>
    <servlet-name>loop</servlet-name>
    <servlet-class>LoopServlet</servlet-class>
  </servlet>

  (中略)

  <servlet-mapping>
    <servlet-name>loop</servlet-name>
    <url-pattern>/loop</url-pattern>
  </servlet-mapping>

前半のservletタグには、servlet-nameとservlet-classという2つの要素が含まれています。servlet-classでは、Servletのクラス名を指定します。ここでは、LoopServletになります。servlet-nameでは、このServletに対する名前を指定します。ここでは、"loop"という名前を付けています。

後半のservlet-mappingタグには、servlet-nameとurl-patternという2つの要素が含まれています。servlet-nameは、先のservletタグの中で指定した名前です。url-patternに、このServletにアクセスするときのURLを記述します。ここでは、"/loop"となることを示しています。

Servlet へのアクセス

まず、Tomcatを起動します。Tomcatがlocalhost上の8080番ポートで動いているとします。

LoopServletやDateServletには、次のURLでアクセスします。先のweb.xmlファイルで指定したURLを使っています。

  http://localhost:8080/test/loop
  http://localhost:8080/test/date