AlmaLinuxで構築するWeb3層構造：Web/AP/DB連携編

今回は、Web、AP、DB各層を連携させ、実際に簡易Webアプリケーションを構築します。
JSPとJDBCを用いて、映画情報を表示・検索できるWeb画面を作成します。

# １．Web構成
```text
+----------------------+
|  クライアントブラウザ |
+----------------------+
            |
         HTTPアクセス
            ↓
+-------------------------------+
| Webサーバ（httpd）             |
| - /var/www/html/mainpage.html |
+-------------------------------+
            |
         JSPリンクをクリック
            ↓
+--------------------------------+
| APサーバ（Tomcat）              |
| - /opt/tomcat/webapps/jsp/*.jsp|
+--------------------------------+
            |
         JDBCでDBに接続
            ↓
+-------------------------------+
| DBサーバ（MySQL）              |
| - sakilaデータベース         　|
+-------------------------------+

```

# 2. Webサーバ側の設定
/var/www/html/mainpage.htmlにメインページのHTMLを記述します。
```html
<!DOCTYPE html>
<html>
<head>
  <title>Sakila 映画情報ポータル</title>
</head>
<body>
  <h1>Sakila 映画情報ポータル</h1>
  <ul>
    <li><a href="http://<WebサーバのIPアドレス>/test/jsp/film_list.jsp">🎬 映画一覧</a></li>
    <li><a href="http://<WebサーバのIPアドレス>/test/jsp/film_search.jsp">🔍 映画検索</a></li>
    <li><a href="http://<WebサーバのIPアドレス>/test/jsp/actor_search.jsp">🧑‍🎤 俳優検索</a></li> 
  </ul>
</body>
</html>
```

# ３．APサーバ側の設定
```bash
cd /opt/tomcat/webapps
mkdir jsp
chown tomcat:tomcat jsp
chmod 750 jsp
```
film_list.jspに以下を記述します。
```jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="java.sql.*" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>映画一覧</title>
</head>
<body>
    <h1>🎬 映画一覧（Sakila DB）</h1>
    <table border="1">
        <tr>
            <th>ID</th>
            <th>タイトル</th>
            <th>説明</th>
            <th>公開年</th>
        </tr>
<%
    String jdbcURL = "jdbc:mysql://<DBサーバのIPアドレス>:3306/sakila?useUnicode=true&characterEncoding=UTF-8";
    String dbUser = "root";
    String dbPass = "<mysql用パスワード>";

    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;

    try {
        Class.forName("com.mysql.cj.jdbc.Driver");
        conn = DriverManager.getConnection(jdbcURL, dbUser, dbPass);
        stmt = conn.createStatement();
        rs = stmt.executeQuery("SELECT film_id, title, description, release_year FROM film LIMIT 20");

        while (rs.next()) {
            int id = rs.getInt("film_id");
            String title = rs.getString("title");
            String desc = rs.getString("description");
            String year = rs.getString("release_year");
%>
        <tr>
            <td><%= id %></td>
            <td><%= title %></td>
            <td><%= desc %></td>
            <td><%= year %></td>
        </tr>
<%
        }
    } catch (Exception e) {
        out.println("<p>エラー: " + e.getMessage() + "</p>");
    } finally {
        if (rs != null) rs.close();
        if (stmt != null) stmt.close();
        if (conn != null) conn.close();
    }
%>
    </table>
</body>
</html>
```
film_search.jspの記述
```jsp
<%@ page import="java.sql.*" %>
<%@ page contentType="text/html; charset=UTF-8" %>
<html>
<head>
    <title>映画検索</title>
</head>
<body>
    <h1>映画タイトル検索</h1>
    <form method="get">
        タイトルを含むキーワード: 
        <input type="text" name="keyword">
        <input type="submit" value="検索">
    </form>
<%
    String keyword = request.getParameter("keyword");
    if (keyword != null && !keyword.trim().isEmpty()) {
        String jdbcURL = "jdbc:mysql://<DBサーバのIPアドレス>:3306/sakila?user=root&password=<mysql用のパスワード>&useUnicode=true&characterEncoding=UTF-8";
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(jdbcURL);
            pstmt = conn.prepareStatement("SELECT film_id, title, description FROM film WHERE title LIKE ?");
            pstmt.setString(1, "%" + keyword + "%");
            rs = pstmt.executeQuery();
%>
    <h2>検索結果：</h2>
    <table border="1">
        <tr><th>ID</th><th>タイトル</th><th>説明</th></tr>
<%
            while (rs.next()) {
%>
        <tr>
            <td><%= rs.getInt("film_id") %></td>
            <td><%= rs.getString("title") %></td>
            <td><%= rs.getString("description") %></td>
        </tr>
<%
            }
%>
    </table>
<%
        } catch (Exception e) {
            out.println("エラー: " + e.getMessage());
        } finally {
            if (rs != null) rs.close();
            if (pstmt != null) pstmt.close();
            if (conn != null) conn.close();
        }
    }
%>
</body>
</html>
```
actor_search.jspに以下を記述。
```jsp
<%@ page import="java.sql.*" %>
<%@ page contentType="text/html; charset=UTF-8" %>
<html>
<head>
    <title>俳優検索</title>
</head>
<body>
    <h1>俳優検索</h1>
    <form method="get">
        姓または名を含むキーワード:
        <input type="text" name="keyword">
        <input type="submit" value="検索">
    </form>
<%
    String keyword = request.getParameter("keyword");
    if (keyword != null && !keyword.trim().isEmpty()) {
        String jdbcURL = "jdbc:mysql://<DBサーバのIPアドレス>:3306/sakila?user=root&password=<mysql用のパスワード>&useUnicode=true&characterEncoding=UTF-8";
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(jdbcURL);
            pstmt = conn.prepareStatement("SELECT actor_id, first_name, last_name FROM actor WHERE first_name LIKE ? OR last_name LIKE ?");
            pstmt.setString(1, "%" + keyword + "%");
            pstmt.setString(2, "%" + keyword + "%");
            rs = pstmt.executeQuery();
%>
    <h2>検索結果：</h2>
    <table border="1">
        <tr><th>ID</th><th>名</th><th>姓</th></tr>
<%
            while (rs.next()) {
%>
        <tr>
            <td><%= rs.getInt("actor_id") %></td>
            <td><%= rs.getString("first_name") %></td>
            <td><%= rs.getString("last_name") %></td>
        </tr>
<%
            }
%>
    </table>
<%
        } catch (Exception e) {
            out.println("エラー: " + e.getMessage());
        } finally {
            if (rs != null) rs.close();
            if (pstmt != null) pstmt.close();
            if (conn != null) conn.close();
        }
    }
%>
</body>
</html>
```

# ４．連携確認
以下のURLにアクセスして、画面表示・画面推移できれば成功！
```
http://<WebサーバのIPアドレス>/mainpage.html
```
![mainpage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4090096/f090cc04-d393-429b-adf3-d0153d65e54f.png)
![film_list.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4090096/af017199-a61d-4560-b12a-7d6d33266499.png)
![film_search_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4090096/dfe82ef1-e9c4-4523-9e43-df9c5a3c9357.png)

# まとめ
本記事では、Web/AP/DBを連携させた簡易Webアプリケーションを構築しました。
これにより、実務でも用いられる3層構造の流れと役割が理解できたと思います。今後はセキュリティや可用性の向上、クラウド環境への応用にもチャレンジしてみてください！
シリーズを通して読んでくださった方、ありがとうございました！