본문으로 바로가기

1. 스프링(Spring) MVC 프레임워크(Model View Controller Framework)

- 스프링이 제공하는 트랜잭션 처리, DI, AOP를 손쉽게 사용

- 스트럿츠2와 같은 프레임워크와 연동이 쉬움



2. 스프링 MVC 주요 구성 요소 및 처리 흐름

- 다른 MVC 프레임워크와 마찬가지로 컨트롤러를 사용하여 요청을 처리

- 스프링에서는 DispatcherServlet이 MVC에서의 컨트롤러(Controller) 부분을 처리



 구성 요소

 설명 

 DispatcherServlet

 클라이언트의 요청을 전달받아 요청에 맞는 컨트롤러가 리턴한 결과값을 View에 전달하여 알맞은 응답을 생성 

 HandlerMapping

 클라이언트의 요청 URL을 어떤 컨트롤러가 처리할지 결정 

 Controller

 클라이언트의 요청을 처리한 뒤, 결과를 DispatcherServlet에게 리턴 

 ModelAndView

 컨트롤러가 처리한 결과 정보 및 뷰 선택에 필요한 정보를 담음 

 ViewResolver

 컨트롤러의 처리 결과를 생성할 뷰를 결정 

 View

 컨트롤러의 처리 결과 화면을 생성, JSP 또는 Velocity 템플릿 파일 등을 뷰로 사용 


3. 스프링 MVC 개발

- 클라이언트에 요청을 받을 DispatcherServlet을 web.xml 파일에 설정

- 클라이언트의 요청을 처리할 컨트롤러 작성

- ViewResolver 설정 (컨트롤러가 전달한 값을 이용해서 응답 화면을 생성할 뷰를 결정)

- JSP나 Velocity 등을 이용하여 뷰영역의 코드를 작성



3.1. DispatcherServlet 설정 및 스프링 컨텍스트 설정

- web.xml(자바 웹 어플리케이션 설정 파일)에 DipathcerServlet 설정 및 공통으로 사용할 어플리케이션 컨텍스트 설정

- <servlet> 태그를 이용하여 DispatcherServlet 설정

- <servlet-mapping> 태그를 이용하여 요청 URL 패턴 설정


3.2. 컨트롤러 구현 및 설정 추가

- @Controller 애노테이션을 클래스에 적용

- @RequestMapping 애노테이션을 이용해서 클라이언트의 요청을 처리할 메서드를 지정

- ModelAndView는 컨트롤러의 처리 결과를 보여줄 뷰와 뷰에서 출력할 모델을 지정

- DispatcherServlet은 스프링 컨테이너에서 컨트롤러 객체를 검색하기 때문에 스프링 설정 파일에 컨트롤러를 빈으로 등록해야 함


3.3. 설정 파일 View Resolver 설정 추가

- 컨트롤러에서 ModelAndView.setViewName() 메서드로 뷰이름을 지정

- 이 뷰이름과 매칭되는 뷰 구현체를 찾기 위해 ViewResolver를 사용

- prefix 프로퍼티와 suffix 프로퍼티를 지정


3.4. 뷰 코드 구현

- ModelAndView.addObject() 메서드로 모델을 추가할 때 사용한 이름을 이용해서 모델의 값을 사용

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>${ message }</title>

</head>

<body>

${ message }

</body>

</html>



4. DispatcherServlet 설정과 ApplicationContext의 관계

- web.xml 파일에 한 개 이상의 DispatcherServlet 설정할 수 있으며, 각각 한 개의 WebApplicationContext를 갖음



4.1. DispatcherServlet 설정

- DipatcherServlet는 기본적으로 /WEB-INF/ 디렉터리에 위치한 [서블릿이름]-servlet.xml 파일로부터 스프링 설정 정보를 읽어 옴

- 한개 이상의 설정 파일, 또는 설정 다른 이름의 설정 파일을 사용할 경우 contextConfigLocation 초기화 파라미터에 설정 파일 목록을 지정

- 설정 파일 구분은 콤마(","), 공백 문자(" "), 탭(\t), 줄 바꿈(\n), 세미콜론(";")을 이용


4.2. ApplicationContext 설정

- 한 개 이상의 DispatcheerServlet을 사용할 때 별도의 WebApplicationContext를 생성

- 이 경우 공통 빈을 필요로 할 때 ContextLoaderListener를 사용하여 사용될 빈을 설정

- ServletListener로 등록, contextConfigLocation 컨텍스트 파라미터를 이용, 공통으로 사용될 빈 정보를 담고 있는 설정 파일 목록을 지정

- ContextLoaderListener가 생성하는 WebApplicationContext는 웹 어플리케이션의 루트 컨텍스트

- DispatcherServlet이 생성하는 WebApplicationContext는 루트 컨텍스트를 부모로 사용하는 자식 컨텍스트

- ContextLoaderListener는 contextConfigLocation 컨텍스트 파라미터를 명시하지 않으면 /WEB-INF/applicationContext.xml을 설정 파일로 사용


5. 캐릭터 인코딩 처리 필터 설정

- 모든 컨트롤러에서 response.setCharacterEncoding() 코드를 실행하는 번거로움을 해소하기 위해 서블릿 필터를 이용 처리

