커맨드 객체 : 중첩, 콜렉션 프로퍼티
스프링 MVC는 커맨드 객체가 리스트 타입의 프로퍼티를 가졌거나 중첩 프로퍼티를 가진 경우에도 요청 파라미터의 값을 알맞게 커맨드 객체에 설정해주는 기능을 제공하고 있다.
설문조사 응답자 클래스
package survey;
public class Respondent {
private int age;
private String location;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
설문조사 답변 클래스
package survey;
import java.util.List;
public class AnsweredData {
private List<String> responses;
private Respondent res;
public List<String> getResponses() {
return responses;
}
public void setResponses(List<String> responses) {
this.responses = responses;
}
public Respondent getRes() {
return res;
}
public void setRes(Respondent res) {
this.res = res;
}
}
이 두 클래스로 예를 들자면 AnsweredData 클래스는 답변 목록을 저장하기 위한 List 타입의 responses 프로퍼티와 응답자 정보를 담기 위해 Respondent 타입의 프로퍼티를 사용했다.
<p>
<label><input type="radio" name="responses[0]" value="서버">서버개발자</label>
<label><input type="radio" name="responses[0]" value="프론트">프론트개발자</label>
<label><input type="radio" name="responses[0]" value="풀스택">풀스택개발자</label>
</p>
<p>
<label>응답자 위치:<br/>
<input type="text" name="res.location">
</label>
</p>
이런식으로~ input 태그의 name 속성이 커맨드 객체의 프로퍼티에 매핑된다.
responses[0] -> responses 프로퍼티(List 타입)의 첫번째 값
res.location -> res 프로퍼티(Respondent 타입)의 location 프로퍼티
Model을 통해 컨트롤러에서 뷰에 데이터 전달하기
컨트롤러는 뷰가 응답 화면을 구성하는데 필요한 데이터를 생성해서 전달해야 한다. 이 때 사용하는 것이 Model이다.
뷰에 데이터를 전달하는 컨트롤러는 다음 두 가지를 하면 된다.
package survey;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.Arrays;
import java.util.List;
@Controller
@RequestMapping("/survey")
public class SurveyController {
@GetMapping
public String form(Model model) {
List<Question> questions = createQuestions();
model.addAttribute("questions", questions);
return "survey/surveyForm";
}
// ModelAndView 를 사용하면 Model을 이용해
// 뷰에 전달할 데이터 설정 및 결과를 보여줄 뷰 이름을 리턴할 수 있다
public ModelAndView formModelAndView() {
List<Question> questions = createQuestions();
ModelAndView mav = new ModelAndView();
mav.addObject("questions", questions);
mav.setViewName("survey/surveyForm");
return mav;
}
private List<Question> createQuestions() {
Question q1 = new Question("당신의 역할은 무엇입니까?", Arrays.asList("서버","프론트","풀스택"));
Question q2 = new Question("많이 사용하는 개발도구는 무엇입니까?", Arrays.asList("이클립스","인텔리J","서브라임"));
Question q3 = new Question("하고 싶은 말을 적어주세요.");
return Arrays.asList(q1, q2, q3);
}
@PostMapping
public String submit(@ModelAttribute("ansData") AnsweredData data) {
return "survey/submitted";
}
}
여기서 궁금한 점 하나 ❗️
Model 객체는 도대체 어디서 생성돼서 매개변수로 받아와지는걸까 ? 검색해보니 컨트롤러는 파라미터를 자동으로 수집하는 기능이 있다고 한다.
스프링은 메소드의 파라미터에 Model 타입이 지정된 경우 Model 타입의 객체를 만들어서 메서드에 주입한다. 즉 스프링이 제공하는 기능이라는 것 ~~!!
GET 방식과 POST 방식에 동일 이름 커맨드 객체 사용하기
<form:form> 태그를 사용하려면 커맨드 객체가 반드시 존재해야 한다.
@PostMapping("/register/step2")
public String handleStep2(@RequestParam(value = "agree", defaultValue = "false") Boolean agree, Model model) {
if (!agree) {
return "register/step1";
}
model.addAttribute("registerRequest", new RegisterRequest());
return "register/step2";
}
이런 식으로 폼 표시 요청이 왔을 때 커맨드 객체를 생성해서 Model에 저장하는데
@PostMapping("/register/step2")
public String handleStep2(@RequestParam(value = "agree", defaultValue = "false") Boolean agree, RegisterRequest registerRequest) {
if (!agree) {
return "register/step1";
}
return "register/step2";
}
커맨드 객체를 파라미터로 추가하면 Model에 직접 객체를 추가하지 않아도 된다.
주요 폼 태그 설명
스프링 MVC는 <form:form>, <form:input> 등 HTML 폼과 커맨드 객체를 연동하기 위한 JSP 태그 라이브러리를 제공한다.