Servlet&Jspを使って自己紹介アプリを作成してみよう

JSP&Servlet

以前にコンソールアプリとして作成した、自己紹介アプリをWebアプリにしてみよう。
いきなりこのお題から着手すると難しいのでコンソール版をやってからこのお題に挑戦することをおすすめする。

手順

1.エクリプス新規動的プロジェクトからselfappを作成。
2.まずは実行例を見ながらどのように実装していけばよいかを考える。

コンソールアプリでの実行例

名前を入力してください>山田花子
初期ステータスが決定しました
[体力:75 魔力:82 パワー:29 きようさ:22 すばやさ:25 ]
種族を選んでください 0…人間,1…ハイエルフ,2…トロル,3…ノーム>3
ノームのボーナスが適用されました!
[体力:85 魔力:82 パワー:29 きようさ:47 すばやさ:45 ]
職業を選んでください 0…戦士,1…盗賊,2…僧侶,3…魔術師>0
戦士のボーナスが適用されました!
[体力:136 魔力:82 パワー:40 きようさ:47 すばやさ:45 ]
***作成成功!***
私は戦士のノーム、山田花子です。
能力値(350)を高い順に並べると
体力:136
魔力:82
きようさ:47
すばやさ:45
パワー:40
です。今後ともよろしく…。

3.まずはmodelから考える。今回の実装を行うためには以下のmodelを作成すればよさそうだ。

package model;

import java.io.Serializable;

public class Hero implements Serializable{
	//フィールド
	private String name;
	private String race;
	private String cls;
	private int hp;
	private int mp;
	private int power;
	private int dex;
	private int agi;
	private int total;
	private String[] ordered;

	//コンストラクタ
	public Hero() {}
	public Hero(String name) {
		this.name = name;
	}
	public Hero(String name, int hp, int mp, int power, int dex, int agi) {
		this(name);
		this.hp = hp;
		this.mp = mp;
		this.power = power;
		this.dex = dex;
		this.agi = agi;
	}
	public Hero(String name, String race, int hp, int mp, int power, int dex, int agi) {
		this(name,hp,mp,power,dex,agi);
		this.race=race;
	}
	public Hero(String name, String race,String cls, int hp, int mp, int power, int dex, int agi) {
		this(name,race,hp,mp,power,dex,agi);
		this.cls=cls;
	}
	//メソッド
	@Override
	public String toString() {
		return String.format("[体力:%d 魔力:%d パワー:%d きようさ:%d すばやさ:%d ]", this.hp,this.mp,this.power,this.dex,this.agi);
	}
	//setter&getter
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getRace() {
		return this.race;
	}
	public void setRace(String race) {
		this.race = race;
	}
	public String getCls() {
		return cls;
	}
	public void setCls(String cls) {
		this.cls = cls;
	}
	public int getHp() {
		return hp;
	}
	public void setHp(int hp) {
		this.hp = hp;
	}
	public int getMp() {
		return mp;
	}
	public void setMp(int mp) {
		this.mp = mp;
	}
	public int getPower() {
		return power;
	}
	public void setPower(int power) {
		this.power = power;
	}
	public int getDex() {
		return dex;
	}
	public void setDex(int dex) {
		this.dex = dex;
	}
	public int getAgi() {
		return agi;
	}
	public void setAgi(int agi) {
		this.agi = agi;
	}
	public int getTotal() {
		return total;
	}
	public void setTotal(int total) {
		this.total = total;
	}
	public String[] getOrdered() {
		return ordered;
	}
	public void setOrdered(String[] orderd) {
		this.ordered = orderd;
	}
}

処理に必要そうなフィールドと、コンストラクタ、setter&getterを実装している。
行数は多いがエクリプスのコード補完機能を使えば3分でできる。

4.HeroLogicクラスの作成。次に実際にフィールドの値を作成するロジッククラスを作成しよう。

package model;

import java.util.Random;

