まずは、JDBCを使うServletを紹介しましょう。基本的には、これまで見てきたServletと同じスタイルです。
import java.io.*;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class JDBCTestServlet 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>JDBCTestServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<p>");
out.println("タイトルに");
out.println("Java");
out.println("という文字列を含む本は");
out.println("</p>");
out.println("<p>");
try {
Class.forName("org.hsqldb.jdbcDriver");
String url = "jdbc:hsqldb:hsql://localhost";
Connection con = DriverManager.getConnection(url, "sa", "");
String selectStatement =
"select title " +
"from books where title like ?";
PreparedStatement prepStmt =
con.prepareStatement(selectStatement);
prepStmt.setString(1, "%" + "Java" + "%");
ResultSet rs = prepStmt.executeQuery();
while (rs.next()) {
String title = rs.getString("title");
out.println(title);
out.println("<br>");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
out.println("</p>");
out.println("</body>");
out.println("</html>");
}
}
このServletをコンパイルするには、ServletのAPIとJDBCドライバをclasspathに含める必要があります。この例では、Tomcatに含まれているServletのAPIと、HSQLDBのJDBCドライバが含まれているjarファイルをclasspathに追加しています。
javac -classpath "%CATALINA_HOME%\common\lib\servlet.jar;%HSQLDB_HOME%\lib\hsqldb.jar" JDBCTestServlet.java (実際には1行で入力する)
また、Tomcat上で実行するには、web.xmlにこのServletの情報を追加します。さらに、WEB-INF/libフォルダに、JDBCドライバが含まれているjarファイルを追加する必要があります。
WEB-INF/ --- web.xml
|- classes/ --- JDBCTestServlet.class
|- lib/ --- hsqldb.jar (JDBCドライバが含まれている)
この講義でこれまで見てきたように、ServletとJSPはそれぞれ同じような処理ができます。では、この2つはどのように使い分ければよいのでしょうか。
ServletにしてもJSPにしても、HTMLとプログラムが混在していると、ソースファイルの見通しが悪く保守が大変になります。現在のWebアプリケーション開発では、HTMLの出力部分とプログラムとを分離するのが良いとされています。
JSPは、HTMLにJavaプログラムを埋め込んだようなスタイルです。スクリプトレットは書きにくく、アプリケーションのロジックがわかりにくくなるという欠点があります。また、Webページのデザイナが、スクリプトレットを書くのは大変です。JSPを使うときには、スクリプトレットをJavaBeansとタグライブラリに置き換えて、JSPはHTMLの出力に専念させるのが良いでしょう。
そして、ServletはJavaプログラムなので、HTMLの出力をさせずに、ロジックの処理に専念させるのが良いでしょう。Servletでの処理結果を、JSPで表示することができます。Servletでのプログラミングは、本質的には、HttpServletRequestとHttpServletResponseに働きかけるというものです。Servletは、RequestをResponseに変換するコンポーネントであると考えられます。
ソフトウェア開発には、「Model-View-Controller (MVC)」と呼ばれている方法論があります。この方法論では、アプリケーションを構成するコンポーネントが、「モデル(Model)」・「ビュー(View)」・「コントローラ(Controller)」と名づけられた、3つの部分に分けられています(図[MVCモデル2]。
「モデル」は、アプリケーションのデータとビジネスロジックをまとめた部分です。「ビュー」は、「モデル」の表示を担当する部分です。「コントローラ」は、「モデル」と「ビュー」を制御する部分です。
最近のJ2EEとその関連技術では、モデルにJavaBeansを使い、ビューにJSPを使い、コントローラにServletを使う開発手法が採用されています。このJ2EEの手法は、「MVCモデル2」と呼ばれています。
ここでは、サンプルを通して、MVCモデル2によるアプリケーションの基本的な構成について見てみましょう。このサンプルは、本の検索アプリケーションです。
このアプリケーションの処理は、まずユーザがWebブラウザに検索したい本の情報を入力し、その情報をもとにServletが処理をして、結果をJSPが表示する、という流れになります。それぞれの部分の役割は、次のようになります。
Servletがコントローラとなり、JSPがビューを担当します。また、モデルであるJavaBeansは、アプリケーションで処理するデータを保持して、ServletからJSPに渡されます。
今回のサンプルプログラムでは、コントローラがBookSearchServletであり、ビューがlist.jspで、モデルが示しているBookDataとBookListになります。
まず、モデルとなるJavaBeansを見てみましょう。BookDataは、1冊の本のデータを表すBeanであり、BookListは、複数のBookDataをリスト化したものです。
package jp.ac.wakhok.library;
public class BookData {
private String ndc = "";
private String tyosya_hyouji = "";
private String id = "";
private String title = "";
private String author = "";
private String publisher = "";
public String getNdc() {
return ndc;
}
public void setNdc(String ndc) {
this.ndc = ndc;
}
public String getTyosya_hyouji() {
return tyosya_hyouji;
}
public void setTyosya_hyouji(String tyosya_hyouji) {
this.tyosya_hyouji = tyosya_hyouji;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
}
package jp.ac.wakhok.library;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
public class BookList {
private List list;
public BookList() {
list = new ArrayList();
}
public void add(BookData data) {
list.add(data);
}
public Iterator getIterator() {
return list.iterator();
}
}
次に、コントローラであるServletのソースを見てみましょう。
import java.io.*;
import java.sql.*;
import javax.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
import jp.ac.wakhok.library.*;
public class BookSearchServlet extends HttpServlet {
private String jspFile = "/list.jsp";
private ServletContext context;
public void init() throws ServletException {
context = getServletContext();
}
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");
String ndc = request.getParameter("ndc");
String tyosya_hyouji = request.getParameter("tyosya_hyouji");
String id = request.getParameter("id");
String title = request.getParameter("title");
String author = request.getParameter("author");
String publisher = request.getParameter("publisher");
BookList list =
search(ndc, tyosya_hyouji, id, title, author, publisher);
HttpSession session = request.getSession();
session.setAttribute("bookList", list);
context.getRequestDispatcher(jspFile)
.forward(request, response);
}
private BookList search(String ndc, String tyosya_hyouji,
String id, String title,
String author, String publisher) {
BookList list = new BookList();
try {
Class.forName("org.hsqldb.jdbcDriver");
String url = "jdbc:hsqldb:hsql://localhost";
Connection con = DriverManager.getConnection(url, "sa", "");
String selectStatement =
"select * " +
"from books where ndc like ? " +
"and tyosya_hyouji like ? " +
"and id like ? " +
"and title like ? " +
"and author like ? " +
"and publisher like ? ";
PreparedStatement prepStmt =
con.prepareStatement(selectStatement);
prepStmt.setString(1, appendPercent(ndc));
prepStmt.setString(2, appendPercent(tyosya_hyouji));
prepStmt.setString(3, appendPercent(id));
prepStmt.setString(4, appendPercent(title));
prepStmt.setString(5, appendPercent(author));
prepStmt.setString(6, appendPercent(publisher));
ResultSet rs = prepStmt.executeQuery();
while (rs.next()) {
BookData book = new BookData();
book.setNdc(rs.getString("ndc"));
book.setTyosya_hyouji(rs.getString("tyosya_hyouji"));
book.setId(rs.getString("id"));
book.setTitle(rs.getString("title"));
book.setAuthor(rs.getString("author"));
book.setPublisher(rs.getString("publisher"));
list.add(book);
}
prepStmt.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
private String appendPercent(String from) {
StringBuffer to = new StringBuffer();
to.append("%");
to.append(from);
to.append("%");
return new String(to);
}
}
このServletでは、まずWebブラウザから入力されたデータを取り出し、JDBCを使って、そのデータを検索しています。そして検索結果を、モデルであるBookListに入れています。
BookList list =
search(ndc, tyosya_hyouji, id, title, author, publisher);
そして次の部分で、HttpSession型のインスタンスsessionに、bookListという名前でBeanを登録します。
HttpSession session = request.getSession();
session.setAttribute("bookList", list);
Beanの内容の出力はlist.jspというJSPページに任せています。
context.getRequestDispatcher("/list.jsp");
.forward(request, response);
最後に、ビューであるJSPのソースを見てみましょう。
<%@ page contentType="text/html; charset=Shift_JIS" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<jsp:useBean id="bookList"
class="jp.ac.wakhok.library.BookList"
scope="session" />
<html>
<head>
<title>検索結果</title>
</head>
<body>
<h1>検索結果</h1>
<ul>
<c:forEach var="book" items="${bookList.iterator}" >
<li>
<c:out value="${book.title}" />
/
<c:out value="${book.author}" />
</li>
</c:forEach>
</ul>
</body>
</html>
まず、Servletの処理で、HttpSessionに登録したBookList Beanの利用を宣言しています。
<jsp:useBean id="bookList"
class="jp.ac.wakhok.library.BookList"
scope="session" />
JSPでは、ユーザが自分でJSP内のタグを定義できます。こうしたタグのことを、「カスタム・タグ」と言います。
カスタム・タグによって、これまでスクリプトレットとして書いていたプログラムを、JSPの要素に閉じ込めることができ、HTMLが見やすくなります。
いくつかの関連する複数のタグは、1つの「タグライブラリ」にまとめられます。ここでは、既存のタグライブラリであるJavaServer Pages Standard Tag Library (JSTL) (http://java.sun.com/products/jsp/jstl/)のサンプルを紹介します。
まず次の部分で、使用するタグライブラリと、その接頭辞を指定します。ここでは、接頭辞に"c"という文字が指定されています。
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
このJSPでは、c:forEachというタグとc:outというタグが使われています。
<c:out value="${book.title}" />
c:outというタグは、値を出力するタグです。valueという属性値で指定したデータを出力します。このタグによって、"<"や"&"といった文字は、エスケープされて出力されます。このことを、タグライブラリを使わずにJSPで実現するには、スクリプトレットを記述する必要があります。
ここでのvalueの値が、
${book.title}
という見慣れないスタイルになっています。これは、Beanであるbookのtitleプロパティの値を示します。
JSTLでは、次のような「式言語」と呼ばれる表現が可能になっています。こうしたスタイルは、今後のJSPで正式に取り上げられる予定です。
${var} ... 変数 var
${param.title} ... フォームから入力されたデータ "title" の値
${book.author} ... book という Bean の author プロパティ
もう一つのc:forEachというタグでは、ループの処理を行っています。
<c:forEach var="book" items="${bookList.iterator}" >
.....
</c:forEach>
このタグは、items属性で与えられたCollection, Iteratorなどに含まれているオブジェクトを繰り返し処理します。現在処理をしているオブジェクトは、bookという変数に入ります。
BookListにはgetIteratorというメソッドがあるので、JavaBeansの命名規則により、BookListというBeanにはiteratorというプロパティがあると判断されます。このため、${bookList.iterator}では、BookList#iteratorメソッドが適用されます。このメソッドはIteratorを返します。Iteratorには、BookDataの集合が含まれているので、この<c:forEach>タグでは、BookDataをひとつひとつ処理することになります。
スクリプトレットを使わなければ書けなかったループの処理が、タグライブラリを使うことによってタグで書けるようになります。
JSTLを利用するためには、JSTLの配布パッケージのlibフォルダに含まれている次の4つのjarファイルをWEB-INF/libフォルダにコピーします。
このサンプルアプリケーションを動かすには、Tomcatには次のようにファイルを配置します。
test --- input.html
|- list.jsp
|- WEB-INF/ ---- web.xml
|-- classes/
| |- BookSearchServlet.class
| |- jp/ac/wakhok/library/ --- BookData.class
| |- jp/ac/wakhok/library/ --- BookList.class
|-- lib/
|- hsqldb.jar
|- jstl.jar
|- standard.jar
|- jaxen-full.jar
|- saxpath.jar
いま見てきた図書検索アプリケーションでは、検索結果をリスト表示するという、単純なものでした。では、このアプリケーションに、1冊の本の詳細を表示する機能を付け加えるとしたら、どのようなプログラムが必要になるでしょうか。
詳細表示用のServletを付け加えるのが、1つの方法です。ただこの方法をとると、Servletが増えるに従って、アプリケーション全体に見通しが悪くなってきます。
こうしたことを解決するため、最近では「Struts」というフレームワークがよく使われています。StrutsはMVCモデル2のビューとコントローラをサポートしており、Webアプリケーションの開発の手間を減らしてくれます。Strutsについては、http://www.ingrid.org/jakarta/struts/を参照してください。