: 클라이언트로부터 어떠한 요청이 오면 Tomcat(톰캣)과 같은 서블릿컨테이너가 요청을 받는데, 이때 제일 앞에서 서버로 들어오는 모든 요청을 처리하는 *프론트 컨트롤러를 Spring에서 정의하였고, 이를 Dispatcher-Servlet이라고 한다.
공통처리 작업을 Dispatcher 서블릿이 처리한 후, 적절한 세부 컨트롤러로 작업을 위임해준다.
Dispatcher-Servlet이 처리하는 url 패턴을 지정해주어야 하는데 일반적으로는 /*.do와 같은 /로 시작하며 .do로 끝나는 url 패턴에 대해서 처리하라고 지정해준다.
**프론트 컨트롤러(Front Controller)
프론트 컨트롤러는 주로 서블릿 컨테이너의 제일 앞에서 서버로 들어오는 클라이언트의 모든 요청을 받아서 처리해주는 컨트롤러이다.
MVC 구조에서 함께 사용되는 패턴이다.
Spring MVC에서 web.xml의 역할을 축소시켜주었습니다.
기존에는 모든 서블릿에 대해 URL 매핑을 활용하기 위해서 web.xml에 모두 등록해주어야 했지만, dispatcher-servlet이 해당 어플리케이션으로 들어오는 모든 요청을 핸들링해주면서 작업을 상당히 편리하게 할 수 있게 되었습니다.
서블릿 클래스는 JSP 페이지와 달리 설치뿐만 아니라 등록을 하는 과정을 필요로 한다. 여기서 서블릿 클래스를 등록하는 곳의 이름을 Web application deployment descriptor
라고 하는데 (줄여서 DD-Deployment Descriptor) 이 역할을 하는 것이 바로 web.xml
이다.
web.xml
파일은 웹 애플리케이션 디렉터리마다 딱 하나씩만 존재할 수 있다.
DD는 WAS 구동 시 /WEB-INF
디렉토리에 존재하는 web.xml
을 읽어 웹 애플리케이션의 설정을 구성하기 위해 존재한다.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<!-- applicationContext.xml에서 설정한 Bean은 모든 서블릿, 필터에서 공유 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/applicationContext.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<!-- 서블릿과 필터에 공유 할 수 있도록 리스너를 설정 -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
<!-- dispatcherServlet 생성 시, 서블릿 설정파일 로드 -->
/WEB-INF/spring/appServlet/servlet-context.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- dispatcherServlet 대한 url-pattern을 정의
/로 들어오는 모든 요청은 DispatcherServlet에서 처리 -->
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
ApplicationContext.xml
<context:component-scan base-package="egovframework">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
Servlet-Context.xml
<context:component-scan base-package="egovframework">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
Controller는 Include 한다
Service와 Repository는 Exclude
/*
Transaction
을 적용하기 위해서이다.스프링 트랜잭션은 AOP를 이용해서 해당 빈의 proxy를 만들어서 tx가 적용되는 bean을 바꿔치기 한다. 그러면 원래 @Service(또는 @Transactional)
어노테이션이 붙은 빈은 뒤로 숨고 tx가 적용된 proxy bean이 @Service
가 붙은 bean으로 대치된다.
만약 Application Context
와 Servlet Context
가 모든 stereotype의 컴포넌트를 풀 스캔 할 경우, tx 설정은 Application Context
에만 적용되어 있기 때문에 Application Context
의 @Service는 트랜잭션이 적용이 되지만 Servlet Context
의 @Service는 트랜잭션이 적용이 안된다.
Bean 객체는 Servlet Context
가 우선되므로 @Controller
가 동작하여 같은 context(Servlet Context)안에서 검색을 하고, @Service
가 지정된 bean이 있으므로 이 bean을 사용한다. 이 @Service
가 지정된 bean은 트랜잭션 적용이 안 되어 있어 트랜잭션 처리가 안된다.
core가 되는 프로젝트는 applicationContext에서 component-scan을 통해 bean을 생성 하고 있었고
각 endpoint가 되는 프로젝트내의 패키지는 모두 servlet-context에서 component-scan을 하고 있었다.
*/
호출 시점
설정 위치
구현 방식
public class MyInterceptor implements HandlerInterceptor{
// controller로 보내기 전에 처리하는 인터셉터
// 반환이 false라면 controller로 요청을 안함
// 매개변수 Object는 핸들러 정보를 의미한다. ( RequestMapping , DefaultServletHandler )
@Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response,
Object obj) throws Exception {
System.out.println("MyInterCeptor - preHandle");
return false;
}
// controller의 handler가 끝나면 처리됨
@Override
public void postHandle(
HttpServletRequest request, HttpServletResponse response,
Object obj, ModelAndView mav)
throws Exception {
}
// view까지 처리가 끝난 후에 처리됨
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response,
Object obj, Exception e)
throws Exception {
}
}
preHandle() : 컨트롤러가 호출되기 전에 실행됩니다.
postHandle() : 컨트롤러가 실행된 후에 호출됩니다.
afterComplete() : 뷰에서 최종 결과가 생성하는 일을 포함한 모든 일이 완료 되었을 때 실행됩니다.
각 메서드의 반환값이 true이면 핸들러의 다음 체인이 실행되지만 false이면 중단하고 남은 인터셉터와 컨트롤러가 실행되지 않습니다.
public class MyInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response,
Object obj) throws Exception {
System.out.println("MyInterCeptor - preHandle");
return true;
}
}
1)설정
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/mobile/**")
.addResourceLocations("classpath:/mobile/")
.setCacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES));
}
}
WebMvcConfigurer를 구현하고 addResourceHandlers
메소드를 오버라이딩 합니다. 그후 registry를 이용해 핸들러를 등록하면 됩니다.
addResourceHandler()
addResourceLocations()
setCacheControl()
2) 파일 경로
InternalResourceViewResolver
를 사용합니다.Default(기본) 뷰 리졸버. JSP를 뷰로 사용할 때 쓰인다.
설정
WebConfig Class
WebConfig
파일에는 아무런 설정이 되어있지 않습니다.HelloController Class
Controller class의 Handler 메소드에는 응답할 view의 전체 경로 및 확장자를 포함하도록 했습니다.
또한 view파일은 WEB-INF 디렉토리 하위에 위치하도록 했습니다.