Spring MVC 3.2とThymeleafテンプレートエンジンを使用してアプリケーションを構築しています。私は、Thymeleafの初心者です。
Thymeleafを含むすべてが機能していますが、コントローラーへの単純なAjaxリクエストを実行し、その結果テンプレート(フラグメント)の一部のみをレンダリングする方法について、シンプルで明確なtoturialを知っている人がいるかどうか疑問に思いました。
私のアプリはすべて設定されており(Spring 3.2、spring-security、thymeleafなど)、期待どおりに動作します。今、私はAjaxリクエストをしたいと思います(jQueryでは非常に簡単ですが、Thymeleafのチュートリアル、第11章:テンプレートフラグメントのレンダリング( link )が言及されているので、私は使用したくないフラグメントで行われます。
現在、私は自分のコントローラーにいます
@RequestMapping("/dimensionMenuList")
public String showDimensionMenuList(Model model) {
Collection<ArticleDimensionVO> articleDimensions;
try {
articleDimensions = articleService.getArticleDimension(ArticleTypeVO.ARTICLE_TYPE);
} catch (DataAccessException e) {
// TODO: return ERROR
throw new RuntimeException();
}
model.addAttribute("dimensions", articleDimensions);
return "/admin/index :: dimensionMenuList";
}
<ul></ul>
メニュー項目を置き換えたいビューの部分:
<ul th:fragment="dimensionMenuList" class="dropdown-menu">
<li th:unless="${#lists.isEmpty(dimensions)}" th:each="dimension : ${dimensions}">
<a href="#" th:text="${dimension.dimension}"></a>
</li>
</ul>
どんな手がかりも大歓迎です。特に、これ以上フレームワークを含める必要がない場合。 JavaそのままのWebアプリでは既に多すぎます。
ブログ投稿 で出会ったアプローチを次に示します。
これらのフレームワークを使用したくなかったので、このセクションではjQueryを使用してAJAXリクエストをサーバーに送信し、レスポンスを待機し、ビューを部分的に更新します(フラグメントレンダリング)。
フォーム
<form>
<span class="subtitle">Guest list form</span>
<div class="listBlock">
<div class="search-block">
<input type="text" id="searchSurname" name="searchSurname"/>
<br />
<label for="searchSurname" th:text="#{search.label}">Search label:</label>
<button id="searchButton" name="searchButton" onclick="retrieveGuests()" type="button"
th:text="#{search.button}">Search button</button>
</div>
<!-- Results block -->
<div id="resultsBlock">
</div>
</div>
</form>
このフォームには、サーバーに送信される検索文字列(searchSurname)を含む入力テキストが含まれています。また、サーバーから受信した応答で更新されるリージョン(resultsBlock div)もあります。
ユーザーがボタンをクリックすると、retrieveGuests()関数が呼び出されます。
function retrieveGuests() {
var url = '/th-spring-integration/spring/guests';
if ($('#searchSurname').val() != '') {
url = url + '/' + $('#searchSurname').val();
}
$("#resultsBlock").load(url);
}
JQueryロード関数は、指定されたURLでサーバーに要求を行い、返されたHTMLを指定された要素(resultsBlock div)に配置します。
ユーザーが検索文字列を入力すると、指定された姓を持つすべてのゲストを検索します。それ以外の場合は、完全なゲストリストを返します。これらの2つの要求は、次のコントローラー要求マッピングに到達します。
@RequestMapping(value = "/guests/{surname}", method = RequestMethod.GET)
public String showGuestList(Model model, @PathVariable("surname") String surname) {
model.addAttribute("guests", hotelService.getGuestsList(surname));
return "results :: resultsList";
}
@RequestMapping(value = "/guests", method = RequestMethod.GET)
public String showGuestList(Model model) {
model.addAttribute("guests", hotelService.getGuestsList());
return "results :: resultsList";
}
SpringはThymeleafと統合されているため、HTMLのフラグメントを返すことができるようになります。上記の例では、戻り文字列「results :: resultsList」は、結果ページにあるresultsListという名前のフラグメントを参照しています。この結果ページを見てみましょう。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
</head>
<body>
<div th:fragment="resultsList" th:unless="${#lists.isEmpty(guests)}" id="results-block">
<table>
<thead>
<tr>
<th th:text="#{results.guest.id}">Id</th>
<th th:text="#{results.guest.surname}">Surname</th>
<th th:text="#{results.guest.name}">Name</th>
<th th:text="#{results.guest.country}">Country</th>
</tr>
</thead>
<tbody>
<tr th:each="guest : ${guests}">
<td th:text="${guest.id}">id</td>
<td th:text="${guest.surname}">surname</td>
<td th:text="${guest.name}">name</td>
<td th:text="${guest.country}">country</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
フラグメントは、ゲストが登録されたテーブルであり、結果ブロックに挿入されます。
レンダリングのみThymeleaf fragments
はModelAndView
でもうまく機能します。
あなたのコントローラー
@RequestMapping(value = "/feeds", method = RequestMethod.GET)
public ModelAndView getFeeds() {
LOGGER.debug("Feeds method called..");
return new ModelAndView("feeds :: resultsList");
}
あなたの見解
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head></head>
<body>
<div th:fragment="resultsList" id="results-block">
<div>A test fragment</div>
<div>A test fragment</div>
</div>
</body>
</html>
実際にレンダリングされるもの
<div id="results-block">
<div>A test fragment</div>
<div>A test fragment
</div>
</div>
Sohailの素晴らしい答えの代替バージョンとして、javascriptを使用してth:オブジェクト全体をコントローラに送信し、Thymeleafをフォームに統合して、乱雑になったり使用できなくなったりする@PathVariableを使用する必要がないバージョンを提供したい多くのフィールドを持つフォームを作成しました。
フォーム(idとStringsという名前のオブジェクトを返し、それらのオブジェクトの一部を値として持つMapをコンボボックスに供給する例を使用して)には次のようになります:
<form method="post" th:action="@{/yourMapping}" th:object="${object}" id="yourFormId">
<select th:field="*{mapOfObjects}">
<option
th:each="entry: ${mapOfObjects}"
th:value="${entry.value.id}"
th:text="${entry.value.name}" >
</option>
</select>
<p>Name:
<input type="text" th:field="*{name}" />
</p>
</form>
このフォームが送信されると(たとえば送信タイプのボタンを使用して)、ドキュメント全体が置き換えられます。ただし、この送信をjavascriptでインターセプトして、ajax方式で行うことができます。これを実現するために、関数を使用してインターセプターをフォームに追加します。まず、フォームの直後にインターセプターを追加する関数を呼び出します。
<script>formInterceptor("yourFormId");</script>
関数は次のようになります(ドキュメントの先頭または必要に応じてどこにでも配置できます)。
<script>
function formInterceptor(formName) {
var $form = $("#" + formName);
$form.on('submit', function(e) {
e.preventDefault();
$.ajax({
url : $form.attr('action'),
type : 'post',
data : $form.serialize(),
success : function(response) {
if ($(response).find('.has-error').length) {
$form.replaceWith(response);
}
else{
$("#ajaxLoadedContent").replaceWith(response);
}
}
});
});
};
</script>
これで、フォームが送信されるたびに、この関数がトリガーされ、次のようになります。
交換した部品は次のようになります
<div id="ajaxLoadedContent"></div>
そして、コントローラーはフォームのth:objectを受け取り、その値を埋めて、次のようにします(オブジェクトをオブジェクトのタイプに、「オブジェクト」を適切な名前に置き換えます):
@PostMapping(value = /yourMapping)
public String ajaxCtrlExample(@ModelAttribute("object") Object object, Model model) {
return yourFragmentPath;
}
そして、それがすべてです。 ajaxバージョンで必要なすべてのフォームの後にインターセプターを追加する関数を呼び出します。