코딩항해기

[Spring] springframework.DispatcherServlet 구조 본문

Spring

[Spring] springframework.DispatcherServlet 구조

miniBcake 2024. 10. 7. 19:39

 

 

org.springframework.web.servlet.DispatcherServlet

 

DispatcherServlet은 이름에도 쓰여있듯이 Servlet 파일이다. Spring에서는 페이지 이동 구분을 ViewResolver가 해주기 때문에 ViewResolver에 대한 의존성을 가지고 있으며, 객체관리를 위해 HandlerMapping을 사용하기 때문에 HandlerMapping에 대한 의존성도 가지고 있다.

 

그 외의 형태는 JSP기반 FrontController와 유사한 형태를 가지고 있다.

 

1. 사용자의 요청을 추출

2. 요청에 해당하는 기능을 수행 (HandlerMapping사용)

3. 응답 (ViewResolver사용)

 

Servlet으로 구조를 보면 이러한 형태를 가지고 있다고 볼 수 있다.

@WebServlet("*.do")
public class DispatcherServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private HandlerMapping handlerMapping;
    private ViewResolver viewResolver;

    public DispatcherServlet() {
        super();
    }

    public void init() {
        this.handlerMapping = new HandlerMapping();
        this.viewResolver = new ViewResolver();
        //세터주입
        this.viewResolver.setPrefic("./");
        this.viewResolver.setSuffix(".jsp");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doAction(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doAction(request, response);
    }

    private void doAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 사용자(클라이언트,브라우저)의 요청 추출
        String uri=request.getRequestURI();
        String command=uri.substring(uri.lastIndexOf("/"));

        // 2. 요청에 해당하는 Controller 기능을 수행
        // 팩토리 패턴을 활용하는 handlerMapping
        String path=this.handlerMapping.getController(command).execute(request, response);

        // 3. 응답(페이지 이동)
        //viewResolver를 사용하여 응답
        if(!path.contains(".do")){
            this.viewResolver.getView(path); //뷰로 갈 수 있게 요청완성
        }
        response.sendRedirect(path);
    }
}

 

DispatcherServlet은 오래된 코드이므로 생성자가 아닌 init을 통해 초기화하고 있다.

 

DispatcherServlet은 springframework에서 제공하고 있는데, web.xml(톰캣)에서 태그로 생성해줄 수 있다.

일반 @WebServlet이 대체한 태그와 동일한데, 클래스를 불러오는 곳이 springframework이다.

 

    <servlet>
        <servlet-name>ds</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--스프링에서 제공하는 Servlet 사용-->
    </servlet>
    <servlet-mapping>
        <servlet-name>ds</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

 

ds라는 이름으로 DispacherServlet을 불러오고 있으며, 이 ds는 .do로 끝나는 모든 요청을 처리한다.

ds는 ds(설정한 서블릿명)-servlet.xml라는 설정 파일을 필요로 하므로 web-inf 하위에 생성해야한다.

 

ds-servlet.xml에는 DispacherServlet이 의존성을 가지고 있는 HandlerMapping과 ViewResolve가 등록되어 있어야한다.

(1007 아직 ViewResolve 진도가 덜 나가 여기까지 정리했다.)

(1008 VeiwResolver 진도 후 추가)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--HandlerMapping과 ViewResolver에 대한 의존성을 가지고 있으므로 추가-->
    
    <!--ds의 HandlerMapping은 한 개라 id 생략가능-->
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <!--SI 주입-->
        <property name="mappings">
            <props>
                <!--<prop key="키 값 ">밸류 값</prop>-->
                <prop key="/login.do">login</prop>
                <prop key="/boardWrite.do">boardWrite</prop>
            </props>
        </property>
    </bean>

	<!--Bean 등록-->
    <bean class="com.koreait.app.view.member.LoginController" id="login"/>
    <bean class="com.koreait.app.view.board.BoardWriteController" id="boardWrite"/>

    <!--어노테이션 스캔-->
    <!--컨트롤러 Autowired 스캔 이후 Repository도 필요하므로 같이 스캔-->
    <context:component-scan base-package="com.koreait.app.view"/>
    <context:component-scan base-package="com.koreait.app.biz"/>

    <!--ViewResolver는 여러 개 될 수 있으므로 id를 반드시 기입-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver">
        <!--SI 주입-->
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

 

HandlerMapping을 등록하기 위해서는 생성할 객체에 대한 Bean이 필요하고 해당 Controller 객체와 Controller 객체가 의존하는 객체가 어노테이션으로 설정되어 있기 때문에 해당 어노테이션을 인지할 수 있도록 context:compent-scan 태그를 사용해 스캔 범위를 지정한다.

 

ViewResolver에서는 SI주입(setter 주입)을 통해 String 값에 대한 의존성을 주입할 수 있으며, 웹 페이지 구동 시 데이터가 필요한 페이지는 사용자가 함부러 접근할 수 없는 WEB-INF 하위에 있으므로 필요한 경로를 작성한다.

 

다시 말해 ViewResolver는 WEB-INF 하위에 있는 페이지에 접근할 때만 사용된다. 사용하지 않을 때는 path앞에 redirect:를 붙여 해당 요청이 리다이렉트이고 ViewResolver를 사용하지 않을 것임을 설정할 수 있다.