web-dev-qa-db-ja.com

Thymeleaf Spring MVCを処理するための推奨される方法AJAXフォームとそのエラーメッセージ

Thymeleaf側でAJAXフォームとそのエラーメッセージを処理するための推奨される方法は何ですか?

私は現在、フィールドとそれぞれのエラーメッセージのJSON概要を返すSpringコントローラーを持っていますが、完全に手書きのJQuery(または通常のJavascript)を使用する必要があるのは少し間違って感じられ、遅くなります。特に、アプリケーションに含める予定のフォームが大量にあるためです。

14
Kristof

エラーが発生したときにフォーム全体を置き換えるのが好きです。以下は、スーパープリミティブの例です。フォームのレンダリングに大量のフラグメントを使用するつもりはありません...単純にしてください。

これは、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コードは、フォームのaction属性で指定された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));

繰り返しますが、これは単なる基本的な例です。上記のコメントで述べたように、これについて正しいまたは間違った方法はありません。これも私の好みの解決策ではありません。私がやろうとしていることには間違いなくいくつかの微調整がありますが、一般的な考え方はそこにあります。

注:私のJSコードにも欠陥があります。フォームを応答のフォームに置き換えると、フォーム送信ハンドラーは新しく置き換えられたフォームに適用されません。この方法を使用する場合は、フォームを置き換えた後、フォームハンドラーを適切に再初期化する必要があります。

24
yorgo

これに関するドキュメントはほとんどありませんが、Webフローに既に精通している場合は、それ以上は必要ないかもしれません。この手法がThymeleafの通常のBeanバインディングでどのように機能するかはわかりません。完全なペットクリニックのデモアプリでこれを使用してコントローラーを確認できるようにしたいと思います。

ドキュメント

0
bwfrieds

それがベストプラクティスと見なすことができるかどうかはわかりませんが、ここで私がやったことです:

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

次に、マップをajax応答に送り返し、「成功」セクションで処理しました。

0
diafragment

まだ興味があるかどうかはわかりませんが、解決策の例を探している人のために、ここではこれを残しておきます。

私はyorgoのソリューションを実装し、フラグメントにスクリプトを含めることで「欠陥」を回避しました。また、追加のパラメーターを持つ複数の送信ボタン(Spring + thymeleafで動的フォームを実装するためによく使用される)がある場合、フォームがシリアル化されると情報が失われるという別の小さな欠陥もありました。この情報をシリアル化されたフォームに手動で追加することで、これを回避しました。

ここに修正を加えたyorgoのソリューションの実装を表示できます: https://github.com/Yepadee/spring-ajax/blob/master/src/main/resources/templates/project_form.html?fbclid=IwAR0kr_ -t05_vFrPJxvbsG1Et7aLGir5ayXyPi2EKI6OHbEALgDfmHZ7HaKI

何がいいのかというと、次の操作を行うだけで、既存のthymeleafフォームに実装できるということです。

  1. スクリプトをフォームに入れ、フォームのIDを参照するようにします
  2. フォームをフラグメントに入れる
  3. コントローラーのpostメソッドを変更して、テンプレート全体ではなくフォームフラグメントを返す
0
Yepadee