この講義でこれまで見てきたように、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 (と、それを複数集めたList)になります。
まず、モデルとなるJavaBeansを見てみましょう。BookDataは、1冊の本のデータを表すBeanです。java.util.Listで複数のBookDataをまとめます。
package jp.ac.wakhok.library; import java.io.Serializable; public class BookData implements Serializable { 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; } }
次に、コントローラであるServletのソースを見てみましょう。
import java.util.List; import java.util.ArrayList; 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"); List list = search(ndc, tyosya_hyouji, id, title, author, publisher); HttpSession session = request.getSession(); session.setAttribute("bookList", list); context.getRequestDispatcher(jspFile) .forward(request, response); } private List search(String ndc, String tyosya_hyouji, String id, String title, String author, String publisher) { List list = new ArrayList(); 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); } rs.close(); prepStmt.close(); con.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を使って、そのデータを検索しています。1冊の本のデータはBookDataに格納されます。そして検索結果は、java.util.Listにまとめられています。
List 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" %> <html> <head> <title>検索結果</title> </head> <body> <h1>検索結果</h1> <ul> <c:forEach var="book" items="${sessionScope.bookList}" > <li> <c:out value="${book.title}" /> / <c:out value="${book.author}" /> </li> </c:forEach> </ul> </body> </html>
このJSPでは、タグライブラリであるJSTLを使っています。まず、Listに含まれているBookDataをひとつずつ処理するためにc:forEachが使われています。また、BookDataのプロパティを出力するためにc:outが使われています。
まず、c:forEachについて見てみましょう。
<c:forEach var="book" items="${sessionScope.bookList}" > ..... </c:forEach>
このタグのitems属性では、ServletでHttpSessionに登録された、bookListというコレクションを取り出しています。
このforEachというタグは、items属性で与えられたCollection, Iteratorなどに含まれているオブジェクトを繰り返し処理します。現在処理をしているオブジェクトは、bookという変数に入ります。この<c:forEach>タグでは、BookDataをひとつひとつ処理することになります。
BookDataのプロパティの出力には、c:outの中で式言語を使っています。
<c:out value="${book.title}" />
このサンプルアプリケーションを動かすには、Tomcatには次のようにファイルを配置します。
test --- input.html |- list.jsp |- WEB-INF/ ---- web.xml |-- classes/ | |- BookSearchServlet.class | |- jp/ac/wakhok/library/ --- BookData.class |-- lib/ |- hsqldb.jar |- jstl.jar |- standard.jar |- jaxen-full.jar |- saxpath.jar