스프링 MVC 어플리케이션의 작동을 구현할때에는 스프링 컨트롤러 클래스중 하나를 확장해서 사용하게 된다.
controller 는 DispatcherServlet 으로 부터 요청을 받아들여 사용자를 대신하여 비즈니스 기능을 수행하게 된다.
스프링 MVC 의 컨트롤러는 스트러츠나 웹워크의 액션과 같은 단순한 액션 계층구조와는 달리 매우 풍부한 컨트롤러 계층 구조를 제공하고 있다는 점이다.
컨트롤러 계층구조의 가장 상위에는Controller 인터페이스가 있다. 이 인터페이스를 구현하는 모든 클래스는 스프링 MVC 프레임웍에서 요청을 처리하는 데 사용될 수 있다. 만약 컨트롤러를 만든다면 반드시 이 인터페이스를 구현해야 한다.
Controller 인터페이스를 직접 구현하여 클래스를 작성할 수 도 있지만 그보다는 계층구조의 아래부분에 위치하는 클래스들 중 하나를 확장해서 사용하는것이 낫다. Controller 인터페이스는 컨트롤러와 스프링MVC 간의 기본적인 규약을 정의하는 반면에, 다른 컨트롤러 클래스들은 그에 대하여 부가적인 기능들도 제공하기 때문이다.
컨트롤러의 종류및 특징에 대해 알아보자...
1. Controller ( 인터페이스 ) : 단순한 유형으로써 간단한 컨트롤러 만들고자 할때 사용된다.
2. AbstractController : 단순한 유형으로써 Controller 인터페이스 보다 약간 더 부가적인 기능을 포함한다.
다음과 같은 프로퍼티를 포함하고 있다.
supportedMethods, requiresSession, synchronizeSession, cacheSeconds, useExpiresHeader, useCacheHeader
EmployeeController.java |
public class EmployeeListController extends AbstractController { @Override protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mav = new ModelAndView(); mav.setViewName("jsp/list/employeeList"); mav.addObject("message", "HelloWorld!!!"); return mav; } } |
위와 같이 handleRequestInternal() 는 AbstractController 실행에 있어서 주된 메소드로서 이 메소드를 제정의 함으로써 컨트롤러의 기능을 구현할 수 있다.
그리고 설정파일(springmvc-servlet.xml) 에서 추가적인 기능을 포함시킬수 있다. 다음은 한 예를 보자.
<bean id="employeeListController" class="com.example.control.EmployeeListController">
<property name="supportedMethods">
<value>GET,POST</value>
</property>
</bean>
supportMethods 는 get방식인지, post 방식인지를 설정하는 property 이다. value 는 get 방식, post 방식, get,post 둘다 설정가능하다.
아주 간단한 경우, Controller를 구현할 때에는 Controller 인터페이스를 직접 구현하기보다는, AbstractController 추상 클래스를 상속 받아 구현하는 경우가 더 많다.
3. AbstractCommandController : AbstractController 에 기반한 컨트롤러를 사용할 경우에는 넘어온 파라미터를 HttpServletRequest. 로 부터 필요한 값을 얻을 것이다..그러나 그렇게 하면 비즈니스 객체에 바인딩시키는 로직을 추가로 작성해야하며 또한 컨트롤러 자체의 유효성 검증 로직도 포함시켜야 한다..바인딩 로직과 유효성 검증은 진정한 컨트롤러의 역할이 아니다. 컨트롤러가 만약에 파라미터에 기초하여 작업을 수행하는 경우라면 AbstractCommandController 를 사용해야한다. 이컨트롤러는 명령객체에 자동으로 바인딩 시켜 주며, 파라미터 유효성 확인을 위한 검증기를 플러그인 할 수 있는 훅(hook) 을 제공한다.
다음의 예제소스를 보자
ExAbstractCommandController.java |
import net.jtlab.example.dao.ExAbstractCommand; import org.springframework.validation.BindException; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractCommandController; public class ExAbstractCommandController extends AbstractCommandController { public ExAbstractCommandController(){ //명령클래스 설정 setCommandClass(ExAbstractCommand.class); } @Override protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { ExAbstractCommand abstractCommand = (ExAbstractCommand)command; System.out.println(abstractCommand.getId()); System.out.println(abstractCommand.getPassword()); System.out.println(abstractCommand.getName()); return null; } } |
예제를 보면 ExAbstractCommandController 클래스는 handle() 메소드는 AbstractCommandController 를 위한 주된 실행 메소드라는 것을 알수 있으며 또한 AbstractController 와 다르게 Object 객체와 BindException 객체가 추가된 것을 알 수 있다.
생성자에서 추가된 ExAbstractCommand 클래스는 요청된 파라미터를 저장하는 객체로서 단순 setter, getter 메소드를 포함하고 있다.
스프링은 handle() 메소드가 호출되기 이전에 , 요청에 전달된 모든 파라미터를 명령객체의 특성에 맞추어 주기 때문에
명령컨트롤러는 요청 파라미터를 명령객체에 바인딩시켜줌으로써 쉽게 다룰수 있다.
파라미터로 넘어온 값을 단순 출력하는 예제 이므로 한번 실습하기를 권한다.
4. SimpleFormController : 사용자가 정보를 등록하고자 할때 그정보가 별다른 문제가 없다면 성공적으로 등록되고 잘못된 데이터를 입력했다면 값을 수정하고 다시 제출해야 할것이다. 이런 경우 등록 절차를 구현하기 위해 폼을 구현하는 AbstractController 와 폼을 처리하기 위한 AbstractCommandController 를 사용해야 할 것이다. 이 두개의 서로 다른 컨트롤러를 관리해야 하는 번거로움을 해결할 수 있는 컨트롤러가 바로 SimpleFormController 이다. 폼 컨트롤러는 명령컨트롤러의 개념을 이어 받았으며 만일 HTTP get 요청을 받았을 경우에는 폼을 보여주고 HTTP post 요청을 받았을 경우에는 폼을 처리하는 기능이 추가된 컨트롤러 이다.
다음의 예제를 살펴보자.
ExSimpleFormController.java |
import org.springframework.web.servlet.mvc.SimpleFormController; public class ExSimpleFormController extends SimpleFormController { public ExSimpleFormController() { setCommandClass(ExSimpleFormCommand.class); } @Override protected void doSubmitAction(Object command) throws Exception { ExSimpleFormCommand exSimpleFormCommand = (ExSimpleFormCommand)command; System.out.println(exSimpleFormCommand.getName()); System.out.println(exSimpleFormCommand.getTel()); System.out.println(exSimpleFormCommand.getAddress()); } } |
명확하지 않은 것은 이 컨트롤러가 어떻게 폼을 보여줄지를 알 수 있는지에 대한 것이다. 또한 성공시킨 후 사용자를 어디로 이동시킬지 또한 명확하지 않다. 또 doSubmitAction() 메소드는 ModelAndView 객체를 리턴하지도 않는다..
SimpleFormController 는 뷰와 관련된 자세한 사항은 컨트롤러의 자바로부터 가급적이면 분리시키도록 설계됐다.. ModelAndView 객체를 하드코딩하는 대신, 다음과 같이 컨텍스트 설정파일에서 컨트롤러를 설정할 수 있는 것이다.
springmvc-servlet.xml |
<bean name="/simpleFormController.do" class="net.jtlab.example.action.ExSimpleFormController"> <property name="formView"> <value>simpleFormView</value> </property> <property name="successView"> <value>successView</value> </property> </bean> |
SimpleFormController 는 어떤 서비스객체 뿐만 아니라 위와같이 formView 특성과 successView 특성을 추가로 설정해야한다.
formView 특성은 컨트롤러가 HTTP GET요청을 받았을때나 또는 에러가 발생했을때 보여줘야할 뷰의 논리적인 이름이다.
successView 특성은 성공적으로 폼이 제출됐을때 보여줘야 할 뷰의 논리적인 이름이다.
그렇지만 doSubmitAction() 의 사용은 제약사항이 있다. ModelAndView 객체를 리턴할 필요성이 없어짐으로써 동시에 모델데이터를 뷰에 넘기는 것도 불가능하게 되었다. 만약에 데이터를 전송하여 뷰에 보여지도록 해야 하는 경우라면 doSubmitAction() 대신에 onSubmit() 메소드를 재정의 해야 할 것이다.
ExSimpleFormController.java |
import org.springframework.web.servlet.mvc.SimpleFormController; public class ExSimpleFormController extends SimpleFormController { @Override protected ModelAndView onSubmit(Object command, BindException errors) throws Exception { ExSimpleFormCommand exSimpleFormCommand = (ExSimpleFormCommand)command; return new ModelAndView(getSuccessView(), "formCommand", exSimpleFormCommand); } } |
다른 컨트롤러의 핸들러메소드와 마찬가지로 ModelAndView 객체를 리턴하지만 여전히 컨텍스트 설정파일에서 성공한 뷰를 설정할 수 있기 때문에 뷰의 논리적인 이름을 설정할때는 반드시 getSuccessView() 메소드를 호출해야한다.
5. MultiActionController : 위의 모든 컨트롤러는 하나의 작업만을 수행하는 것들이었다. 컨트롤러의 하나의 액션은 아무래도 제한적일 수 있으며 비슷하거나 관련된 기능을 수행하는 컨트롤러들 사이에 많은 양의 반복적인 코드를 만들 여지가 있어야 한다. MutiActionController는 다중액션을 수행할 수 있는 특별한 종류의 컨트롤러로서 각 액션은 다양한 메소드와 연결될 수 있다.
다음의 예제를 살펴보자.
ExMultiActionController.java |
import org.springframework.web.servlet.mvc.multiaction.MultiActionController; public class ExMultiActionController extends MultiActionController { public ModelAndView add(HttpServletRequest request, HttpServletResponse response){ System.out.println("Add Data!!!"); return new ModelAndView("AddView"); } public ModelAndView delete(HttpServletRequest request, HttpServletResponse response){ System.out.println("Delete Data!!!"); return new ModelAndView("DeleteView"); } public ModelAndView retrieve(HttpServletRequest request, HttpServletResponse response){ System.out.println("Retrieve Data!!!"); return new ModelAndView("RetrieveView"); } public ModelAndView update(HttpServletRequest request, HttpServletResponse response){ System.out.println("Update Data!!!"); return new ModelAndView("UpdateView"); } } |
위의 소스 예제를 보면 메소드 4개를 선언했으며 각각의 ModelAndView 객체에 뷰의 논리적인 이름을 명시하여 리턴하였다..
이제 어떤 요청이 있을 경우 해당 메소드를 실행할지 결정하는 일이 남아 있다..
MultiActionController 는 메소드 이름 리졸버에 기초하여 메소드의 이름을 결정한다.
Spring 에서는 NameResolver를 제공하고 있다.
- ParameterMethodNameResolver : 요청 파라미터를 기초로 하여 실행 메소드 이름을 결정한다.
- PropertiesMethodNameResolver : 키 - 값 쌍의 목록을 기초로 하여 실행 메소드 이름을 결정한다.
우선 ParameterMethodNameResolver 사용하여 설정하면 설정파일은 다음과 같다.
springmvc-servlet.xml |
<bean id="exMultiActionController" class="net.jtlab.example.action.exMultiActionController"> <property name="methodNameResolver"> <ref local="exPropertiesMethodNameResolver"/> </property> </bean> <bean id="exPropertiesMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"> <property name="mappings"> <props> <prop key="/addMultiActionData.do">add</prop> <prop key="/deleteMultiActionData.do">delete</prop> <prop key="/updateMultiActionData.do">update</prop> <prop key="/retrieveMultiActionData.do">retrieve</prop> </props> </property> </bean> |
출처 -