MVC練習4(すしオーダーアプリ(session))

JSP&Servlet

今回は受講生(T氏)からのお題を題材にMVCに分けて行う開発の学習しよう。
ショッピングカートシステムを作る際の基礎となる処理だ。スコープにはSessionスコープを用いる。

お題

お寿司オーダーシステムを作成せよ。お寿司はすべて1皿100円とする。

実行例

ホスト名/sushi/OrderMain

上記のURLでブラウザからアクセスすると。以下のようなフォームが表示される

項目を入力し、送信ボタンを押す

以下のように出力される

戻るを押すとフォームに戻る。このとき皿数は復元されている。

注文を変更して、注文ボタンを押す

情報が更新された。確定を押そう。

以下のように合計が表示される。

戻るリンクを押すと、最初の未入力の状態に戻る

作成

ファイル構成

model

model.Order.java //javaBeansの仕様を満たしたクラス
model.OrderLogic.java //確定した際にお会計情報を含んだインスタンスを完成させるクラス

controller

controller.OrderMain.java //HttpServletクラスを継承して作成する(サーブレット)

view

/WEB-INF/view/form.jsp //フォームを表示する
/WEB-INF/view/form.jsp //確認画面を表示する
/WEB-INF/view/result.jsp //結果を表示する

作成

model.Order.java

結果画面を見て、何が必要なのかを考慮し以下のようなクラスを作成する。

package model;

import java.io.Serializable;

public class Order implements Serializable{
	private final String[] names={"まぐろ","サーモン","エビ","タコ","イカ","いくら"};
	private String[] counts;//それぞれの個数が入る
	private int totalCount;//合計の皿数
	private int totalFee;//合計金額
	private String msg;//「まぐろが2皿エビが3皿」などの情報が入る
	
	public Order() {
		//new された際に、すしの種類の数だけ"0"を入れる
		this.counts=new String[names.length];
		for(int i=0;i<this.counts.length;i++) {
			this.counts[i]="0";
		}
	}
	public String[] getNames() {
		return names;
	}
	public String[] getCounts() {
		return counts;
	}
	public void setCounts(String[] counts) {
		this.counts = counts;
	}
	public int getTotalCount() {
		return totalCount;
	}
	public void setTotalCount(int totalCount) {
		this.totalCount = totalCount;
	}
	public int getTotalFee() {
		return totalFee;
	}
	public void setTotalFee(int totalFee) {
		this.totalFee = totalFee;
	}
	public String getMsg() {
		return msg;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}
}

model.OrderLogic.java

package model;

public class OrderLogic {
	public void execute(Order order) {
		String[] names=order.getNames();//{"まぐろ","サーモン","エビ","タコ","イカ","いくら"};
		String[] counts=order.getCounts();//{"6","1","2","0","1","3"}
		int countsTotal=0;
		String msg="";
		for(int i=0;i<names.length;i++) {
			int count=Integer.parseInt(counts[i]);
			if(count > 0) {
				countsTotal+=count;
				msg+=String.format("%sが%d皿", names[i],count);
			}
		}
		//orderインスタンスに情報をセットする
		order.setTotalCount(countsTotal);
		order.setTotalFee(countsTotal * 100);
		order.setMsg(msg);
	}
}

controller.OrderMain.java

処理の流れを考えながらまずはdoGetを作成する。今回はsessionスコープを利用してインスタンスを保存する。(doPostはカラにしておく)

package controller;

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 javax.servlet.http.HttpSession;

import model.Order;
import model.OrderLogic;

@WebServlet("/OrderMain")
public class OrderMain extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//フォワード先path
		String forwardPath="/WEB-INF/view/form.jsp";
		//リクエストパラメータの取得
		String action=request.getParameter("action");
		//sessionを使う準備
		HttpSession session=request.getSession();
		//sessionスコープからorderインスタンスの取得を試みる
		Order order=(Order)session.getAttribute("order");
		if(action == null) {
			//action属性が来ていなかったらOrderインスタンスを新しく生成する。
			order=new Order();
		}
    //sessionスコープにorderインスタンスを保存する
		session.setAttribute("order", order);
		
		//フォワード処理
		RequestDispatcher rd=
				request.getRequestDispatcher(forwardPath);
		rd.forward(request, response);
	}

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

}

/WEB-INF/view/form.jsp

WebContentの中にあるWEB-INFフォルダ内にviewフォルダを作成し、その中にform.jspファイルを作成する。内容は以下
今回はセッションスコープから取り出したインスタンスの情報をもとにフォームを作成している。なお、name属性はすべてcountsとしている

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="model.Order" %>
<%
//セッションスコープからインスタンスを取得する
Order order=(Order)session.getAttribute("order");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>すしアプリ</title>
</head>
<body>
<p>注文数を入力してください</p>
<form action="/sushi/OrderMain" method="post">
<% for(int i=0;i<order.getNames().length;i++){ %>
<%=order.getNames()[i] %><input type="number" min="0" name="counts" value="<%=order.getCounts()[i]%>">皿<br>
<%} %>
<input type="submit" value="注文">
</form>
</body>
</html>

確認

