열심히 끝까지

디바이스 융합 자바(Java) day68 - Spring에서의 MVC2 패턴 본문

디바이스 융합 자바(Java)기반 풀스택 개발자 양성과정(수업내용)

디바이스 융합 자바(Java) day68 - Spring에서의 MVC2 패턴

노유림 2022. 9. 19. 17:44

[ MVC 패턴의 변화 ]
.jsp 작업을 할 때, ...

1) main.jsp
   <%
           if(요청 메서드가 POST일 때) {
                vo에 사용자가 form에 작성한 데이터를 매핑해서 setter 하는 코드;
           }
           DB와 연동할 수 있는 코드;
    %>
           <form>
           </form>

2) main.jsp + ctrl.jsp
           <form action="ctrl.jsp?action=insert">
           </form>
---------------------------
<jsp:useBean vo>
<jsp:setProperty vo>
<%
          if(요청한 기능이 ㅁㅁㅁ일 때) {
                vo에 사용자가 form에 작성한 데이터를 매핑해서 setter 하는 코드;
                DB와 연동할 수 있는 코드;
          }
%>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
   <jsp:useBean id=""/>
   <jsp:setProperty property="" name=""/>
   <!-- 2번과 비슷 -->
<%
	String mid=request.getParameter("mid");
	String mpw=request.getParameter("mpw");
	
	MemberDAO mDAO = new MemberDAO();
	
	if(action.equals("login")){
		mvo = mDAO.selectOne(mvo);
		if(mvo==null){
			이전 페이지;
		}
		else{
			메인페이지
		}
	}
%>

>> 회사에서 1, 2번으로 하고 있는 회사는 거의 없음


3) main.jsp + Frontcontroller.java(서블릿) => MVC2 패턴 적용
           <form action="insert.do">
           </form>
---------------------------
서블릿 컨테이너(==톰캣,웹서버)에게 *.do 요청에 대해서 
FrontController 서블릿으로 올 수 있도록 매핑 설정을 해줘야 함
   -> web.xml
   => @webServlet("*.do")



>> com.ryo.biz.common에 ctrl 작성하지만
     파악하기 위해 새로 package 생성


4) MVC2의 과정을 Spring 스타일로 직접 제작해보자!!!!
FrontController 역할을 하는 서블릿을 DispatcherServlet이라고 함
DS(DispatchServlet)는 Action 역할을 수행하는 Controller 들을 호출해서 사용자의 요청을 처리함
DS는 자신이 직접 C들을 하지 않고 HandlerMapping을 통해서 호출함
C는 수행의 결과로 다음 View의 경로(String)를 반환(ActionForward 반환)하는데, 
이 경로 정보는 ViewResolver(어떻게 가야하는지를 잘 처리해줄 수 있는 객체 == boolean)에게 전달되어 
사용자에게 view 화면(String)을 제공해줌

// 기존에는 actionForwardExecute였는데 어떻게가 반환 되기 때문에 String만 반환하면 된다!!!
// ViewResolver가 .jsp를 추가하기 때문에 생략해서 반환

>> Servlet에 @(어노테이션)이 없는데..?
   : web.xml에 존재(src>main>webapp>WEB-INF>web.xml)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>com.ryo.biz.controller.DispatcherServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

>> 다음 항목은 삭제할 것(servlet-name 위에 있었음)
    <description></description>
    <display-name>DispatcherServlet</display-name>

 


순서 정리
사용자의 요청 --*.do--> DS(DispatcherServlet)(FC 격) -> HM(HandlerMapping) -
-> C호출 -> 경로정보를 반환 -> VR(ViewResolver) -> 사용자에게 화면을 제공

 

- ViewResolver.java

package com.ryo.biz.controller;

public class ViewResolver {
	public String prefix; // ex )  app
	// 의존관계 -> DI -> setter 주입
	public String suffix; // ex ) .jsp
	// 의존관계 -> DI -> setter 주입
	
	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 viewName) {
		return prefix+viewName+suffix; 
		// Spring 프레임워크에서 제공하는 패턴
		// 정확한 경로 퉤 하고 뱉음
	}
}

- DS(DispatchedServlet).java : FC(FrontController와 같은 역할)

