🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

Thymeleaf

Thymeleaf(タイムリーフ)とは、Java用のテンプレートエンジンで、特定のフレームワークに依存せず使用することが可能です。

Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

Q&A

解決済

1回答

5370閲覧

[Spring Boot+thymleaf] プルダウンの中身だけを更新したい

tohmey

総合スコア10

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

Thymeleaf

Thymeleaf(タイムリーフ)とは、Java用のテンプレートエンジンで、特定のフレームワークに依存せず使用することが可能です。

Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

0グッド

0クリップ

投稿2019/10/31 04:47

編集2019/11/01 05:35

前提・実現したいこと

[Spring Boot+thymleaf] プルダウンの中身だけを更新したい

発生している問題・エラーメッセージ

期待値は、thymeleafのテンプレートフラグメントという機能によって、指定した場所にプルダウンが再構築されることですが、
実際は、(おそらく)thymeleafを通らずhtmlで処理されてしまっており、"index :: flgmntA"という指定がそのまま文字列として画面に表示されてしまう。

【index.html】(メイン画面)

html

1<html xmlns="http://www.w3.org/1999/xhtml" 2 xmlns:th="http://www.thymeleaf.org" 3 xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"> 4<head></head> 5<body> 6 <input type="text" id="ss1" /> <!--☆検索条件☆--> 7 <input type="text" id="ss2" /> <!--☆検索条件☆--> 8 <input type="text" id="ss3" /> <!--☆検索条件☆--> 9 <table> 10 <tr> 11 <td><div>選択肢</div></td> 12 <td id="tdid"> 13 <div th:replace="replace :: flgmntB" th:fragment="flgmntA"></div> <!--★ここに置き換わる★--> 14 </td> 15 </tr> 16 </table> 17</body> 18</html>

【replace.html】

html

1<!DOCTYPE html> 2<html xmlns:th="http://www.thymeleaf.org"> 3<head> 4 <meta charset="UTF-8"/> 5 <title></title> 6</head> 7<body> 8 <select id="id1" name="id1" th:fragment="flgmntB"> <!--★これが置き換わる★--> 9 <option value="">------------------------------------</option> 10 <option th:each="item : ${selectLst}" 11 th:value="${item.value}" 12 th:selected="${item.value == id1}" th:inline="text">[[${item.key}]] 13 </option> 14 </select> 15</body> 16</html>

【js】

JavaScript

