이번 포스팅에서는 DispatcherServlet과 ViewResolver의 역할, 의존성 주입 방식, 그리고 JSP에서 스프링으로 넘어가는 과정에 대해 다루려고 한다.
DispatcherServlet의 기본 구조
DispatcherServlet은 스프링 프레임워크에서 요청을 처리하고, 적절한 컨트롤러로 전달한 뒤 응답을 제공하는 중심 역할을 담당하는 서블릿이다.
이 서블릿은 FrontController 역할을 하며, 클라이언트의 요청을 받아들이고 HandlerMapping을 통해 적절한 컨트롤러를 찾아 처리 후, ViewResolver를 통해 응답을 생성한다.
즉, FrontController == DispatcherServlet 라고 생각하면 된다.
package com.yn.app.view.controller;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@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() { // init 생성 함수로 주입
this.handlerMapping = new HandlerMapping(); // 생성자 주입
this.viewResolver = new ViewResolver(); // setter 주입 이므로 기본생성자 + setter까지 호출함
this.viewResolver.setPrefix("./");
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);
}
//get인지 post인지 모르기에 모든 액션을 처리하는 doAction 생성
private void doAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 사용자(클라이언트, 브라우저)의 요청 추출
String uri = request.getRequestURI();
String command = uri.substring(uri.lastIndexOf("/"));
// 2. 요청에 해당하는 Controller 기능을 수행
Controller controller = this.handlerMapping.getController(command);
// 팩토리 패턴을 활용하는 handlerMapping
String path = controller.execute(request, response);
// 3. 응답(페이지 이동)
if(!path.contains(".do")) {
// C로 보내주세요 라는 뜻
path=this.viewResolver.getView(path);
}
response.sendRedirect(path);
}
}
@WebServlet 어노테이션
XML 설정 방식 대신, 스프링에서는 @WebServlet 어노테이션을 사용해 서블릿을 정의할 수 있다.
이 어노테이션을 사용하면 XML 파일에 추가 설정 없이 서블릿 매핑이 가능하다.
@WebServlet("*.do")
public class DispatcherServlet extends HttpServlet {
.
.
.
@ViewResolver와 Forward/ Redirect
ViewResolver는 스프링에서 페이지 이동을 담당하는 객체로, 컨트롤러가 반환하는 String 값만으로도 어떤 페이지로 이동할지를 결정해준다.
JSP에서는 ActionForward를 사용해 페이지 이동을 처리하지만, 스프링에서는 ViewResolver가 이를 대신한다.
JSP / ActionForward 예시 )
package controller.common;
public class ActionForward {
private String path;
private boolean redirect;
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public boolean isRedirect() {
return redirect;
}
public void setRedirect(boolean redirect) {
this.redirect = redirect;
}
}
Spring / ViewResolver 예시 )
package com.yn.app.view.controller;
public class ViewResolver {
private String prefix;
private String suffix;
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
public String getView(String path) { // ./ login .jsp
return prefix + path + suffix;
}
}
Spring에서는 prefix와 suffix를 이용해 JSP 파일의 경로를 설정할 수 있으며, 단순히 문자열을 반환해도 스프링이 자동으로 포워딩/리다이렉팅을 처리해준다.
Controller가 반환한 View 이름이 login일 때, ViewResolver는 앞에 ./와 뒤에 .jsp를 붙여서 최종적으로 ./login.jsp 파일을 찾는다.
ViewResolver는 클라이언트 요청에 따라 "어디로 페이지 이동을 시킬지" 결정하는 역할을 한다.
의존성 주입 방식
Spring에서는 DispatcherServlet 내에서 HandlerMapping과 ViewResolver를 의존성 주입 방식으로 사용한다.
Spring에서 의존성 주입은 생성자 주입, Setter 주입, @ 어노테이션 주입 세 가지 방식이 있으며, 각각의 방식에 따라 객체를 주입할 수 있다.
1) FrontController - DispatcherServlet - init
- FrontController는 MVC 패턴에서 모든 요청을 받아서 처리하는 중앙 관리자 역할을 한다.
- Spring에서는 DispatcherServlet이 이 FrontController 역할을 하며, 모든 웹 요청을 받아서 적절한 Controller로 분배한다.
- init 주입은 DispatcherServlet이 처음 생성될 때, 필요한 의존성을 초기화하는 방식을 의미한다. DispatcherServlet이 서블릿이기 때문에, 서블릿 컨테이너(Tomcat)가 이 서블릿을 관리하고 주입 과정을 처리한다.
2) HandlerMapping - 생성자 주입
- HandlerMapping은 들어오는 요청 URL을 분석하여, 해당 URL에 맞는 Controller를 찾아주는 역할을 한다. 이때 요청된 경로와 그에 맞는 Controller를 매핑(mapping)한다.
- 생성자 주입은 객체가 생성될 때, 필요한 의존성을 생성자를 통해 전달받는 방식이다. HandlerMapping은 생성될 때 DispatcherServlet에 의해서 주입된다. DispatcherServlet의 init 메서드에서 HandlerMapping 객체가 생성된다.
public void init() { // init 생성 함수로 주입
this.handlerMapping = new HandlerMapping(); // 생성자 주입
this.viewResolver = new ViewResolver(); // setter 주입 이므로 기본생성자 + setter까지 호출함
this.viewResolver.setPrefix("./"); //setter
this.viewResolver.setSuffix(".jsp"); // setter
}
3) ViewResolver - Setter 의존 주입
- ViewResolver는 Controller가 반환하는 View 이름(String)을 보고, 실제 페이지 파일 경로를 찾아주는 역할을 한다. 예를 들어, login이라는 View 이름을 반환하면 ViewResolver는 해당 페이지의 파일 경로를 결정한다.
- 접두어(prefix)와 접미어(suffix)를 사용하여 최종 경로를 만들어낸다. 예를 들어, ViewResolver는 ./와 .jsp를 설정하여, Controller에서 login을 반환할 경우 ./login.jsp로 해석한다.
- Setter 주입은 생성자가 아닌, 메서드를 통해 필요한 의존성을 주입하는 방식이다. ViewResolver는 setPrefix()와 setSuffix() 메서드를 통해 접두어와 접미어를 설정받는다.
Spring MVC 구조
최종적으로 DispatcherServlet은 Spring에서 요청을 중앙에서 관리하는 FrontController 역할을 하며, HandlerMapping을 통해 요청 URL에 맞는 Controller를 찾는다.
그 이후, Controller가 반환한 View 이름을 ViewResolver가 처리하여 적절한 JSP 파일로 변환해 최종적으로 클라이언트에게 응답을 전달한다.
'Spring' 카테고리의 다른 글
[Spring] ViewResolver (1) | 2024.10.09 |
---|---|
[Spring] DispatcherServlet과 Spring MVC의 핵심 흐름 분석 (0) | 2024.10.07 |
[Spring] Spring DI와 비즈니스 로직 (2) | 2024.10.06 |
[Spring] Spring에서의 객체 관리: XML 설정 파일 vs 어노테이션 기반 DI (4) | 2024.10.04 |
[Spring] 의존성 주입 (0) | 2024.10.02 |