jsp/servletでナンバーゲームを作成しよう

JSP&Servlet

1-99の中に正解番号が隠れている。これをヒントをもとに見つけ出すゲームを作成しよう。色々な作成方法があるが、ここではMVCに処理を分割し、Sessionスコープを使っていく。

実行例

①初期画面

②数字を予想して入力する

③結果が出力される(もっと上というヒントがでている)

④ヒントをもとに数字を入力

⑤結果が出力される(もっと大きいようだ)

⑥この作業を正解がでるまで繰り返す(Bingoと出れば正解。新しい問題のリンクが表示される)

⑦New Gameを押すと最初から

実際に遊んで見る

以下のリンクから実際に遊ぶことができる。(php版)
https://joytas.net/php/numbergame.php

作成例

新規動的Webプロジェクトからhigherlowerを作成する。

Model

MVCに分割して開発する際にはまずはモデルから作成する。実行例を実現するにはどういったモデルを作成すればよいかしっかり吟味する必要がある。
また、viewであるjspからなるべくjavaの処理を排除していく方針で行っていく。
今回は
1,42,Higher!
という毎回の結果を3つの文字列と考え
List<List<String>> nums
それらを要素して持つ上記のような入れ子のListを用意した。
以下のようにmodel.HigherLower.javaを作成する

package model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class HigherLower implements Serializable{
	/***フィールド***/
	private int bingo;//正解番号
	private List<List<String>> nums;//履歴リスト
	private boolean isFinished;//正解したか
	/***コンストラクタ***/
	public HigherLower() {}
	public HigherLower(int bingo) {
		this.bingo=bingo;
		this.nums=new ArrayList<>();
	}
	/***getter & setter***/
	public int getBingo() {
		return bingo;
	}
	public void setBingo(int bingo) {
		this.bingo = bingo;
	}
	public List<List<String>> getNums() {
		return nums;
	}
	public void setNums(List<List<String>> nums) {
		this.nums = nums;
	}
	public boolean isFinished() {
		return isFinished;
	}
	public void setFinished(boolean isFinished) {
		this.isFinished = isFinished;
	}

}

model.Logic

Beanを作成したので、次は実際にフィールドを操作するロジッククラスを作成していこう。ここでは日頃学習しているJavaをがしがし書いて構わない、jspに負担がかからないようにここでしっかりとデータを作成しよう。

package model;

import java.util.ArrayList;
import java.util.List;

public class Logic {
	//ユーザーが入力した値を受け取ってインスタンスを更新するメソッド
	public void execute(HigherLower hl,int userNum) {
		//新たなリスト作成
		List<String> row=new ArrayList<>();
		//何回目かを追加
		row.add(String.valueOf(hl.getNums().size()+1));
		//入力された数字を追加
		row.add(String.valueOf(userNum));
		//結果を追加
		String result;
		if(userNum == hl.getBingo()) {
			result="Bingo!!";
			hl.setFinished(true);
		}else if(userNum > hl.getBingo()) {
			result="Lower!";
		}else {
			result="Higher!";
		}
		row.add(result);
		//入れ子のリストに今回のデータを追加
		hl.getNums().add(row);
	}
}

Controller

新規サーブレットからcontroller.Main.javaを以下のように作成する。
今回、get通信でアクセスがあった場合に当たり番号決める等の初期化処理を行うこととする。

package controller;

import java.io.IOException;
import java.util.Random;

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.HigherLower;
import model.Logic;

@WebServlet("/main")
public class Main extends HttpServlet {
	private static final long serialVersionUID = 1L;
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//sessionを取得
		HttpSession session = request.getSession();
		//ランダムインスタンス作成
		Random rand=new Random();
		//1-99の数をランダムに生成
		int bingo=rand.nextInt(99)+1;
		//HigherLowerインスタンスを作成
		HigherLower hl=new HigherLower(bingo);
		//セッションスコープに保存
		session.setAttribute("hl", hl);
		//forward処理
		RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/view/main.jsp");
		rd.forward(request, response);
	}

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

Viewの作成

まずは以下のように/WEB-INF/view/main.jspを作成し、form部分を作成する。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Number Game</title>
</head>
<body>
<h1>Number Game!</h1>
<h2>1-99の値を当ててね</h2>
<p>いくつかな?</p>
<form action="/higherlower/main" method="post">
<p>
<input type="number" name="num" min="1" max="99" autofocus>
<input type="submit" value="送信">
</p>
</form>
</body>
</html>

