이전에 Hello World 출력하기에서 살펴보았듯이..
Spring에서는 MVC 프레임워크를 제공한다..
다시 한 번 Spring MVC의 동작이 어떻게 되는지 살펴보자...
1. 클라이언트의 요청
2. DispatcherServlet 시작
3. HanderMapping을 이용하여 해당 Controller 검색
4. 해당 Controller가 요청 처리 후 ModelAndView 리턴
5. ViewResolver를 이용하여 View 검색
6. View에 출력
Spring MVC에서 C에 해당하는 부분이 바로 DispatcherServlet이다...
이 녀석이 클라이언트의 요청을 받아 Controller를 검색하고...
Controller의 처리 결과인 ModelAndView를 전달 받아 View를 출력해주는 역할을 한다...
우리가 할 일은 실제 요청을 처리할 Controller를 만들고..
처리한 결과를 출력해 줄 View를 만드는 것뿐이다..
물론 DB 정보가 필요하다면 Model을 만드는 것도 우리가 할 일이다...
자... 그렇다면 이제 이전 HelloWorld 출력하기에서 했던 내용을 좀 더 자세히 알아보자..
DispatcherServlet은 기본적으로 /WEB-INF/ 디렉토리에 서블릿이름-servlet.xml 파일을 설정파일로 사용한다...
아래와 같이 설정했다면 cuvic-servlet.xml 파일로 저장하면 된다...
<servlet>
<servlet-name>cuvic</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
가끔 설정 파일을 한 개 이상 사용하고 싶은 경우가 있다...
그런 경우 <init-param>으로 contextConfigLocation을 설정해준다...
<servlet>
<servlet-name>cuvic</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/appContext.xml, /WEB-INF/sqlContext.xml</param-value>
</init-param>
</servlet>
위와 같이 하면 appContext.xml과 sqlContext.xml 파일을 설정 파일로 사용하게 된다...
설정 파일은 콤마(,)나 공백문자 또는 탭과 세미콜론(;) 중 하나로 구분한다..
Spring MVC에서는 1개 이상의 DispatcherServlet을 설정할 수 있다..
<servlet>
<servlet-name>cuvic1</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app1Context.xml</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>cuvic2</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app2Context.xml</param-value>
</init-param>
</servlet>
위와 같이 2개의 DispatcherServlet을 설정할 수 있다..
하지만 위와 같이 설정을 하게 되면 cuvic1과 cuvic2는 서로 독립적인 서블릿이 되버린다..
따라서 서로의 빈 객체를 사용할 수가 없게 된다..
대부분 동일한 서비스 객체와 퍼시스턴트 객체를 사용하므로 따로 사용할 필요가 없다...
이처럼 공통으로 사용할 빈 객체가 필요한 경우 ContextLoaderListener를 사용하면 된다...
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app.xml, /WEB-INF/sql.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
위와 같이 설정해주면 app.xml과 sql.xml 에 있는 빈들은 모든 서블릿에서 공통으로 사용할 수 있게 된다...
이번에는 자바를 하게 되면 항상 발생하는 인코딩 문제를 해결해보자...
이전에 살펴봤듯이 한글을 제대로 표현하기 위해서는 UTF-8 형식으로 보내는 것이 현명한 방법이다..
하지만 대부분 기본으로 8859_1이나 EUC_KR을 많이 사용하곤 한다...
따라서 request.setCharacterEncoding("UTF-8") 메소드를 이용해서 변경해주는데...
모슨 소스 코드에 이를 해주는 것은 매우 번거롭고 귀찮은 일이다..
아래와 같이 서블릿 필터를 등록하면 쉽게 인코딩을 설정할 수 있다...
<filter>
<filter-name>encoder</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
이번에는 해당 요청을 처리하는 Controller를 검색하기 위한 HandlerMapping을 살펴보자...
Spring에서 제공하는 HandlerMapping 클래스는 4가지가 있다...
SimpleUrlHandlerMapping : URL 패턴에 매칭되는 지정된 Controller를 사용
BeanNameUrlHandlerMapping : URL과 일치하는 이름을 갖는 빈을 Controller로 사용
ControllerClassNameHandlerMapping : URL과 일치하는 클래스 이름을 갖는 빈을 Controller로 사용
DefaultAnnotationHandlerMapping : @RequestMapping Annotation을 이용
위의 4가지 클래스는 AbstractUrlHandlerMapping 클래스를 상속한다..
Annotation을 이용하는 방법은 다음에 알아보도록 하고 나머지 3개 먼저 알아보도록 하자...
이 클래스는 요청 URL의 서블릿 컨텍스트까지를 기준으로 Controller를 매핑한다...
즉 서블릿 컨텍스트가 test이고 아래와 같은 URL 요청이 있다면..
http://localhost/test/hello/HelloWorld.cmd
/hello/HelloWorld.cmd를 사용하여 Controller를 찾게 된다..
그렇다면 BeanNameUrlHandlerMapping을 이용한 설정을 살펴보자...
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean id="/hello/HelloWorld.cmd" class="org.test.web.HelloController"/>
<servlet>
<servlet-name>test</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>*.cmd</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
위와 같은 경우에는 확장자가 cmd이거나 /hello/로 들어오는 모든 요청을 DispatcherServlet에 보내게 된다...
즉 위의 URL 요청인 경우 *.cmd 패턴은 /hello/HelloWorld.cmd로 검색하게 되고 /hello/* 패턴은 /HelloWorld.cmd로 검색한다...
따라서 위의 예제에서는 빈의 이름이 /hello/HelloWorld.cmd 혹은 /HelloWorld.cmd인 Controller를 선택되게 된다...
만약 항상 서블릿 컨텍스트 이후의 전체 경로를 사용하고자 한다면...
아래와 같이 alwaysUseFullPath를 true로 지정해준다...
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true"/>
</bean>
또한 위에서 살펴보았듯이 BeanNameUrlHandlerMapping은 빈의 이름을 Ant 경로 패턴을 사용하게 된다..
Ant 경로 패턴은 다음과 같은 규칙이 있다...
? : 1개의 문자와 매칭
* : 0개 이상의 문자와 매칭
** : 0개 이상의 디렉토리와 매칭
예를 들어 /hello/**/*.cmd 라고 하면..
/hello/hello.cmd, /hello/1/hello.cmd, /hello/1/2/hello.cmd 등의 값이 매핑될 수 있다...
이번에는 HelloWorld 출력하기에서 살펴보았던 SimpleUrlHandlerMapping에 대해서 알아보자..
가장 많이 사용되는 HandlerMapping으로 패턴 매칭을 이용하여 Controller를 매핑한다...
위의 예제는 아래와 같이 사용될 수 있다..
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="*.cmd">helloController</prop>
<prop key="/hello/*">helloController</prop>
</property>
</bean>
<bean id="helloController" class="org.test.web.HelloController"/>
<servlet>
<servlet-name>test</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>*.cmd</url-pattern>
</servlet-mapping>
그리고 Spring에서는 다수의 HandlerMapping을 사용할 수 있다..
만약 아래와 같이 위의 2가지를 모두 사용한다면...
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"/>
<property name="mappings">
<props>
<prop key="*.cmd">helloController</prop>
<prop key="/hello/*">helloController</prop>
</property>
</bean>
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
과연 어떤 HandlerMapping을 먼저 사용하게 될까...
order 프로퍼티를 사용하지 않는다면 설정 파일에 입력된 순서대로 Controller를 검색하게 되고...
만약 order 프로퍼티를 주게 되면 낮은 순서에 따라 Controller를 검색하게 된다...
즉 위의 예제는 order 속성이 없으므로 먼저 설정한 SimpleUrlHandlerMapping이 먼저 적용되고...
아래의 예제와 같은 경우 order가 1로 설정된 BeanNameUrlHandlerMapping을 먼저 적용하게 된다...
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="order" value="2">
<property name="mappings">
<props>
<prop key="*.cmd">helloController</prop>
<prop key="/hello/*">helloController</prop>
</property>
</bean>
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="order" value="1">
</bean>
마지막으로 ControllerClassNameHandlerMapping을 한 번 알아보자...
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
<bean id="helloController" class="org.test.web.HelloController"/>
위와 같이 설정해주면 알아서 Controller의 이름 패턴으로 매핑을 시켜준다...
즉 HelloController는 다음 URL 패턴과 매핑된다...
/helloController*
만약 MultiActionController를 상속하여 구현하였다면 다음 URL 패턴과 매핑된다...
/helloController/*
상당히 편리한 기능이 아닐 수 없다...
MultiActionController는 무엇인지 모르지만 일단은 저렇게 사용된다고 기억해두도록 하자...
HandlerMapping은 여기까지 알아보고... 실제 Controller 만드는 방법은 다음에 다시 알아보도록 하자...
'프레임워크 > Spring' 카테고리의 다른 글
어노테이션을 이용한 설정 (0) | 2015.11.06 |
---|---|
@Autowired 와 @Resource (0) | 2015.11.06 |
Spring MVC 기초 (0) | 2015.10.16 |
Spring HelloWorld! 띄우기 (0) | 2015.10.16 |
Spring 강좌 웹개발자 샤쿠 (0) | 2015.10.16 |