Spring WebアプリケーションでSessionを使うチュートリアル

code html digital coding web 1076536

Spring Webでセッションを使って数当てゲームを作成します。

目次

プロジェクトの作成

Intellij IDEAでSpring Initializrを選択しプロジェクトを作成します。

依存関係として、以下を選択します。

  • Spring Web
  • Spring Boot DevTools
  • Thymeleaf
  • Lombok

Controllerクラスの作成

package com.example.bigorsmallspring;

import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@Controller
public class GameController {
    @Autowired
    HttpSession session;

    @GetMapping("/")
    public String index() {
        session.invalidate();

        Random rnd = new Random();
        int answer = rnd.nextInt(100) + 1;
        session.setAttribute("answer", answer);
        System.out.println("answer=" + answer);
        return "game";
    }

    @PostMapping("/challenge")
    public ModelAndView challenge(@RequestParam("number") int number,
                                  ModelAndView mv) {
        int answer = (Integer)session.getAttribute("answer");

        @SuppressWarnings("unchecked")
        List<History> histories = (List<History>)session.getAttribute("histories");

        if (histories == null) {
            histories = new ArrayList();
            session.setAttribute("histories", histories);
        }

        if (answer < number) {
            histories.add(new History(histories.size() + 1, number, "Too large"));
        } else if (answer > number) {
            histories.add(new History(histories.size() + 1, number, "Too small"));
        } else {
            histories.add(new History(histories.size() + 1, number, "Correct!"));
        }

        mv.setViewName("game");
        mv.addObject("histories", histories);
        return mv;
    }
}

@Autowiredアノテーションは、セッションオブジェクトであるsessionを初期化する役割があります。通常はHttpSessionオブジェクトHttpServletRequest(jakarta.servlet.http.HttpServletRequest)オブジェクトからgetSession()メソッドで取得します。@Autowiredを付与することで、コントローラークラス起動時にセッションの取得処理が自動的に行われ、sessionオブジェクトに格納されます。

History Class

ユーザーが試行した回答結果を記録しておくためのクラスです。

package com.example.bigorsmallspring;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public class History {
    private int seq;
    private int yourAnswer;
    private String result;
}

アノテーション@AllArgsConstructorを付記することで、以下のようなコンストラクタを生成します。このコンストラクタは実際のコードは生成されず暗黙に存在します。

public History(int seq, int yourAnswer, String result) {
    super();
    this.seq = seq;
    this.yourAnswer = yourAnswer;
    this.result = result;
}

アノテーション@Getterは全フィールドに対するゲッターメソッドを暗黙に生成します。

テンプレート

Thymeleafテンプレートを作成します。src/main/resources/templates/game.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Big or Small</title>
    <style>
      th, td {
        border: solid 1px;
      }
      table{
        border-collapse: collapse;
      }
    </style>
</head>
<body><h1>Big or Small</h1><form action="/challenge"method="post">
  <p><input type="text" name="number" placeholder="Input from 1 to 100"></p>
  <p><input type="submit"value="Answer"></p></form>
<hr>
<table><tr><th>Num</th><th>Your answer</th><th>Result</th></tr>
  <tr th:each="h:${histories}">
    <td th:text="${h.seq}"></td>
    <td th:text="${h.yourAnswer}"></td>
    <td th:text="${h.result}"></td></tr></table>
<p><a href="/">Start Over</a></p>
</body>
</html>	

ポイントは以下の th:eachです。

<tr th:each="h:${histories}">

コレクションオブジェクトであるhistoriesを受け取り、要素の数分繰り返して<tr>…</tr>を生成します。各ループごとにhistoriesオブジェクトから取り出したオブジェクトをhに代入し、入れ子となっている<td>...</td>ではhオブジェクトのプロパティにアクセスしています。

このhistoriesオブジェクトはControllerchallengeメソッド内の最後にある以下の行でModelAndViewにセットされています。

mv.addObject("histories", histories);

th:textの代わりに[[...]]というインライン式を使うことが出来ます。th:textに比べると相対的に記述量が少なくシンプルに書くことが出来ます。

<tr th:each="h:${histories}">
<td [[${h.seq}]]</td>
<td [[${h.yourAnswer}]]</td>
<td [[${h.result}]]</td>
</tr>

実行

ブラウザにアクセスします。


実際にいくつか数字を入れて遊んでみましょう。

よかったらシェアしてね!
目次