Servletは、JSPと同じく、Webブラウザからの要求を処理して動的なページを作成するためのものです。また、JSPと同様にTomcatなどのWebコンテナの内部で動きます。
Servletは、HttpServletというクラスを継承して、必要なメソッドをオーバーライドしたクラスになります。CGIと同じように、ServletからHTMLを出力できます。
JSPのところで、サンプル1,サンプル2, ...サンプル5のような出力をするloop.jspというサンプルプログラムを示しました。ここでは、同じ働きをするServletのプログラムを見てみましょう。
// 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
// 現在の日時をブラウザに表示する 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です。
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を使ってクエリーを処理します。
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"));
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
%CATALINA_HOME%\testというフォルダがあったとすると、その中のWEB-INF/classesフォルダにServletを置きます。Servletは、コンパイル済みのクラスファイルを配置します。
先のサンプルのServletを追加したときの、WEB-INFフォルダ以下の構成を示します。
WEB-INF/ --- web.xml
|- classes/ --- LoopServlet.class
|- DateServlet.class
|- lib/
Servletを使うときには、WEB-INFフォルダの中にあるweb.xmlを編集して、Servletに関する情報を記述する必要があります。JSPの場合は、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"となることを示しています。
まず、Tomcatを起動します。Tomcatがlocalhost上の8080番ポートで動いているとします。
LoopServletやDateServletには、次のURLでアクセスします。先のweb.xmlファイルで指定したURLを使っています。
http://localhost:8080/test/loop http://localhost:8080/test/date