Powered by SmartDoc

MVCモデル2によるWebアプリケーション

ServletとJSPの使い分け

この講義でこれまで見てきたように、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に変換するコンポーネントであると考えられます。

MVCモデル2

MVCモデル2とは

ソフトウェア開発には、「Model-View-Controller (MVC)」と呼ばれている方法論があります。この方法論では、アプリケーションを構成するコンポーネントが、「モデル(Model)」・「ビュー(View)」・「コントローラ(Controller)」と名づけられた、3つの部分に分けられています(図10.1[MVCモデル2])。

MVCモデル2

最近のJ2EEとその関連技術では、モデルにJavaBeansを使い、ビューにJSPを使い、コントローラにServletを使う開発手法が採用されています。このJ2EEの手法は、「MVCモデル2」と呼ばれています。

では、この「モデル・ビュー・コントローラ」について見てみましょう。

モデル

「モデル」は、アプリケーションのデータと、データの処理をするプログラムをまとめた部分です。この「データの処理をするプログラム」のことを「ビジネスロジック」と言います。

JavaBeans (あるいはそのコレクション)がモデルとして利用されます。

ビュー

「ビュー」は、「モデル」の表示を担当する部分です。J2EEでは、JSPがよく利用されます。

ビュー

「コントローラ」は、「モデル」と「ビュー」を制御する部分です。Servletが担当します。

処理の流れ

MVCモデル2を用いたWebアプリケーションの処理の流れは、次のようになります。

まず、ServletがHTTPから要求を受け取ります。そして、データベースへのアクセスなどの必要な処理をします。

処理した結果はJavaBeansに格納します。ServletはJavaBeans (または、Beansをまとめたコレクション)をJSPに渡します。

JSPはタグライブラリを駆使して処理結果を出力します。このとき、JavaBeansのプロパティを出力することになります。

サンプルアプリケーション

ここでは、サンプルを通して、MVCモデル2によるアプリケーションの基本的な構成について見てみましょう。このサンプルは、本の検索アプリケーションです。

基本的な処理の流れ

このアプリケーションの処理は、まずユーザがWebブラウザに検索したい本の情報を入力し、その情報をもとにServletが処理をして、結果をJSPが表示する、という流れになります。それぞれの部分の役割は、次のようになります。

Webブラウザ
Servlet
JSP

Servletがコントローラとなり、JSPがビューを担当します。また、モデルであるJavaBeansは、アプリケーションで処理するデータを保持して、ServletからJSPに渡されます。

今回のサンプルプログラムでは、コントローラがBookSearchServletであり、ビューがlist.jspで、モデルがBookData (と、それを複数集めたList)になります。

モデルとなる JavaBeans

まず、モデルとなるJavaBeansを見てみましょう。BookDataは、1冊の本のデータを表すBeanです。java.util.Listで複数のBookDataをまとめます。

BookData.java
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 の働き

次に、コントローラであるServletのソースを見てみましょう。

BookSearchServlet.java
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 とタグライブラリ

最後に、ビューであるJSPのソースを見てみましょう。

list.jsp
<%@ page contentType="text/html; charset=Shift_JIS" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/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