Edited at

Spring(Java) + Thymeleaf でページの一部更新(Ajax)

More than 3 years have passed since last update.


ページの一部更新を非同期通信で行う

日本語の参考サイトを見つけられなかったのでメモ

Webアプリ開発中、

検索を行ったあとページ全体を更新するのではなく

結果部分だけを更新したいときがあったので仕方なく実装した。

Thymeleafのバージョンが古かったので調べたとおり書いても希望通り動かなかったが、

バージョンを「 2.1.3 」に更新したらちゃんと出来た。


環境設定(準備/確認)


◆. Maven設定

  「 pom.xml 」のThymeleaf設定部分を以下へ変更する

  ※なければ追加する


pom.xml


~省略~

<dependency>
  <groupId>org.thymeleaf</groupId>
  <artifactId>thymeleaf-spring3</artifactId>
  <version>2.1.3.RELEASE</version>
</dependency>

~省略~



◆. SpringとThymeleafのView関連の設定

  「 servlet-context.xml 」を変更する

  ※設定してなければ以下のように設定する

  ⇒ 参考にしたサイト(日本語)


servlet-context.xml


~省略~

<beans:bean id="templateResolver"
  class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
  <beans:property name="prefix" value="/WEB-INF/templates/" />
  <beans:property name="suffix" value=".html" />
  <property name="characterEncoding" value="UTF-8" />
  <beans:property name="templateMode" value="HTML5" />
</beans:bean>

<beans:bean id="templateEngine"
  class="org.thymeleaf.spring3.SpringTemplateEngine">
  <beans:property name="templateResolver" ref="templateResolver" />
</beans:bean>

<beans:bean class="org.thymeleaf.spring3.view.ThymeleafViewResolver">
  <beans:property name="templateEngine" ref="templateEngine" />
  <property name="characterEncoding" value="UTF-8" />
</beans:bean>

~省略~



あとは実装


◆. Controller

  リクエストを受け取って値を返す処理


HogeController.java

~省略~

/**
* パターンA:fragmentを利用してHTMLを返す場合
* ※FugaModel:自前のクラス
*/
@RequestMapping(value="/search_Html", method=RequestMethod.GET, produces="text/plain;charset=UTF-8")
public String showHtmlResult(final ModelMap model, FugaModel param) {

  // 値取得などいろいろな処理
  HogeModel dataCollection = hogehogeMethod(param);

  // 返す値を設定する
  model.addAttribute("dataCollection", dataCollection);

  // Thymeleafが描画する対象のfragmentを指定して戻す
  return "view_name :: fragmentName";
}

/**
* パターンB:値をjson形式で返す場合
*
*/
@RequestMapping(value="/search_json", method=RequestMethod.GET, produces="text/plain;charset=UTF-8")
public String showJsonResult(FugaModel param) {

  // 値取得などいろいろな処理
  HogeModel dataCollection = hogehogeMethod(param);

  Gson gson = new Gson();
  return gson.toJson(dataCollection);
}

~省略~



◆. View(パターンAについて)

  リクエストを出して、返ってきた値をどうにかする処理

  hoge_fragment.htmlの中身が更新されてview_name.htmlの「div#resultBox」へ反映される


view_name.html

~省略~

<form name="searchForm" method="get">
  <input type="search" name="code" th:value="${dataCollection.search.code}"/>
  <input type="search" name="name" th:value="${dataCollection.search.name}"/>
  <input type="search" name="hogeData" th:value="${dataCollection.search.hogeData}"/>
</form>
<a id="searchBtn" th:href="@{controllerの@RequestMapping値/search_html}">検索ボタン</a>

<div id="resultBox">
  <div th:substituteby="hoge_fragment::hogehoge" th:fragment="fragmentName"></div>
</div>

<script type="text/javascript">
/*
* 検索ボタン押下
*/
$("a#searchBtn").click(function(event) {
  event.preventDefault();
  var paramUrl = $(this).attr("href") + '?' + $('form[name="searchForm"]').serialize();

  // fragment(html)取得
  $.ajax({
    type : "GET",
    url : paramUrl,
    dataType : "html",
    success : function(data, status, xhr) {
      // div#resultBoxへ結果(HTML)を反映
      $('#resultBox').html(data);
    },
    error : function(XMLHttpRequest, status, errorThrown) {
      // エラー処理
    }
  });
});

</script>

~省略~



hoge_fragment.html

~省略~

<ul th:fragment="hogehoge">
  <li th:each="data : ${dataCollection.result}" th:if="${dataCollection.result != null}">
    <span th:text="${data.code}"></span>
    <span th:text="${data.name}"></span>
    <span th:text="${data.hogeData}"></span>
  </li>
</ul>

~省略~


  上記はController中の「パターンA」の処理。

  この場合は画像を含むデータなんかを受け取ろうとすると途中で落ちてしまう。

  なのでそういう通信結果がほしい時のためにJSONを返すバージョン(パターンB)を作成した。

  これだと画像などのバイナリデータ(実際にはBase64に変換したもの)も取得して表示できた。

  パターンBについては後日。。。(?)