티스토리 뷰
초보 웹 개발자를 위한 스프링 5 프로그램 입문을 보고 복습 겸 개인 학습 정리입니다. (windows 기준)
이전 글에선 스프링 MVC로 main화면에서 회원 가입 → 가입 완료 후 → 메인화면으로도 돌아가는 것까지 만들어보았다.
이번 chap 11에서 서버에서 발생할 수 있는 오류들을 정리하고, 설문조사 페이지를 만들면서 모델처리를 하는 방법들에 대해 조금(?) 깊게 알아보았다.
예제 프로젝트 만들기 (메이븐 기준) 예제 코드
sp5-chap11 프로젝트 폴더 생성
프로젝트(sp5-chap11) 하위 폴더로 아래 폴더 생성
- src/main/java
- src/main/java/webapp
- src/main/java/webapp/WEB-INF
- src/main/java/webapp/WEB-INF/view
+ step.jsp 파일 복붙
+ chap 08 spring 패키지의 파일 복붙하기
+ 데이터 베이스 생성
sp5-chap11 폴더 내부에 pom.xml 생성
+ pom.xml 파일에 <packaging> war 값 추가, 서블릿 3.1, JSP 2.3, JSTL 1.2 dependency 추가
※ war : web application archive를 의미
이클립스에서 sp5-chap11 폴더에 생성한 메이븐 프로젝트 import
자주 발생하는 오류들
404 Not Found
→ 요청 경로를 처리할 컨트롤러가 존재하지 않거나, WebMvcConfigurer를 이용한 설정이 없다면 404 error 발생
경로가 올바른지, 컨트롤러에 설정한 경로, 컨트롤러 클래스에 빈 등록, 컨트롤러 클래스에 @Controller 애노테이션 적용 했는지 확인해야 한다.
405 Method Not Allowed
→ 지원하지 않은 전송 방식(Method)을 사용한 경우 405 error 발생
요청에 맞는 전송 방식을 사용해야 한다.
400 Bad Request
→ @RequestRaram의 필수 파라미터가 존재하지 않을 경우
RegisterController클래스의 hadleStep2 메서드에 @RequestRaram 애노테이션을 설정하고 기본값을 지정하지 않았을 때 약관 동의 버튼을 누르지 않고 다음 단계버튼을 누르게 되면 400 error 가 발생한다.
400 Bad Request
→ @RequestRaram가 적용된 파라미터의 타입으로 변환할 수 없는 경우
step2.jsp파일의 input 태그의 value값이 "ture1"값을 boolean 타입으로 변환할 수 없기 때문에 400 error가 발생한다.
커맨드 객체
중첩과 컬렉션 프로퍼티
15. 설문조사 폼 추가
세 개의 설문 항목과 응답자의 지역, 나이를 입력받는 설문 조사 정보를 담기 위해 survey 패키지를 만들고 클래스를 추가로 작성하자 (코드를 짧게 보여주기 위해 줄였다..ㅎ.)
Respondent 클래스는 응답자의 정보를 담는다.
→ chap11/src/main/java/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 클래스는 설문 항목에 대한 답변과 응답자 정보를 함께 담는다.
그리고 답변 목록을 저장하기 위해 List 타입의 responses 프로퍼티를 사용했고,
응답자 정보를 담기 위해 Respondent 타입의 res 프로퍼티를 사용했다.
→ chap11/src/main/java/survey/AnsweredData.java
package survey;
import java.util.*;
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;}
}
16. 컨트롤러 클래스 추가
→ chap11/src/main/java/survey/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")
public class SurveyController {
@GetMapping
public String form() {
return "survey/surveyForm";
}
@PostMapping
public String submit(@ModelAttribute("ansData") AnsweredData data) {
return "survey/submitted";
}
}
17. 위에서 만든 컨트롤러 클래스를 빈 객체 등록
→ chap11/src/main/java/config/ControllerConfig.java
package config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import controller.RegisterController;
import spring.MemberRegisterService;
import survey.SurveyController;
@Configuration
public class ControllerConfig {
@Autowired
private MemberRegisterService memberRegSvc;
@Bean
public RegisterController registerController(){
RegisterController controller = new RegisterController();
controller.setMemberRegisterService(memberRegSvc);
return controller;
}
@Bean
public SurveyController surveyController() {
return new SurveyController();
}
}
18. 설문조사 응답자에 대한 폼(submitted)과 설문조사 폼(surveyForm)에 대한 .jsp를 추가 (접은 글로 대체)
📌 surveyForm을 살펴보면 각 문항의 <input> 태그 안에 name="responses [ ]" 속성이 들어가있는데 앞서 커맨드 객체의 프로퍼티에 매핑된다.
→ chap11/src/main/webapp/WEB-INF/view/survey/surveyForm.xml
<%@ 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>
<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="VisualStudio">VisualStudio</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>
→ chap11/src/main/webapp/WEB-INF/view/survey/submitted.xml
<%@ 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>
19. 서버 실행
[Run As] → [Run on Server] → [톰캣😺 서버 실행]
설문 조사에 대한 주소 설정을 했기 때문에 서버를 실행하고 http://localhost:8090/sp5-chap11/survey에 접속하면 아래와 같이 surveyForm 이 먼저 나오고 응답을 하고 전송을 누르면 데이터가 커맨드 객체에 알맞게 저장된 것을 확인할 수 있다.
20. Model을 통해 컨트롤러에서 뷰로 데이터 전달하기
이제 컨트롤러는 뷰가 응답화면을 구성하는데 필요한 데이터를 생성해서 전달해야 한다. 이때 Model을 사용한다.
뷰에 데이터를 전달하는 컨트롤러는 다음 두가지를 하면 된다.
- 요청 매핑 애노테이션이 적용된 메서드의 파라미터로 Model 추가
- Model 파라미터의 addAttribute() 메서드로 뷰에서 사용할 데이터를 전달
※ chap 09의 컨트롤러 뷰에서 작성했었다.
이전에 작성했던 surveyForm 클래스는 하드 코딩이었기 때문에 이제 설문 항목을 컨트롤러에서 생성해서 뷰에 전달하는 방식으로 변경하기 위해 Question 클래스를 작성한다.
Question 클래스의 title과 options는 각 질문 제목과 답변 옵션을 보관하며,
주관식일 경우 생성자(16행 public Question(String title) {this(title, Collections.<String>emptyList());} )를 사용해서 답변 옵션이 없는 Question 객체를 생성한다.
→ chap11/src/main/java/survey/Question.java
package survey;
import java.util.Collections;
import java.util.List;
public class Question {
private String title;
private List<String> options;
public Question(String title, List<String> options) {
this.title = title;
this.options = options;
}
public Question(String title) {
this(title, Collections.<String>emptyList());
}
public String getTitle() {
return title;
}
public List<String> getOptions(){
return options;
}
public boolean isChoice() {
return options != null&& !options.isEmpty();
}
}
21. SurveyController가 Quesion 객체 목록을 생성해서 뷰에 전달하도록 구현하기
※ DB에서 정보를 읽어와 Question 목록을 생성하는 게 맞지만 예제에서는 컨트롤러에서 생성하도록 구현했다.
이전에 작성한 SurveyController 클래스 내용을 수정하자. (16번 코드와 비교해 보기)
form 메서드 파라미터에 Model model을 추가했고, addAttrivute() 메서드로 questions라는 이름으로 모델에 추가했다.
→ chap11/src/main/java/survey/SurveyController.java
package survey;
import java.util.Arrays;
import java.util.List;
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;
import org.springframework.ui.Model;
@Controller
@RequestMapping("/survey")
public class SurveyController {
@GetMapping
public String form(Model model) {
List<Question> questions = createQuestions();
model.addAttribute("question", questions);
return "survey/surveyForm";
}
private List<Question> createQuestions(){
Question q1 = new Question("희망하는 역활은 무엇인가요?", Arrays.asList("서버","프론트","풀스택"));
Question q2 = new Question("자주 사용하는 개발도구는 무엇인가요?", Arrays.asList("이클립스","인텔리제이","비쥬얼스튜디오"));
Question q3 = new Question("하고싶은 말을 적어주세요.");
return Arrays.asList(q1, q2, q3);
}
@PostMapping
public String submit(@ModelAttribute("ansData") AnsweredData data) {
return "survey/submitted";
}
}
22. 컨트롤러가 전달한 Question 리스트를 사용해서 화면을 생성하도록 surveyForm.jsp도 수정한다
수정 전
→ <input> 태그 안에 name="responses [ ]" 속성을 사용하여 커맨드 객체의 프로퍼티에 매핑을 했다.
수정 후
→ Model 파라미터의 addAttribute() 메서드로 생성한 "questions"을 뷰에 사용할 데이터를 전달한다.
23. 서버 실행
[Run As] → [Run on Server] → [톰캣😺 서버 실행]
20~ 22번 과정을 거친 폼을 보면 외관상 큰 차이는 없어 보이지만 내부 코드에 많은 변화가 있었다
기존 하드코딩한 (19번) 설문 항목을 컨트롤러에서 생성해서 뷰에 전달 한 폼
24. ModelAndView를 사용하여 한 번에 처리하기
20번에서 Model을 사용하여 뷰에 전달할 데이터를 설정하고 결과를 보여줄 뷰 이름을 리턴했다면, ModelAndView를 사용하면 한 번에 처리할 수 있다.
addObject() 메서드로 뷰에 전달할 모델 데이터를 추가하고, 뷰 이름은 setViewName() 메서드를 이용해서 지정한다.
'study > Spring' 카테고리의 다른 글
chap 12 - 커맨드 객체 검증과 에러 메시지 (0) | 2023.02.15 |
---|---|
chap 12 - MVC 메세지 처리 (0) | 2023.02.13 |
chap 11 - MVC 1 (1) (0) | 2023.02.06 |
chap 10 - 스프링 MVC 프레임워크 동작 방식 (0) | 2023.01.30 |
chap 09 - 스프링 MVC 설정 (0) | 2023.01.30 |
- Total
- Today
- Yesterday
- 배열
- 톰캣
- API
- 면접을 위한 CS 전공 지식 노트
- python3
- django
- 웹페이지
- django-environ
- musma
- 디자인 패턴
- path variable
- error: failed to push some refs to 'https://github.com/
- 회원 로그인
- Magazine K
- 회원가입
- git
- 한글 형태소 분석기
- git 공부
- Python
- 암호화
- Java
- authenticate()
- Django tutorial
- 검색 결과 내 페이지네이션
- django.contrib.auth
- Spring
- 혼자 공부하는 파이썬
- 환경 변수 설정
- git공부
- 커맨드 객체
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |