前回、GCEにあげたWebアプリの更新方法を学習した。今回はjspファイルや画像なども使ってsmallアプリを作ってGCEにアップしてみよう。
MVC(model,view,controller)に分けて制作を行うのでMVCパターンの復習にもなる。

プロジェクトの作成

1.エクリプスにて新規動的Webプロジェクトを選択。名前はbmi-appでいいだろう。今回はbmi計測アプリを作成する。

画像の配置

WebContentの直下にimagesフォルダを新規に作成し、その中に6枚の画像を配置する。配置する画像は以下からダウンロードできる。

modelの作成

modelを作ろう。新規クラスからBMIクラスを作成する、その際パッケージ名はmodelとすること。

以下のようにBMIクラスにソースコードを記述する。

package model;

import java.io.Serializable;

public class BMI implements Serializable{
	private double height;//身長
	private double weight;//体重
	private double bmi;//bmi
	private String imgPath;//画像ファイルのパス
	
	//コンストラクタ
	public BMI(){}
	
	//setter & getter
	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 double getBmi() {
		return bmi;
	}
	public void setBmi(double bmi) {
		this.bmi = bmi;
	}
	public String getImgPath() {
		return imgPath;
	}
	public void setImgPath(String imgPath) {
		this.imgPath = imgPath;
	}
	
}

Controllerの作成

新規サーブレットからMain.javaを作成する。その際、パッケージ名はcontrollerとすること。

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.BMI;


@WebServlet("/Main")
public class Main extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//フォワード処理
		RequestDispatcher rd=request.getRequestDispatcher("/WEB-INF/view/main.jsp");
		rd.forward(request, response);
	}

	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//リクエストパラメータの取得
		double height=Double.parseDouble(request.getParameter("height"));
		double weight=Double.parseDouble(request.getParameter("weight"));
		//BMIの計算
		double bmi=weight/Math.pow(height/100, 2);
		//画像パスの設定
		String imgPath;
		if(bmi<18.5) {
			imgPath="img1.jpg";
		}else if(bmi < 25) {
			imgPath="img2.jpg";
		}else if(bmi<30) {
			imgPath="img3.jpg";
		}else if(bmi < 35) {
			imgPath="img4.jpg";
		}else if(bmi<40) {
			imgPath="img5.jpg";
		}else {
			imgPath="img6.jpg";
		}
		//BMIインスタンスの作成
		BMI b=new BMI();
		//値をつめる
		b.setHeight(height);
		b.setWeight(weight);
		b.setBmi(Math.round(bmi*100)/100d);//小数点2桁にする処理
		b.setImgPath(imgPath);
		//リクエストスコープにインスタンスを保存する
		request.setAttribute("bmi", b);
		
		//doGetに処理をバトンタッチ
		doGet(request, response);
	}
}

Viewの作成

WEB-INFフォルダの直下にviewフォルダを作成してその中にmain.jspを作成する

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="model.BMI" %>
<%
//リクエストスコープからbmiインスタンスの取得を試みる(スコープになかったらnullが帰る)
BMI bmi=(BMI)request.getAttribute("bmi");
//スコープにあった場合は変数にその値、なかった場合には空文字を入れる(この処理はフォームの復元の際に必要になる)
String height=bmi==null? "":String.valueOf(bmi.getHeight());
String weight=bmi==null? "":String.valueOf(bmi.getWeight());
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>BMIapp</title>
</head>
<body>
<form action="/bmi-app/Main" method="post">
Height:<input type="number" name="height" step="0.1" min="0.0" placeholder="Enter Height(cm)" value="<%=height%>"><br>
Weight:<input type="number" name="weight" step="0.1" min="0.0" placeholder="Enter Weight(kg)" value="<%=weight%>"><br>
<button type="submit">Send</button>
</form>
 <% if(bmi != null){ %>
 <p>Your BMI is <%=bmi.getBmi() %></p>
 <img src="/bmi-app/images/<%=bmi.getImgPath()%>" width="100">
 <%} %>
