JavaによるWebアプリケーションの仕組みをざっくり説明

#はじめに
私は数ヶ月前に未経験としてIT企業に入社しました。
2ヶ月間ほどJavaを用いたWebアプリケーションの開発を研修で行ったので
わかったことを簡単にまとめて行こうと思います。
間違っていることもたくさんあると思いますので、どんどん指摘して頂けると助かります。
**※ 開発方法や手順は書いていません。知識として必要な用語や全体像をざっくりと記載しています。**

###対象
- HTML/CSSで静的なWebページを作成したことがあるが、動的なWebアプリケーションを作るにあたってどのような知識が必要なのかがわからない方
- Javaのコードの書き方はわかるが、動的なWebアプリケーションを作る時の全体像が見えない方

##WebクライアントとWebサーバー
まず、今ブラウザ上で見ているようなWebページは、**クライアント**と**サーバー**というコンピュータ（ソフトウェア）によって実現されています。

###Webクライアント
サーバーに対して何らかのサービスを要求し、サーバーからそのサービスを提供されるコンピュータ（ソフトウェア）をクライアントと呼び、
Webサーバーに保管してあるWebページにアクセスして利用できるものをWebクライアントと呼ぶ。
Webクライアントとは、ChromeやIEなどのブラウザのことだとイメージすれば大丈夫です。

###Webサーバー
クライアントからの要求に対して、何らかのサービスや機能をクライアントに提供するコンピュータ（ソフトウェア）をサーバーと呼びます。
サーバーにはWebサーバーやメールサーバー、データベースサーバー、アプリケーションサーバーなどあり、
Webクライアントからのアクセスに応じるものをWebサーバーと呼びます。
ApacheやIIS、nginxなどが有名なWebサーバーソフトウェアになります。

<img width="584" alt="スクリーンショット 2018-10-01 22.32.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/296506/190df5b7-5c5f-4c3b-b452-6b11a235f194.png">

##Webページを表示する流れ
ではどのようにWebページを表示させているかについてですが、
例えば、ユーザーがGoogleで何か検索したいなと思った時、ブラウザ上のURL欄に
`https://www.google.com`と入力してアクセスすると思います。
実際にアクセスしたらGoogleのページは一瞬で表示されますが、クライアントとサーバー間で見た場合、
ユーザーがGoogleのページにアクセスしようとする間に以下のようなやりとりが行われます。
<img width="767" alt="スクリーンショット _流れ2.png" src="https://qiita-image-store.s3.amazonaws.com/0/296506/24de38c8-c2f9-05b4-2a7e-17942ec8397c.png">

**1. WebクライアントがWebサーバーにRequestメッセージを送信**
**2. そのメッセージを元に、WebサーバーがWebクライアントから要求されたWebページを用意**
**3. WebサーバーがWebクライアントにResonseメッセージを送信し、Webページが表示**
ここで送受信しているメッセージは**HTTP**というプロトコルでやりとりを行っています。

##プロトコル
プロトコルとは、簡単にいうとコンピュータ同士がやりとりする際のルールみたいなものです。
例えば、日本人同士で会話をする時、日本語という言語(ルール)で会話するのと同様に
WebクライアントとWebサーバーがやりとりをする時、HTTPというプロトコル(ルール)で送受信を行います。
そうすることで、クライアント側でWebページを閲覧することができています。
しかし、単なるWebサーバーだけでは静的なWebページを表示させることしかできず、動的なWebページを表示させるためには、処理を実行させるためのソフトウェアが必要になってきます。
また、クライアントがWebサーバーに送るRequestメッセージとして、**GET**と**POST**という２種類の送信方法があり、これをうまく使い分けて動的なWebページを実現させていく必要があります。
まず、そのソフトウェアやGET,POSTの説明の前に静的なWebページと動的なWebページを比較してみます。

##静的コンテンツと動的コンテンツ
###静的なWebページ
以下の画像のように、静的なWebページを表示する際、WebクライアントがWebサーバーへ要求したWebページを
そのまま応答としてWebクライアントへ返しているので、何度要求しても同じページの内容が返ってきます。
つまり、Webサーバーにあらかじめ保管してあるHTMLファイルをそのまま返すようなイメージ。
<img width="1317" alt="スクリーンショット_静的なページ.png" src="https://qiita-image-store.s3.amazonaws.com/0/296506/a425de2c-6d7c-e5b7-fff6-9300af06a9fb.png">

