11章 Model, View, Controller

11.2 郵便番号検索のMVCによる実装

11.2.1 Model

zip/Model.java

package zip;

import java.util.*;
import java.sql.*;

public class Model {
  private String zip;
  private List<String[]> results;
  
  public List<String[]> getResults() {
    return results;
  }
  public void setZip(String zip) {
    this.zip = zip.replace("-","");
  }
  public void execute(){
    Connection conn=null;
    try{
      javax.naming.Context ctx=new javax.naming.InitialContext();
      javax.sql.DataSource ds=(javax.sql.DataSource)ctx.lookupLink("java:comp/env/jdbc/mydb");
      conn= ds.getConnection();
      
      PreparedStatement stmt=conn.prepareStatement("SELECT * FROM zips WHERE zip LIKE ?");
      stmt.setString(1,zip+"%");
      stmt.setMaxRows(100);
      ResultSet rs=stmt.executeQuery();
      
      results=new LinkedList<String[]>();
      while(rs.next()){
        String result[]={rs.getString("zip"),
            rs.getString("addr1")
            +rs.getString("addr2")
            +rs.getString("addr3")
            +rs.getString("addr4")
            +rs.getString("establishment")};
        results.add(result);
      }
    } catch (Exception e){
      System.out.println("in Model.execute, "+e.getMessage());
    } finally{
      if(conn!=null){
        try {
          conn.close();
        } catch (SQLException e) {}
      }
    }
  }
}

11.2.2 Controller

zip/Controller.javaの一部

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    doPost(request,response);                             //何もせずにdoPostを呼び出す
  }
  
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String zip=request.getParameter("zip");
    
    if(zip!=null){                                        //データが送信されていたなら,
      Model model=new Model();                            //モデルを生成し,
      model.setZip(zip);                                  //パラメータ(zip)を設定,
      model.execute();                                    //メイン・タスクを実行する(実装はModel).
      request.setAttribute("theModel",model);             //requestにModelを保管(Viewで取り出す).
    }
    this.getServletContext().getRequestDispatcher("/View.jsp").forward(request,response); //制御をJSPに渡す
  }

web.xmlの一部

  <servlet>
    <description></description>
    <display-name>Controller</display-name>
    <servlet-name>Controller</servlet-name>
    <servlet-class>zip.Controller</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>Controller</servlet-name>
    <url-pattern>/Controller</url-pattern>
  </servlet-mapping>

11.2.3 View

View.jsp

<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>郵便番号検索</title>
</head>
<body>
<form action="Controller" method="post">
  <p>
    <input type="text" name="zip" value='<c:out value="${param.zip}" />' />
    <input type="submit" name="submit" value="検索" />
  </p>
</form>
<c:if test="${!empty theModel}">
  <h2>検索結果</h2>
  <ul>
    <c:forEach var="result" items="${theModel.results}">
      <li><c:out value="${result[0]}: ${result[1]}" /></li>
    </c:forEach>
  </ul>
</c:if>
</body>
</html>

11.3 プロフィール登録システム

テーブル:people

CREATE TABLE people(
  id INT AUTO_INCREMENT,
  firstName VARCHAR(30) DEFAULT '' NOT NULL,
  lastName VARCHAR(30) DEFAULT '' NOT NULL,
  birthday DATE DEFAULT '1900-01-01' NOT NULL,
  zip CHAR(7) DEFAULT '' NOT NULL,
  address TEXT,
  CONSTRAINT id_pri PRIMARY KEY (id),
  INDEX firstName_idx (firstName),
  INDEX lastName_idx (lastName)
);

11.3.2 Model

mypackage/Person.java

package mypackage;

import java.util.*;
import java.sql.*;

public class Person {
  private String firstName;
  private String lastName;
  private Calendar birthday=Calendar.getInstance();
  private String zip;
  private String address;
  
  public Person(){}
  
  public Person(String fName,String lName){
    firstName=fName;
    lastName=lName;
  }
  public void zipSearch(){
    if(zip!=null){
      zip.Model model=new zip.Model();
      model.setZip(zip);
      model.execute();
      
      //検索結果の1番目を住所として設定
      String[] result=model.getResults().get(0);
      this.setZip(result[0]);
      this.setAddress(result[1].replaceAll("以下に掲載がない場合",""));
    }
  }
  public void execute() {
    Connection conn =null;
    try{
      javax.naming.Context ctx=new javax.naming.InitialContext();
      javax.sql.DataSource ds
        =(javax.sql.DataSource)ctx.lookupLink("java:comp/env/jdbc/mydb");
      conn = ds.getConnection();
      
      PreparedStatement stmt
        =conn.prepareStatement("INSERT INTO people "
            +"(firstName,lastName,birthday,zip,address) "
            +"values (?,?,?,?,?)");
      stmt.setString(1, firstName);
      stmt.setString(2, lastName);
      stmt.setDate(3, new java.sql.Date(birthday.getTime().getTime()));
      stmt.setString(4, zip);
      stmt.setString(5, address);
      
      stmt.execute();
    } catch (Exception e){
      System.out.println("in Model.execute, "+e.getMessage());
    } finally{
      if(conn!=null){
        try {
          conn.close();
        } catch (SQLException e) {}
      }
    }
  }
  public int getAge(){
    Calendar today=Calendar.getInstance();
    int year=today.get(Calendar.YEAR);
    int month=today.get(Calendar.MONTH);
    int date=today.get(Calendar.DAY_OF_MONTH);
    
    if(getMonth()<month) return year-getYear();
    if(getMonth()>month) return year-getYear()-1;
    if(getDate()<=date) return year-getYear();
    return year-getYear()-1;
  }
  public void run(){
    System.out.println("RUN!");
  }
  public String getAddress() {
    return address;
  }
  public void setAddress(String address) {
    this.address = address;
  }
  public String getZip() {
    return zip;
  }
  public void setZip(String zip) {
    this.zip = zip;
  }
  public String getFirstName() {
    return firstName;
  }
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  public String getLastName() {
    return lastName;
  }
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  public Calendar getBirthday(){
    return birthday;
  }
  public void setBirthday(int year,int month,int date){
      birthday.set(year, month-1, date,0,0,0); //1月が0だから
  }
  public int getYear(){
    return birthday.get(Calendar.YEAR);
  }
  public int getMonth(){
    return birthday.get(Calendar.MONTH)+1;
  }
  public int getDate(){
    return birthday.get(Calendar.DAY_OF_MONTH);
  }
}