1$('input').change(function() { 2 event.preventDefault(); 3 var dataWhere = { 4 "s1" : $("#ss1").val(), 5 "s2" : $("#ss2").val(), 6 "s3" : $("#ss3").val(), 7 }; 8 $.ajax({ 9 type : "POST", 10 url : /* [[@{/contrMthd}]] */'/contrMthd', 11 dataType : "html", 12 data : JSON.stringify(dataWhere), 13 contentType : 'application/json', 14 success : function(data, status, xhr) { 15 $('#tdid').html(data); // ★data="index :: flgmntA" 16 }, 17 error : function(XMLHttpRequest, textStatus, errorThrown) { 18 (略) 19 } 20 }); 21});

【Controller】

java

1@RestController 2public class TLController { 3 4 // 初期表示 5 @RequestMapping(value = "/", method = RequestMethod.GET) 6 public ModelAndView index(ModelAndView mav) { 7 // 初期表示のMap 8 Map<String, String> map = new LinkedHashMap<String, String>(); 9 map.put("key1", "value1"); 10 map.put("key2", "value2"); 11 map.put("key3", "value3"); 12 13    mav.setViewName("index"); 14    mav.addObject("selectLst", map); // ★プルダウンの中身★ 15    return mav; 16 } 17 18 // 絞り込み検索 19 @RequestMapping(value = "contrMthd", consumes = MediaType.APPLICATION_JSON_VALUE) 20 public String pulldown(@RequestBody String data, ModelMap model) { 21 22 ObjectMapper mapper = new ObjectMapper(); 23 try { 24 Map<String, String> whr = mapper.readValue(data, new TypeReference<HashMap<String, String>>() { 25 }); 26 // whrで検索したつもりのMap 27 Map<String, String> map = new LinkedHashMap<String, String>(); 28 map.put("key1", "value1"); 29 map.put("key2", "value2"); 30 31 model.addAttribute("selectLst", map); // ★プルダウンの中身★ 32 return "index :: flgmntA"; // ★置換指示★ 33 34 } catch (Exception e) { 35 e.printStackTrace(); 36 } 37 } 38}

試したこと

※こちらのサイトを参考にさせていただきました。
Spring(Java) + Thymeleaf でページの一部更新(Ajax)
(類似のサイトも複数参考にさせていただきました)

初期表示はうまくいっており、初期表示用に送り出したListの内容がプルダウンになって
index.htmlの<div th:replace="replace :: flgmntB"></div>
の箇所に表示されています。
また、
index.htmlの<input type="text" id="ss1" />などに入力した値はcontorollerに送られ、
それらによる検索結果がModelMapにセットされているところまでは確認できています。
ですが、
jsの$('#tdid').html(data);の実行結果は

<td id="tdid">index :: flgmntA</td>となり、contorollerから送った文字列が画面に表示されるばかりです。

試したこと2

$('#tdid').html(data); を、
$('#tdid').html('<div th:replace="replace :: flgmntB"></div>'); と、
直接タグを送り込むなどもしましたが、何も表示されない(replace :: flgmntBが働かないのでdivがカラ)だけでした。とにかくThymeleafがどこにもいない。という感じです。

補足情報(FW/ツールのバージョンなど)

thymeleaf 3.0.11.RELEASE
(環境構築した者が現場にはすでに居らず、thymeleafを初めて触る者しか居りません…)

コードの書き方の問題というよりは、表示後の画面においてthymeleafが有効にならないことが問題なのでは、と、現時点では思っております。そのため、
https://teratail.com/questions/220606
https://teratail.com/questions/220621
といった質問もさせていただいております。

あわせてよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2019/10/31 05:01

コード、リンクなどはマークダウンを利用してください。(ヘルプページ参照)
tohmey

2019/10/31 06:04

左上の四角にソース名?を入れるところを探し中ですが、おおむね修正できたのではと思います。 失礼いたしました。
m.ts10806

2019/10/31 06:09

例 ```JavaScript //コード ``` ファイル名やクラス名ではなく言語名を書きます。
tohmey

2019/10/31 06:23

うまくいきました。ありがとうございました。
m.ts10806

2019/10/31 06:26

すごく細かいことを言うと、コード以外の情報は外にだしてもらったほうがいいです。コードブロックの角にある+ボタンでコピーできるんですが、回答者が再現確認するための機能で、原則コピペで動かせるようにするためにはあっては邪魔になります(赤の他人なのでそれが本当に入ってるかどうかまで判断できませんしね)
m.ts10806

2019/10/31 06:27

あとTymeleaf以外のタグが消えてますが、戻しておいた方が良いです。関連するタグをきちんとつけておかないと目につく機会が減ります。
tohmey

2019/10/31 06:48

タグですが、Tymeleafを先頭にもってきたかっただけで、他を改めて追加するつもりが、追加の仕方がわからなくなりました……。探し中です。
m.ts10806

2019/10/31 06:51

順番が影響することは少ないですが、強いてならSpring先頭の方が良いのではと。基本は入力→サジェスチョンから選択 をタグ付けのところで繰り返すだけと思います。
tohmey

2019/10/31 07:16

何度もすみません。 基本は入力→サジェスチョンから選択 とは、編集ボタンから編集するときに出せるものでしょうか。それとも、編集とはまた別の作業ですか? いちばん最初の入力時には選択ができましたが、編集時にはみつかりません…。
m.ts10806

2019/10/31 07:22

ごめんなさい。質問をしたことがないので投稿画面で確認したのと、これまで追記修正依頼で対応してもらった経験からの推測です。 タグを自由に切り替えできるところから、新規投稿画面と同じように入力できるのでは、と思っています(思うだけで試せる材料が手元にないので…)
tohmey

2019/10/31 07:53

ありがとうございました。追記修正依頼で対応できた方がいらっしゃるのですね…。 ヘルプも舐めるように確認しましたが、見つかりませんでした。 基本すぎてマニュアルにも書かれていないことがトラブルの原因になっていることは日常でもよくあって、わかると「なんだ、こんな簡単なところで…」となりますよね。 なんだーそうだったのか。とわかる瞬間がくるといいのですが…。
tohmey

2019/11/01 00:49

タグの追加方法わかりました!
guest

回答1

0

ベストアンサー

下記の環境およびソースコードで動作確認できました。
ページを部分的に変更する方法についてはspring bootとthymeleafでfragmentsを使用してajaxをするという記事が分かりやすかったので一度ご覧ください。

動作確認環境
  • OpenJDK 11.0.2
  • Spring Boot 2.1.9
  • Thymeleaf 3.0.11
コード変更点

テンプレートファイル(*.html)については大きな変更はありません。動作確認用に若干手を入れているくらいです。
コントローラの方は下記の修正を入れました。(この他にコードを見やすくするために若干変えていますが、動作に影響はありません。)

  • クラスのアノテーションを @RestController から @Controller
  • pulldownメソッドの戻り値を "index :: flgmntA" から "replace :: flgmntB"

1つ目のアノテーションについては変えなくても問題ないかもしれませんが(未確認です)、2つ目の戻り値が一番の原因だったようです。

【index.html】(メイン画面)

<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"> <head> <meta charset="UTF-8"/> <script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script> <title>index</title> </head> <body> <input type="text" id="ss1" /><br> <input type="text" id="ss2" /><br> <input type="text" id="ss3" /><br> <table> <tr> <td>選択肢</td> <td id="tdid"> <div th:replace="replace :: flgmntB"></div> </td> </tr> </table> <script> $('input').change(function() { event.preventDefault(); var dataWhere = { "s1": $("#ss1").val(), "s2": $("#ss2").val(), "s3": $("#ss3").val() }; $.ajax({ type : "POST", url : /* [[@{/contrMthd}]] */'/contrMthd', dataType : "html", data : JSON.stringify(dataWhere), contentType : 'application/json', success : function(data, status, xhr) { $('#tdid').html(data); }, error : function(XMLHttpRequest, textStatus, errorThrown) { console.log(textStatus); console.log(errorThrown); } }); }); </script> </body> </html>

【replace.html】

<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title></title> </head> <body> <select id="id1" name="id1" size="5" th:fragment="flgmntB"> <option value="">------------------------------------</option> <option th:each="item : ${selectLst}" th:value="${item.value}" th:text="|<<${item.key}>>:${item.value}|" th:selected="${item.value == id1}"></option> </select> </body> </html>

【Controller】

import java.util.LinkedHashMap; import java.util.Map; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class TLController { @RequestMapping(value = "/", method = RequestMethod.GET) public String index(Model model) { Map<String, String> map = new LinkedHashMap<>(); map.put("key1", "value1"); map.put("key2", "value2"); map.put("key3", "value3"); model.addAttribute("selectLst", map); return "index"; } @RequestMapping(value = "/contrMthd", method = RequestMethod.POST) public String pulldown(@RequestBody Map<String, String> data, Model model) { Map<String, String> map = new LinkedHashMap<>(); map.put("key1", "値1"); map.put("key2", "値2"); model.addAttribute("selectLst", map); return "replace :: flgmntB"; } }

動作確認の様子

イメージ説明

投稿2019/11/01 05:59

rubytomato

総合スコア1752

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tohmey

2019/11/01 06:40

ご教示ありがとうございます! まさに、 @Controllerと@RestControllerの違い が影響していたと思われます。 なにしろ、 @RestControllerを@Controllerに変えただけで、 ……通常検索がコケるようになってしまいました。 (JS→controllerがつながらない) こんなに影響があるのか、と、改めて調べてみましたところ、 @Controllerは主にWebページ用のコントローラで使用する。 Webページ用コントローラはJSPやテンプレートエンジンのViewに遷移してレスポンスのHTMLを生成するので、基本的にメソッドの戻り値はViewの遷移先を指定するのに使用する。 @RestControllerはJsonやXML等を返すWebAPI用のコントローラで使用する。 こちらはViewに遷移しないのでメソッドの戻り値はレスポンスのコンテンツになる。 参考<https://qiita.com/tag1216/items/3680b92cf96eb5a170f0> まさに、"replace :: flgmntB"といった返却値が文字列として処理されてしまっていた原因と言えそうです。 とはいえ、当環境で@RestControllerを@Controllerに変更するには、他の機能の調整も必要になりますので、実現には少し工夫が要りそうです。 うまく収まりましたら、改めてご報告させていただきます!! ひとまず、ありがとうございました。
rubytomato

2019/11/01 06:52

> とはいえ、当環境で@RestControllerを@Controllerに変更するには、他の機能の調整も必要になりますので、実現には少し工夫が要りそうです。 ご事情があることわかりました。 簡単に済ますなら、フラグメント(html)を返すpulldownメソッドを別の新しいコントローラに切り出すか、 今回の実装内容でいえば、フラグメント(html)を返すのでなく、selectのoption要素を構成するデータだけを返すようにしてJSでselectを組み立てるのもありかもしれません。
tohmey

2019/11/01 06:56

ありがとうございました。 まさに!まさにでした。 controllerを切り出して、THYMLEAF専用controllerを作りました。 実行結果は◎です。 やっと、やりたいことが実現できました。 本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問