package com.ryo.biz.controller;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * Servlet implementation class DispatcherServlet
 */
public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	// 스프링 프레임워크에서 제공하는 방식을 강사님께서 사용
	// 의존관계 발생
	private HandlerMapping handlerMapping;
	private ViewResolver viewResolver;
	// init() 메서드를 통해서 DI에 진입
	public void init() throws ServletException{
		handlerMapping = new HandlerMapping();
		viewResolver = new ViewResolver();
		viewResolver.setPrefix("./");
		viewResolver.setSuffix(".jsp");
	}
    /**
     * @see HttpServlet#HttpServlet()
     */
    public DispatcherServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doAction(request,response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		doAction(request,response);
	}

	private void doAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String command=request.getRequestURI();
		command=command.substring(command.lastIndexOf("/"));
		
		System.out.println(command);
		
		Controller ctrl=handlerMapping.getController(command);
		String viewName=ctrl.handleRequest(request, response);
		// null은 화면을 호출하지 않음
		
		String view = null;
		if(viewName.contains(".do")) {
			view=viewName; // 그냥 이동하면 됨
		}
		else {
			view = viewResolver.getView(viewName); 
			// 추가하여 저장
		}
		response.sendRedirect(view);
		
	}
}


- HM(Handler Mapping).java

package com.ryo.biz.controller;

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

public class HandlerMapping { // 싱글톤 패턴이 유지됨
	// input : 어떤 요청에 대해 == String
	// output : 무슨 Controller 객체를 제공해야하는지 == Controller
	// 객체의 무분별한 생성을 막기 위해서 == 싱글톤 패턴을 유지하기 위해서 HandlerMapping 사용
	private Map<String,Controller> mappings; // 의존관계 -> DI => 생성자 주입
	
	// 만들어지는 시점에 
	public HandlerMapping() { // 생성자로 new
		mappings = new HashMap<String,Controller>();
		mappings.put("/login.do", new LoginController()); // 객체만 꺼내서 사진
		mappings.put("/main.do", new MainController());
		mappings.put("/signin.do", new SigninController());
		mappings.put("/board.do", new BoardController());
	}
	
	
	public Controller getController(String command) {
		// controller 객체를 반환
		return mappings.get(command);
	}
}

 

    : 의존관계 존재함 - mappings
        mappings에 DI - 생성자 주입

 

- Controller.interface

package com.ryo.biz.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface Controller {
	String handleRequest(HttpServletRequest request, HttpServletResponse response);
	// 기존에는 actionForwardExecute였는데 어떻게가 반환 되기 때문에 String만 반환하면 된다!!!
}

- LoginController.java(MemberDAO2[jdbc Template 사용])

package com.ryo.biz.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import com.ryo.biz.member.MemberService;
import com.ryo.biz.member.MemberVO;
// import com.ryo.biz.member.impl.MemberDAO;

public class LoginController implements Controller{
	
	@Override
	public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
		// MemberDAO2를 사용할 시 가져와야할 것
		AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
		MemberService ms = (MemberService)factory.getBean("memberService");
		
		String mid=request.getParameter("mid");
		String mpw=request.getParameter("mpw");
		// MemberDAO mDAO = new MemberDAO(); // MemberDAO 사용 시
		MemberVO mVO = new MemberVO();
		mVO.setMid(mid);
		mVO.setMpw(mpw);
		// mVO = mDAO.selectOneMember(mVO); // MemberDAO 사용 시
		mVO = ms.selectOneMember(mVO);
		factory.close();
		if(mVO==null) {
			return "login";
			// ViewResolver가 .jsp를 추가하기 때문에 생략해서 반환
		}
		else {
			HttpSession session = request.getSession();
			session.setAttribute("member", mVO);
			
			return "main.do";
		}
	}
	
}

 

>> 좋아지는 것
※ 메모리를 불필요하게 사용하던 객체들이 현저히 줄어듦
※ 하드코딩이 줄어듦(ㅁㅁㅁ.execute) (코드의 불필요한 반복패턴이 줄어듦) => 코드가 간결해짐
※ 결합도가 엄청 낮아짐 + 응집도가 높아짐 => 유지보수 용이