1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Thymeleaf】POSTで一覧画面から詳細画面の遷移を行う【Spring Boot】

Posted at

はじめに

現場ではCSRF対策でトークンを使用するため、POSTで画面遷移を行う必要がありました。
この記事を参考に実装されたものを流用したのですが、今回Thymeleafで少し詰まってしまったのでまとめます。

バージョン

Spring Boot 2.7.3
Thymeleaf 3.0.15

コード例

まずは動作した例です。
※全てのコードはこちらを参照→https://github.com/1noseA/mailnaxx

htmlでは、table td内のaタグに詳細画面遷移のJavaScript関数を入れています。
詳細画面遷移用のformは下に設置(一部抜粋のため省略していますが、formが入れ子にならないように)。

list.html
// 一覧表示部分のみ抜粋
<div class="container">
    <div class="listArea mx-auto">
        <div class="table-responsive">
            <table class="table table-striped table-hover">
                <thead>
                    <tr class="border-bottom border-dark">
                        <th scope="col" class="text-canter">選択</th>
                        <th scope="col">社員番号</th>
                        <th scope="col">氏名</th>
                        <th scope="col">入社年月</th>
                        <th scope="col">所属</th>
                        <th scope="col">権限区分</th>
                        <th scope="col"><!-- 営業 --></th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>
                            <div class="form-check d-flex justify-content-center align-items-center">
                                <input class="form-check-input" type="checkbox" name="deleted_flg" value="1">
                                <input type="hidden" name="user_id" th:value="${userList.user_id}">
                            </div>
                        </td>
                        <td>
                            <a href="javascript:void(0);" th:onclick="showDetail('[[${userList.user_id}]]')">
                                <span th:text="${userList.user_number}"></span>
                            </a>
                        </td>
                        <td>
                            <a href="javascript:void(0);" th:onclick="showDetail('[[${userList.user_id}]]')">
                                <span th:text="${userList.user_name}"></span>
                            </a>
                        </td>
                        <td>
                            <a href="javascript:void(0);" th:onclick="showDetail('[[${userList.user_id}]]')">
                                <span th:text="${#strings.replace(userList.hire_date, '-', '/')}"></span>
                            </a>
                        </td>
                        <td>
                            <a href="javascript:void(0);" th:onclick="showDetail('[[${userList.user_id}]]')">
                                <span th:text="${userList.affiliation_id}"></span>
                            </a>
                        </td>
                        <td>
                            <a href="javascript:void(0);" th:onclick="showDetail('[[${userList.user_id}]]')">
                                <th:block th:each="roleClass : ${roleClassList}">
                                    <th:block th:if="${userList.role_class == roleClass.value}">
                                        <span th:text="${roleClass.viewName}"></span>
                                    </th:block>
                                </th:block>
                            </a>
                        </td>
                        <td>
                            <a href="javascript:void(0);" th:onclick="showDetail('[[${userList.user_id}]]')">
                                <span th:text="${userList.sales_flg == '1'} ? '営業' : ' '"></span>
                            </a>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</div>
<form method="post" th:action="@{/user/detail}" id="detailForm">
</form>

htmlの下に設置したformに対象のユーザIDをhiddenで入れ、submitしています。

user.js
function showDetail(id) {
    let form = document.getElementById('detailForm');
    let input = document.createElement('input');
    input.setAttribute('type', 'hidden');
    input.setAttribute('name', 'user_id');
    input.setAttribute('value', id);
    form.appendChild(input);
    form.submit();
}
UsersController.java
// 一部抜粋
// 詳細画面初期表示
@PostMapping("/user/detail")
public String detail(int user_id, Model model) {
    Users userInfo = usersMapper.findById(user_id);
    model.addAttribute("userInfo", userInfo);
    return "user/detail";
}

詰まったこと

①ThymeleafのJavaScript関数の引数にJavaの値を入れる書き方が分からない
jsのデバッグでそのまま文字列として表示されていました。

list.html
 // JavaScript関数部分のみ抜粋
// NG例①
showDetail('${userList.user_id}')

// NG例②
showDetail('__${userList.user_id}__')

// OK例
showDetail('[[${userList.user_id}]]')

②aタグにJavaScript関数を入れる書き方が分からない

list.html
 // NG例
<td>
    <a href="javascript:showDetail('[[${userList.user_id}]]')">
        <span th:text="${userList.user_name}"></span>
    </a>
</td>

 // OK例
<td>
    <a href="javascript:void(0);" th:onclick="showDetail('[[${userList.user_id}]]')">
        <span th:text="${userList.user_name}"></span>
    </a>
</td>

③403になってしまう
トークンのエラーと予想できました。
一覧画面では複数のformがある状態だったので、jsでformを作成しsubmitするようにしていました。
Spring Boot+Thymeleafではform内の「th:action〜」をつけることでCSRFトークンを設定してくれるのだそうです。
jsでどうトークンを設定するのかは分からず、html上にformを作成することで対処しました。

user.js
// NG例
function showDetail(id) {
    let form = document.createElement('form');
    form.setAttribute('action', '/user/detail');
    form.setAttribute('method', 'post');
    
    let input = document.createElement('input');
    input.setAttribute('type', 'hidden');
    input.setAttribute('name', 'user_id');
    input.setAttribute('value', id);
    form.appendChild(input);
    
    form.submit();
}

最後に

最近は現場でも家でもASP.NETをやっており、久しぶりのSpring BootでThymeleafの書き方どうだったっけという感じでした。
Controllerの書き方の違いはそんなに気にならないですが、htmlはテンプレートエンジンの書き方を調べながらになりますね。。

参考

Thymeleafでjavascriptの関数を呼び出したときに引数がうまく渡せない
Spring Boot + ThymeleafのCSRFトークン設定は超簡単

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?