JAVA를 잡아라!...

Spring Framework_ControllerVersion01_DispatcherServlet, HandlerMapping, Controller, ViewResolver 본문

Spring

Spring Framework_ControllerVersion01_DispatcherServlet, HandlerMapping, Controller, ViewResolver

onivv 2024. 3. 4. 17:16

[ Spring MVC구조 ] ⭐

웹의 흐름 : 요청 → 응답 (1cycle)

  1. 사용자(브라우저, Client)가 요청을 보냄
  2. DispatcherServlet(FrontController)에서 요청을 확인
    • 서블릿 컨테이너가 사용자 요청을 받고,
      web.xml 파일이나 어노테이션을 통해 DispatcherServlet에게 어떤 URL 패턴의 요청을 전달할지 설정
      이후 DispatcherServlet은 해당 URL 패턴에 맞는 컨트롤러로 요청을 전달
    • 사용자의 모든 URL요청(xxx.do)을 받아들이고, 요청을 적절한 Controller에 전달
    • web.xml 파일에서 설정
  3. HandlerMapping에서 해당 요청에 대해 어떤 Controller가 처리할지 확인
    • 팩토리 패턴을 활용해 요청(String)을 받으면 Controller(객체)를 반환
    • URL과 컨트롤러의 매핑 : [ key - 요청 URL , value - new xxxController() ]
  4. Controller메서드 수행 후 String 반환(경로, 방식)
    • 어떤 경로로 가야하는지와 어떻게(redirect/forward)가야하는지에 대한 정보를 String으로 반환
    • 메서드 수행 시 Service를 이용하고 Service는 DAO를 이용
    • Controller > Service > DAO (서로가 의존관계)
  5. ViewResolverController에서 반환된 String을 보고 사용자(브라우저, Client)에게 View 페이지를 응답

[ JSP_MVC 패턴_ControllerVersion00 ]

https://onivv.tistory.com/97

 

JSP_MVC2 패턴 & Servlet Container

MVC 1 → MVC 2 Model DTO : 테이블 DAO : 결합도를 낮추기 위해 인자를 DTO 가짐 View 사용자 편의성 UI/UX 유효성 검사 안내 웹 접근성 표준 지침 Controller MVC 1 controller.jsp에서 기능별로 코드를 구현xx → 응

onivv.tistory.com

https://onivv.tistory.com/110

 

Factory Pattern_HandlerMapping

[ Design Patterns ] - ★ MVC Pattern MVC 역할을 분리작업해 응집도를 높이고 결합도를 낮춰 유지보수에 유리한 패턴 Singleton Pattern 객체를 메모리에 1번만 생성(new)함으로써 메모리 사용을 최적화 필요할

onivv.tistory.com

 

✅ 기존 Version00 ▶ 변경 Version01_개발자가 직접 만든 DS, HM, VR

  1. FrontController ▶ DispatcherServlet
    • not POJO인 Servlet 클래스
    • @WebServlet(".*do") : 사용자 요청을 확인
  2. HandlerMapping
    • getAction(String 요청) 메서드를 통해 요청에 맞는 Action객체를 반환
  3. Action ▶ Controller
    • FrontController에서 클래스를 호출할 때, 메서드명을 강제하기 위한 인터페이스
    • 모든 xxxAction은 implements Action을 함으로써 execute()를 @Override 하게됨
  4. ActionForward ▶ ViewResolver
    • execute() return값으로 사용되는 클래스
    • 멤버변수 : 경로, 방식

 

[ ControllerVersion01 ]

web.xml

  • 기존 FrontController는  extends HttpServlet을 상속받는 유일한 Servlet 클래스로,
    @WebServlet("*.do")로 사용자 요청을 받아왔음
  • DispatcherServlet도 HttpServlet을 상속받고 있는 not POJO인 Servlet 클래스로, 서블릿 컨테이너에 의해 관리됨
    Spring MVC에서는 DispatcherServlet 등록을 web.xml 설정 파일에서할 수 있음
web.xml

<servlet>	: HttpServlet을 상속받고 있는 클래스를 web.xml에 등록할 때 사용
<servlet-name>	: 등록하는 Servlet의 이름 부여 (별칭)
<servlet-class>	: Servlet 클래스 경로 지정

<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>com.spring.controller.common.DispatcherServlet</servlet-class>	
</servlet>

<servlet-mapping> : DispatcherServlet 서블릿과 '*.do' URL패턴을 매핑
<servlet-name>	: 실행할 Servlet 이름 지정
<url-pattern>	: Servlet을 실행할 때 사용할 URL 지정

<servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>*.do</url-pattern>	// '.do'로 끝나는 모든 요청이 dispatcherServlet에게 전달
</servlet-mapping>

 

DispatcherServlet.java - Class

package com.spring.controller.common;

import java.io.IOException;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	private HandlerMapping handler;
	private ViewResolver viewResolver;

	public void init() {
		handler = new HandlerMapping();
		viewResolver = new ViewResolver();
		viewResolver.setPrefix("./");
		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 {

		String uri = request.getRequestURI();
		String cp = request.getContextPath();
		String commend = uri.substring(cp.length());

		Controller controller = handler.getController(commend);
		String view = controller.execute(request, response);

		if (!view.contains(".do")) {
			view = viewResolver.getView(view);
		}
		response.sendRedirect(view);

	}
}

 

HandlerMapping.java - Class

  • DispatcherServlet의 멤버변수로 HandlerMapping handler 존재하고,
    getController() 메서드를 통해 URL을 인자로 받고, Controller 객체를 반환해줌
package com.spring.controller.common;

import java.util.HashMap;
import java.util.Map;

import com.spring.controller.member.LoginController;

public class HandlerMapping {
	private Map<String, Controller> mappings;
	
	public HandlerMapping() {
		mappings = new HashMap<String,Controller>();
		
		mappings.put("/xxx.do", new xxxController());
			º
			º
			º
	}
	
	public Controller getController(String commend) {
		return mappings.get(commend);
	}
}

 

Controller.java - Interface

  • HandlerMapping에서 반환해준 Controller 객체는 모두 해당 Interface를 implements함
    모든 xxxController 객체는 execute() 를 @Override 하게됨
package com.spring.controller.common;

import java.io.IOException;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public interface Controller {
	// ActionForward → String
	String execute(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException;
}

 

ViewResolver.java - Class

package com.spring.controller.common;

public class ViewResolver {
	public String prefix;
	public String suffix;

	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}

	public void setSuffix(String suffix) {
		this.suffix = suffix;
	}

	public String getView(String view) {
		return prefix + view + suffix;
	}
}

DispatcherServlet.java

  • DispatcherServlet 클래스의 init() 초기화 메서드를 통해
    ViewResolver 객체를 생성하고 View 페이지 경로의 접두사와 접미사를 초기화

DispatcherServlet.java

  • Controller에서 execute()메서드를 수행하면 String타입의 View페이지의 경로를 return 함
    < return값 3가지 >
    1) redirect 방식 : "redirect:___.do"       
    2) forward 방식 : "___.do"                    (기본적으로 forward 방식 사용)
    3) jsp : "___"
  • return값에 ".do"가 포함되지 않으면 → viewResolver.getView(return값)를 통해  ./___.jsp 로 경로 설정
  • return값에 ".do"가 포함되면 → return값으로 경로 설정