###動的なWebページ
動的なWebページを表示する際、WebクライアントがWebサーバーへ要求し、
何かしらの処理を行ってからWebページをWebクライアントに返しています。
つまり、Webサーバー側で何らかの処理（プログラム）を実行して、HTMLテキストを生成しているイメージ。
以下の画像の場合、アクセスしたばかりのWebページの表示内容は`HelloWorld!`であるが、
入力フォームに`Qiita`と入力してボタンを押すことでWebページの表示内容を`Qiita`に変更させることができます。
<img width="825" alt="スクリーンショット_動的なページ4.png" src="https://qiita-image-store.s3.amazonaws.com/0/296506/c915cef4-956f-eff8-1273-4cd386aa9f46.png">

このように、動的なWebページを実現するためには何らかの処理（プログラム）が必要で、
その処理を実行させるためにプログラムを実行するソフトウェアが必要になってきます。
この何らかの処理というのを、C言語やPHPやJavaなどのプログラミング言語で実装していくことになります。

##動的なWebページを表示する流れ
先ほど、Webページを表示する流れを説明しましたが、動的なWebページを表示するということ（プログラムの実行）に焦点を置いて
Webページを表示する流れを説明していきたいと思います。

###Webサーバー内でアプリケーションを実行
 
まず例としてWebページをPHPで実装する場合、WebサーバーにはPHPファイルを実行するモジュールがないため、
PHP実行用モジュールをWebサーバーに組み込んで、Webサーバーを拡張させます。
WebサーバーがApacheを使用している場合、mod_php5というPHP実行用モジュールを組み込んでPHPスクリプトを実行します。
そうすることでWebサーバー内でHTMLファイルを生成し、クライアントへ返します。
つまり、流れは以下のようになる。
**1. WebクライアントがWebサーバーにRequestメッセージを送信**
**2. そのメッセージを元に、Webサーバーに組み込まれたモジュールでアプリケーションを実行**
**3. 実行されたアプリケーションがHTMLテキストを生成**
**4. WebサーバーがWebクライアントにResonseメッセージを送信し、Webページが表示**
<img width="957" alt="スクリーンショット_流れ_php.png" src="https://qiita-image-store.s3.amazonaws.com/0/296506/cee0b25e-3b71-ac69-f98e-1b7f7a975b9b.png">

###アプリケーションサーバーでアプリケーションを実行

次に例としてWebページをJavaで実装する場合、アプリケーションサーバーを用意します。アプリケーションサーバーはアプリケーションを実行するためのソフトウェアであり、
Javaのアプリケーションサーバーで有名なものとしては、**Tomcat**やJetty, GlassFishがあります。
ここで用意したアプリケーションサーバーはWebサーバーと別物なので簡単にやりとりができません。
WebクライアントとWebサーバー間がHTTPプロトコルでやりとりできるように、
Webサーバーとアプリケーションサーバー間もやりとりできるようにするための何かしらのプロトコルを必要とします。
Webサーバーを**Apache**,アプリケーションサーバーを**Tomcat**とした場合、
Apacheには**mod_jk**と呼ばれる連携用モジュールが提供されており、これをApacheの拡張機能として組み込みます。
連携用モジュール**mod_jk**が**ajp13**というプロトコルを使用することで、Webサーバーとアプリケーションサーバー間でのやりとりを実現させています。
ちなみに、Tomcatは簡易的なWebサーバーも持っているため、連携しなくても動的Webページを表示できます。
Webサーバーとアプリケーションサーバー間でやりとりができるようになったことで、Webクライアントからの要求がアプリケーションサーバーに届き、
メッセージを元に処理を実行することでHTMLテキストを生成しています。
つまり、流れは以下のようになります。
**1. WebクライアントがWebサーバーへHTTPプロトコルでRequestメッセージを送信**
**2. Webサーバーがアプリケーションサーバー(Tomcat)へajp13プロトコルでRequestメッセージを送信**
**3. そのメッセージを元にアプリケーションサーバーがアプリケーションを実行**
**4. 実行されたアプリケーションがHTMLテキストを生成**
**5. アプリケーションサーバーがWebサーバーへajp13プロトコルでResonseメッセージを送信**
**6. WebサーバーがWebクライアントへHTTPプロトコルでResonseメッセージを送信し、Webページが表示**
<img width="1035" alt="スクリーンショット_流れ_java.png" src="https://qiita-image-store.s3.amazonaws.com/0/296506/8b999844-d756-da88-822e-19e3088cee25.png">
このように、モジュールやアプリケーションサーバーを用いることで動的なWebページの表示が実現できます。
次に、どのようなアプリケーションを実行してHTMLファイルを生成しているかについて、Javaを用いて説明していきます。