</body>
</html>

実行

これで準備OKだ。以下のようにMain.javaを右クリックしてサーバーで実行してみよう。

アプリが起動した!
自分の身長と体重を入れてSendを押してみよう。

OK!これでアプリは完成だ。

本番環境にデプロイ

それではいよいよこのアプリをGCE にデプロイし、世界中の人が利用できるようにしよう。下図のようにアプリ名を右クリックしてwarファイルを作成する。

保存する場所を聞かれるので、今回はデスクトップにbmiフォルダを作ってそこに保存しよう。以下は場所指定後の確認画面

確認

ファイルが出来ているかターミナルから確認しよう。この際、GCEにログインした状態であった場合はexitを何回か押してログアウトしておく。ログアウト状態から以下のコマンドを打つ

$ cd ~/desktop/bmi
$ ls -la
確かに存在している。

GCEにコピー

では作成されたwarファイルをGCEにコピーしよう。コマンドは以下
いつものようにIPアドレスとユーザー名は自分のものをいれること

$ scp bmi-app.war mjpurin@00.000.00.00:/home/mjpurin

確認

GCEにログインしてファイルを確認しよう。

$ ssh mjpurin@00.000.00.00
$ ls -la
確かに存在している。

webappsに配置

権限の問題があるのでrootユーザーになってwarファイルをwebappsに移動しよう。

$ su
Password:入力する。
$ mv bmi-app.war /opt/apache-tomcat-9.0.29/webapps

確認

確認しよう。以下のようにコマンド

# ls -la /opt/apache-tomcat-9.0.29/webapps
作成されている。

Apacheの設定

OK。これでデプロイの完了だ。最後にリクエストが転送されるようにApacheの編集をしよう。

#  vi /etc/httpd/conf.d/proxy-ajp.conf

開いたら以下のように追記する。

<Location /docs/>
    ProxyPass ajp://127.0.0.1:8009/docs/
</Location>
<Location /NowTime/>
    ProxyPass ajp://127.0.0.1:8009/NowTime/
</Location>
<Location /bmi-app/>
    ProxyPass ajp://127.0.0.1:8009/bmi-app/
</Location>

Apacheの設定を変えたので再起動しておこう。

service httpd restart

Webブラウザで確認

OK!これで終了だ。Webブラウザから
http://IPアドレス/bmi-app/Main
と入力してみよう。

パーフェクト!!
体重と身長を入力して動作確認をしてみよう。

これで世界中の人が利用できるBMI測定アプリの完成だ。

何が起こってるか調査

warファイルを配置するだけという超強力なデプロイだが背後で何がおこっているのであろうか?今回はその内部に潜入してみよう。自動生成されたbmi-appフォルダに移動してlsしてみよう。

# cd /opt/apache-tomcat-9.0.29/webapps/bmi-app
# ls -la

これはエクリプスのWebContentフォルダの構成と同じだ

WEB-INFの中を確認してみよう。

# cd WEB-INF
# ls -la

ここで注目はclassesフォルダだ。中身を覗いてみよう。

# cd classes
# ls -la

おお、これは!
そう作成したパッケージフォルダが出来ている。
もちろん、この中にはコンパイル済みのクラスファイルが入っている。

tomcatではコンパイルしたクラスファイルはWEB-INF/classesフォルダに置くことになっている。エクリプスで開発をしているとこの部分をまったくやらないのでしっかり基本を理解しておこう。

いずれにせよwarファイルさえ配置してしまえば、tomcatはすべて適切な位置にファイル群を配置してくれる。手動でファイル一つ一つ適切な位置に置く手間を考えると実にありがたい仕組みだ。

bmi-app完成!

以上でbmiアプリの完成だ。エクリプスで開発さえできてしまえばあとはwarファイルをおいてURLの設定をするだけだ。実に簡単だったのではないだろうか?

次回はいよいよMySQLに登場してもらう。GCE+Tomcatのアプリづくりも佳境だ。楽しみにしていてもらいたい。