11.3.3 Controller

mypackage/Register.javaの一部

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    doPost(request,response);
  }
  
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.setCharacterEncoding("utf-8");
    
    HttpSession session=request.getSession();                            //sessionからモデルを取得
    Person thePerson=(Person)session.getAttribute("thePerson");
    if(thePerson==null){                                                 //モデルがまだ無かったら
      thePerson=new Person();                                            //新たに生成
      session.setAttribute("thePerson", thePerson);                      //sessionに登録
    }
    
    String forwardUrl="/Registration.jsp";                               //デフォルトの転送先
    String command=request.getParameter("submit");                       //ボタンによって動作を変える
    
    if(command!=null){                                                   //データを受信したか
      if(command.equals("登録")){
        this.setProfile(request);
        forwardUrl="/Confirmation.jsp";
      }
      else if(command.equals("住所を検索")){
        this.setProfile(request);
        thePerson.zipSearch();
      }
      else if(command.equals("完了")){
        thePerson.execute();
        session.invalidate();
        forwardUrl="/Thanks.jsp";
      }
    }
    getServletContext().getRequestDispatcher(forwardUrl).forward(request,response);
  }
  
  private void setProfile(HttpServletRequest request){
    Person thePerson=(Person)request.getSession().getAttribute("thePerson");
    thePerson.setLastName(request.getParameter("lastName"));
    thePerson.setFirstName(request.getParameter("firstName"));
    thePerson.setBirthday(Integer.parseInt(request.getParameter("year")),
    Integer.parseInt(request.getParameter("month")),
    Integer.parseInt(request.getParameter("date")));
    thePerson.setZip(request.getParameter("zip"));
    thePerson.setAddress(request.getParameter("address"));
  }

11.3.4 View

11.3.4.1 Registration.jsp

<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>プロフィール登録</title>
</head>
<body>
<p>プロフィールを入力してください</p>
<form action="Register" method="post">
  <table summary="profile">
    <tr>
      <td>姓</td>
      <td><input type="text" name="lastName" value='<c:out value="${thePerson.lastName}" />' />
      </td>
    </tr>
    <tr>
      <td>名</td>
      <td><input type="text" name="firstName" value='<c:out value="${thePerson.firstName}" />' />
      </td>
    </tr>
    <tr>
      <td>生年月日</td>
      <td>西暦
        <input type="text" name="year" value='<c:out value="${thePerson.year}" />' size="4"/>年
        <input type="text" name="month" value='<c:out value="${thePerson.month}" />' size="2"/>月
        <input type="text" name="date" value='<c:out value="${thePerson.date}" />' size="2"/>日
      </td>
    </tr>
    <tr>
      <td>郵便番号</td>
      <td>
        <input type="text" name="zip" value='<c:out value="${thePerson.zip}" />' size="8" />
        <input type="submit" name="submit" value="住所を検索" />
      </td>
    </tr>
    <tr>
      <td>住所</td>
      <td><input type="text" name="address" value='<c:out value="${thePerson.address}" />' size="50"/>
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" name="submit" value="登録" /></td>
    </tr>
  </table>
</form>
</body>
</html>

11.3.4.2 Confirmation.jsp

Confirmation.jspの一部

<body>
<p>プロフィールを確認してください</p>
<form action="Register" method="post">
  <table summary="profile">
    <tr>
      <td>姓</td>
      <td><c:out value="${thePerson.lastName}" /></td>
    </tr>
    <tr>
      <td>名</td>
      <td><c:out value="${thePerson.firstName}" /></td>
    </tr>
    <tr>
      <td>生年月日</td>
      <td>
        <c:out value="西暦${thePerson.year}年 ${thePerson.month}月 ${thePerson.date}日" />
      </td>
    </tr>
    <tr>
      <td>郵便番号</td>
      <td><c:out value="${thePerson.zip}" /></td>
    </tr>
    <tr>
      <td>住所</td>
      <td><c:out value="${thePerson.address}" /></td>
    </tr>
    <tr>
      <td></td>
      <td>
        <input type="submit" name="submit" value="完了" />
        <input type="submit" name="submit" value="修正" />
      </td>
    </tr>
  </table>
</form>
</body>

11.3.4.3 Thanks.jsp

Thanks.jspの一部

<body>
  <p>Thanks!</p>
  <p><a href="Register">戻る</a></p>
</body>