DispatcherServlet이란?
프론트컨트롤러(=Front Controller)이다. 자바 서버의 Servlet 컨테이너에서 HTTP 프로토콜을 통해 들어오는
모든 요청을 프리젠테이션 계층의 제일앞에 둬서 중앙집중식으로 처리할 수 있는 컨트롤러이다.
DispatcherServlet은 서블릿 컨테이너가 생성하고 관리하는 오브젝트이다.
즉, 스프링이 관여하는 오브젝트가 아니므로 직접 DI를 해줄 방법이 없다. 대신 web.xml에서 설정한 웹어플리케이션 컨텍스를 참고하여 필요한 전략을 DI하여 사용할 수 있다. <참고:기본7가지 DI전략>
Spring MVC의 기본 핵심인 DispatcherServlet에 대해 알아보자~!
1. DispatcherServlet의 HTTP 요청접수
▶ 자바 서버의 서블릿 컨테이너의 요청을 받는다.
2~3. DispatcherServlet은 URL이나 parameter정보, HTTP 명령등을 참고하여 Handler Mapping에게 어떤 컨트롤러에게 작업을 위임할지 결정받는다.
4~5. DispatcherServlet이 모든 웹 요청 정보가 담긴 HttpServletRequest 타입의 오브젝트를 핸들러어댑터에게 전달하면 핸들러어댑터는 컨트롤러의 메소드가 받을 수 있는 파라미터로 적절히 변환하여 해당 컨트롤러에게 전달해준다.
6. 컨트롤러가 작업을 하고 최종적으로 DispatcherServlet에게 돌려줄 정보는 모델과 뷰이다.
▶ 컨트롤러의 작업 순서
6.1 사용자 요청 분석.
6.2 실제 비즈니스로직 수행을 위해 서비스 계층 오브젝트에게 작업 위임.
6.3 결과를 받아 모델 생성.
6.4 어떤 뷰를 사용할지 결정.
7~8. 컨트롤러가 직접 뷰오브젝트를 리턴할 수도 있지만, 보통은 뷰의 논리적인 이름을 리턴해주면 DispatcherServlet의 전략인 뷰 리졸버가 이를 이용해 뷰 오브젝트를 생성해준다.
9~10. 뷰 리졸버를 통해 받은 뷰(=뷰오브젝트)에게 모델을 전달해주고 클라이언트에게 돌려줄 최종 결과물을 생성해달라고 요청한다.
11. 뷰작업을 통해 전달받은 최종 결과물은 HttpServletResponse 오브젝트에 담아 넘긴다.
viralpatel.net 이라는 사이트에서 스프링3 MVC 에 대한 간략한 소개 및 예제를 보게 되었다.
이해하기 쉽도록 설명하고 있고, 예제 또한 따라하기 쉽고 잘 설명되어 있어서 나의 발번역으로
좀 더 보기 쉽게 ( 나중에 또 볼때 더 빨리 볼 수 있게 ) 블로그에 남겨 놓고자 한다.
혹시라도 이 글을 보시는 분들께서는 영어 번역이 허접이라 많이 미숙하다는 점을 알고 봐주시면 감사하겠습니다.ㅋ
Spring3 MVC Framework 소개
Spring MVC는 Spring framework의 웹 컴포넌트 이다. 이것은 풍부한 기능을 제공하고, 견고한 웹 어플리케이션을 만드는데 도움을 준다.
Spring MVC framework 는 모든 조각의 로직과 기능들이 highly configurable 하도록 디자인되고 설계되었다.
그리고 스프링은 Struts, Webwork, Java Server Faces, Tapestry 와 같은 다른 유명한 웹 프레임 워크와도 효과적으로 통합된다.
이말은 이중 하나의 프레임워크를 이용하기 위해 Spring 프레임워크를 사용할 수 도 있다는 말이다.
또한 스프링은 클라이언트에게 렌더링 하여 화면을 보여주는 데 있어서 Servlet 또는 JSP 와 결합이 강하지 않다.
다른 View 기술들인 Velocity, Freemaker, Excel 또는 Pdf 까지 통합하는것이 가능하다.
요청 처리의 생명주기 ( Request Processing LifeCycle )
이미지 출처 : Springsrouce
Spring web MVC framework 는 다른 웹 프레임워크 들과 마찬가지로 요청들에 대해서 컨트롤러 들로 분배하고, 프레임워크의 여러가지 기능을 제공하는 servlet 중심으로 설계되어 있다. 이게 바로 Spring에서 DispatcherServlet 인데 완전하게 Spring IoC container 와 통합되어 있으며, Spring의 다른 모든 기능들을 사용 할 수 있도록 해준다.
Spring 3.0 MVC 의 요청 처리 절차는 아래와 같다.
1. 클라이언트가 http request 형태로 web container 에 요청을 보낸다.
2. 들어오는 request 는 Front Controller (DispatcherServlet) 에 의해서 가로채 지고, 적절한 HandlerMapping을 찾는다.
3. Handler Mapping의 도움으로, DispatcherServlet 은 들어온 요청을 적절한 Controller 로 보낸다.
4. Controller 는 들어온 요청을 처리하고(비즈니스로직수행) 그 결과로 Model과 View 를 ModelAndView 라는 객체의 인스턴스 형태로 Front Controller 에 다시 전달한다.
5. Front Controller 는 ViewResolver 오브젝트를 이용하여 이 view 를 분석한다 (이것은 JSP일 수도 있고, velocity, freemaker 등이 될 수 있다).
6. 선택된 view 는 변환되어 다시 클라이언트에게 보여진다.
Spring 3.0 의 기능들
- Spring 3.0 framework 는 Java 5.0 을 지원 : annotation 기반의 설정을 지원한다. Java 5의 기능인 generics, annotations, vargs 등을 스프링에서 사용 가능하다.
- 새로운 expression language 인 Spring Expression Language SpEL 이 소개되었다.
- REST web service 를 지원한다.
- 데이터 변환이 매우 쉽다. 어노테이션 기반의 데이터 포멧팅을 지원한다. @DateTimeFormat(iso=ISO.DATE)와 @NumberFormat(style=STYLE.CURRENCY) 어노테이션을 이용하여 날짜형식 및 통화형식으로 형변환이 가능하다.
- JPA 2.0 지원이 시작됐다.
Spring 3.0 설정하기
Spring 3.0 MVC 의 시작점은 바로 DispatcherServlet 이다. DispatcherServlet은 HttpServlet 을 부모클래스로하여 구현하고 있는 일반적인 servlet 클래스 이다. 따라서 web.xml 에 설정을 해줄 필요가 있다.
- <web-app>
- <servlet>
- <servlet-name>example</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>example</servlet-name>
- <url-pattern>*.html</url-pattern>
- </servlet-mapping>
- </web-app>
위 코드를 통해 web.xml 에 DispatcherServlet 을 설정해 주었다.
예제의 DispatcherServlet 에서 *.html 의 url패턴의 요청에 대해 매핑을 해준것을 기억 하길 바란다.
따라서 *.html 형태의 요청이 들어왔을 때, Spring 3.0 MVC 의 Front Controller 가 호출 될 것이다.
DispatcherServlet 이 초기화 되고 나면, [서블릿이름]-servlet.xml 이란 파일을 웹 어플리케이션의 WEB-INF 폴더 하위에서 찾게 된다.
위의 예에서는 프레임워크가 example-servlet.xml 이란 파일을 찾을 것이다.
다음 글 [Spring3 MVC (2)] Spring 3.0 MVC 로 Hello world 프로젝트 만들기 에서 실제로 동작하는
Hello world 어플리케이션을 만들어 보도록 한다.
출처 -
http://choija.com/212
출처 -
http://javacan.tistory.com/entry/130
Added by kim su young, last edited by 이윤정 on 2월 23, 2006
오픈 소스 스터디
Table of Contents
Spring Introduction
Spring에 대한 전반적인 내용은 아래를 참조하기 바란다.
http://wiki.javajigi.net/pages/viewpage.action?pageId=280
http://martinfowler.com/articles/injection.html
Spring MVC
Spring의 웹 MVC framework는 설정가능한 핸들러 맵핑들, view분석, 로케일과 파일 업로드를 위한 지원같은 테마분석과 함께 핸들러에 요청을 할당하는 DispatcherServlet을 기반으로 디자인되었다.
디폴트 핸들러는 ModelAndView handleRequest(request,response)메소드를 제공하는 매우 간단한 컨트롤러 인터페이스이다.
이것은 이미 애플리케이션 컨트롤러를 위해 사용될수 있지만 AbstractController, AbstractCommandController그리고 SimpleFormController같은 것들을 포함한 구현 구조를 포함한것을 더 선호할것이다.
애플리케이션 컨트롤러들은 전형적으로 이것들의 하위 클래스가 된다. 당신이 선호하는 빈 클래스를 선택하도록 하라.
만약에 당신이 form을 가지지 않는다면 당신은 FormController가 필요없다. 이것이 Struts와 가장 큰 차이점이다.
유연한 MVC 웹 어플리케이션 프레임웍은 Core Spring과 상호작용하여 만들어진다.
이 프레임웍은 전략적인 인터페이스를 거쳐 높은수준으로 만들어진다. 그리고, JSP, Velocity, Tiles, iText, POI처럼 다양한 view 기술을 수용한다.
Spring middle tier는 Struts, WebWork, Tapestry와 같은 다른 웹 MVC 프레임워크를 기반으로 한 웹티어와 결합할수 있다.
Spring프레임웍에서 Model-View-Controller를 지원하는 기능이다.
강좌가 올라와있네요...
Spring MVC에서 클라이언트 요청의 처리 과정을 먼저 살펴보시면 이해가 되실거 같습니다.
http://wiki.javajigi.net/pages/viewpage.action?pageId=1133
참 고 : http://www.springframework.org/docs/reference/
번역본 : http://openframework.or.kr/framework_reference/spring/ver1.2.2/html/
설정 방법
Spring MVC를 사용하기 위해서는
- web-app/WEB-INF/lib 아래로 spring.jar 또는 spring-webmvc.jar파일을 복사한다.
- web-app/WEB-INF/web.xml에 DispatcherServlet를 설정한다.
- <web.xml>
<servlet> <servlet-name>action</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping>
.do, .html 로 끝나는 모든 요청은 DispatcherServlet에서 담당한다.
- DispattcherServlet이 초기화 할 때 디폴트로 사용하는 빈 설정파일의 이름은 "서블릿 이름-servlet.xml"이 된다.
- web-app/WEB-INF/web.xml에서 설정한 <servlet-name>인 action-servlet.xml 파일을 생성한다.
즉 spring.jar 와 web.xml에 DispatcherServlet 을 사용한다는 선언 그리고 서블릿 이름-servlet.xml 을 작성하면 사용할 수 있다.
다양한 예제들
Spring MVC를 사용한 초간단 예제
링크된 강좌를 살펴보고 대략적인 것을 파악한다면 Spring MVC 사용하기 위해서 개발자들이 만들어야 하는 것은 Controller 라는 것을 알게 될 것이다. 물론 화면에 보여주는 jsp(여기선 jsp 를 연결) 파일, 빈 설정 파일을 만드는 것은 당연한 것이다.
Controller를 생성하고 빈 설정파일에 맵핑 하는 방법 등의 관계를 보여주기 위한 데이터를 가져와서 List 형태로 보여주는 예제이다
- Controller
위에서 보면 직접적으로 Controller 인터페이스를 구현해서 ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception; 를 구현한다. Spring MVC에서 제공하는 다양한 Controller 들은 모두 Controller 인터페이스를 구현하기 때문에 가장 기본적인 구조라고 생각할 수 있다.
Service 객체는 setter Injection을 통해 생성된 것이다. 이것은 이미 앞에서 다 이해했을 것이다.
handleRequest(... ) 안에서 실제 메소드를 호출한 뒤 ModelAndView 객체를 통해 리턴을 하였다.
링크된 Spring MVC의 요청에 대한 생명주기를 보게 되면 비지니스 계층에서 전달된 모델 데이타와 클라이언트에게 보여줄 뷰화면에 대한 정보를 ModelAndView 클래스에 담아서 반환을 하게 되어 있다. 즉 전달 데이타 모델, 화면이름, 화면에서 사용될 객체 이름 등을 담아서 ModelAndView객체를 생성, 리턴한다.
ModelAndView 객체의 View정보가 논리적인 view이름(String) 인 경우 빈 설정 파일에 정의되어 있는 ViewResolver클래스를 이용하여 클라이언트에세 출력할 화면이름을 만들어 낼 수 있다. ModelAndView의 첫번째 인자인 "bbs/list"가 view 이름이기 때문에 설정파일의 ViewResolver를 만나서 리턴되는 화면의 전체이름이 완성되는 것이다.
- action-servlet.xml
설정파일을 보면 ViewResolver로 InternalResourceViewResolver클래스를 사용한다.
그리고 JSTLView를 사용해서 jsp 로 화면을 출력할 것이라는 것을 알 수 있다. 위에 설정된 것과 ModelAndView객체에 넘긴 view이름을 조합해 보면 /jsp/bbs/list.jsp 가 되는 것이다. (prefix+view 이름+suffix )
설정파일을 보면 BeanNameUrlHandlerMapping 클래스를 사용해서 Controller와 URL을 맵핑해주는 것을 알 수 있다.
만일 빈 설정파일에 HandlerMapping이 설정되어 있지 않으면 default 로 BeanNameURLHandlerMapping을 설정한다.
맵핑 방법에는 BeanNameURLHandlerMapping, SimpleUrlHandlerMapping,CommonsPathMapHandlerMapping 등이 있다.
- BeanNameURLHandlerMapping
빈 이름과 URL을 mapping 하는 방법이다.
즉 요청이 ..../bbs/listBbs.do가 오면 BbsController 클래스를 호출하겠다는 의미이다. name에는 <bean name="/bbs/listBbs.do /bbs/listBbs2.do".. /> 로 여러 개를 기술할 수 있다.
- SimpleUrlHandlerMapping
매핑에 대한 정보를 각각의 Controller에서 설정하는 것이 아니라 하나의 저장소에서 관리하는 것이다.
Controller를 개발하는 개발자들은 빈을 정의하기만 하고 이 Controller가 어떻게 맵핑되어서 사용하는지에 대해서는 몰라도 된다.
위의 설정파일을 SimpleUrlHandlerMapping으로 바꾸어 보면
실제 Controller에 대한 정의는 일반 빈을 정의 할 때와 다르지 않게 된다. 맵핑에 대한 정보는 별도의 빈(urlMapping)에서 관리되고 있다. 만일 더욱 많은 Controller가 생성되고 맵핑을 해 줘야 할 때 모든 매핑 정보는 한곳에서 관리를 할 수 있게 되는 것이다. Controller 마다 맵핑정보까지 나열할 필요가 없게 된다.
urlMapping 빈에서 Controller와 URL을 맵핑할 때 <props/>를 사용해서 기술할 수 있다. 또 다른 방법은 <props/>를 사용하지 않고 별도의 Properties 파일에서 관리 할 수도 있다.
- CommonsPathMapHandlerMapping
Spring MVC를 사용하여 다중요청 처리하기
개발자들이 Controller 만 만들면 되지만 개발하면서 페이지, 기능이 추가 될 때마다 새로운 Contoller를 만드는 것은 굉장히 짜증이 나는 작업이다. 게다가 점점 관리해야 하는 파일의 수가 많아져서 빈 설정파일도 점점 복잡해질 것이다.이 같은 상황을 해결하기 위하여 Spring MVC는 MultiActionController를 제공한다. MultiActionController은 하나의 Controller를 구현함으로써 다수의 요청을 처리하는 것이 가능하다.
아래 예는 회원가입,수정을 통해 MultiActionController 구현을 보여준다.
Controller 객체인 MemberController.java
package net.javajigi.member.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.javajigi.member.model.Member; import net.javajigi.member.service.MemberService; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.multiaction.MultiActionController; public class MemberController extends MultiActionController{ private MemberService memberService = null; public void setMemberService(MemberService memberService){ this.memberService = memberService; } public ModelAndView add(HttpServletRequest request, HttpServletResponse reponse) throws Exception{ Member command = new Member(); bind(request,command); memberService.addMember(command); return new ModelAndView("main"); } public ModelAndView update(HttpServletRequest request, HttpServletResponse reponse) throws Exception{ Member command = new Member(); bind(request,command); memberService.updateMember(command); return new ModelAndView("list"); } }
위의 예제는 add(가입), update(수정)을 구현하기 위해 MultiActionController를 상속받은 Controller 이다.
각각의 메소드에 로직이나 서비스 호출 부분들의 소스를 구현하다.
add 메소드를 보면 화면에서 입력받은 내용을 bind()를 사용해 domain 객체에 넘기고 있다.(이 내용은 나중에..)
그 뒤 서비스의 addMember()를 호출한다.
처리 후 리턴될 페이지를 설정한다.(add->main.jsp, update->list.jsp)
Controller를 작성 후 webapps/WEB-INF/action-servlet.xml 파일에 빈을 매핑한다.
action-servlet.xml
<bean id="memberService" class="net.javajigi.member.service.MemberService"/> <bean name="/member/addMember.do /member/updateMember.do" class="net.javajigi.member.web.MemberController"> <property name="methodNameResolver"> <ref local="memberControllerMethodNameResolver"/> </property> <property name="memberService"> <ref local="memberService"/> </property> </bean> <bean id="memberControllerMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"> <property name="mappings"> <props> <prop key="/member/addMember.do">add</prop> <prop key="/member/updateMember.do">update</prop> </props> </property> </bean>
MemberController는 두 개의 URL(/member/addMember.do,/member/updateMember.do)에 맵핑이 되었다.각각의 URL이 호출될 때 MemberController 안의 어떤 메소드가 호출될 지는 "memberControllerMethodNameResolver"빈에서 PropertiesMethodNameResolver를 통해 매핑이 된다. 결국 /member/addMember.do 가 호출되면 MemberController의 add 메소드가 /member/updateMember.do가 호출되면 update 메소드가 호출된다.
결국 위의 예는 빈 설정파일에서 URL을 다르게 함으로써 메소드에 접근할 수 있도록 설정한 것이다. (PropertiesMethodNameResolver 클래스를 통해서)
<bean name="/member/member.do" class="net.javajigi.member.web.MemberController"> <property name="methodNameResolver"> <ref local="methodNameResolver"/> </property> </bean> <bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> <property name="paramName"> <value>method</value> </property> <property name="defaultMethodName"> <value>add</value> </property> </bean>
위의 예를 보면 MemberController는 하나의 URL에 맵핑이 되었다. 그럼 어떻게 MemberController의 다른 메소드를 호출할 수 있을까? 그것은 "methodNameResolver" 빈의 "ParameterMethodNameResolver" 를 이용해서 호출이 가능하다.
URL을 통해 전달되는 인자중에 "paramName"인 method라는 이름을 가지는 인자의 값에 해당하는 메소드를 호출해 주는 것이다.
즉 /member/member.do?method=add 를 하게 되면 MemberController의 add()를 호출하는 것이다. /member/member.do?method=update를 하면 update()를 호출하게 될 것이다. 만일 아무 값도 없다면 default 으로 add()를 호출하게 된다. 호출하는 URL은 같지만 뒤 인자의 인자값을 변경해 줌으로써 다른 메소드를 호출할 수 있다.
ParameterMethodNameResolver를 이용하면 MultiActionController를 상속받은 Controller 에 메소드가 추가되더라도 설정파일에 추가적인 설정이 필요 없을 것이다. 하지만 호출할 때 추가된 메소드 이름을 알아야 한다.
데이터 바인딩(Data Binding)
웹 애플리케이션 개발에서 입력, 수정과 관련된 기능을 구현하기 위해서 입력하는 값에 대한 유효성 체크와 입력 값을 도메인 모델로 바인딩 하는 기능이 필요하다.그 동안 개발자들은 유효성 체크를 위해서 화면단에는 많은 자바스크립트를 데이타 바인딩을 위해서는 HttpServletRequest에 담긴 인자를 꺼내서 다시 도메인 모델로 set하는 코드들이 난무했을 것이다.
Spring MVC 에서는 입력화면(또는 수정화면)에서 전달되는 입력 데이터를 비즈니스 계층에 전달하기 위하여 HttpServletRequest에 담긴 인자와 도메인 모델의 속성을 자동적으로 연결하는 데이터 바이팅을 지원하고 있다.
위에 나온 bind()가 그 역할을 하는 것이다.
bind(request,command);
Bind request parameters onto the given command bean
@param request request from which parameters will be bound
@param command command object, that must be a JavaBean
@throws Exception in case of invalid state or arguments
대신 클라이언트가 입력한 데이터를 도메인 모델과 데이터 바인딩 하기 위해서는 입력 화면에서 사용한 속성이름과 도메인 모델의 속성이름이 같아야 한다.
- 회원가입 입력폼인 memberEntry.jsp
<%-- 작성자 : 난다 일자 : 2006.02.13 설명: 회원가입 --%> <%@page contentType="text/html; charset=euc-kr"%> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>사용자 관리 - 회원 가입</title> <link rel="stylesheet" type="text/css" href="../css/style.css" media="screen"> </head> <body> <div id="member"> <form name="thisform" method="post" action="${pageContext.request.contextPath}/member/addMember.do"> <table summary="회원가입"> <caption>회원 정보 </caption> <tr> <th id="id">* 아이디</th> <td headers="id"> <input type="text" id="id" name="id" /> </td> </tr> <tr> <th id="password">* 비밀번호</th> <td headers="password"> <input type="text" id="password" name="password" /> </td> </tr> <tr> <th id="passwordRepeat">* 비밀번호</th> <td headers="passwordRepeat"> <input type="text" id="passwordRepeat" name="passwordRepeat" /> </td> </tr> <tr> <th id="password_hint">* 비밀번호 힌트 </th> <td headers="passwordHint"> <input type="text" id="passwordHint" name="passwordHint" /> </td> </tr> <tr> <th id="passwordAnswer">* 비밀번호 답 </th> <td headers="passwordAnswer"> <input type="text" id="passwordAnswer" name="passwordAnswer" /> </td> </tr> <tr> <th id="email">* e-mail</th> <td headers="email"> <input type="text" id="email" name="email" /> </td> </tr> </table> <center> <input type="submit" value="확인" tabindex="4" /> </center> </form> </div> </body> </html>
- 도메인 모델 Member.java
package net.javajigi.member.model; import org.apache.commons.lang.builder.ToStringBuilder; public class Member { private String userId = null; private String password = null; private String passwordRepeat = null; private String passwordHint = null; private String passwordAnswer = null; private String email = null; 변수들에 대한 getter,setter 메소드... . . . public String toString() { return ToStringBuilder.reflectionToString(this); } }
memberEntry.jsp의 입력필드의 이름은 id,password,passwordRepeat,passwordHint,passwordAnswer,email로 정의 되어 있다.
그리고 바인딩되는 도메인 모델 Member도 id,password,passwordRepeat,passwordHint,passwordAnswer,email 가 정의되어 있다.
즉 같은 속성이름에 대해서는 가져올 수 있지만 만일 다르다면 가져오지 못하게 된다.
위의 예제에서 사용한 MultiActionController는 입력데이터에 대한 유효성 체크 기능을 지원하지 않는다. 만일 유효성 체크도 원한다면 MultiActionContorller를 상속받아서는 사용할 수 없다.
유효성 체크와 바인딩 기능까지 모든 기능을 사용하길 원한다면 AbstractCommandControllder 클래스를 상속받아야 한다.
AbstractCommandControllder를 상속받은 Controller
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.validation.BindException; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractCommandController; import com.tmax.spring.domain.Member; import com.tmax.spring.service.app.MemberService; public class MemberAbstractCommandController extends AbstractCommandController{ private static transient Log log = LogFactory.getLog(MemberAbstractCommandController.class); private MemberService memberService = null; public void setMemberService(MemberService memberService){ this.memberService = memberService; } public MemberAbstractCommandController(){ setCommandClass(Member.class); } protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { Member member = (Member)command; //memberService.addBbs(command); log.error("가져오는지..."+member.toString()); return new ModelAndView("../index"); } }
AbstractCommandController를 상속받아 구현 하려면 바인딩하는 클래스를 디폴트 생성자 안에 setCommandClass()를 통해서 설정해야 한다. 위의 예를 보면
public MemberAbstractCommandController()
Unknown macro: { setCommandClass(Member.class); }
그러면 들어오는 입력 값들과 설정한 클래스와의 바인딩이 이전에 보았던 bind() 라는 메소드 없이 Casting 만으로 이루어 진다.
하지만 AbstractCommandController는 요청에 대해 각각의 Controller를 만들어야 한다.결국 데이터 바인딩 및 데이터에 대한 유효성 체크 기능을 지원하고 있지만 AbstractCommandController를 상속받은 Controller로는 다수의 요청을 처리 할 수 없는 것이다.즉 Controller 를 이용하면 요청에 따라 추가되고 빈 설정 정보또한 수정해 주어야 한다.
결국 큰 주제로 했던 다수의 요청을 한 Controller에서 처리하는 방법은 아니지만 좀 더 손쉽게 유효성체크와 데이터 바인딩을 할 수 있다는 점에서는 유용하다. 간단한 CRUD 같은 작업은 MultiController를 구현해 한 Controller에서 사용할 수도 있고( 물론 유효성체크는 스크립트나 다른 방법을 통해) 복잡하고 많은 입력 필드를 가지고 있는 화면이라면 AbstractCommandController를 사용해 좀 더 손쉽게 처리 할 수 있을 것이다.
이것은 각각의 프로젝트, 요구사항등에 맞추어 결정하면 될 것이다.
action-servlet.xml 추가사항
- 실제로직을 담당하는 비지니스 객체인 MemberService.java 파일을 생성한다.
package net.javajigi.member.service; import net.javajigi.member.model.Member; public class MemberService { public void addMember(Member member){ //로직처리 } public void updateMember(Member member){ //로직처리 } }
하나의 Controller만으로 입력,수정처리하기
<ation-servlet.xml>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/login.do">loginFormController</prop> </props> </property> </bean> <bean id="loginFormController" class="spring.LoginFormController"> <property name="formView"><value>/login</value></property> <property name="successView"><value>/main</value></property> </bean> <bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass"> <value>org.springframework.web.servlet.view.JstlView</value> </property> <property name="cache"> <value>false</value> </property> <property name="prefix"> <value>/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean> </beans>
Controller를 URL과 매핑해주어야 한다.
login.do에 대한 요청을 loginFormController가 담당하며, 이 Controller는 로그인을 위한 로직처리를 포함하고, 사용자가 직접 작성해야한다.
입력화면은 /login 이며, 로직을 무사히 처리한후에는 /main으로 이동한다.
JSTL pages , jsp Page를 사용하기위해 JstlView를 선언하였다.
- web-app/login.jsp 로그인 페이지를 생성한다.
<login.jsp>
<%@page contentType="text/html; charset=euc-kr"%> <%@ page language="java" import="java.util.*" %> <html> <head> <title>My JSP 'login.jsp' starting page</title> </head> <body> <form name="myForm" method="post" action="/spring/login.do"> <table> <tr> <td> ID : <input type="text" name="userId" value="1"> </td> </tr> <tr> <td> PASSWORD : <input type="password" name="password" value="2"> </td> </tr> <tr> <td> <input type="submit" name="login" value="로그인"/> </td> </tr> </table> </form> </body> </html>
- web-app/main.jsp 로그인성공후 이동할 메인 페이지를 생성한다.
<main.jsp>
<%@page contentType="text/html; charset=euc-kr"%> <%@ page language="java" import="java.util.*" %> <html> <head> <title>My JSP 'main.jsp' starting page</title> </head> <body> Login Success~!! </body> </html>
- web-app/WEB-INF/net.javajigi.user.web.LoginFormController.java 파일을 생성한다.
package net.javajigi.user.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import net.javajigi.user.model.Authenticate; import org.springframework.validation.BindException; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.SimpleFormController; public class LoginFormController extends SimpleFormController { public LoginFormController() { // bean 객체 setCommandName("authenticate"); setCommandClass(Authenticate.class); } public ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { if (request.getParameter("login") != null) { Authenticate auth = (Authenticate) command; try { //로직처리 //boolean bResult = UserLoginProc.login(auth); //View 객체 리턴 return new ModelAndView(getSuccessView()); } catch (Exception e) { request.setAttribute("errorMessage", e.getMessage()); return new ModelAndView(getFormView()); } } else { HttpSession session = request.getSession(); if (session.getAttribute("loginUser") != null) { return new ModelAndView("decorators/logout"); } else { return new ModelAndView("decorators/login"); } } } }
SimpleFormController 을 상속받은 LoginFormController.java 파일을 생성한다.
- web-app/WEB-INF/net.javajigi.user.model.Authenticate.java 파일을 생성한다.
package net.javajigi.user.model; public class Authenticate { private String userId = null; private String password = null; public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } }
LoginFormController.java에서 호출되는 bean객체를 생성한다.
참고문헌
출처 -
http://www.javajigi.net/display/OSS/Spring+MVC
The Spring series, Part 3: Swing into Spring MVC
Spring MVC로 애플리케이션 개발하기
난이도 : 중급
Naveen Balani, 아키텍트, Webify Solutions
2005 년 9 월 06 일
Naveen Balani의 Spring series, 세 번째 글이다. Spring 프레임웍을 사용하여 MVC 기반 애플리케이션을 개발하는 방법을 설명한다.
이번에는 Spring series의 Spring Model-View-Controller (MVC)에 대해 설명하겠다. 이전 글과 마찬가지로 뱅킹 예제를 통해 애플리케이션의 모델링과 구현 방법을 설명하고자 한다. 이 예제 애플리케이션에는 여러분이 이미 배운 기술(종속관계 투입) 뿐만 아니라 Spring MVC의 기능들까지 함축되어 있다.
시작하기에 앞서 소스를 다운로드하라. 참고자료에는 Spring 프레임웍과 Tomcat 5.0 관련 링크가 있다.
Spring 프레임웍은 웹 애플리케이션 구현에 사용되는 완전한 MVC 모듈을 제공한다. Spring의 플러거블(pluggable) MVC 아키텍처에서는 빌트인 Spring 웹 프레임웍 또는 Struts 같은 웹 프레임웍을 사용할 지를 결정할 수 있다. 이 프레임웍은 전략 인터페이스를 통해 설정이 가능하며, JavaServer Pages (JSP), Velocity, Tiles, iText, POI 같은 여러 뷰(view) 기술이 포함되어 있다. Spring MVC는 컨트롤러의 역할, 모델 객체의 역할, 디스패쳐(dispatcher)의 역할, 핸들러 객체의 역할을 분리한다. 따라서 커스터마이징이 쉽다.
웹 MVC 프레임웍은 요청을 핸들러에 보내는(dispatch) DispatcherServlet
을 중심으로 디자인된다. 여기에 설정 가능한 핸들러 매핑, 뷰 해상도, 로케일, 테마 해상도, 업로드 파일 지원 등이 포함된다. 기본 핸들러는 단 한 개의 메소드 ModelAndView handleRequest(request, response)
를 가진 매우 간단한 Controller
인터페이스이다. Spring은 하위 클래스로 분류될 수 있는 컨트롤러 계층을 제공한다. 애플리케이션이 사용자 엔트리 형식을 처리해야 한다면, AbstractFormController
를 하위 클래스로 분류한다. 다중 페이지 엔트리를 한 개의 형식으로 처리하려면AbstractFormController
를 하위 클래스로 분류한다.
예제 애플리케이션을 통해서 이러한 기능들을 먼저 배우게 될 것이다. 뱅킹 애플리케이션에서는 사용자가 계좌 정보를 검색할 수 있다. 이를 구현하는 과정에서 Spring MVC 프레임웍을 설정하는 방법과 프레임웍의 뷰 레이어를 구현하는 방법을 배우게 된다. 뷰 레이어는 아웃풋 데이터를 렌더링하는 JavaServer Pages와 JSTL 태그들로 구성된다.
|
예제 애플리케이션 구현을 시작하려면 Spring MVC의 DispatcherServlet
을 설정한다. web.xml 파일에 모든 설정을 등록한다. Listing 1은 sampleBankingServlet
의 설정 방법이다.
Listing 1. Spring MVC DispatcherServlet 설정
|
DispatcherServlet
은 XML 파일에서 Spring 애플리케이션 컨텍스트를 로딩한다. XML 파일의 이름은 해당 서블릿 이름에 -servlet이 붙어있는 형태이다. 이 경우 DispatcherServlet
은sampleBankingServlet-servlet.xml 파일에서 애플리케이션 컨텍스트를 로딩한다.
다음에는 sampleBankingServlet
이 핸들 할 URL을 설정한다. 다시 강조하지만 web.xml 파일에 이 모든 설정을 등록해야 한다.
Listing 2. URL 설정
|
이제 설정 파일을 로딩 할 차례이다. Servlet 2.3 스팩에는 ContextLoaderListener
를 Servlet 2.2 이전 스팩에는 ContextLoaderServlet
을 등록한다. 백워드 호환을 위해 ContextLoaderServlet
을 사용한다. 웹 애플리케이션을 시작하면 ContextLoaderServlet
은 Spring 설정 파일을 로딩한다. Listing 3은 ContextLoaderServlet
의 등록 모습이다.
Listing 3. ContextLoaderServlet 등록
|
contextConfigLocation
매개변수는 로딩 할 Spring 설정 파일을 정의한다.
|
sampleBanking-services.xml 파일은 뱅킹 애플리케이션 예제에 대한 설정 및 서비스의 빈 설정을 파일이다. 다중 Spring 설정 파일을 로딩해야 했기 때문에 <param-value>
태그에 콤마를 사용할 수 있었다.
|
이 뱅킹 애플리케이션은 사용자가 고유 아이디와 패스워드를 사용하여 계좌 정보를 볼 수 있다. Spring MVC가 다른 옵션들도 제공하지만 나는 JSP를 사용하겠다. 이 샘플 애플리케이션은 사용자 인풋(아이디와 패스워드)을 위한 한 개의 뷰 페이지와 사용자 계좌 정보를 디스플레이 하는 페이지로 구성된다.
Spring MVC의 LoginBankController
를 확장한 LoginBankController로 시작한다. SimpleFormController
는 HTTP GET
요청을 받을 때 형식을 디스플레이하고 HTTP POST
를 받을 때 같은 형식 데이터를 처리하는 기능이 있다. LoginBankController
는 인증 및 계좌 작동에 AuthenticationService
와 AccountServices
서비스를 사용한다. "뷰 속성 설정" 섹션의 Listing 5는 AuthenticationService
와AccountServices
LoginBankController
로 전달하는 방법을 보여준다. Listing 4는 LoginBankController
의 코드이다.
이제 HTTP GET
요청을 받을 때 디스플레이 될 페이지를 등록해야 한다. formView
속성을 사용하여 Spring 설정에 이 페이지를 등록한다. (Listing 5). sucessView
속성은 형식 데이터가 게시되고 로직이 doSubmitAction()
메소드에서 성공적으로 실행된 후에 디스플레이 되는 페이지이다. formView
와 sucessView
속성 모두 뷰의 논리적 이름이다. 이것은 실제 뷰 페이지와 매핑된다.
Listing 5. LoginBankController 등록
|
commandClass
와 commandName
태그는 뷰 페이지에서 작동할 빈을 결정한다. 예를 들어, loginCommand
빈은 애플리케이션의 로그인 페이지인 login.jsp를 통해 접근할 수 있다. 사용자가 로그인 페이지를 제출하면 애플리케이션은 LoginBankController
의 onSubmit()
메소드에 있는 명령어 객체에서 형식 데이터를 검색할 수 있다.
Spring MVC의 뷰 리졸버(view resolver)는 각 논리적 이름을 실제 리소스(계좌 정보를 포함하고 있는 JSP 파일)로 바꾼다. 여기에서는 Spring의 InternalResourceViewResolver
를 사용한다.(Listing 6)
사용자의 로그인 이름은 /jsp/login.jsp로 바뀌고 viewClass
는 JstlView
로 바뀐다. JSP 페이지에서 JSTL 태그를 사용했기 때문이다.
앞서 언급했듯이, LoginBankController
는 Spring의 AccountServices
와 AuthenticationService
를 갖고 있다. AuthenticationService
클래스는 뱅킹 애플리케이션의 인증을 관리한다.AccountServices
클래스는 일반적인 뱅킹 서비스를 핸들한다. Listing 7은 뱅킹 애플리케이션의 인증 및 계좌 서비스의 설정 모습이다.
Listing 7. 인증 및 계좌 서비스의 설정
|
위 서비스들을 sampleBanking-services.xml에 등록한다. 여기에는, web.xml 파일이 로딩된다. 컨트롤러와 서비스가 설정되면 이 애플리케이션은 완성된다. 이제 전개하여 테스트해보자.
|
여기에서는 이 애플리케이션 예제를 Tomcat 서블릿 컨테이너에 전개했다. Tomcat은 Java Servlet과 ServerPages 기술의 공식 레퍼런스 구현에 사용되는 서블릿 컨테이너이다. download jakarta-tomcat-5.0.28.exe를 다운로드하여 Tomcat을 설치한다. (c:\tomcat5.0
)
그런 다음, 예제 코드를 다운로드하고 c:\에 압축을 푼다. Spring 프로젝트 폴더를 만들었다면 이것을 열어 spring-banking 하위폴더를 c:\tomvat5.0\webapps에 복사한다. spring-banking 폴더는 Spring MVC 예제 애플리케이션을 포함하고 있는 웹 아카이브이다. lib 폴더에는 Spring 프레임웍, Spring 관련 MVC 라이브러리, JSTL 태그 라이브러리, jar 파일이 들어있다.
Tomcat 서버를 시작하려면 다음 명령어를 실행한다.
cd bin C:\Tomcat 5.0\bin> catalina.bat start
Tomcat 이 시작되고 Spring MVC 예제 애플리케이션을 전개한다.
|
애플리케이션을 테스트하려면 웹 브라우저를 열어 http://localhost:tomcatport/springbanking으로 가서 tomcatport를 Tomcat 서버를 실행하는 포트로 대체한다. 로그인 스크린이 나타난다. (그림 1). 사용자 아이디 "admin"과 "password"를 입력하고 Login 버튼을 누른다. 다른 아이디와 패스워드를 입력하면 에러가 된다.
그림 1. Spring MVC 로그인 스크린
로그인이 성공하면 계좌 정보를 볼 수 있는 페이지가 디스플레이 된다. (그림 2)
그림 2. Spring MVC 계좌 정보 스크린
|
지금까지 Spring series의 Spring MVC 프레임웍을 설명했다. Spring MVC 애플리케이션의 설치 및 개발 방법, 종속관계를 설정하여 Spring MVC 컨트롤러로 주입하는 방법, JavaServer Pages를 사용하여 애플리케이션 뷰를 개발하는 방법, 페이지를 Spring 뷰 레이어로 통합하는 방법을 설명했다. Tomcat 서블릿 컨테이너에 애플리케이션을 전개하여 테스트도 해 보았다.
다음 Spring series에서는 JMS 기반 애플리케이션과 Spring 프레임웍을 통합하는 방법을 설명하겠다. 참고자료 섹션의 리소스들을 숙지하기 바란다.
|
설명 | 이름 | 크기 | 다운로드 방식 |
---|---|---|---|
Example source code, spring files, jar files | wa-spring3-SpringProjectPart3.zip | 1966 KB | FTP |
다운로드 방식에 대한 정보 | Get Adobe® Reader® |
|
교육
- "The Spring series, Part 1: Spring 프레임웍 소개" (developerWorks, June 2005), "The Spring series, Part 2: Hibernate와 Spring" (developerWorks, August 2005)
- "AOP tools comparison, Part 1" (Mik Kersten, developerWorks, February 2005)
- "The emergence of Spring" (Bruce Tate, developerWorks, June 2005)
- "Ruby on Rails and J2EE: Is there room for both?" (Aaron Rustad, developerWorks, July 2005)
- The Web Architecture zone
제품 및 기술 얻기
토론
|
Naveen Balani, 아키텍트, Webify Solutions |
출처 - http://www-128.ibm.com/developerworks/kr/library/wa-spring3/#download
'Framework & Platform > Spring' 카테고리의 다른 글
spring MVC 예제 3 (9) | 2012.03.21 |
---|---|
spring MVC 예제 2_MyBatis 적용 (0) | 2012.03.21 |
Spring Framework 소개 (0) | 2012.01.31 |
Spring AOP(Aspect Oriented Programming) 개념 (0) | 2010.12.18 |
spring - IOC (Inversion of Control) (0) | 2010.12.18 |