2015. 12. 1. 15:24ㆍFramework/Spring Framework
- 목차
7. Spring MVC
7.1. 모델 1 개발 방식
1) 장점
개발 속도가 빠르며 개발자의 스킬이 낮아도 배우기 쉬워 빠르게 적용할 수 있다.
2) 단점
JSP 페이지에서 프리젠테이션 로직과 비즈니스 로직을 모두 포함하기 때문에 JSP 페이
지가 너무 복잡해 진다. 또한 개발자와 디자이너의 분리된 작업이 어려워진다.
가장 큰 문제는 JSP 페이지의 코드가 복작해 짐으로 인해 유지보수 하기 어려워진다.
이는 정교한 Presentation 레이어를 구현하기 힘들다.(유효성 체크, 에러 처리 등)
7.2. 모델 2 개발 방식
1) 장점 (Spring MVC를 기준으로)
- Presenation에서 명확한 역할 분담이 된다.
- UI 레이어를 단순화 시킴으로써 디자이너도 작업하는 것이 가능하게 된다. 단지 Display용으로만 사용된다.
- Presentation 레이어의 정교한 개발이 가능하다. 유효성 체크, 에러 처리와 같은 기능들은 Spring 프레임워크에서 제공한다.
- Dependency Pull 없이 Dependency Injection만을 이용해서 애플리케이션을 개발하는 것이 가능하다.
- UI 레이어가 단순해 짐으로서 유지보수가 쉽다.
2) 단점
- 새로운 기술을 익혀야 하는 부담감이 있다.
- 프로젝트 초반에 개발 속도의 저하를 가져올 수 있다.
7.3. Spring MVC에서 하나의 요청에 대한 Life Cycle
Spring MVC내에서 처리되는 하나의 요청에 대한 Life Cycle과정은 위 그림과 같다.
① 클라이언트의 요청에 대한 최초 진입 지점은 DispatcherServlet이 담당하게 된다.
대부분의 MVC를 지원하는 프레임워크가 메인 Servlet을 가지는 것처럼 Spring MVC
또한 메인 Servlet이 최초 진입지점으로 다음의 작업을 처리하게 된다.
② DispatcherServlet은 Spring Bean Definition에 설정되어 있는 Handler Mapping 정보를 참조하여 해당 요청을 처리하기 위한 Controller를 찾는다.
③ DispatcherServlet은 선택된 Controller를 호출하여 클라이언트가 요청한 작업을 처리.
④ Controller는 Business Layer와의 통신을 통하여 원하는 작업을 처리한 다음 요청에 대한 성공유무에 따라 ModelAndView 인스턴스를 반환한다. ModelAndView 클래스에는 UI Layer에서 사용할 Model데이터와 UI Layer로 사용할 View에 대한 정보가 포함되어있다.
⑤ DispatcherServlet은 ModelAndView의 View의 이름이 논리적인 View 정보이면 ViewResolver를 참조하여 이 논리적인 View 정보를 실질적으로 처리해야할 View를 생성하게 된다.
⑥ DispatcherServlet은 ViewResolver를 통하여 전달된 View에게 ModelAndView를 전달하여 마지막으로 클라이언트에게 원하는 UI를 제공할 수 있도록 한다. 마지막으로 클라이언트에게 UI를 제공할 책임은 View 클래스가 담당하게 된다.
7.4. Spring 프레임워크에서 지원하는 기능들
Spring 프레임워크에서는 위 그림에서 보여지는 각 항목들에 대하여 여러가지 형태의 API들을 지원하고 있다. HandlerMapping도 한가지 방식으로 Mapping을 지원하는 것이 아니라 요청 URI를 바탕으로 지원하는 방식, Bean 이름을 기준으로 지원하는 방식등 여러가지 형태로 사용 가능하도록 지원하고 있다.
Controller, ViewResolver, View 또한 너무도 많은 종류를 지원하고 있어서 이 중에 어느것을 사용해야 하는지를 판단하는 것조차 힘든 것이 사실이다. 그러나 기본적으로 위 그림과 같은 방식으로 처리된다는 것을 이해하고 있다면 웹 애플리케이션을 개발할 때 필요로하는 API들을 사용하면 된다. 또한 Spring 프레임워크에서 지원하지 못하는 기능들이 있다면 기존의 API들을 확장해서 우리들만의 기능들을 추가하는 것이 가능하다.
Spring 프레임워크는 다양한 방식으로 유연성을 제공하고 있다. 이와 같은 유연성은 Spring 프레임워크에서 제공하는 API들을 활용함으로써 얻게 될 수도 있으며, Spring 프레임워크에서 제공하는 API를 확장해서 우리들만의 기능을 추가함으로써 확장이 가능한 것이다.
7.5. DispatchserServlet 설정
DispatchserServlet은 Spring MVC에서 프론트 컨트롤러의 역항을 하는 서블릿으로서, Spring MVC의 심장이라고 할 수 있다. DispatchserServlet을 web.xml에 정의해야 한다.
DispatchserServlet은 어플리케이션이 시작할 때 DispatchserServlet의 init() 메소드가 호출되면서 Bean 설정 파일의 초기화가 진행된다.
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatchserServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-name>은 매우 중요하다. DispatchserServlet은 서블릿의 이름에 따른 XML 파일로부터 Spring 어플리케이션 컨텍스트를 로드한다. DispatchserServlet이 초기화될 때 디폴트로 사용하는 Bean 설정 파일의 이름은 "서블릿명-servlet.xml" 된다.
즉, action-servlet.xml이라는 파일로부터 어플리케이션 컨텍스트를 로드하려고 시도할 것이다.
그 다음엔 DispatchserServlet에 의해 다뤄질 URL을 지정해야 한다. web.xml에 다음과 같이 설정한다.
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
설정 파일이 모두 로드 되도록 하기 위해서는 web.xml에 컨텍스트 로더를 설정해야 한다.
컨텍스트 로더는 DispatchserServlet이 로드하는 것 이외의 컨텍스트 설정 파일들을 로드할 수 있다.
<listener>
<listener-class>web.context.ContextLoaderListener</listener-class>
</listener>
어떤 컨텍스트 로더를 사용하든 간에, 로드해야 할 Spring 설정 파일의 위치를 지정해야 한다. 만약 지정하지 않는다면 컨텍스트 로더는 기본적으로 /WEB-INF/applicationContext.xml 이라는 Spring 설정 파일을 찾는다.
그러나 이 파일을 그 자체로 어플리케이션 계층에 따른 어플리케이션 컨텍스트의 분리를 지원하지 않기 때문에, 이 기본값을 그대로 사용하지 않는 것이 좋다.
개선책으로 서블릿 컨텍스트에 contextConfigLocation 이라는 파라미터를 설정함으로써, 컨텍스트 로더가 로드할 수 있는 하나 이상의 Spring 설정 파일을 지정한다.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
7.6. Spring 프레임워크에서 지원하는 Controller
7.7. 요청과 컨트롤러와의 매핑
■ BeanNameUrlHandlerMapping
컨트롤러의 Bean 이름에 기초해 컨트롤러를 URL과 매핑.
■ SimpleUrlHandlerMapping
컨텍스트 설정 파일에 정의돼있는 일련의 특성들을 사용해 컨트롤러를 URL과 매핑.
■ CommonsPathMapHandlerMapping
컨트롤러의 코드에 있는 소스 수준의 메타데이터를 사용하여 컨트롤러를 URL과 매핑.
1) URL과 Bean이름과의 매핑
예를 들어, ListCoursesControll Bean이 http://localhost/listCourses.do 라면, 컨텍스트 설정 파일에 BeanNameUrlHandlerMapping Bean을 선언해야 한다.
<bean id="beanNameUrlMapping"
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
그 다음엔 처리돼야 할 URL 패턴으로 컨트롤러 Bean의 이름을 지정해야 한다.
ListCoursesController를 위한 URL 패턴은 'listCourses.do' 이므로, 다음과 같이 컨텍스트 설정 파일에 컨트롤러를 선언한다.
<bean name="/listCourses.do" class="com.springaction.test.mvc.ListCoursesController">
<property name="courseService">
<ref bean="courseService">
</property>
</bean>
2) SimpleUrlHandlerMapping
대부분의 경우에 사용되는 핸들러 매핑이다. 특별한 방법으로 Bean의 이름을 지정할 필요 없이, URL 패턴을 직접적으로 컨트롤러에 매필할 수 있도록 해준다.
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/register.htm">registerStudentController</prop>
<prop key="/student/listCourses.htm">listCourseController</prop>
<prop key="/student/displayCourse.htm">displayCourseController</prop>
<prop key="/student/enroll.htm">enrollController</prop>
</props>
</property>
</bean>
3) 컨트롤러 매핑을 위한 메타데이터 사용 (CommonsPathMapHandlerMapping)
컨트롤러의 소스 코드 내에서 URL 매핑을 결정하기 위한 소스 수준의 메타데이터를 사용. 컨스턴트 설정 파일에서 이 핸들러 매핑을 <bean>으로 선언해 준다.
<bean id="urlMapping" class="org.springframework.web.servlet.handler.metadata.CommonsPathMapHandlerMapping" />
그 다음에 URL 패턴을 선언하는 PathMap 속성을 사용하여 각 컨드롤러에 캐그를 달면된다.
7.8. 컨트롤러를 사용한 요청 처리
컨트롤러는 Spring MVC의 두뇌 역할을 한다. Spring MVC 어플리케이션의 작동을 구현할때에는, Spring의 컨트롤러 클래스 중 하나를 확장하여 사용하게 될 것이다. 컨트롤러는 DispatchserServlet으로부터 요청을 받아들여, 사용자를 대신하여 어떤 비즈니스 기능을 수행하게 된다.
1) 단순한 컨트롤러 작성
컨트롤러의 요구사항이 직관적이고 단순한 경우라면 AbstractController의 서브 클래스로 구현할 수 있다.
public class ListCourseController extends AbstractController {
public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
Set allCourses = courseService.getAllCourses();
return new ModelAndView("courseList", "courses", allCourses);
}
// INJECTED
private CourseService courseService;
public void setCourseService(CourseService courseService) {
this.courseService = courseService;
}
}
handleRequestInternal() 메소드는 AbstractController 실행에 있어서의 주된 메소드이다.
■ ModelAndView 개요
모든 컨트롤러의 실행 메소드는 반드시 ModelAndView를 리턴해야 한다.
return new ModelAndView("courseList", "courses", allCourses);
courseList : 출력을 보여주는데 사용될 뷰 컴포넌트의 논리적인 이름.
courses : 파라메타 명
allCourses : 파라메타 값
■ 컨트롤러 묶기
ListCoursesController 작성 후 이를 컨텍스트 설정 파일에서 설정한다.
이 컨트롤러는 Spring MVC 컴포넌트 설정인 서블릿명-servlet.xml 파일에 설정.
<bean id="listCourseController" class="com.springinaction.training.mvc.ListCourseController">
<property name="courseService"><ref bean="courseService"/></property>
</bean>
2) 명령 처리
AbstractController에 기반한 컨트롤러에서도 HttpServletRequest로 부터 필요한 파라미터를 얻을 수 있다.
그러나 바인딩 로직과 유효성 검증 로직은 진정한 컨트롤러의 역할이 아니다.
파라미터에 기반하여 작업을 수행하는 상황이라면 AbstractCommandController와 같은 명령 컨트롤러를 확장해야 한다. 이 컨트롤러는 파라미터를 명령 객체에 자동으로 바인딩시켜 줄 것이며, 파라미터의 유효성 확인을 위한 검증기를 플러그인 할 수 있는 hook을 제공한다.
public class DisplayCourseController extends AbstractCommandController {
public DisplayCourseController() {
setCommandClass(DisplayCourseCommand.class);
}
protected ModelAndView handle(HttpServletRequest request,
HttpServletResponse response, Object command,
BindException errors) throws Exception {
DisplayCourseCommand displayCommand = (DisplayCourseCommand) command;
Course course = courseService.getCourse(displayCommand.getId());
return new ModelAndView("courseDetail", "course", course);
}
// INJECTED
private CourseService courseService;
public void setCourseService(CourseService courseService) {
this.courseService = courseService;
}
}
DisplayCourseController 작성 후 이를 컨텍스트 설정 파일에서 설정한다.
이 컨트롤러는 Spring MVC 컴포넌트 설정인 서블릿명-servlet.xml 파일에 설정한다.
<bean id="displayCourseController" class="com.springinaction.training.mvc.DisplayCourseController">
<property name="courseService"><ref bean="courseService"/></property>
</bean>
handle() 메소드는 AbstractCommandController를 위한 주된 실행 메소드이다.
HttpServletRequest와 HttpServletResponse 이외에도 컨트롤러의 명령에 해당하는 Object를 파라미터로 취한다.
- 이 종 화 (ingenuity.egloos.com) -
'Framework > Spring Framework' 카테고리의 다른 글
Spring Framework 뷰결정 / 에러처리 (0) | 2015.12.03 |
---|---|
Spring Framework form 처리 (0) | 2015.12.03 |
Spring Framework Bean 설정 파일 관리 (0) | 2015.11.27 |
Spring Framework AOP (0) | 2015.11.26 |
Spring Framework IoC (0) | 2015.11.24 |