いざ実行

では実際にサーブレットを実行してみよう。以下のように表示されれば成功だ。(まだ、送信は押せない)

Controllerの修正

controller.Main.javaにPost通信時の処理を以下のように追記する。

package controller;

import java.io.IOException;
import java.util.Random;

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.HigherLower;
import model.Logic;

@WebServlet("/main")
public class Main extends HttpServlet {
	private static final long serialVersionUID = 1L;
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//sessionを取得
		HttpSession session = request.getSession();
		//ランダムインスタンス作成
		Random rand=new Random();
		//1-99の数をランダムに生成
		int bingo=rand.nextInt(99)+1;
		//HigherLowerインスタンスを作成
		HigherLower hl=new HigherLower(bingo);
		//セッションスコープに保存
		session.setAttribute("hl", hl);
		//forward処理
		RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/view/main.jsp");
		rd.forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//ユーザーが入力した数値を受け取りintに変換
		int userNum=Integer.parseInt(request.getParameter("num"));
		//sessionの取得
		HttpSession session=request.getSession();
		//sessionからHigherLowerインスタンスの取り出し
		HigherLower hl=(HigherLower)session.getAttribute("hl");
		//Logicインスタンスの生成
		Logic logic=new Logic();
		//今回のデータを入れてhlインスタンスを更新
		logic.execute(hl, userNum);
		//sessionに詰め直す
		session.setAttribute("hl", hl);
		//forward処理
		RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/view/main.jsp");
		rd.forward(request, response);
	}
}

Viewの修正

それではすべてを知っているHigherLowerインスタンスをセッションスコープから取り出して実行例のようにしていこう。以下のように追記する

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<%@ page import="model.*,java.util.*" %>
<%
HigherLower hl = (HigherLower)session.getAttribute("hl");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Number Game</title>
</head>
<body>
<h1>Number Game!</h1>
<h2>1-99の値を当ててね</h2>
<p>いくつかな?</p>
<form action="/higherlower/main" method="post">
<p>
<input type="number" name="num" min="1" max="99" autofocus>
<input type="submit" value="送信">
</p>
</form>
<%if(hl.getNums().size() > 0){ %>
	<table border="1">
	<%for(List<String> row:hl.getNums()){ %>
	<tr>
		<%for(String s:row){ %>
			<td><%=s %></td>
		<%} %>
	</tr>
	<%} %>
	</table>
	<%if(hl.isFinished()){ %>
	<p>
	<a href="/higherlower/main">New Game</a>
	</p>
	<%} %>
<%} %>
</body>
</html>

完成!

実行してみよう。最初の記したように遊べれば成功だ。
今回はMVCの練習用に分割したが、処理を実現するだけならばjsp一枚でもできる。どちらのパターンでも作成できるように応用力をつけていこう。

jsp一枚で実装した例

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.*"%>
<%
String num=request.getParameter("num");
List<Integer> nums;
int bingo;
if(num==null){
	Random rand=new Random();
	bingo=rand.nextInt(99)+1;
	session.setAttribute("bingo",bingo);
	nums=new ArrayList<>();
	session.setAttribute("nums",nums);
}else{
	int userNum = Integer.parseInt(num);
	nums=(List<Integer>)session.getAttribute("nums");
	nums.add(userNum);
	session.setAttribute("num",nums);
	bingo=(Integer)session.getAttribute("bingo");
}

%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Number Game!</title>
</head>
<body>
<h1>Number Game!</h1>
<h2>1-99の値を当ててね</h2>
<p>いくつかな?</p>
<form method="post">
<p>
<input type="number" name="num" min="1" max="99" autofocus>
<input type="submit" value="送信">
</p>
</form>
<%if(nums.size() > 0){ %>
	<%boolean isFinished=false; %>
	<table border="1">
	<%for(int i=0;i<nums.size();i++){ %>
	<tr>
	<td><%=i+1 %></td>
	<td><%=nums.get(i) %></td>
		<% if(nums.get(i) == bingo){isFinished=true; %>
		<td>Bingo!!</td>
		<%}else{ %>
		<td><%=nums.get(i) < bingo?"Higher!":"Lower!" %></td>
		<%}%>
	</tr>
	<%} %>
	</table>
	<%if(isFinished){ %>
	<p>
	<a href="/highlow/main.jsp">New Game</a>
	</p>
	<%} %>
<%} %>
</body>
</html>

コメント

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