- 서블릿 필터에서 캐틱터 인코딩을 설정할 수 있는 CharacterEncodingFilter 클래스를 제공

- web.xml 파일에 설정


6. 컨트롤러 구현

- 스프링 3.0 버전 부터는 @Controller 애노테이션을 이용해서 컨트롤러 클래스를 구현하도록 권장



6.1. @Controller 애노테이션, @RequestMapping 애노테이션

- 컨트롤러 클래스에 @Controller 애노테이션 적용

- 클라이언트의 요청을 처리할 메서드에 @RequestMapping 애노테이션 적용

- 설정 파일에 컨트롤러 클래스를 빈으로 등록

- @RequestMapping 애노테이션은 해당 메서드에서 처리할 URI를 값으로 갖음

- @RequestMapping 애노테이션의 메서드의 리턴 타입은 상황에 따라 알맞은 타입을 선택


6.2. 컨트롤러 메서드 HTTP 전송 방식(method) 한정

- 하나의 요청 URL에 대해 HTTP GET 요청과 POST 요청을 한 개의 컨트롤러에서 처리할 경우

- @RequestMapping 애노테이션의 method 속성을 이용해서 메서드가 처리할 HTTP 메서드를 제한


- 두 메서드가 동일한 URI를 처리하는 경우 @RequestMapping 애노테이션을 클래스에 적용해서 해당 클래스가 처리할 기본 URI를 지정가능

- @RequestMapping 애노테이션에 method 속성을 설정하지 않을 경우 모든 HTTP 전송방식(GET, POST, DELETE 등)을 처리


6.3. HTML 폼, 커맨드 객체

- HTML 폼에 입력한 데이터를 자바빈 객체를 이용해서 전달 받음

- HTML 폼의 항목 이름과 자바빈 클래스의 프로퍼티 이름이 일치할 경우 폼에 입력한 값을 프로퍼티 값으로 설정

- @RequestMapping 애노테이션이 적용된 메서드의 파라미터로 자바빈 타입을 추가

- 폼에 입력한 값은 모두 문자열이지만 스프링은 자바빈의 타입 변환 처리 기능으로 프로퍼티의 타입으로 알맞게 변환


<!-- writeForm.jsp -->


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>WriteForm</title>

</head>

<body>

<form action="write.do" method="post">

<input type="text" name="name" placeholder="폰 이름" required="required" size="50"><br>

<input type="text" name="manufacturer" placeholder="폰 제조사" required="required" size="50"><br>

<input type="text" name="price" placeholder="폰 가격" required="required" size="50"><br>

<input type="submit" value="작성"><input type="reset" value="취소">

</form>

</body>

</html>


6.3.1. 뷰에서 커맨드 객체 접근

- 뷰에서 @RequestMapping 애노테이션 메서드에서 전달받은 커맨드 객체(자바빈 객체)의 클래스명을 이용해서 접근 가능(단 첫글자는 소문자)


<!-- writeSubmit.jsp -->


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>WriteSubmit</title>

</head>

<body>

<input type="text" name="name" placeholder="폰 이름" required="required" readonly="readonly" size="50" value="${ phoneDTO.name }"><br>

<input type="text" name="manufacturer" placeholder="폰 제조사" required="required" readonly="readonly" size="50" value="${ phoneDTO.manufacturer }"><br>

<input type="text" name="price" placeholder="폰 가격" required="required" readonly="readonly" size="50" value="${ phoneDTO.price }"><br>

</body>

</html>


- 뷰에서 사용할 모델의 이름을 변경할 때는 @ModelAttribute 애노테이션을 이용, 커맨드 객체의 모델 이름을 지정


<!-- writeSubmit.jsp -->


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>WriteSubmit</title>

</head>

<body>

<input type="text" placeholder="폰 이름" required="required" readonly="readonly" size="50" value="${ p.name }"><br>

<input type="text" placeholder="폰 제조사" required="required" readonly="readonly" size="50" value="${ p.manufacturer }"><br>

<input type="text" placeholder="폰 가격" required="required" readonly="readonly" size="50" value="${ p.price }"><br>

</body>

</html>


6.3.2. 커맨드 객체로 List 받기

- 폼에서 "프로퍼티명[인덱스].프로퍼티" 같이 입력 폼의 이름을 구성



<!-- writeListForm.jsp -->


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>WriteListForm</title>

</head>

<body>

<form action="writeList.do" method="post">

<input type="text" name="phoneItems[0].name" placeholder="폰 이름1" required="required" size="50"><br>

<input type="text" name="phoneItems[0].manufacturer" placeholder="폰 제조사1" required="required" size="50"><br>

<input type="text" name="phoneItems[0].price" placeholder="폰 가격1" required="required" size="50"><br>

<hr>

<input type="text" name="phoneItems[1].name" placeholder="폰 이름2" required="required" size="50"><br>

<input type="text" name="phoneItems[1].manufacturer" placeholder="폰 제조사2" required="required" size="50"><br>

<input type="text" name="phoneItems[1].price" placeholder="폰 가격2" required="required" size="50"><br>

<hr>

<input type="submit" value="작성"><input type="reset" value="취소">

</form>

</body>

</html>