【Spring Boot x Thymeleaf】foreach文で同じ要素を大量に作り出す(そして良い塩梅にif文を挟む)


おうち時間を有意義に過ごすために
皆さんはおうち時間をいかがお過ごしでしょうか?

我が家はもうダメです。

毎日「ひまだね〜」「やることないね〜」から1日が始まり、夜寝る前には「あれやればよかったね〜」「まあいっか、おやすみ〜」で1日が終わる自堕落な生活を送っております。

そこで、

  • その日やること(前日に書いたものが引き継がれる)
  • その日やったこと
  • その日の反省
  • 明日やること

を書き留められるwebアプリをイントラで動かし始めたのですが、その時に…

「投稿や編集の歴をタイムライン的に表示したい」
「自分が作成したものは編集できるけど、他人のものは編集できないようにしたい」

と言う仕様を実現するためにthymeleafをイジイジしたので、備忘も兼ねて記事を残したいと思います。


完成図
自分の投稿にはeditリンクがあり、他人の投稿にはeditリンクがない。


コード
Viewはこんな感じ。thymeleafで実装しています。

<div id="timeline" th:if="timelineList != null" style="margin-top: 64px;">
	<div th:each="d : ${timelineList}" class="container-fluid">
		<div class="mdl-card mdl-shadow--2dp" style="margin: auto; margin-top: 10px; min-width: 90%;">
			<div class="mdl-card__title" th:style="${d.category == 'TL_MSG'} ? 'background: #3498DB; color: #FFF; overflow: visible;' : 'background: #009688; color: #FFF; overflow: visible;'">
				<h2 class="mdl-card__title-text">
					<img th:src="${d.picture}" style="width: 32px; height: 32px; margin-right: 4px;">
					<span th:utext="${d.username}"></span>
				</h2>
			</div>
			<div class="mdl-card__supporting-text">
				<th:block th:if="${d.message}">
					<th:block th:each="str, stat : ${d.message.split('\r\n|\r|\n', -1)}">
						<th:block th:text="${str}" />
						<br th:if="${!stat.last}" />
					</th:block>
				</th:block>
				<p th:if="${d.otherid}!=0">
					<a th:href="@{/open(repid=${d.otherid})}">open</a> / 
					<a th:if="${d.userid == userid}" th:href="@{/edit(repid=${d.otherid})}">edit</a>
				</p>
			</div>
			<div class="mdl-card__actions mdl-card--border" style="text-align: right;">
				<span style="font-size: 0.8em;" th:utext="${#dates.format(d.entryDate, 'yyyy/MM/dd HH:mm')}"></span>
			</div>
		</div>
	</div>
</div>

Controllerはこんな感じ。

@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index(@AuthenticationPrincipal OidcUser user, ModelAndView mav) {
	mav.setViewName("index");
	mav.addObject("message", "");
	mav.addObject("username", user.getFullName());
	mav.addObject("userid", user.getEmail());
	mav.addObject("picture", user.getPicture());
	List<TimelineContent> timelineContentList = timelineRepo.findAllByOrderByIdDesc();
	mav.addObject("timelineList", timelineContentList);
	return mav;
}

timelineListで渡したjava.util.Listから1件ずつforeachで中身を取り出してtimelineを作成しています。

<div th:each="d : ${timelineList}" class="container-fluid">

のところですね。

で、中身を取り出す際は

<img th:src="${d.picture}" style="width: 32px; height: 32px; margin-right: 4px;">
<span th:utext="${d.username}"></span>

と、してあげると取り出せます。

if文なんかも取り込めて、

<a th:if="${d.userid == userid}" th:href="@{/edit(repid=${d.otherid})}">edit</a>

と書いてあげて、投稿の作成者が自分だったら編集リンクを出すみたいなことをやっています。
※Java側にも編集者と作成者が一致していることを確認するロジックを入れてあげるとより安全だと思います。

if文は、もちろんこんな感じで書くこともできます。

<div class="mdl-card__title" th:style="${d.category == 'TL_MSG'} ? 'background: #3498DB;' : 'background: #009688;'">

投稿のカテゴリごとに、カードの背景色を変更するようにしています。
CSSは後から書くので許して・・・。


総括
実装は至ってシンプルなので、サンプルコードさえあれば迷わずにさくっと実装できるのではないかと思います。

って、ことで備忘も兼ねてコードを残しました。


最後まで読んでいただきありがとうございます。もしこの記事を気に入って頂けたようであればシェアをお願い致します。非常に励みになります。


コメントを残す