##サーブレット
サーブレットとは、Javaで作られたHTMLなどのWebコンテンツを生成するためのプログラムのことで、Tomcatなどのアプリケーションサーバーによって実行されます。
実際に以下のような、`ServletController.java`という簡単なサーブレットを作成してみました。

```java:ServletController.java
import java.io.IOException;
import java.io.PrintWriter;

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

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

    public ServletController() {
        super();
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//文字コードの設定
		response.setContentType("text/html; charset=UTF-8");

        //クライアントに送るHTML
		PrintWriter out = response.getWriter();
		out.println("<html>");

		//ヘッダー
		out.println("<head>");
		out.println("<title>");
		out.println("Test");
		out.println("</title>");
		out.println("</head>");

		//ボディー
		out.println("<body>");

		out.println("<h1>");
		out.println("動的なWebページ");
		out.println("</h1>");

		out.println("<p>");
		out.println("これはTomcatによって実行されたサーブレットが生成したWebコンテンツです。");
		out.println("</p>");

		out.println("</body>");
		out.println("</html>");
        out.close();
	}

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

}
```

このサーブレットを実行することで、ブラウザ上で以下のようなWebページを表示させることができます。
<img width="914" alt="スクリーンショット_サーブレット2.png" src="https://qiita-image-store.s3.amazonaws.com/0/296506/094c02a7-9ace-9e84-4cfb-7525f8636073.png">
ちなみにこのWebページは表示内容を変更したりすることができないため、静的なWebページだと感じると思いますが、
Webクライアントからの要求後、Webサーバーに保管してあるHTMLファイルをそのまま返すような流れで表示している訳ではなく、
アプリケーションサーバーがjavaファイルを実行してHTMLテキストを生成し、ブラウザに表示しているので、これは動的なWebページになります。

##GETとPOST
次に、上の例の動的なWebページ(静的コンテンツと動的コンテン内のブラウザ画像)のように、表示内容をどのように変更しているかについて説明していく。
上の例の動的なWebページでは、`HelloWorld!`から`Qiita`という文字に変更しました。
Webページを表示する流れで示したように、Webクライアントは、Webサーバーへ情報を送る方法としてRequestメッセージを送信することしかできません。
つまり、Webページの表示内容を変更させるには、Requestメッセージにパラメータ(任意の値)を持たせて送信する必要があります。
そこでRequestメッセージの送信方法としてGETとPOSTという2種類あるので、これらがどのようにパラメータを持っているか比較していきます。

以下のような、RequestメッセージをGETもしくはPOSTで送信できる簡単なWebページを用意しました。
ちなみに、このWebページにアクセスした時のURLは`192.168.56.101/Test/TestController`になります。
<img width="722" alt="スクリーンショット_GETPOST1.png" src="https://qiita-image-store.s3.amazonaws.com/0/296506/5f687108-225c-ecbd-9fa0-ed69c57d1ddf.png">

###GET
まず、RequestメッセージをGETで、パラメータは`Qiita`として送信してみます。
<img width="688" alt="スクリーンショット_GETPOST6.png" src="https://qiita-image-store.s3.amazonaws.com/0/296506/d1d05039-d9cf-81c1-4c24-bc041e1b84f1.png">
もちろん`HelloWorld!`と表示されていた部分が`Qiita`と変更されましたが、
それと同時にURLも`192.168.56.101/Test/TestController`から、`192.168.56.101/Test/TestController?inputText=Qiita`に変更されました。
つまり、Requestメッセージの送信方法としてGETを用いた場合、送信したパラメータはURLに組み込まれてWebサーバーに届きます。
ちなみに、この場合`inputText`はキーで、`Qiita`がそのキーに対する値になります。
###POST
次に、RequestメッセージをPOSTで、パラメータは`Qiita`として送信してみます。
<img width="594" alt="スクリーンショット_GETPOST7.png" src="https://qiita-image-store.s3.amazonaws.com/0/296506/c2c1ffb9-d3e9-4a76-048d-f666e3d2b58c.png">
もちろんこちらも`HelloWorld!`と表示されていた部分が`Qiita`と変更されましたが、
GETとは異なり、URLは`192.168.56.101/Test/TestController`のままです。
つまり、Requestメッセージの送信方法としてPOSTを用いた場合、送信したパラメータをURLに組み込まず、Requestメッセージ内に組み込まれてWebサーバーに届きます。

