Spring BootとHTMLで始めるシングルページアプリケーション開発

docs

今までJavaの基本的な文法やオブジェクト指向について学んだよね。今回は、その知識を活かして、Webアプリケーション開発の第一歩を踏み出してみよう。とくに、最近よく耳にする「シングルページアプリケーション(SPA)」を、Spring BootHTMLを使って作る方法を解説するよ。

シングルページアプリケーション(SPA)ってなに?

SPAは、ユーザーがページを移動しても、ブラウザの画面全体が再読み込みされないWebアプリケーションのこと。例えば、TwitterやFacebookなんかがそうだね。従来のWebサイトだと、リンクをクリックするたびにページ全体が読み込まれて、一瞬画面が真っ白になることがあったけど、SPAならそれがほとんどないから、ユーザー体験がすごくスムーズなんだ。

SPAの裏側では、最初にHTML、CSS、JavaScriptなどの必要なファイルをすべて読み込んで、その後のデータのやり取りはJavaScriptが非同期通信(Ajax)を使って行うことが多いよ。

Spring BootでSPAのバックエンドを作ろう

まずは、SPAのデータを提供するバックエンド(サーバーサイド)をSpring Bootで作ってみよう。Spring Bootは、JavaでWebアプリケーションを簡単に開発するためのフレームワークだよ。

1. Spring Bootプロジェクトの作成

Spring Initializr(https://start.spring.io/)を使うと、必要な依存関係を簡単に設定してプロジェクトのひな形を作れるよ。

  • Project: Maven Project
  • Language: Java
  • Spring Boot: 3.x.x (最新版を選ぶといいよ)
  • Dependencies:
    • Spring Web: Webアプリケーションを作るために必要
    • Lombok: ボイラープレートコード(定型的なコード)を減らすため

これらの設定でプロジェクトを生成して、好きなエディタ(IntelliJ IDEAとかEclipseがおすすめ)で開いてみてね。

2. RESTful APIの作成

SPAでは、バックエンドとJSON形式でデータをやり取りすることが一般的。Spring BootでJSONを返すAPI(RESTful API)を作ってみよう。

Java

// src/main/java/com/example/demo/controller/HelloController.java
package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController // これをつけると、このクラスのメソッドがAPIとして使えるようになるよ
public class HelloController {

    // GETリクエストで/api/helloにアクセスすると、このメソッドが実行される
    @GetMapping("/api/hello")
    public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
        // "name"というパラメータを受け取って、それを使ってメッセージを返す
        return String.format("Hello, %s!", name);
    }

    // GETリクエストで/api/messageにアクセスすると、このメソッドが実行される
    @GetMapping("/api/message")
    public Message message() {
        // MessageクラスのオブジェクトをJSON形式で返す
        return new Message("これはSpring Bootからのメッセージだよ!", "森山太郎");
    }
}

Java

// src/main/java/com/example/demo/model/Message.java
package com.example.demo.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data // getter, setter, equals, hashCode, toStringメソッドを自動生成してくれるアノテーション
@AllArgsConstructor // 全てのフィールドを引数に持つコンストラクタを自動生成
@NoArgsConstructor // 引数のないコンストラクタを自動生成
public class Message {
    private String content;
    private String author;
}

@RestControllerアノテーションをつけたクラスのメソッドに@GetMappingなどのアノテーションをつけると、そのメソッドがWeb APIとして公開されるんだ。今回は/api/hello/api/messageという2つのAPIを作ったよ。

Messageクラスは、Lombokのアノテーションを使って、データクラスとして簡単に定義できる。@Dataがあるから、ゲッターやセッターを自分で書く必要がなくて便利だよね。

SPAのフロントエンドをHTMLとJavaScriptで作ろう

次に、ユーザーが実際に操作するフロントエンド(クライアントサイド)を作ってみよう。今回は、HTMLと素のJavaScriptを使ってSPAの基本的な仕組みを理解するよ。

1. index.htmlの作成

Spring Bootのプロジェクトのsrc/main/resources/staticディレクトリにindex.htmlファイルを作成してね。このディレクトリに置いたファイルは、Spring Bootが自動的に公開してくれるんだ。

HTML

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Spring Boot & SPA</title>
    <style>
        body { font-family: sans-serif; margin: 20px; }
        .tab-content { display: none; }
        .tab-content.active { display: block; }
        .tab-button {
            padding: 10px 15px;
            cursor: pointer;
            border: 1px solid #ccc;
            border-bottom: none;
            background-color: #f0f0f0;
            margin-right: 5px;
        }
        .tab-button.active {
            background-color: #fff;
            border-bottom: 1px solid #fff;
        }
    </style>
