よくやり方忘れるのでメモ。
こんな画面を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>