DispatcherServlet의 의미
DispatcherServlet에서 Dispatch의 의미는 급파하다, 파견 등의 의미로, 해석할시 받은 요청을 어딘가로 빨리빨리 보내는 서블릿이라는 뜻이다. 또한, 프론트 컨트롤러라고 불리기도 한다.
Spring에서의 DispatcherServlet
Spring에서는 jsp 다이나믹 웹 프로젝트 때 처럼 /home.jsp << 이런식으로 사용자가 직접 들어가는 것이 불가능하다. 이것은 DispatcherServlet을 이용하여 사용자가 직접 해당내용으로 접근하는 것을 막는 것인데 아래 그림을 보면 이해가 가능하다.
Spring-mvc (동작원리)
스프링에서는 Dispatcher Servlet의 내용을 확인할 수 없다. 이 내용을 jsp에서 풀어쓴다면
DispatcherServlet(jsp)
package com.itbank.test2;
import java.io.IOException;
import java.util.Date;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DispatcherServlet extends HttpServlet{
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//프로젝트 + 파일경로
String command = request.getRequestURI();
//프로젝트 + Path
String cpath = request.getContextPath();
System.out.println(command);
System.out.println(cpath);
String requestmapping = command.substring(cpath.length());
System.out.println(requestmapping);
// 요청 주소에 따라 서로 다른 코드를 실행하고, 포워딩할 JSP의 이름을 만들어낸다
String viewName = null;
switch (requestmapping) {
case "/":
request.setAttribute("serverTime", new Date());
viewName = "home";
break;
case "/info":
String name = request.getParameter("name");
int age = Integer.parseInt(request.getParameter("age"));
String adult = age >= 20 ? "성인" : "미성년자";
String msg = String.format("%s의 나이는 %d살이고, %s입니다", name, age, adult);
request.setAttribute("msg", msg);
viewName = "info";
break;
}
viewName = prefix + viewName + suffix;
RequestDispatcher rd = request.getRequestDispatcher(viewName);
rd.forward(request, response);
System.out.println("===========================");
}
private final String prefix = "/WEB-INF/views/";
private final String suffix = ".jsp";
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>test2</display-name>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>com.itbank.test2.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
이런 코드가 탄생한다. 위 코드에서 새로운 내용을 추가하기 위해서는 case에 기존 jsp파일의 name을 적어주며 사용 메소드를 만들어줘야한다. 즉, spring이 없는 환경에서 spring의 방식을 사용할 수 있으나 굉장히 지저분한 것을 확인 가능하다.
아래는 Spring에서의 controller이다.
위 코드를 풀어서 해석할 시
1. (프로젝트 + 파일경로) - (프로젝트+path) = "남는 값" (위 코드의 경우 "/") => 포워딩할 이름
2. 브라우저에서 /로 요청
3. servletMapping에서 /hello에 대한 key값 찾는다.
4. 해당 value값(서블릿이름)에 해당하는 childeren(서블릿)의 key 값을 찾는다.
5. 해당 값에 대응하는 서블릿을 처리한다.
단, URL에 대응하는 서블릿이 없다면??
404 NOT FOUND에러가 발생한다.
Spring Controller
package com.itbank.test1;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
class HomeController {
@RequestMapping("/")
public String home(HttpServletRequest request) {
request.setAttribute("serverTime", new Date());
return "home";
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 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 https://java.sun.com/xml/ns/javaee/web-app_3_1.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.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>appServlet</servlet-name>
<!-- DispatcherServlet을 스프링프레임워크에서 자동으로 가져오
는 것을 확인 가능하다 -->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 위 jsp에서의 코드와 같이 xml 상에서 처리된 것을 확인할 수 있다 -->
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.itbank.test1" />
</beans:beans>
스프링의 DispatcherServlet
스프링에서는 요청 URL에 대응하는 서블릿이나 JSP를 사용하지 않기 때문에 모든 요청을 "/" 즉, Default Servlet으로 처리한다. 이를 DispatcherServlet이라고 한다.
모든 요청을 먼저 이 곳에서 받고 DispatcherServlet 안에서 내부적으로 요청에 해당하는 URL을 해당 Controller로 매핑시켜준다.
그림으로 정리하는 DispatcherServlet [FrontController 패턴]
Front-Controller 패턴은 웹 애플리케이션에서 주로 사용되는 디자인 패턴으로, 컨트롤러에서 중복으로 처리해야 하는 공통 기능들을 처리하는 입구 역할을 하는 컨트롤러를 두는 개념이다.
Front-Controller 패턴을 적용하면 다수의 서블릿이 아닌 하나의 프런트 컨트롤러 서블릿으로 다수의 클라이언트 요청을 받을 수 있고, 다양한 HTTP 요청에 대해 공통 처리가 가능하여 코드 재사용성과 유연성을 높이며 중복을 줄일 수 있다. 또한, 중앙 집중식 제어를 통해 보안이 강화되며 사용자 트랙킹에도 유리하다.
DispatcherServlet이 바로 위 그림에서 공통의 로직을 처리하는 Front-controller 역할을 수행하게 된다
Spring MVC의 Front-Controller = DispatcherServlet
Front-Controller는 어떠한 요청이 와도 매핑해주지 않은 url주소가 오면 안된다.
'개발자 > Spring' 카테고리의 다른 글
[Spring] 간단한 UpDown 게임 구현 (0) | 2022.12.27 |
---|---|
[SPRING] Spring 컨트롤러 메서드 (0) | 2022.12.27 |
[SPRING] Spring MVC // + Controller 자세히. (0) | 2022.12.27 |
[SPRING] 인코딩 필터 (0) | 2022.12.27 |
[SPRING] 의존성(dependencies) (0) | 2022.12.26 |