###GETとPOSTの使い分け
実際の例を考えてみます。
Google`https://www.google.com`にアクセスして検索ワードに`Qiita`と入力すると、
ブラウザ上のURL欄には`https://www.google.com/search?hl=ja&q=Qiita`としてアクセスしています。
つまり、Googleの検索はGETでRequestメッセージを送信しています。
GETで送信していることによって、後でまたこのページを見たいという時にブックマークしたりして再度簡単にアクセスすることができます。
検索条件など他の人に見られてもあまり問題なく、かつパラメータごと保存できる方が便利な場合はGETを使用した方が良いです。
逆にPOSTは、人に見られてはいけない内容を送信してアクセスする場合や、データベースを書き換えたりする場合に使用するべきです。
以下に違いを簡単にまとめました。

||GETリクエスト|POSTリクエスト|
|:-:|:-:|:-:|
|利用するメソッド|GET|POST|
|パラメータの格納場所|URL|メッセージボディ|
|セキュリティ|低い|比較的高い|
|パラメータの長さ|古いソフトウェアでは255文字以内|制限なし|
|パラメータの保存・再現|しやすい|しにくい|


###サーブレットとGET・POSTの関係性
RequestメッセージがGETとPOSTのいずれかで送信されることによって、アプリケーション側ではどのような処理をされているかについてですが、
先ほどのサーブレットのソースコードを見てもらえばわかるように、
ServletControllerクラス内には**doGet**と**doPost**というメソッドがありました。
RequestメッセージがGETで送られてきた場合、doGetメソッドが実装され、
RequestメッセージがPOSTで送られてきた場合、doPostメソッドが実装されて、HTMLテキストを生成します。

###GETとPOSTの送信方法
実際にWebページの表示のために生成されたHTMLテキストはどのような内容なのか確認してみます。
`192.168.56.101/Test/TestController`にアクセスした時のHTMLテキストは以下のようになります。

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
	<h1>動的なWebページ</h1>
	<p>GETでパラメータを送信</p>
	<form action="TestController" method="get">
		<input type="text" name="inputText" >
		<button type="submit">文字変更(GET)</button>
	</form>
	<p>POSTでパラメータを送信</p>
	<form action="TestController" method="post">
		<input type="text" name="inputText" >
		<button type="submit">文字変更(POST)</button>
	</form>
	<p>HelloWorld!</p>

</body>
</html>
```

formタグで指定している、`action`と`method`についてですが、
actionは、どのclassファイル（.java）を実行するかの指定をしており、
methodは、requestメッセージの送信方法（getかpost）を指定します。
つまり、クライアント側で、あるformタグ内のsubmitボタンを押した場合、requestメッセージがWebサーバーへ送信され、
actionで指定したクラスの`doGet`か`doPost`のメソッドが実行されます。
その際、送信するパラメータがあればパラメータも一緒に送信されます。
この場合、inputタグのnameがキー`inputText`となり、入力した文字列が値`Qiita`として送信されます。
そして`192.168.56.101/Test/TestController`のサーブレットは、以下のようになります。

```java:TestController.java
package controller;

import java.io.IOException;

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

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

    public TestController() {
        super();
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//文字コード設定
		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");

        //JSPで使用するパラメータの設定
		if(request.getParameter("inputText") != null) {
			request.setAttribute("inputText", request.getParameter("inputText"));
		}

		//ページ移動
		ServletContext context = this.getServletContext();
		RequestDispatcher dispatcher = context.getRequestDispatcher("/TestView");
		dispatcher.forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//文字コード設定
		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");

        //JSPで使用するパラメータの設定
		if(request.getParameter("inputText") != null) {
			request.setAttribute("inputText", request.getParameter("inputText"));
		}

		//ページ移動
		ServletContext context = this.getServletContext();
		RequestDispatcher dispatcher = context.getRequestDispatcher("/TestView");
		dispatcher.forward(request, response);
	}

}

```

このソースファイルの内容は詳細に理解する必要は全くないのですが、注意してもらいたいのは、
`ServletController.java`に記載していたようなhtmlタグなどを出力する処理がないところです。
この処理が記載しなくても良いのは、**サーブレット**と**JSP**で役割を分担して連携させているためです。

##JSP
JSPとは、簡単にいうとHTML形式の中にJavaのコードを埋め込んだものです。
処理を行うサーブレットと、それを表示するJSPに分担させることで、効率よく開発を行うことができます。
以下は、先ほど上で取り上げていたサーブレットの`TestController.java`から呼ばれるJSP`TestView.jsp`です。

```HTML:TestView.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
	<h1>動的なWebページ</h1>
	<p>GETでパラメータを送信</p>
	<form action="TestController" method="get">
		<input type="text" name="inputText" >
		<button type="submit">文字変更(GET)</button>
	</form>
	<p> </p>
	<p>POSTでパラメータを送信</p>
	<form action="TestController" method="post">
		<input type="text" name="inputText" >
		<button type="submit">文字変更(POST)</button>
	</form>
	<p>
	<%
	if(request.getAttribute("inputText") == null){
		out.println("HelloWorld!");
	}else{
		out.println(request.getAttribute("inputText"));
	}
	%>
	</p>
