SIer だけど技術やりたいブログ

SpringMVC 複数のフォームオブジェクトにバインドする方法

Java Spring

よくやり方忘れるのでメモ。

こんな画面をSpringMVCで作りたい

familyNameとgivenNameが1つのFormで、それを複数繰り返す。

実装方法(サーバ側)

Controllerクラスの引数に受け取るFormを用意する

本筋と外れるけど、入力値チェックも設定する。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserForm {
  @Size(max = 10, min = 1)
  private String familyName;
  @Size(max = 10, min = 1)
  private String givenName;
}

子フォームの入力値チェックが有効になるように@Validを設定する。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ParentForm {
  @Valid
  private List<UserForm> userFormList;
}

Controllerクラスで引数として受け取る

(1)…ControllerクラスではFormを引数に取るだけ。
(2)…初期画面表示のために、初期値を設定する。

@Controller
public class HomeController {

  @RequestMapping(value = "/", method = RequestMethod.GET)
  public String home(Model model) {
    return "welcome/home";
  }

  @RequestMapping(value = "/entry", method = RequestMethod.POST)
  public String entry(@Validated ParentForm form,  … (1)
                   BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
      return "welcome/home";
    }
    return "welcome/home";
  }

  @ModelAttribute … (2)
  public ParentForm setUpParentForm() {
    ParentForm parentForm = new ParentForm();
    parentForm.setUserFormList(Arrays.asList(new UserForm("value1", "value2"), new UserForm("value3", "value4")));
    return parentForm;
  }

}

あとはサーバ側が受け取れるリクエストパラメータの形式で送るだけ。

Formのフィールド変数名[添え字].子Formのフィールド変数名

例えば、

userFormList[0].familyName=value1
userFormList[0].givenName=value2

クライアント側(JSP)

ForEachで複数Form回すだけ。
pathの指定は『親Formのフィールド変数名[添え字].子Formのフィールド変数名』。

<h1>複数入力画面</h1>
<form:form method="post" action="${pageContext.request.contextPath}/entry" modelAttribute="parentForm">

  <c:forEach items="${parentForm.userFormList}" varStatus="rowStatus" var="item">
    <div>
      familyName
      <form:input path="userFormList[${rowStatus.index}].familyName"/>
      <form:errors path="userFormList[${rowStatus.index}].familyName"/>

      givenName
      <form:input path="userFormList[${rowStatus.index}].givenName"/>
      <form:errors path="userFormList[${rowStatus.index}].givenName"/>
    </div>
  </c:forEach>
  <input type="submit" value="send"/>
</form:form>

サンプル書いた

https://github.com/kimullaa/multi-form

JSONで送るなら、こんなめんどくさいこと考えなくていいのに。

参考

- 4.4. アプリケーション層の実装 — TERASOLUNA Server Framework for Java (5.x) Development Guideline 5.1.0.RELEASE documentation
- Spring MVC Multiple Row Form Submit in List collection. Multi row beans in Spring 3 MVC