public class HeroLogic {
	//名前が決まったインスタンスから各パラメータを決定するメソッド
	public void init(Hero h) {
		int seed=0;
		for(int i=0;i<h.getName().length();i++) {
			seed += h.getName().charAt(i);
		}
		int[] vals=makeStatus(seed,new int[] {100,100,50,50,50});
		h.setHp(vals[0]);
		h.setMp(vals[1]);
		h.setPower(vals[2]);
		h.setDex(vals[3]);
		h.setAgi(vals[4]);
	}
	//シード値をもとにint配列を返却するメソッド
	private int[] makeStatus(int seed,int[] maxArr){
		int[] vals=new int[maxArr.length];
		Random rand=new Random(seed);
		for(int i=0;i<vals.length;i++){
			vals[i]=rand.nextInt(maxArr[i])+1;
		}
		return vals;
	}
	//人種が決まったインスタンスから各パラメータを変更するメソッド
	public void setRace(Hero h) {
		int[][] raceMatrix={
				{10,10,10,10,10},
				{0,20,0,10,20},
				{30,0,20,0,0},
				{10,0,0,25,20},
			};
		int index=Integer.parseInt(h.getRace());
		h.setHp(h.getHp()+raceMatrix[index][0]);
		h.setMp(h.getMp()+raceMatrix[index][1]);
		h.setPower(h.getPower()+raceMatrix[index][2]);
		h.setDex(h.getDex()+raceMatrix[index][3]);
		h.setAgi(h.getAgi()+raceMatrix[index][4]);
		String[] raceNames={"人間","ハイエルフ","トロル","ノーム"};
		h.setRace(raceNames[index]);

	}
	//職業が決まったインスタンスから各パラメータを調整し、
	//結果出力必要なフィールドを設定するメソッド
	public void setCls(Hero h) {
		double[][] clsMatrix={
				{1.6,1,1.4,1,1},
				{1.1,1,1.2,1.3,1.3},
				{1.3,1.5,1.1,1,1},
				{1,1.9,1,1,1.1},
			};
		int index=Integer.parseInt(h.getCls());
		h.setHp((int)(h.getHp()*clsMatrix[index][0]));
		h.setMp((int)(h.getMp()*clsMatrix[index][1]));
		h.setPower((int)(h.getPower()*clsMatrix[index][2]));
		h.setDex((int)(h.getDex()*clsMatrix[index][3]));
		h.setAgi((int)(h.getAgi()*clsMatrix[index][4]));
		String[] clsNames={"戦士","盗賊","僧侶","魔術師"};
		h.setCls(clsNames[index]);
		h.setTotal(h.getHp()+h.getMp()+h.getPower()+h.getDex()+h.getAgi());
		String[] keys= {"体力","魔力","きようさ","すばやさ","パワー"};
		int[] vals= {h.getHp(),h.getMp(),h.getPower(),h.getDex(),h.getAgi()};
		for(int i=0;i<vals.length-1;i++) {
			for(int j=i+1;j<vals.length;j++) {
				if(vals[i]<vals[j]) {
					String t1=keys[i];
					keys[i]=keys[j];
					keys[j]=t1;
					int t2=vals[i];
					vals[i]=vals[j];
					vals[j]=t2;
				}
			}
		}
		String[] ordered=new String[keys.length];
		for(int i=0;i<keys.length;i++) {
			String line=keys[i]+":"+vals[i];
			ordered[i]=line;
		}
		h.setOrdered(ordered);
	}
}

5.viewの作成。まずは最初のビューを作成しよう。

/WEB-INF/の中にviewフォルダを作成し、その中に以下のようなnameForm.jspを作成する。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>自己紹介App</title>
</head>
<body>
<form action="/selfapp/First" method="post">
名前を入力してください
<input type="text" name="name">
<button type="submit">送信</button>
</form>
</body>
</html>

6.Servletの作成。まずは最初のリクエストを処理するサーブレットを作成しよう。
新規サーブレットを作成を選択肢、controllerパッケージの中にFirst.javaを作成する。

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 model.Hero;
import model.HeroLogic;

@WebServlet("/First")
public class First extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		RequestDispatcher rd=request.getRequestDispatcher("/WEB-INF/view/nameForm.jsp");
		rd.forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		String name=request.getParameter("name");
		Hero h=new Hero(name);
		HeroLogic hl=new HeroLogic();
		hl.init(h);
		request.setAttribute("hero", h);
		RequestDispatcher rd=request.getRequestDispatcher("/WEB-INF/view/raceForm.jsp");
		rd.forward(request, response);
	}

}

最初のリクエストで先程作成したフォームを表示し、フォーム入力後のポスト通信では名前を取得しインスタンスを作成してリクエストスコープに格納している。

7.raceForm.jspの作成。続いて人種を入力するフォームを作成しよう。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="model.Hero"%>
<%
   Hero h=(Hero)request.getAttribute("hero");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>自己紹介APP</title>
</head>
<body>
<p>初期ステータスが決定しました</p>
<p><%=h %></p>
<form action="/selfapp/Second" method="post">
種族を選んでください
<input type="radio" name="race" value="0">人間
<input type="radio" name="race" value="1">ハイエルフ
<input type="radio" name="race" value="2">トロル
<input type="radio" name="race" value="3">ノーム
<input type="hidden" name="name" value="<%=h.getName() %>">
<input type="hidden" name="hp" value="<%=h.getHp() %>">
<input type="hidden" name="mp" value="<%=h.getMp() %>">
<input type="hidden" name="power" value="<%=h.getPower() %>">
<input type="hidden" name="dex" value="<%=h.getDex() %>">
<input type="hidden" name="agi" value="<%=h.getAgi() %>">
<button type="submit">送信</button>
</form>
</body>
</html>