</body>
</html>
```

JSPはHTML形式なのでJavaコードを組み込む際は、
`<% ... %>`というタグの中に組み込んでいきます。
Webページに文字を出力させるには、`out.println();`の引数に表示させたい文字列を入れれば良い。
そのほかにも、`<%= 変数 %>`で文字列を出力させることができます。
CSSやJavaScriptの外部ファイルを読み込みたい場合もHTMLと同様にヘッダー部分に記入していきます。

このように、処理担当のサーブレットと表示担当のJSPで役割を分けることで開発しやすくなります。
しかし、何らかのデータ保存や管理をしながらWebアプリケーションを扱いたい場合、単にサーブレットとJSPで分けただけでは効率よく開発ができないのと同時に、
大量のデータを保存し管理できるサーバーが必要になってきます。
その大量のデータを保存・管理できるサーバーというのが、**データベースサーバー**です。
MySQLやOracle DataBase、PostgreSQLなどが有名なデータベースサーバーソフトウェアになります。
このようなデータベースサーバーを用いることで、Webアプリケーションを通じて大量のデータベースを管理することができます。
そして、その大量のデータベースを扱ってWebアプリケーションを開発する場合は**MVCモデル**という開発手法を用いることで、より大規模な開発を効率よく行うことができます。


##MVCモデル
MVCモデルは、アプリケーションソフトウェアを**Model**,**View**,**Controller**の３つの役割に分けて開発していきます。それぞれ簡単に説明していきます。
###Model
モデルはアプリケーションの処理を担当します。例えば、データの管理、データベースへのアクセスやメソッドの管理についてを行います。コントローラーからの指示により処理を実行します。一般的なjavaファイルがモデルにあたります。
###View
ビューは、アプリケーションの表示を担当します。コントローラーから出力結果を渡されます。HTML形式に書かれているJSPファイルがビューにあたります。
###Controller
コントローラーは、View(画面)からの情報入力を受け、Model(処理やデータ)を呼び出し、Viewへの結果の出力を担当します。つまり、一つのコントローラーに、特定のViewに対する処理や特定の処理の流れが書かれています。
サーブレットクラスがコントローラーにあたります。
###MVCモデルの流れ
この３つの役割に分けた場合のアプリケーションの処理の流れは以下のようになります。
**1. クライアントがサーバーへRequestメッセージを送信**
**2. アプリケーション内のControllerがRequestメッセージを元に実行され、Modelの処理を呼び出し**
**3. Controllerから呼び出されたModelがDBアクセスもしくは処理実行**
**4. Modelが処理結果をControllerへ受け渡す**
**5. 処理結果を元にControllerがViewへ出力の指示(HTMLテキストの生成)**
**6. サーバーがクライアントへResonseメッセージを送信し、Webページが表示**
<img width="804" alt="スクリーンショット_MVC.png" src="https://qiita-image-store.s3.amazonaws.com/0/296506/572e89e4-509e-dabd-48b3-d5fe1b98e329.png">
これがMVCモデルの簡単な流れであるが、厳密にはMVC2やMVP、MVVMなど種類があり、開発するアプリケーションによって適切に変えていくべきでしょう。

##Webアプリケーション全体の流れ
以上を踏まえ、JavaによるWebアプリケーションの全体の仕組みは以下のようになります。
<img width="1038" alt="スクリーンショット_All流れ.png" src="https://qiita-image-store.s3.amazonaws.com/0/296506/aefd382f-d1a2-7297-43b4-66906c217f1a.png">
クライアントサイドとしてはもちろんWebクライアントが存在しており、サーバーサイドにはWebサーバーやアプリケーションサーバー、データベースサーバーがあります。
サーバーを構築する場合、Webサーバー、アプリケーションサーバー、データベースサーバー等をインストールし、それぞれ実行する事で、Webアプリケーションにアクセスした際、正常に動作されます。
もし新しくアプリケーションを追加する場合も、それを実行するアプリケーションサーバーをインストールして実行していき、拡張させていけます。

##参考
小森 裕介　(2010/4/10)『「プロになるためのWeb技術入門」 ――なぜ、あなたはWebシステムを開発できないのか』技術評論社