まずは、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/を参照してください。