【问题标题】:Recommended way to handle Thymeleaf Spring MVC AJAX Forms and their error messages处理 Thymeleaf Spring MVC AJAX 表单及其错误消息的推荐方法
【发布时间】:2015-11-18 16:56:23
【问题描述】:

在 Thymeleaf 方面处理 AJAX 表单及其错误消息的推荐方法是什么?

我目前有一个 Spring 控制器,它返回字段的 JSON 概览及其各自的错误消息,但不得不求助于完全手写的 JQuery(或只是普通的 Javascript)感觉有点不对劲,而且速度很慢;特别是因为我打算在应用程序中使用大量表格。

【问题讨论】:

  • 没有正确、错误或推荐的方法来做到这一点。这实际上取决于您的应用程序的设置方式、您的 MVC 层以及您想要显示的内容。您的选项包括警报、片段、分组消息等。我使用多种方法,具体取决于我想要返回给用户的内容和格式。
  • 嗯,我主要是在寻找最快的方法。拉德和所有。所以我可以快速为我的后端构建一个好看的前端,这需要更多的工程。
  • 再次,这真的取决于您的设置方式。对于我使用片段的表单,这样一切都是标准化的。对于单数输入/选择,我使用 javascript 对象来隐藏/显示错误。
  • 你有这方面的一些例子吗,Aeseir?这将是我的问题的答案。

标签: jquery ajax spring spring-mvc thymeleaf


【解决方案1】:

不知道是否还有人感兴趣,但我将把它留在这里,以供任何人寻找示例解决方案。

我实现了 yorgo 的解决方案,并通过在片段中包含脚本来解决“缺陷”。还有一个小缺陷,如果有多个带有额外参数的提交按钮(通常用于在 spring + thymeleaf 中实现动态表单),则在序列化表单时信息会丢失。我通过手动将此信息附加到序列化表单中解决了这个问题。

您可以在此处查看我对 yorgo 解决方案的实施以及修复:https://github.com/Yepadee/spring-ajax/blob/master/src/main/resources/templates/new_project.html

它的好处在于,您只需执行以下操作即可在任何现有的 thymeleaf 表单上实现它:

  1. 将脚本放入表单并使其引用表单的id
  2. 将表单放入片段中
  3. 更改控制器中的 post 方法以返回表单片段而不是整个模板

【讨论】:

    【解决方案2】:

    不确定是否可以将其视为最佳做法,但这是我所做的:

    Map<String, String> errorMap = binding.getFieldErrors()
       .stream().collect(Collectors.toMap(
            e -> e.getField(), e -> messageSource.getMessage(e, locale)));
    

    然后我将地图发送回 ajax 响应以在“成功”部分进行处理。

    【讨论】:

      【解决方案3】:

      我喜欢做的是在发生错误时替换整个表单。下面是一个超级原始的例子。我不会使用大量片段来呈现表单……只是保持简单。

      这是用 Spring 4.2.1 和 Thymeleaf 2.1.4 编写的

      代表用户信息表单的基本类:UserInfo.java

      package myapp.forms;
      
      import org.hibernate.validator.constraints.Email;
      import javax.validation.constraints.Size;
      import lombok.Data;
      
      @Data
      public class UserInfo {
        @Email
        private String email;
        @Size(min = 1, message = "First name cannot be blank")
        private String firstName;
      }
      

      控制器:UsersAjaxController.java

      import myapp.forms.UserInfo;
      import myapp.services.UserServices;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Controller;
      import org.springframework.ui.Model;
      import org.springframework.validation.BindingResult;
      import org.springframework.web.bind.annotation.*;
      
      import javax.transaction.Transactional;
      
      @Controller
      @Transactional
      @RequestMapping("/async/users")
      public class UsersAjaxController {
        @Autowired
        private UserServices userServices;
      
        @RequestMapping(value = "/saveUserInfo", method = RequestMethod.POST)
        public String saveUserInfo(@Valid @ModelAttribute("userInfo") UserInfo userInfo,
                                   BindingResult result,
                                   Model model)  {
          // if any errors, re-render the user info edit form
          if (result.hasErrors()) {
              return "fragments/user :: info-form";
          }
          // let the service layer handle the saving of the validated form fields
          userServices.saveUserInfo(userInfo);
          return "fragments/user :: info-success";
        }
      }
      

      用于呈现表单和成功消息的文件:fragments/user.html

      <div th:fragment="info-form" xmlns:th="http://www.thymeleaf.org" th:remove="tag">
        <form id="userInfo" name="userInfo" th:action="@{/async/users/saveUserInfo}" th:object="${userInfo}" method="post">
          <div th:classappend="${#fields.hasErrors('firstName')}?has-error">
            <label class="control-label">First Name</label>
            <input th:field="*{firstName}" type="text" />
          </div>
          <div th:classappend="${#fields.hasErrors('first')}?has-error">
            <label class="control-label">Email</label>
            <input th:field="*{email}" ftype="text" />
          </div>
          <input type="submit" value="Save" />
        </form>
      </div>
      
      <div th:fragment="info-success" xmlns:th="http://www.thymeleaf.org" th:remove="tag">
        <p>Form successfully submitted</p>
      </div>
      

      JS 代码将简单地将表单提交到表单操作属性中提供的 URL。当响应返回到 JS 回调时,检查是否有任何错误。如果有错误,请将表单替换为响应中的表单。

      (function($){
        var $form = $('#userInfo');
        $form.on('submit', function(e) {
          e.preventDefault();
          $.ajax({
            url: $form.attr('action'),
            type: 'post',
            data: $form.serialize(),
            success: function(response) {
              // if the response contains any errors, replace the form
              if ($(response).find('.has-error').length) {
                $form.replaceWith(response);
              } else {
                // in this case we can actually replace the form
                // with the response as well, unless we want to 
                // show the success message a different way
              }
            }
        });
      })
      }(jQuery));
      

      同样,这只是一个基本示例。正如上面的 cmets 所述,没有正确或错误的方法可以解决这个问题。这也不完全是我的首选解决方案,我肯定会对此进行一些调整,但总体思路就在那里。

      注意:我的 JS 代码也存在缺陷。如果您将表单替换为响应中的表单,则表单提交处理程序将不会应用于新替换的表单。如果走这条路线,您需要确保在替换表单后正确地重新初始化表单处理程序。

      【讨论】:

        【解决方案4】:

        这方面的文档很少,但如果您已经熟悉 Web Flow,则可能不需要更多。我不确定这种技术如何与 Thymeleaf 中的普通 bean 绑定一起工作。我很想看到一个完整的宠物诊所演示应用程序使用它,这样我就可以看到控制器。

        docs

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-05-26
          • 2023-04-10
          • 2012-08-20
          • 1970-01-01
          • 2016-03-14
          • 1970-01-01
          • 2014-05-30
          相关资源
          最近更新 更多