참고 도서 : 스프링5 프로그래밍 입문 - 최범균 저 |
ch11. MVC 1: 요청 매핑/커맨드 객체/ 리다이렉트/ 폼 태그/모델
*[이 장 학습내용] : 스프링 MVC의 기본적인 컨트롤러 구현 방법 ▶요청 매핑 애노테이션 이용 -> 요청 경로 처리 메소드 설정 방법 ▶커맨드 객체 사용 -> 폼에 입력한 데이터를 받아서 처리 방법 ▶모델을 통해 뷰가 응답 생성 시 필요한 데이터 전달하는 방법 |
*스프링 MVC를 사용해서 웹 어플리케이션을 개발한다는 것 = [컨트롤러, 뷰 코드 구현한다는 것] -어떤 컨트롤러를 이용해서 어떤 경로를 처리할지 결정 -웹브라우저의 요청에 필요한 처리 후 결과를 JSP 이용(뷰 코드) 해서 보여줌 |
1. [프로젝트 준비]
src/main/java : 자바코드, 설정 파일 위치 src/main/webapp : HTML/CSS/JS 위치할 폴더 src/main/webapp/WEB-INF: web.xml 파일 위치할 폴더 src/main/webapp/WEB-INF/view : 컨트롤러 결과 보여줄 JSP 파일 위치 |
▶[pom.xml] 모듈 의존 추가
-<dependency>에 웹 위한 모듈 / DB 연동 위한 모듈에 대한 의존 설정을 한다
-> 이클립스에 프로젝트 파일 임포트하기
<dependencies> //웹 MVC 위한 모듈 의존 설정 추가 <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.2-b02</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> //DB 연동을 위한 모듈 의존 추가 <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jdbc</artifactId> <version>8.5.27</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.45</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> </dependencies> |
▶[설정 파일 작성]
-➀ DB 설정 파일 (DataSource, 트랜잭션 관련설정 ) -➁ 스프링 MVC 기본 설정 파일 -➂ web.xml 설정 파일 (DispatcherServlet 등록) |
➀ <MemberConfig 클래스 작성 > : DB 연동 위한 설정 파일
@Configuration //스프링 설정 파일
@EnableTransactionManagement //@Transactional 활성화 위해 추가
public class MemberConfig {
@Bean(destroyMethod = "close") //DB 연동을 위해 빈으로 등록
public DataSource dataSource() {
DataSource ds = new DataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost/spring5fs?characterEncoding=utf8");
ds.setUsername("spring5");
ds.setPassword("spring5");
ds.setInitialSize(2);
ds.setMaxActive(10);
ds.setTestWhileIdle(true);
ds.setMinEvictableIdleTimeMillis(60000 * 3);
ds.setTimeBetweenEvictionRunsMillis(10 * 1000);
return ds;
}
@Bean
public PlatformTransactionManager transactionManager() {
DataSourceTransactionManager tm = new DataSourceTransactionManager();
tm.setDataSource(dataSource());
return tm;
}
@Bean
public MemberDao memberDao() {
return new MemberDao(dataSource());
}
@Bean
public MemberRegisterService memberRegSvc() {
return new MemberRegisterService(memberDao());
}
@Bean
public ChangePasswordService changePwdSvc() {
ChangePasswordService pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao());
return pwdSvc;
}
}
➁ <MemberConfig 클래스 작성 > : DB 연동 위한 설정 파일
@Configuration
@EnableWebMvc //스프링 웹 MVC 사용위해 추가
public class MvcConfig implements WebMvcConfigurer { //인터페이스 상속받음
@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/view/", ".jsp");
}
}
➂<web.xml> 파일 작성 : DispatcherServlet 등록
<servlet> <servlet-name>dispatcher</servlet-name> //이름 등록 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextClass</param-name> //초기화 파라미터 설정 <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value> </init-param> <init-param> <param-name>contextConfigLocation</param-name> <param-value> //스프링 설정 클래스 목록 지정 config.MemberConfig config.MvcConfig config.ControllerConfig </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name |
▷ “프로젝트 준비가 끝났다” |
2. [요청 매핑 애노테이션 적용 메소드 이용 -> 경로 매핑]
*요청 매핑 애노테이션 : @RequestMapping, @GetMapping, @PostMapping |
[경로매핑]
: 컨트롤러 클래스 안에서 요청 매핑 애노테이션 메소드르 통해 처리할 요청 경로를 지정 -> 이 요청 경로를 해당 메소드가 처리하도록 설정 -> 관련 요청 경로들을 묶어서 한 개의 컨트롤러 클래스 안에서 처리할 수 O |
@Controller
public class HelloController{
@GETMapping("/hello") //요청 경로 지정 (메소드)
public String hello(Medo model, ) {
model.addAttribute("greeting")
}
}
<<+추가>>
공통 경로를 클래스 위에서 묶어주고, 개별 경로를 각 메소드 위에서 묶어 처리한다. -> 스프링 MVC는 클래스에 적용한 요청 매핑 애노테이션 경로와 메소드에 적용한 요청 매핑 애노테이션 경로를 합쳐서 경로를 찾기 때문 |
@Controller
@RequestMapping("/register") //공통 경로
public class RegistController { //클래스
@RequestMapping("/step1") //개별 경로
public String handleStep1() {
}
@RequestMapping("/step2") //개별 경로
public String handleStep2() {
}
@RequestMapping("/step3") //개별 경로
public String handlStep3() {
}
}
[약관 동의 화면 요청 처리] -> [회원정보 입력 처리] -> [가입 처리 결과 화면 보여주기] |
➀ 요청 URL 처리 코드 (컨트롤러 작성)
▶[약관 동의 화면 요청 처리]
이 경우, 별다른 처리 없이 약관 내용만 보여주면 되기 때문에 약관 내용 보여줄 뷰 이름만 리턴
@Controller
public class RegisterController { //(회원가입) 컨트롤러 클래스
//필드
private MemberRegisterService memberRegisterService;
public void setMemberRegisterService(
MemberRegisterService memberRegisterService) {
this.memberRegisterService = memberRegisterService;
}
@RequestMapping("/register/step1") //약관 동의 화면 요청 처리 매핑
public String handleStep1() {
return "register/step1"; //약관 동의 화면 결과 뷰 이름 반환
}
}
➁ 처리 결과를 응답하는 코드 (뷰 코드 작성)
-컨트롤러가 리턴한 뷰 이름 코드
<%@ page contentType="text/html; charset=utf-8" %>
<!DOCTYPE html>
<html>
<head>
<title>회원가입</title>
</head>
<body>
<h2>약관</h2>
<p>약관 내용</p>
<form action="step2" method="post"> // 전송 방식 = POST
<label>
<input type="checkbox" name="agree" value="true"> 약관 동의
</label>
<input type="submit" value="다음 단계" />
</form>
</body>
</html>
➂ 컨트롤러 설정 클래스(파일) 작성
이 파일 안에 컨트롤러 클래스를 빈으로 등록
@Configuration
public class ControllerConfig { //컨트롤러 설정 파일
@Autowired //자동 의존 주입
private MemberRegisterService memberRegSvc;
@Bean
public RegisterController registerController() { //컨트롤러 클래스를 빈으로 등록
RegisterController controller = new RegisterController();
controller.setMemberRegisterService(memberRegSvc); //의존 주입
return controller;
}
}
3. [GET 과 POST 구분: @GetMapping / @PostMapping ]
-스프링 MVC 는 별도 설정 없으면 기본적으로 @RequestMapping 에 지정한 경로와 일치하는 요청을 처리한다. |
<요청 방식에 대한 제한 걸기> ▶POST 방식 요청만 처리하고 싶다면 @PostMapping 애노테이션으로 제한할 수 있다. -> 이 경우 해당 경로에 대한 POST 방식의 요청 경로만 처리하며 GET 방식의 요청 경로는 처리하지 않는다. ▶GET 방식 요청만 처리하고 싶다면 @GetMapping 애노테이션으로 제한할 수 있다. ▶같은 경로에 대해 GET과 POST 방식을 각각 다른 메소드가 처리하도록 설정할 수 있다. |
4. [요청 파라미터 접근]
<컨트롤러 메소드에서 요청 파라미터에 접근하는 방법 >
➀ HttpServletRequest 직접 사용하기 : 여러 개 일 때
- 컨트롤러 처리 메소드의 파라미터로 HttpServletRequest 타입 사용하고 getParameter() 메소드로 파라미터의 값을 구하면 된다.
@PostMapping("/register/step2")
public String handleStep2(HttpServletRequest request) {
Satring agreeParam = request.getParameter("agree");
...
}
➁ @RequestParam 사용하기 : 몇 개 안될 때
-스프링 MVC는
String 타입으로 받은 요청 파라미터 값을 읽어와서 해당 타입에 대한 변환을 지원한다.
@PostMapping("/register/step2")
public String handleStep2(
@RequestParam(value = "agree", defaultValue="false") Boolean agree ) {
... ..
}
➂ 커맨드(command) 객체 사용하기 (뒤에서 설명)
➀ 요청 URL 처리 코드 (컨트롤러 작성)
▶[회원 정보 입력 처리]
앞선 동의 여부에 따라 다른 폼 반환하도록 처리
@Controller
public class RegisterController {
@PostMapping("/register/step2")
public String handleStep2( //회원 정보 입력 처리
@RequestParam(value = "agree", defaultValue = "false") Boolean agree,
Model model) {
if (!agree) { //만약 약관 동의X
return "register/step1"; // 다시 약관 폼 뷰 반환
}
model.addAttribute("registerRequest", new RegisterRequest());
return "register/step2"; //동의 O -> 회원 정보 입력 폼 뷰 반환
}
}
➁ 처리 결과를 응답하는 코드 (뷰 코드 작성)
<!DOCTYPE html>
<html>
<head>
<title>회원가입</title>
</head>
<body>
<h2>회원 정보 입력</h2>
<form:form action="step3" modelAttribute="registerRequest">
<p>
<label>이메일:<br>
<form:input path="email" />
</label>
</p>
<p>
<label>이름:<br>
<form:input path="name" />
</label>
</p>
<p>
<label>비밀번호:<br>
<form:password path="password" />
</label>
</p>
<p>
<label>비밀번호 확인:<br>
<form:password path="confirmPassword" />
</label>
</p>
<input type="submit" value="가입 완료">
</form:form>
<form action="step3" method="post">
<p>
<label>이메일:<br>
<input type="text" name="email" id="email" value="${registerRequest.email}">
</label>
</p>
<p>
<label>이름:<br>
<input type="text" name="name" id="name" value="${registerRequest.name}">
</label>
</p>
<p>
<label>비밀번호:<br>
<input type="password" name="password" id="password">
</label>
</p>
<p>
<label>비밀번호 확인:<br>
<input type="password" name="confirmPassword" id="confirmPassword">
</label>
</p>
<input type="submit" value="가입 완료">
5. [리다이렉트 처리]
*잘못된 전송 방식 요청이 왔을 때 알맞은 경로로 리다이렉트 처리하기
-요청 매핑 적용 메소드가 “redirect:경로” 리턴한 경우.
➀ redirect: ‘/’로 시작하는 경로 -실제 리다이렉트 경로 = 웹 어플리케이션 경로 + 리턴한 경로 합친 경로 사용 ➁ redirect: ‘/;로 시작하지 않는 경로 -현재 경로 기준 -> 상대 경로를 사용 ➂ redirect: ‘완전한 URL’ 경로 : 완전한 URL 해당 경로 사용 |
6. [커맨드 객체 이용 -> 요청 파라미터 사용하기]
-폼이 전송한 파라미터 정보를 컨트롤러 코드에서 사용하기 위해서
<컨트롤러 메소드에서 요청 파라미터에 접근하는 방법 > ➀ HttpServletRequest 사용 : 여러 개 일 때 단, 요청 파라미터 개수 증가할 때마다 코드 길이도 길어짐 ➁ @RequestParam : 몇 개 안될 때 ➂ 커맨드(command) 객체 사용하기 ** |
➂ 커맨드(command) 객체 사용하기 **
-폼에 입력한 값을 커맨드 객체로 전달받아 처리 -스프링은 요청 파라미터 값을 커맨드 객체에 담아주는 기능을 제공한다. -스프링 MVC는 처리 메소드에 전달할 커맨드 객체를 생성하고 해당 객체의 세터 메소드를 이용해서 일치하는 요청 파라미터의 값을 전달하여 사용한다. -커맨드 객체 = 요청 매핑 애노테이션 적용 메소드의 파라미터에 위치 |
➀ 요청 URL 처리 코드 (컨트롤러 작성)
▶[가입 처리 결과 화면 보여주기]
@PostMapping("/register/step3") //처리 결과 매핑
public String handleStep3(RegisterRequest regReq) { //커맨드 객체로 전달 받음
try { //회원 가입 성공 시,
memberRegisterService.regist(regReq);
return "register/step3"; //결과 폼 리턴
} catch (DuplicateMemberException ex) {
//회원 가입 실패 시,
return "register/step2"; //다시 이전 폼 리턴
}
}
}
➁ 처리 결과를 응답하는 코드 (뷰 코드 작성)
<html>
<head>
<title>회원가입</title>
</head>
<body>
<p><strong>${registerRequest.name}님</strong>
회원 가입을 완료했습니다.</p>
<p><a href="<c:url value='/main'/>">[첫 화면 이동]</a></p>
</body>
</html>
7. [뷰 JSP 코드에서 커맨드 객체 사용하기]
-가입할 때 입력한 정보를 회원 가입 완료 화면에서 보여줄 때 사용
-뷰 코드가 커맨드 객체에 접근하여 속성을 사용하고자 할 때,
➀ (기본)
-커맨드 객체의 기본 이름은 클래스 이름을 그대로 사용하며 -뷰 코드는 클래스(첫 글자 소문자) 이름을 사용하여 객체에 접근할 수 있다. |
➁ (변경) @ModelAttribute 애노테이션 사용
-@ModelAttribute 애노테이션 사용하면 커맨드 객체에 접근할 속성 이름 변경 O -커맨드 객체 파라미터 앞에 ModelAttribute를 붙여주고 그 값에 변경할 이름을 지정함 |
8. [커맨드 객체와 스프링 폼 연동] : 사전 taglib 디렉티브 설정필요
스프링 MVC 가 제공하는 커스텀 태그를 사용하면 간단하게 커맨드 객체 값을 출력 가능 커스텀 태그 사용 : 커맨드 객체의 값을 폼의 태그 생성하여 출력 O <form:form> 태그 : HTML의 <form> 태그 생성 <form:input> 태그 : HTML의 <input> 태그 생성 <form:password> 태그 : HTML의 password타입의 <input> 택그 생성 |
9. [컨트롤러 구현 없이 단순 경로 매핑]
-특별한 처리 없이 요청 경로와 뷰 이름을 연결해주는 기능을 위해 따로 컨트롤러 작성하는 것이 번거롭다. -MvcConfig 클래스에서 작성 (스프링 MVC 기본 설정 위해 작성한 설정 파일) -WebMvcConfigurer 인터페이스의 addViewControllers()메소드 재정의하여 사용하면 별도의 컨트롤러 구현 없이도 요청 경로와 뷰 이름 연결할 수 있다 |
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController(“/main”).setViewName(“main”);
} //요청 경로 <-> 뷰 이름 단순 경로 매핑
10. [주요 에러 발생 상황 정리] : 콘솔 로그 메시지 잘 확인할 것
1) 요청 매핑 애노테이션 관련 주요 익셉션
< 404 에러 > -요청 경로 처리 올바른지 -컨트롤러 설정 경로 올바른지 -컨트롤러 클래스 빈 등록 여부 -컨트롤러 클래스에 @Controlloer 적용 여부 -반환한 뷰 이름에 해당하는 JSP 파일 존재 여부 < 405 에러> -지원하지 않는 전송 방식을 사용한 경우 |
2) @RequestParam/커맨드 객체 관련 주요 익셉션
< 400 에러> 요청 파라미터 값을 적용된 파라미터 타입으로 변환 할 수 없는 경우 -커맨드 객체에 요청 파라미터 값을 복사하는 과정에서 타입 변환 불가능한 경우 |
11. [커맨드 객체 : 중첩/ 콜렉션 프로퍼티]
-스프링 MVC 는 커맨드 객체가
➀ 리스트 타입의 프로퍼티를 가졌거나 : 프로퍼티이름[인덱스] 형식으로 접근
➁ 중첩 프로퍼티를 가진 경우에도 요청 파라미터 값을 알맞게 커맨드 객체에 설정 기능 제공
: 프로퍼티이름.프로퍼티이름 형식으로 접근
12. [Model을 통해 컨트롤러에서 뷰에 데이터 전달하기]
-< 뷰에 데이터 전달 컨트롤러 > ⓐ 요청 애노테이션 메소드의 파라미터로 Model 타입 추가 ⓑ Model 파라미터의 addAttribute() 메소드로 뷰에 데이터 전달 -> 뷰 코드는 Model을 통해 전달받은 데이터를 ${_____} 이용해서 사용 |
13. [ModelAndView -> 한 번에 뷰 선택, 모델 전달 하기]
-지금까지 구현한 컨트롤러의 기능은
결과 보여줄 뷰 이름 리턴 / Model 이용해서 뷰에 전달할 데이터 설정 하는 것
-이 두 가지를 ModelAndView 사용하여 한 번에 처리 가능
-ModelAndView = 모델과 뷰 이름을 함께 제공함
-요청 매핑 애노테이션 적용 메소드는 ModelAndView 타입으로 리턴 가능
@GetMapping
public ModelAndView form() {
ModelAndView mav = new ModelAndView();
mav.addObject(“questions”, questions); //뷰에 전달할 모델 데이터
mav.setViewName(“survey/surveyForm”); //뷰 이름 설정
return mav; //반환
}
14. [주요 폼 태그]
(1) <form> 태그를 위한 커스텀 태그 : <form:form> (2) <input> 관련 커스텀 태그: <form:input>, <form:password>, <form:hidden> (3) <select> 관련 커스텀 태그 : <form.select>, <form:options>, <form:option> (4) 체크 박스 관련 커스텀 태그: <form:chechboxes>, <form:checkbox> (5) 라디오 버튼 관련 커스텀 태그: <form:radiobuttons>, <form:radiobutton> (6) <textarea> 태그를 위한 커스텀 태그: <form:textarea> |
'Web(웹)_관련 공부 모음 > [개념]_스프링 5 프로그래밍' 카테고리의 다른 글
ch13. MVC 3: 세션 /인터셉터 / 쿠키 (0) | 2022.02.02 |
---|---|
ch 12. MVC 2: 메시지 / 커맨드 객체 검증 (0) | 2022.02.02 |
ch10. 스프링 MVC 프레임워크 동작 방식 (0) | 2022.01.31 |
ch09. 스프링 MVC 시작하기 (0) | 2022.01.31 |
ch08. DB 연동 (0) | 2022.01.28 |