ここで着目すべき点は、hiddenで現在の値を埋め込んでいる点だ。リクエストスコープのみで処理を行う場合はこの処理をいれないと情報が消失してしまう。

8.Second.javaを作成。新規サーブレットでSecond.javaを作成し以下のように記述

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 model.Hero;
import model.HeroLogic;

@WebServlet("/Second")
public class Second extends HttpServlet {

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		String race=request.getParameter("race");
		String name=request.getParameter("name");
		int hp=Integer.parseInt(request.getParameter("hp"));
		int mp=Integer.parseInt(request.getParameter("mp"));
		int power=Integer.parseInt(request.getParameter("power"));
		int dex=Integer.parseInt(request.getParameter("dex"));
		int agi=Integer.parseInt(request.getParameter("agi"));
		Hero h=new Hero(name,race,hp,mp,power,dex,agi);
		HeroLogic hl=new HeroLogic();
		hl.setRace(h);
		request.setAttribute("hero", h);
		RequestDispatcher rd=request.getRequestDispatcher("/WEB-INF/view/clsForm.jsp");
		rd.forward(request, response);
	}

}

リクエストパラメータで飛んできた情報を元にインスタンスを生成しHeroLogicクラスをつかってパラメータの調整をしている。

9.clsForm.jspの作成。ここはさきほどの人種の処理とほとんど同じだ。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="model.Hero"%>
<%
	Hero h=(Hero)request.getAttribute("hero");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>自己紹介APP</title>
</head>
<body>
<p><%=h.getRace() %>のボーナスが適用されました!</p>
<p><%=h %></p>
<form action="/selfapp/Third" method="post">
職業を選んでください
<input type="radio" name="cls" value="0">戦士
<input type="radio" name="cls" value="1">盗賊
<input type="radio" name="cls" value="2">僧侶
<input type="radio" name="cls" value="3">魔術師
<input type="hidden" name="name" value="<%=h.getName() %>">
<input type="hidden" name="race" value="<%=h.getRace() %>">
<input type="hidden" name="hp" value="<%=h.getHp() %>">
<input type="hidden" name="mp" value="<%=h.getMp() %>">
<input type="hidden" name="power" value="<%=h.getPower() %>">
<input type="hidden" name="dex" value="<%=h.getDex() %>">
<input type="hidden" name="agi" value="<%=h.getAgi() %>">
<button type="submit">送信</button>
</form>
</body>
</html>

10.Third.javaの作成。新しくThirdという名のサーブレットを作成し以下を記述する。

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 model.Hero;
import model.HeroLogic;

@WebServlet("/Third")
public class Third extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		String cls=request.getParameter("cls");
		String name=request.getParameter("name");
		String race=request.getParameter("race");
		int hp=Integer.parseInt(request.getParameter("hp"));
		int mp=Integer.parseInt(request.getParameter("mp"));
		int power=Integer.parseInt(request.getParameter("power"));
		int dex=Integer.parseInt(request.getParameter("dex"));
		int agi=Integer.parseInt(request.getParameter("agi"));
		Hero h=new Hero(name,race,cls,hp,mp,power,dex,agi);
		HeroLogic hl=new HeroLogic();
		hl.setCls(h);
		request.setAttribute("hero", h);
		RequestDispatcher rd=request.getRequestDispatcher("/WEB-INF/view/result.jsp");
		rd.forward(request, response);
	}
}

11.result.jspが以下のようになるように作成する。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="model.Hero"%>
<%
   Hero h=(Hero)request.getAttribute("hero");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>自己紹介APP</title>
</head>
<body>
<p><%=h.getCls() %>のボーナスが適用されました!</p>
<p><%=h %></p>
<p>***作戦成功***</p>
<p>私は<%=h.getCls() %> の<%=h.getRace() %>、<%=h.getName() %>です。</p>
<p>能力値(<%=h.getTotal() %>)を高い順に並べると<p>
<ol>
<%for(String line:h.getOrderd()){ %>
<li><%=line %></li>
<%} %>
</ol>
<p>です。今後ともよろしく...</p>
</body>
</html>

完成

以上で完成だ。サーバーサイドの開発は処理の流れをしっかりと理解することがとても大切だ。しっかりと慣れていこう!

コメント

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