</head>
<body>
    <h1>シンプルなSPAを作ってみよう!</h1>

    <div>
        <button class="tab-button active" onclick="showTab('home')">ホーム</button>
        <button class="tab-button" onclick="showTab('about')">アバウト</button>
        <button class="tab-button" onclick="showTab('api-test')">APIテスト</button>
    </div>

    <div id="home" class="tab-content active">
        <h2>ようこそ!</h2>
        <p>ここはホーム画面だよ。</p>
    </div>

    <div id="about" class="tab-content">
        <h2>このアプリについて</h2>
        <p>Spring BootとHTMLでSPAを体験するサンプルアプリだよ。</p>
    </div>

    <div id="api-test" class="tab-content">
        <h2>APIテスト</h2>
        <p>Spring BootのAPIからデータを取得してみよう!</p>
        <button onclick="getHelloMessage()">Helloメッセージを取得</button>
        <p id="hello-message"></p>
        <hr>
        <button onclick="getApiMessage()">APIメッセージを取得</button>
        <p id="api-message-content"></p>
        <p id="api-message-author"></p>
    </div>

    <script>
        function showTab(tabId) {
            // 全てのタブコンテンツを非表示にする
            document.querySelectorAll('.tab-content').forEach(tab => {
                tab.classList.remove('active');
            });
            // 選択されたタブコンテンツを表示する
            document.getElementById(tabId).classList.add('active');

            // 全てのタブボタンのactiveクラスを解除
            document.querySelectorAll('.tab-button').forEach(button => {
                button.classList.remove('active');
            });
            // クリックされたタブボタンにactiveクラスを追加
            event.currentTarget.classList.add('active');
        }

        async function getHelloMessage() {
            try {
                // Spring BootのAPIにアクセス
                const response = await fetch('/api/hello?name=ユーザー');
                const data = await response.text(); // テキスト形式で取得

                document.getElementById('hello-message').innerText = 'メッセージ: ' + data;
            } catch (error) {
                console.error('Helloメッセージの取得に失敗しました:', error);
                document.getElementById('hello-message').innerText = 'エラーが発生しました。';
            }
        }

        async function getApiMessage() {
            try {
                // Spring BootのAPIにアクセス
                const response = await fetch('/api/message');
                const data = await response.json(); // JSON形式で取得

                document.getElementById('api-message-content').innerText = 'コンテンツ: ' + data.content;
                document.getElementById('api-message-author').innerText = '作成者: ' + data.author;
            } catch (error) {
                console.error('APIメッセージの取得に失敗しました:', error);
                document.getElementById('api-message-content').innerText = 'エラーが発生しました。';
                document.getElementById('api-message-author').innerText = '';
            }
        }
    </script>
</body>
</html>

2. JavaScriptの解説

このindex.htmlには、いくつかの重要なJavaScriptの機能が組み込まれているよ。

  • showTab(tabId)関数:
    • これは、SPAの「ページ遷移」を実現するための関数だよ。実際にはページの再読み込みは行わず、表示するコンテンツを切り替えているんだ。
    • document.querySelectorAll('.tab-content')で全てのタブコンテンツを取得して、一度全部非表示にする。
    • それから、引数で渡されたtabIdに対応するタブコンテンツだけを表示するようにactiveクラスを付与しているよ。
    • タブボタンのスタイルも、アクティブなボタンがわかるように切り替えているよ。
  • fetch API:
    • getHelloMessage()getApiMessage()関数の中で使われているfetchは、JavaScriptでサーバーにHTTPリクエストを送るためのAPIだよ。これを使って、Spring Bootで作ったAPIからデータを取得するんだ。
    • await fetch('/api/hello?name=ユーザー')/api/helloにリクエストを送ってる。awaitを使うと、通信が終わるまで次の処理を待ってくれるから、非同期処理を分かりやすく書けるんだ。
    • response.text()は、サーバーから返ってきたデータをテキストとして取得する場合に使うよ。
    • response.json()は、サーバーから返ってきたデータがJSON形式の場合に、JavaScriptのオブジェクトに変換してくれるんだ。Spring BootのMessageクラスのオブジェクトが、HTML側ではJavaScriptのオブジェクトとして扱えるようになるんだよ。

動かしてみよう!

  1. Spring Bootアプリケーションの起動: エディタからDemoApplication.java(メインクラス)を実行するか、ターミナルでプロジェクトのルートディレクトリに移動して./mvnw spring-boot:run(Windowsの場合はmvnw spring-boot:run)コマンドを実行してみてね。
  2. ブラウザでアクセス: アプリケーションが起動したら、ブラウザでhttp://localhost:8080にアクセスしてみて。index.htmlが表示されて、タブをクリックするとコンテンツが切り替わるのがわかるはずだよ。
  3. APIテスト: 「APIテスト」タブを開いて、「Helloメッセージを取得」や「APIメッセージを取得」ボタンをクリックしてみて。Spring Bootのバックエンドから取得したデータが画面に表示されるのが確認できるはずだよ!

まとめ

今回は、Spring BootHTMLを使ってシンプルな**シングルページアプリケーション(SPA)**の基本を学んだね。

  • Spring Bootで、JSONを返すRESTful APIを簡単に作れること。
  • HTMLJavaScriptfetch APIを使って、そのAPIからデータを非同期で取得できること。
  • JavaScriptでDOM(Document Object Model)を操作して、ページの再読み込みなしにコンテンツを切り替えられること。

これがSPAの基本的な仕組みだよ。実際にはもっと複雑なフレームワーク(React, Vue.js, Angularなど)を使って開発することが多いけど、根っこにある考え方は今回学んだことと一緒だから、しっかり覚えておくといいよ!

次回の記事も楽しみにしててね!

ToolDocs | 様々なツールや技術情報を紹介します

コメント

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