Spring MVC 3.2 Thymeleaf Ajax 片段

Posted

技术标签:

【中文标题】Spring MVC 3.2 Thymeleaf Ajax 片段【英文标题】:Spring MVC 3.2 Thymeleaf Ajax Fragments 【发布时间】:2014-01-25 18:54:51 【问题描述】:

我正在使用 Spring MVC 3.2 和 Thymeleaf 模板引擎构建应用程序。我是 Thymeleaf 的初学者。

我的一切正常,包括 Thymeleaf,但我想知道是否有人知道关于如何向控制器执行简单的 Ajax 请求并最终渲染模板(片段)的一部分的简单而清晰的教程。

我的应用程序已配置所有内容(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";

我想替换&lt;ul&gt;&lt;/ul&gt;菜单项的视图部分:

<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 应用程序来说,它已经太多了。

【问题讨论】:

【参考方案1】:

这是我在blog post 中遇到的一种方法:

我不想使用这些框架,所以在本节中,我使用 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 load 函数在指定的 url 向服务器发出请求,并将返回的 html 放入指定的元素(resultsBlock div)中。

如果用户输入一个搜索字符串,它将搜索所有具有指定姓氏的客人。否则,它将返回完整的客人列表。这两个请求将到达以下控制器请求映射:

@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>

片段,它是一个注册客人的表格,将被插入到结果块中。

【讨论】:

【参考方案2】:

仅渲染 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>

【讨论】:

它会刷新页面吗? 取决于你如何称呼它。如果它是一个 ajax 调用,则页面不会刷新,否则它会。 我真的很喜欢这个。我尝试返回视图名称方法,它也可以。像这样:public String getFeeds() return "feeds :: resultsList"; 如何返回多个片段?? @AbdullahKhan【参考方案3】:

作为 Sohail 出色答案的替代版本,我想提供一个使用 javascript 可以将整个 th:object 发送到控制器的版本,将 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>

提交此表单时(例如,使用类型为 submit 的按钮)整个文档将被替换。但是,我们可以使用 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>

现在只要提交表单,就会触发这个函数,它会:

阻止原始表单提交 使用表单的 th:action 中定义的 url 进行 ajax 调用 序列化表单数据。您的控制器将能够在对象中接收此信息 用返回的片段替换部分 html 代码

替换后的部分应该是这样的

<div id="ajaxLoadedContent"></div>

并且控制器可以接收表单中的 th:object,并填充它的值,如下所示(将 Object 替换为您的对象的类型,将“object”替换为正确的名称):

@PostMapping(value = /yourMapping)
public String ajaxCtrlExample(@ModelAttribute("object") Object object, Model model) 
    return yourFragmentPath;

这就是一切。在 ajax-version 中调用每个表单后添加拦截器的函数。

【讨论】:

以上是关于Spring MVC 3.2 Thymeleaf Ajax 片段的主要内容,如果未能解决你的问题,请参考以下文章

spring mvc 整合jsp和thymeleaf两个模板引擎

Spring MVC thymeleaf 随机崩溃

Thymeleaf 和 Spring MVC 的表单参数为空

Spring-Boot + Spring-MVC + Thymeleaf + Apache Tiles

Spring MVC 和 Thymeleaf 资源版本控制

Thymeleaf + Spring MVC中的绑定复选框