Web

Ch11. MVC 1 : 커맨드 객체 : 중첩, 콜렉션 프로퍼티

tose33 2022. 7. 16. 21:36

우선 다음 두 클래스를 보자.

다음 두 클래스는 세 개의 설문(survey) 항목과 응답자의 지역과 나이를 입력받는 설문조사를 담기 위한 클래스들이다. 

 

Respondent.java

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; }
	
}

AnsweredData.java

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; } 	
}

 

Respondent 클래스는 응답자의 정보를담고,

AnswerdData 클래스는 설문 항목에 대한 답변과 응답자 정보 Respondent 를 담는다. 

 

AnsweredData는 커맨드 객체로서 사용할 클래스다.

 

AnsweredData는 필드에 Respondent 타입이 있는데, Respondent는 그 자체로 age와 location 프로퍼티를 갖는다. 

즉 Respondent.age, Respondent.location을 갖는데, 이를 중첩된 형식이라고 표현한다.

 

또한 AnsweredData는 List<String> responses의 리스트 타입의 프로퍼티가 있다. 

 

 


커맨드 객체 : 중첩, 콜렉션 프로퍼티 

스프링 MVC는 커맨드 객체가 리스트 타입의 프로퍼티를 가졌거나 중첩 프로퍼티를 가진 경우에 요청 파라미터의 값을 커맨드 객체에 설정해준다.

 

예를들어 AnsweredData 객체는 List<String> responses, Respondent 를 프로퍼티로 갖는다.

 

- HTTP 요청 파라미터 이름이 "프로퍼티이름[인덱스]" 형식이면 List 타입 프로퍼티의 값 목록으로 처리한다.

 예를들어 <input> 태그가 다음과 같고 커맨드 객체가 AnsweredData 라면

<input type="radio" name="responses[0]" value="서버">서버개발자</label>

커맨드 객체인 AnsweredData의 List 타입인 List<String> responses의 0번째 인덱스에 매핑된다.

 

 

- HTTP 요청 파라미터 이름이 "프로퍼티이름.프로퍼티이름" 형식이면 중첩 프로퍼티 값을 처리한다.

예를들어 <input> 태그가 다음과 같고 커맨드 객체가 AnswerdData 라면 

<input type="text" name="res.location">

커맨드 객체인 AnsweredData의 Respondent res의 location에 매핑된다. 

 


설문 관련을 처리할 컨트롤러 클래스를 작성한다.

 

SurveyController.java

package survey;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/survey") // 이 클래스는 "/survey" 경로 처리  
public class SurveyController 
{
	// GET 방식의 "/survey" 경로 요청 처리 (주소창 직접 입력은 GET 방식) 
	@GetMapping
	public String form() 
	{
		return "survey/surveyForm";			
	}

	// POST 방식의 "/survey" 경로 요청 처리  
	// surveyForm.jsp에서 form이 submit되서 오면 여기서 처리됨 
	@PostMapping 
	public String submit(@ModelAttribute("ansData") AnsweredData data) // 커맨드 객체 
	{
		return "survey/submitted";
	}
}

해당 클래스는 @RequestMapping("/survey")로 "/survey" 요청 경로를 처리한다.

두 개의 메서드가 있는데 각각 @GetMapping, @PostMapping 으로서, 

@GetMapping인 form() 메서드는 "/survey" 요청 경로이면서 GET 방식 요청을 처리한다. (주소창 입력이 GET 방식이다) 

@PostMapping인 submit() 메서드는 "/survey" 요청 경로이면서 POST 방식 요청을 처리한다. 

 

 

컨트롤러 클래스를 설정 파일에서 빈으로 추가.

@Configuration 
public class ControllerConfig 
{
	... // 생략 
    
	@Bean
	public SurveyController surveyController() 
	{
		return new SurveyController();
	}
}

 

 

WEB-INF/view/survey/surveyForm.jsp

더보기

 

<%@ page contentType="text/html; charset=utf-8" %>
<!DOCTYPE html>
<html>

<head>
<title>설문조사</title> 
</head>

<body>
	<h2>설문조사</h2> 
	<form method="post">
	
	<p>
		1. 당신의 역할은? <br/>
		<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>
		2. 가장 많이 사용하는 개발도구는? <br/>
		<label><input type="radio" name="responses[1]" value="Eclipse">Eclipse</label>
		<label><input type="radio" name="responses[1]" value="Intellij">Intellij</label>
		<label><input type="radio" name="responses[1]" value="Sublime">Sublime</label>	
	</p>
	
	<p>
		3. 하고 싶은 말 <br/>
		<input type="text" name="responses[2]">
	</p>
	
	<p>
		<label>응답자 위치:<br>
		<input type="text" name="res.location">
		</label>
	</p>
	
	<p>
		<label>응답자 나이:<br>
		<input type="text" name="res.age"> 
		</label>
	</p>
	<input type="submit" value="전송">
		
	</form>
</body>
</html>

 

WEB-INF/view/survey/submitted.jsp

더보기
<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 

<!DOCTYPE html>
<html>
<head>
	<title>응답 내용</title>
</head>

<body>
	<p>응답 내용</p>
	<ul>
		<c:forEach var="response" items="${ansData.responses}" varStatus="status">
		<li>${status.index+1}번 문항: ${response } </li>
		</c:forEach>			
	</ul>	
	<p>응답자 위치: ${ansData.res.location} </p>
	<p>응답자 나이: ${ansData.res.age} </p> 
</body>

</html>

 

 


흐름

서버를 시작하고 "http://localhost:8080/sp5-chap11/survey" 로 가면 아래 화면이 나온다. 

SurveyController 클래스에서 @RequestMapping으로 "/survey" 경로를 처리한다고 하였고, 주소창에 직접 입력하는 것은 GET 방식 이므로 SurveyController 클래스의 form() 메서드가 이를 처리하고 이 메서드는 뷰 이름으로 "survey/surveyForm" 을 리턴한다. 따라서 surveyForm.jsp 에 따라 위 화면이 출력되는 것이다.

 

항목을 채우고 전송하는 경우를 생각해보자.

surveyForm.jsp의 <form>에 데이터들이 쌓일 것이다.

surveyForm.jsp의 다음 <input> 태그를 보자.

<label><input type="radio" name="responses[0]" value="서버">서버개발자</label>

 

responses[0]은 여기서 사용되는 커맨드 객체의 responses 프로퍼티의 (이 프로퍼티는 List일 것이다) 0번째 인덱스에 value 값인 "서버"가 저장될 것이다. 

 

항목을 채우고 전송을 누른다. 이 <form> 태그의 method는 "post"이기 때문에, "/survey" 경로의 POST 방식을 처리하는 submit() 메서드가 이를 처리한다. submit() 메서드를 보면 커맨드 객체로 AnsweredData를 사용한다. 

또한 뷰이름으로서 "survey/submitted"를 리턴하기 때문에 submitted.jsp가 뷰를 처리한다.

 

submitted.jsp를 보면 아래와 같은 foreach 문이 있다.

submitted.jsp

커맨드 객체 AnswerdData의 response를 순회하면서 출력하고 있다. 

 

 

 

출처 : 스프링5 프로그래밍 입문 (최범균 저)