Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

私は数ヶ月前に未経験として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サーバーソフトウェアになります。

スクリーンショット 2018-10-01 22.32.10.png

Webページを表示する流れ

ではどのようにWebページを表示させているかについてですが、
例えば、ユーザーがGoogleで何か検索したいなと思った時、ブラウザ上のURL欄に
https://www.google.comと入力してアクセスすると思います。
実際にアクセスしたらGoogleのページは一瞬で表示されますが、クライアントとサーバー間で見た場合、
ユーザーがGoogleのページにアクセスしようとする間に以下のようなやりとりが行われます。
スクリーンショット _流れ2.png

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

プロトコル

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

静的コンテンツと動的コンテンツ

静的なWebページ

以下の画像のように、静的なWebページを表示する際、WebクライアントがWebサーバーへ要求したWebページを
そのまま応答としてWebクライアントへ返しているので、何度要求しても同じページの内容が返ってきます。
つまり、Webサーバーにあらかじめ保管してあるHTMLファイルをそのまま返すようなイメージ。
スクリーンショット_静的なページ.png

動的なWebページ

動的なWebページを表示する際、WebクライアントがWebサーバーへ要求し、
何かしらの処理を行ってからWebページをWebクライアントに返しています。
つまり、Webサーバー側で何らかの処理(プログラム)を実行して、HTMLテキストを生成しているイメージ。
以下の画像の場合、アクセスしたばかりのWebページの表示内容はHelloWorld!であるが、
入力フォームにQiitaと入力してボタンを押すことでWebページの表示内容をQiitaに変更させることができます。
スクリーンショット_動的なページ4.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ページが表示
スクリーンショット_流れ_php.png

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

次に例としてWebページをJavaで実装する場合、アプリケーションサーバーを用意します。アプリケーションサーバーはアプリケーションを実行するためのソフトウェアであり、
Javaのアプリケーションサーバーで有名なものとしては、TomcatやJetty, GlassFishがあります。
ここで用意したアプリケーションサーバーはWebサーバーと別物なので簡単にやりとりができません。
WebクライアントとWebサーバー間がHTTPプロトコルでやりとりできるように、
Webサーバーとアプリケーションサーバー間もやりとりできるようにするための何かしらのプロトコルを必要とします。
WebサーバーをApache,アプリケーションサーバーをTomcatとした場合、
Apacheにはmod_jkと呼ばれる連携用モジュールが提供されており、これをApacheの拡張機能として組み込みます。
連携用モジュールmod_jkajp13というプロトコルを使用することで、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ページが表示
スクリーンショット_流れ_java.png
このように、モジュールやアプリケーションサーバーを用いることで動的なWebページの表示が実現できます。
次に、どのようなアプリケーションを実行してHTMLファイルを生成しているかについて、Javaを用いて説明していきます。

サーブレット

サーブレットとは、Javaで作られたHTMLなどのWebコンテンツを生成するためのプログラムのことで、Tomcatなどのアプリケーションサーバーによって実行されます。
実際に以下のような、ServletController.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ページを表示させることができます。
スクリーンショット_サーブレット2.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になります。
スクリーンショット_GETPOST1.png

GET

まず、RequestメッセージをGETで、パラメータはQiitaとして送信してみます。
スクリーンショット_GETPOST6.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として送信してみます。
スクリーンショット_GETPOST7.png
もちろんこちらもHelloWorld!と表示されていた部分がQiitaと変更されましたが、
GETとは異なり、URLは192.168.56.101/Test/TestControllerのままです。
つまり、Requestメッセージの送信方法としてPOSTを用いた場合、送信したパラメータをURLに組み込まず、Requestメッセージ内に組み込まれてWebサーバーに届きます。

GETとPOSTの使い分け

実際の例を考えてみます。
Googlehttps://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クラス内にはdoGetdoPostというメソッドがありました。
RequestメッセージがGETで送られてきた場合、doGetメソッドが実装され、
RequestメッセージがPOSTで送られてきた場合、doPostメソッドが実装されて、HTMLテキストを生成します。

GETとPOSTの送信方法

実際にWebページの表示のために生成されたHTMLテキストはどのような内容なのか確認してみます。
192.168.56.101/Test/TestControllerにアクセスした時の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タグで指定している、actionmethodについてですが、
actionは、どのclassファイル(.java)を実行するかの指定をしており、
methodは、requestメッセージの送信方法(getかpost)を指定します。
つまり、クライアント側で、あるformタグ内のsubmitボタンを押した場合、requestメッセージがWebサーバーへ送信され、
actionで指定したクラスのdoGetdoPostのメソッドが実行されます。
その際、送信するパラメータがあればパラメータも一緒に送信されます。
この場合、inputタグのnameがキーinputTextとなり、入力した文字列が値Qiitaとして送信されます。
そして192.168.56.101/Test/TestControllerのサーブレットは、以下のようになります。

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から呼ばれるJSPTestView.jspです。

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の3つの役割に分けて開発していきます。それぞれ簡単に説明していきます。

Model

モデルはアプリケーションの処理を担当します。例えば、データの管理、データベースへのアクセスやメソッドの管理についてを行います。コントローラーからの指示により処理を実行します。一般的なjavaファイルがモデルにあたります。

View

ビューは、アプリケーションの表示を担当します。コントローラーから出力結果を渡されます。HTML形式に書かれているJSPファイルがビューにあたります。

Controller

コントローラーは、View(画面)からの情報入力を受け、Model(処理やデータ)を呼び出し、Viewへの結果の出力を担当します。つまり、一つのコントローラーに、特定のViewに対する処理や特定の処理の流れが書かれています。
サーブレットクラスがコントローラーにあたります。

MVCモデルの流れ

この3つの役割に分けた場合のアプリケーションの処理の流れは以下のようになります。
1. クライアントがサーバーへRequestメッセージを送信
2. アプリケーション内のControllerがRequestメッセージを元に実行され、Modelの処理を呼び出し
3. Controllerから呼び出されたModelがDBアクセスもしくは処理実行
4. Modelが処理結果をControllerへ受け渡す
5. 処理結果を元にControllerがViewへ出力の指示(HTMLテキストの生成)
6. サーバーがクライアントへResonseメッセージを送信し、Webページが表示
スクリーンショット_MVC.png
これがMVCモデルの簡単な流れであるが、厳密にはMVC2やMVP、MVVMなど種類があり、開発するアプリケーションによって適切に変えていくべきでしょう。

Webアプリケーション全体の流れ

以上を踏まえ、JavaによるWebアプリケーションの全体の仕組みは以下のようになります。
スクリーンショット_All流れ.png
クライアントサイドとしてはもちろんWebクライアントが存在しており、サーバーサイドにはWebサーバーやアプリケーションサーバー、データベースサーバーがあります。
サーバーを構築する場合、Webサーバー、アプリケーションサーバー、データベースサーバー等をインストールし、それぞれ実行する事で、Webアプリケーションにアクセスした際、正常に動作されます。
もし新しくアプリケーションを追加する場合も、それを実行するアプリケーションサーバーをインストールして実行していき、拡張させていけます。

参考

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした