MVCモデルの簡単な例

基本的に**スッキリわかる サーブレット&jsp入門 第7章のBMI計算プログラム**に準じます。
##MVCモデルとは
|要素　　　|役割　　　|ファイル|
|:---------------------|:------------------|:------------------|
| Model          |アプリケーションの主たる処理やデータの格納などを行う|一般的なクラス|
| View          |ユーザーに対して画面の表示を行う　　　　　　|JSPファイル　　　　　　|
| Controller    |ユーザーからの要求を受け取り、処理の実行をモデルに依頼し、その結果の表示をビューに依頼する　　　　|サーブレットクラス|

##javaBeams
インスタンスを保存できる領域の一つ。
以下のルールがある。
1. 直列化可能
2. クラスはpublicでパッケージに所属
3. publicで引数のないコンストラクタを持つ
4. フィールドはカプセル化されている
5. 命名規則に従ったgetter/setterを持つ


##サンプルプログラム
コードごとに随時解説を入れます。

###Model
アプリケーションの主たる処理やデータの格納などを行う
modelパッケージに保存。

```Health.java
package model;

import java.io.Serializable;

public class Health implements Serializable {
  private double height, weight, bmi;
  private String bodyType;

  public double getHeight() {
    return height;
  }

  public void setHeight(Double height) {
    this.height = height;
  }

  public double getWeight() {
    return weight;
  }

  public void setWeight(Double weight) {
    this.weight = weight;
  }

  public void setBmi(Double bmi) {
    this.bmi = bmi;
  }

  public double getBmi() {
    return this.bmi;
  }

  public void setBodyType(String bodyType) {
    this.bodyType = bodyType;
  }

  public String getBodyType() {
    return this.bodyType;
  }
}
```
このコードがいわゆるJavaBeansである。

```HealthCheckLogic.java
package model;

public class HealthCheckLogic {
  public void execute(Health health) {
    // BMIを算出して設定
    double weight = health.getWeight();
    double height = health.getHeight();
    double bmi = weight / (height / 100.0 * height / 100.0);
    health.setBmi(bmi);

    // BMI指数から体格を判定して設定
    String bodyType;
    if (bmi < 18.5) {
      bodyType = "痩せ型";
    } else if (bmi < 25) {
      bodyType = "普通";
    } else {
      bodyType = "肥満";
    }
    health.setBodyType(bodyType);
  }
}
```
特筆して書くことはなし.

###Controller
ユーザーからの要求を受け取り、処理の実行をモデルに依頼し、その結果の表示をビューに依頼する。
servletパッケージに保存。

```HealthCheck.java
package servlet;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import model.Health;
import model.HealthCheckLogic;

@WebServlet("/HealthCheck")
public class HealthCheck extends HttpServlet {
  private static final long serialVersionUID = 1L;

  protected void doGet(HttpServletRequest request,
      HttpServletResponse response)
      throws ServletException, IOException {

    // フォワード
    RequestDispatcher dispatcher =
        request.getRequestDispatcher
            ("/WEB-INF/jsp/healthCheck.jsp");
    dispatcher.forward(request, response);
  }

  protected void doPost(HttpServletRequest request,
      HttpServletResponse response)
      throws ServletException, IOException {

    // リクエストパラメータを取得
    String weight = request.getParameter("weight"); // 身長
    String height = request.getParameter("height"); // 体重

    // 入力値をプロパティに設定
    Health health = new Health();
    health.setHeight(Double.parseDouble(height));
    health.setWeight(Double.parseDouble(weight));
    // 健康診断を実行し結果を設定
    HealthCheckLogic healthCheckLogic = new HealthCheckLogic();
    healthCheckLogic.execute(health);

    // リクエストスコープに保存
    request.setAttribute("health", health);

    // フォワード
    RequestDispatcher dispatcher =
        request.getRequestDispatcher
            ("/WEB-INF/jsp/healthCheckResult.jsp");
    dispatcher.forward(request, response);
  }
}
```
####URLパターン
`@WebServlet("/HealthCheck")`に記述。

####serialVersionUID
`private static final long serialVersionUID = 1L;`は一種のおまじないのようなものに感じるが違う。
直列化した時、つまりjava.io.Serializableをインポートしたときに必要。
Serializableクラスのバージョンコントロールとして使用される。

####リクエストスコープ
リクエストごとに生成されるスコープ。フォワード先とフォワード元でインスタンスを共有することが可能になる。

```.java
request.setAttribute("属性名", インスタンス)
```
**属性名**にスコープに保存するインスタンスの管理用の名前を指定。
**インスタンス**に保存するインスタンスを指定

リクエストスコープからインスタンスを取得する場合は以下のように記載。今回はhealthCheckResult.jspでこの処理を行っている。

```.java
取得するインスタンスの型 名前　= (取得するインスタンスの型)request.getAttribute("属性名")
```
キャストが必要な点に注意

####フォワード
フォワードを利用することで、処理を他のサーブレットクラスやJSPファイルに移すことが可能。

```.java
RequestDispatcher dispatcher =
request.getRequestDispatcher
    ("フォワード先");
dispatcher.forward(request, response);
```

フォワード先の指定方法
JSPファイル　→ /WebContentからのパス
サーブレットクラス　→　/URLパターン

###View
ユーザーに対して画面の表示を行う。
ここでは/WebContent/Web-INF/jspに保存。

```healthCheck.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>スッキリ健康診断</title>
</head>
<body>
<h1>スッキリ健康診断</h1>
<form action="/example/HealthCheck" method="post">
身長：<input type="text" name="height">(cm)<br>
体重：<input type="text" name="weight">(kg)<br>
<input type="submit" value="診断">
</form>
</body>
</html>
```
10行目`<form action="/example/HealthCheck" method="post">`action属性の指定は以下のようになる。
サーブレットクラスの場合　→　/アプリケーション名/URLパターン
JSPファイルの場合 → /アプリケーション名/WebContentからのパス



```healthCheckResult.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="model.Health" %>
<%
// リクエストスコープに保存されたHealthを取得
Health health = (Health) request.getAttribute("health");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>スッキリ健康診断</title>
</head>
<body>
<h1>スッキリ健康診断の結果</h1>
<p>
身長：<%= health.getHeight() %><br>
体重：<%= health.getWeight() %><br>
BMI：<%= health.getBmi() %><br>
体格：<%= health.getBodyType() %>
</p>
<a href="/example/HealthCheck">戻る</a>
</body>
</html>
```
2行目の`<%@ page import="model.Health" %>`でmodelパッケージのHealth.classを呼び出している。
このコードがjavaBeansの使い方を理解するのに最適かも。


##最後に
**スッキリわかるサーブレット＆JSP入門**(国本大悟 著）を参照してください。
また本稿のソースコードの著作権は株式会社フレアリンクに帰属します。
Creative Commons BY-SA 4.0従い利用しています。