【问题标题】:Spring MVC 3.2 Thymeleaf Ajax FragmentsSpring MVC 3.2 Thymeleaf Ajax 片段
【发布时间】: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 应用程序来说,它已经太多了。

【问题讨论】:

    标签: ajax spring spring-mvc thymeleaf


    【解决方案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 中调用每个表单后添加拦截器的函数。

      【讨论】:

        猜你喜欢
        • 2016-04-22
        • 2016-03-14
        • 1970-01-01
        • 2015-11-25
        • 1970-01-01
        • 2018-01-07
        • 2018-06-12
        • 2019-06-28
        • 2016-03-13
        相关资源
        最近更新 更多