참고도서
|
1. 커맨드 객체
1 2 3 4 5 6 7 8 9 10 11 12 | @RequestMapping(value = "/register/step3", method = RequestMethod.POST) public String handleStep3(HttpServletRequest request) { String email = request.getParameter("email"); String name = request.getParameter("name"); String password = request.getParameter("password"); String confirmPassword = request.getParameter("confirmPassword"); RegisterRequest regReq = new RegisterRequest(); regReq.setEmail(email); regReq.setName(name); ... 생략 } | cs |
처리해야 할 파라미터가 늘어나면 늘어날 수록 작성해야 할 코드가 많아진다.
그래서 스프링은 커맨드(Command) 객체라는 것을 지원하고 있다.
http 요청 파라미터의 이름을 이용한 setter 메소드를 작성한 클래스를 만들고,
이 클래스의 객체(커맨드 객체)를 메소드의 파라미터 값으로 넣어주면,
스프링은 요청 파라미터의 값을 커맨드 객체에 담아준다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <!-- ContextPath/WEB-INF/view/register/step2.jsp --> <!-- /register/step3 요청 경로로 컨트롤러에 요청하는 뷰 --> <form action="step3" method="post"> <input type="text" name="name" id="name"> <input type="submit" value="제출"> </form> <!-- 폼 값으로 tinkerbell 을 넣고 제출 --> @RequestMapping(value = "/register/step3", method = RequestMethod.POST) // RegisterRequest 커맨드 객체를 메소드의 파라미터로 사용 // 폼에서 넘어오는 값들이 RegisterRequest 커맨드 객체에 설정된다 public String handleStep3(RegisterRequest regReq) { try{ System.out.println(regReq.getName()); // 출력 결과는 폼에서 넘어온 tinkerbell memberRegisterService.regist(regReq); return "register/step3"; catch(AlreadyExistionMemberException ex){ return "register/step2"; } } // 커맨드 객체를 생성하는 클래스 class RegisterRequest{ private String eamil; private String password; private String confirmPassword; private String name; ... setter, getter } | cs |
요청 파라미터 이름이 name
=> 커맨드 객체의 setter 로 요청 파라미터의 값을 넣어줌, public void setNane(String Name){this.name=name;}
=> setter 로 필드에 값이 들어간 커맨드 객체를 요청을 처리할 컨트롤러의 메소드의 파라미터로 설정
=> 요청을 처리할 컨트롤러의 메소드에서 요청 파라미터의 값을 사용할 수 있음
(2) 뷰 JSP 에서 커맨드 객체 사용하기
스프링 MVC 는 커맨드 객체의(첫 글자를 소문자로 바꾼) 클래스 이름과 동일한 속성 이름을 사용해서 커맨드 객체를 뷰에 전달한다.
따라서 뷰로 사용하는 JSP 에서 커맨드 객체에 접근할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | // 커맨드 객체를 생성하는 클래스 class RegisterRequest{ private String eamil; private String password; private String confirmPassword; private String name; ... setter, getter } @RequestMapping(value = "/register/step3", method = RequestMethod.POST) public String handelStep3(RegisterRequest regReq) { try { memberRegisterService.regist(regReq); // 커맨드 객체 RegisterRequest 를 모델에 담고 // register/step3 을 뷰에 담아서 리턴 // viewResolver 에 의해 ContextPath/WEB-INF/view/register/step3.jsp 가 호출됨 return "register/step3"; } catch (AlreadyExistingMemberException ex) { return "register/step2"; } } <!-- ContextPath/WEB-INF/view/register/step3.jsp --> <!-- 뷰 에 전달되는 커맨드 객체 이름, registerRequest --> <!-- 커맨드 객체에 담긴 값 사용 --> ${registerRequest.name} | cs |
뷰에서 커맨드 객체에 접근할 때 사용할 속성명을 변경하려면, @ModelAttribute 어노테이션을 사용하면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | // 커맨드 객체를 생성하는 클래스 class RegisterRequest{ private String eamil; private String password; private String confirmPassword; private String name; ... setter, getter } @RequestMapping(value = "/register/step3", method = RequestMethod.POST) // @ModelAttribute 을 사용해서 모델에서 사용할 속성 이름을 formData 로 설정 // 커맨드 객체는 모델에 담길 때, formData 속성명을 가지고 담긴다 public String handelStep3(@ModelAttribute("formData") RegisterRequest regReq) { try { memberRegisterService.regist(regReq); // 커맨드 객체 RegisterRequest 를 속성값 formData 로 지정해서 모델에 담고 // register/step3 을 뷰에 담아서 리턴 // viewResolver 에 의해 ContextPath/WEB-INF/view/register/step3.jsp 가 호출됨 return "register/step3"; } catch (AlreadyExistingMemberException ex) { return "register/step2"; } } <!-- ContextPath/WEB-INF/view/register/step3.jsp --> <!-- 뷰 에 전달되는 커맨드 객체 이름, formData --> <!-- 커맨드 객체에 담긴 값 사용 --> ${formaData.name} | cs |
(3) 커맨드 객체와 스프링 폼 연동
회원 정보 입력 폼에서 중복된 이메일 주소를 입력하면 다시 입력 폼을 보여 주는데,
이 경우 앞에서 입력했던 내용이 사라진 텅 빈 폼 화면을 보게 된다.
다시 입력 폼을 보여줄 때 커맨드 객체의 값을 이용해서 앞에서 입력한 값을 폼에서 보여줄 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <!-- ContextPath/WEB-INF/view/register/step2.jsp --> <!-- /register/step3 요청 경로로 컨트롤러에 요청하는 뷰 --> <form action="step3" method="post"> <input type="text" name="name" id="name"> <input type="submit" value="제출"> </form> @RequestMapping(value = "/register/step3", method = RequestMethod.POST) // RegisterRequest 커맨드 객체를 메소드의 파라미터로 사용 // 폼에서 넘어오는 값들이 RegisterRequest 커맨드 객체에 설정된다 public String handleStep3(RegisterRequest regReq) { try{ memberRegisterService.regist(regReq); return "register/step3"; catch(AlreadyExistionMemberException ex){ // 예외가 발생하면 // 커맨드 객체 RegisterRequest 를 모델에 담고 // register/step2 을 뷰에 담아서 리턴 // viewResolver 에 의해 요청이 넘어왔던 ContextPath/WEB-INF/view/register/step2.jsp 가 다시 호출됨 return "register/step2"; } } <!-- ContextPath/WEB-INF/view/register/step2.jsp --> <!-- 예외가 발생하여 다시 넘어온 뷰 --> <!-- 커맨드 객체를 사용하여 예외가 발생하기 전에 입력한 값을 넣어서 출력 --> <form action="step3" method="post"> <input type="text" name="name" id="name" value="${registerRequest.name"> <input type="submit" value="제출"> </form> | cs |
2. 커맨드 객체 : 중첩, 컬렉션 프로퍼티
(1) 포함관계에 있는 클래스
HTTP 요청 파라미터 이름이 "프로퍼티이름.프로퍼티이름" 과 같은 형식이면, 중첩 프로퍼티의 값을 처리한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | public class Respondent { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class AnsweredData { // 포함관계를 맺는다 private Respondent res; public Respondent getRes() { return res; } public void setRes(Respondent res) { this.res = res; } } /* AnsweredData 클래스에서 res.setName("냥냥"); 으로 Respondent 클래스의 필드값을 설정해 줄 수 있다(중첩 프로퍼티). 이런 포함관계에 있는 클래스가 있을 때, 뷰 JSP 에서 AnsweredData 커맨드 객체를 통해 Respondenet 객체의 값을 설정하려면, <input type="text" name="res.name"> 처럼 <input> 태그의 name 속성을 설정해 주면 된다. 그러면 스프링은 commandObj.getRes().setName(request.getParameter("res.name")); 과 유사한 방식으로 커맨드 객체에 파라미터 값을 전달한다. */ // 컨트롤러 @Controller @RequestMapping("/survey") public class SurveyController { // 주소창에 직접 survey 경로를 입력하면 이 메소드가 실행 // 리다이렉트 방식이 아니므로 주소 변동 없음, 그대로 요청한 경로 그대로 survey // 이 메소드가 리턴하는 뷰 surveyForm.jsp 에서 POST 방식으로 요청을 보내면 // 주소에 변동이 없었기 때문에, POST 방식으로 /survey 요청 @RequestMapping(method = RequestMethod.GET) public String form() { return "survey/surveyForm"; } // survey/surveyForm.jsp 에서 POST 방식으로 /survey 요청이 들어오면 이 메소드가 실행 @RequestMapping(method = RequestMethod.POST) public String submit(@ModelAttribute("ansData") AnsweredData data) { return "survey/submitted"; } } <!-- survey/surveyForm.jsp --> <!-- POST 방식으로 /survey 요청을 하는 뷰 --> <!-- AnsweredData와 포함관계에 있는 Respondent 객체의 name 필드에 값이 들어간다 --> <input type="text" name="res.name"> <!-- ansDate 속성명을 가지는 AnsweredData 커맨드 객체의 값 사용 --> <!-- survey/submitted.jsp --> <!-- survey/surveyForm.jsp 에서 POST 방식으로 /survey 요청을 했을 때 결과를 보여주는 뷰 --> ${ansData.res.name} <!-- 커맨드객체속성명.프로퍼티이름.프로퍼티이름 --> <!-- AnsweredData 커맨드 객체와 포함관계에 있는 Respondent 객체의 name 필드 값이 출력 --> | cs |
(2) 컬렉션 프로퍼티
HTTP 요청 파라미터 이름이 "프로퍼티이름[인덱스]" 형식이면 List 타입의 프로퍼티의 값 목록으로 처리힌다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 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; } } /* 뷰 JSP 에서 AnsweredData 커맨드 객체의 이름이 responses 이고 List 타입인 컬렉션에 값을 담으려면, 요청 파라미터 이름으로 responses 를 사용하고, 인덱스 값을 [] 를 이용해서 지정해 주면 된다. <input type="text" name="responses[0]"> => List 컬레션의 첫 번째 인덱스에 들어가는 값 <input type="text" name="responses[1]"> => List 컬레션의 두 번째 인덱스에 들어가는 값 폼 입력으로 responses[0] 에 냥냥, responses[1] 에 멍멍 을 입력하고 전송 ==> List 컬렉션에는 {"냥냥", "멍멍"} 이 담기게 된다. */ // 컨트롤러 @Controller @RequestMapping("/survey") public class SurveyController { @RequestMapping(method = RequestMethod.GET) public String form() { return "survey/surveyForm"; } @RequestMapping(method = RequestMethod.POST) public String submit(@ModelAttribute("ansData") AnsweredData data) { return "survey/submitted"; } } <!-- survey/surveyForm.jsp --> <!-- POST 방식으로 /survey 요청을 하는 뷰 --> <input type="text" name="responses[0]"> <input type="text" name="responses[1]"> <!-- ansDate 속성명을 가지는 AnsweredData 커맨드 객체의 값 사용 --> <!-- survey/submitted.jsp --%> <!-- survey/surveyForm.jsp 에서 POST 방식으로 /survey 요청을 했을 때 결과를 보여주는 뷰 --> <c:forEach var="response" items="${ansData.responses}" varStatus="status"> ${status.index + 1}번: ${response}</li> </c:forEach> <!-- froEach JSTL 을 사용해서 AnsweredData 객체의 resoponses 이름을 가지는 List 컬렉션에 담긴 값을 하나씩 꺼내와서 출력 --> | cs |
3. Model, ModelAndView 을 통해 컨트롤러에서 뷰에 데이터 전달하기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | <!-- Model 객체에 담을 Question 객체를 생성하는 클래스 --> public class Question { private String title; private List<String> options; public Question(String title, List<String> options) { this.title = title; this.options = options; } public String getTitle() { return title; } public List<String> getOptions() { return options; } public boolean isChoise() { return options != null && !options.isEmpty(); } } @Controller @RequestMapping("/survey") public class SurveyController { @RequestMapping(method = RequestMethod.GET) // Model 객체를 파라미터로 설정 public String form(Model model) { // Question 객체를 생성해서 컬렉션 List 에 담는 메소드 호출 List<Question> questions = createQuestions(); // Model 객체에 // [속성명 questions, 속성값 List 컬렉션 questions(Question 객체가 담긴 List)] 을 담는다. model.addAttribute("questions", questions); // survey/surveyForm.jsp 호출 return "survey/surveyForm"; } // Question 객체를 생성해서 컬렉션 List 에 담는 메소드 // Arrays.asList 배열을 컬렉션 List 로 반환 private List<Question> createQuestions() { Question q1 = new Question("당신의 역할은 무엇입니까?", Arrays.asList("서버", "프론트")); Question q2 = new Question("많이 사용하는 개발도구는 무엇입니까?", Arrays.asList("이클립스", "인텔리J")); return Arrays.asList(q1, q2); } } <!-- survey/surveyForm.jsp --> <!-- 속성명 questions 속성값 Question 객체가 담긴 컬렉션 List 가 Model 객체를 통해 넘어왔다 --> <form method="post"> // 속성명 questions 를 이용해서 데이터를 꺼낸다 <c:forEach var="q" items="${questions}" varStatus="status"> <p> ${status.index + 1}. ${q.title} <br /> <c:if test="${q.choice}"> <c:forEach var="option" items="${q.options}"> <label><input type="radio" name="responses[${status.index}]" value="${option}"> ${option}</label> </c:forEach> </c:if> <c:if test="${! q.choice }"> <input type="text" name="responses[${status.index}]"> </c:if> </p> </c:forEach> | cs |
(2) ModelAndView
Model 과 View 객체를 같이 담는 통 => ModelAndView 객체
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // Model 객체 사용 @RequestMapping(method = RequestMethod.GET) public String form(Model model) { List<Question> questions = createQuestions(); model.addAttribute("questions", questions); return "survey/surveyForm"; } // ModelAndView 객체 사용 @RequestMapping(method = RequestMethod.GET) // 리턴 타입 ModelAndView public ModelAndView form(Model model) { List<Question> questions = createQuestions(); // ModelAndView 객체 생성 ModelAndView mav = new ModelAndView(); // ModelAndView 객체의 메소드 addObject() 를 사용해서 Model 에 데이터를 담는다 mav.addObject("questions", questions); // ModelAndView 객체의 메소드 SetViewName() 을 사용해서 View 이름을 설정 mav.setViewName("survey/surveyForm"); // ModelAndView 객체 반환 return mav; } | cs |
'Programming > Spring' 카테고리의 다른 글
Spring MVC 에서 제공하는 폼 태그 (0) | 2017.08.26 |
---|---|
Spring MVC (요청 매핑, 리다이렉트) (0) | 2017.08.24 |
Spring MVC 프레임워크 동작 방식 (0) | 2017.08.23 |
Spring MVC 기본 설정 (0) | 2017.08.23 |
Spring JdbcTemplate Transaction (0) | 2017.08.22 |
댓글