ここまで書けたら一度確認する。サーブレットのOrderMain.javaを右クリックしてサーバーで実行を選択。以下のように表示されればOKだ。

controller.OrderMain.javaに追記

フォームから入力された値はpost通信で送信されてくるのでdoPostを以下のように追記

package controller;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import package controller;

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 javax.servlet.http.HttpSession;

import model.Order;
import model.OrderLogic;

@WebServlet("/OrderMain")
public class OrderMain extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//フォワード先path
		String forwardPath="/WEB-INF/view/form.jsp";
		//リクエストパラメータの取得
		String action=request.getParameter("action");
		//sessionを使う準備
		HttpSession session=request.getSession();
		//sessionスコープからorderインスタンスの取得を試みる
		Order order=(Order)session.getAttribute("order");
		if(action == null) {
			//action属性が来ていなかったらOrderインスタンスを新しく生成する。
			order=new Order();
		}
		//sessionスコープにorderインスタンスを保存する
		session.setAttribute("order", order);

		//フォワード処理
		RequestDispatcher rd=
				request.getRequestDispatcher(forwardPath);
		rd.forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//getParameterValuesでcountsというname属性で送られてきたデータを配列として取得できる。
		String[] counts=request.getParameterValues("counts");//{"6","2"...."1"}
		HttpSession session = request.getSession();
		//セッションスコープからインスタンスを取り出す。
		Order order = (Order)session.getAttribute("order");
		//counts配列をセットする
		order.setCounts(counts);
		//セッションスコープに格納
		session.setAttribute("order", order);
		
		//フォワード処理
		RequestDispatcher rd=
				request.getRequestDispatcher("/WEB-INF/view/confirm.jsp");
		rd.forward(request, response);
	}

}

/WEB-INF/view/confirm.jsp

スコープからインスタンスを取り出し、スクリプト式を使って値を出力する。
この際、リンクにはリクエストパラメーターを付与して処理を分岐できるようにしておく。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="model.Order" %>
<%
Order order=(Order)session.getAttribute("order");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>すしアプリ</title>
</head>
<body>
<p>確認</p>
<% for(int i=0;i<order.getNames().length;i++){ %>
<%=order.getNames()[i] %>:<%=order.getCounts()[i] %>皿<br>
<%} %>
<a href="/sushi/OrderMain?action=back">戻る</a>
<a href="/sushi/OrderMain?action=submit">確定</a>
</body>
</html>

controller.OrderMain.javaに追記

get通信でaction属性が付与されたときの分岐処理を追記する。
今回、backで行う処理はないのでこの部分は消してしまっても構わない。

package controller;

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 javax.servlet.http.HttpSession;

import model.Order;
import model.OrderLogic;

@WebServlet("/OrderMain")
public class OrderMain extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//フォワード先path
		String forwardPath="/WEB-INF/view/form.jsp";
		//リクエストパラメータの取得
		String action=request.getParameter("action");
		//sessionを使う準備
		HttpSession session=request.getSession();
		//sessionスコープからorderインスタンスの取得を試みる
		Order order=(Order)session.getAttribute("order");
		if(action == null) {
			//action属性が来ていなかったらOrderインスタンスを新しく生成する。
			order=new Order();
		}
		else if(action.equals("back")) {
			//今回ここでやる処理はない
		}
		else if(action.equals("submit")) {
			//OrderLogicインスタンスを作成
			OrderLogic logic = new OrderLogic();
			//executeして会計情報を付与する
			logic.execute(order);
			//フォワード先の変更
			forwardPath="/WEB-INF/view/result.jsp";
		}
		//sessionスコープにorderインスタンスを保存する
		session.setAttribute("order", order);

		//フォワード処理
		RequestDispatcher rd=
				request.getRequestDispatcher(forwardPath);
		rd.forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//getParameterValuesでcountsというname属性で送られてきたデータを配列として取得できる。
		String[] counts=request.getParameterValues("counts");//{"6","2"...."1"}
		HttpSession session = request.getSession();
		//セッションスコープからインスタンスを取り出す。
		Order order = (Order)session.getAttribute("order");
		//counts配列をセットする
		order.setCounts(counts);
		//セッションスコープに格納
		session.setAttribute("order", order);
		
		//フォワード処理
		RequestDispatcher rd=
				request.getRequestDispatcher("/WEB-INF/view/confirm.jsp");
		rd.forward(request, response);
	}

}

/WEB-INF/view/result.jsp

最後にお会計結果画面を作成しよう。orderインスタンスがすべて情報を持っているのでスクリプト式を使って内容を出力するだけだ。このようにjsp内では極力javaの処理を排除していく方針が大切となる。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="model.Order" %>
<%
Order order=(Order)session.getAttribute("order");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>すしアプリ</title>
</head>
<body>
<p>ご注文は「<%=order.getMsg() %>」ですね!</p>
<p>合計<%=order.getTotalCount() %>皿で<%=order.getTotalFee() %>円頂戴致します!</p>
<a href="/sushi/OrderMain">戻る</a>
</body>
</html>

完成

今回はセッションスコープを使ってショッピングカートもどきの処理を作成した。セッションスコープの基本を確認してもらいたい。

コメント

タイトルとURLをコピーしました