웹 프로그래밍/Web

[Web] 2. MVC 패턴 - Controller와 View

코딩하는 문과생 2020. 1. 30. 09:07

[Preview]

전체 흐름

- 패턴의 종류: 싱글톤 패턴, MVC패턴...

- jsp와 servlet만 가지고도 만들 수 있다. But, 비효율적

 

***따라서 servlet은 Controller역할, JSP가 View의 역할을 맡는다.***

해당 글 부분

[Front Servlet 생성]

요청과 응답만을 담당
package front.ctrl;

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

/**
 * Servlet implementation class DispatcherServlet
 */
@WebServlet("*.inc")
public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.getWriter().append("Served at: ").append(request.getContextPath());
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

 

 *.inc를 통해 .inc로 들어오는 모든 url을 받을 수 있다.

[Front Servlet 수정]

package front.ctrl;

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

//*.inc로 들어오는 모든 request를 받는다.
@WebServlet("*.inc")
public class DispatcherServlet extends HttpServlet {
	//request 객체를 통해 사용자의 ip나 인코딩 방식을 알아낼 수 있다.
	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException {
		requestProc(request, response);
	}

	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException {
		requestProc(request, response);
	}
	
	protected void requestProc(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException {
		String uri = request.getRequestURI();
		System.out.println("client uri : " + uri);
	}

}
//수정 후 restart

.inc로 접속
.inc로 접속
url 들어올때마다 변경


[Controller 생성]

Class로 생성

- Controller의 역할 -

  1. 파라미터를 Front Controller로부터 넘겨받아서, 때로는 유효성 체크를 진행한다.
  2. 객체를 생성하고 View에 데이터를 심는 작업을 진행한다.

[Controller 인터페이스 생성]

Ctrl에 사용할 메소드 정의
package com.sinc.intern.util;

import java.io.IOException;

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

public interface Controller {
	public void execute(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException;
}

[Ctrl에서 인터페이스의 메소드 구현]

package com.sinc.intern.insa.ctrl;

import java.io.IOException;

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

import com.sinc.intern.util.Controller;

public class SelectCtrl implements Controller{
	@Override
	public void execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("InsertCtrl execute");
		
	}
}
package com.sinc.intern.insa.ctrl;

import java.io.IOException;

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

import com.sinc.intern.util.Controller;

public class InsertCtrl implements Controller{
	@Override
	public void execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("InsertCtrl execute");
		
	}
}

[Factory 생성]

Factory를 통해 Front Controller와 Controller가 연결된다.
Django와 Rails에서 라우터 역할이라 생각하면 될 듯하다.
// 기본 틀
package com.sinc.intern.factory;

import com.sinc.intern.util.Controller;

public class BeanFactory {
	private BeanFactory() {
	}
	
	public static void getInstance() {
		// TODO Auto-generated method stub

	}
	public Controller getBean(String uri) {
		
	}
}
package com.sinc.intern.factory;

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

import com.sinc.intern.insa.ctrl.InsertCtrl;
import com.sinc.intern.insa.ctrl.SelectCtrl;
import com.sinc.intern.util.Controller;

public class BeanFactory {
	private static BeanFactory instance;
	private Map<String, Controller> map = new HashMap<>();
	
	
	
	private BeanFactory() {
		map.put("/incWEB/insert.inc", new InsertCtrl());
		map.put("/incWEB/select.inc", new SelectCtrl());
	}
	
	public static BeanFactory getInstance() {
		if(instance == null) {
			instance = new BeanFactory();
		}
		return instance;
	}
	public Controller getBean(String uri) {
		return map.get(uri);
	}
}

[Front에서 Factory를 통해 작업]

들어오는 url바탕으로 ctrl생성
package front.ctrl;

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

import com.sinc.intern.factory.BeanFactory;
import com.sinc.intern.util.Controller;


@WebServlet("*.inc")
public class DispatcherServlet extends HttpServlet {
	//request 객체를 통해 사용자의 ip나 인코딩 방식을 알아낼 수 있다.
	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException {
		requestProc(request, response);
	}

	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException {
		requestProc(request, response);
	}
	
	protected void requestProc(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException {
		String uri = request.getRequestURI();
		System.out.println("client uri : " + uri);
		
		BeanFactory factory = BeanFactory.getInstance();
		Controller ctrl = factory.getBean(uri);
		
		ctrl.execute(request, response);
		
	}

}

 


[ModelAndView 생성]

Controller와 Front Controller를 이어주기 위해서
package com.sinc.intern.view.util;

public class ModelAndView {
	private boolean send;
	private String path;
	
	public ModelAndView() {
		super();
	}
	public ModelAndView(boolean send, String path) {
		super();
		this.send = send;
		this.path = path;
	}
	public boolean isSend() {
		return send;
	}
	public void setSend(boolean send) {
		this.send = send;
	}
	public String getPath() {
		return path;
	}
	public void setPath(String path) {
		this.path = path;
	}
	@Override
	public String toString() {
		return "ModelAndView send = " + send + ", path = " + path;
	}
}

[반환형 수정 및 Controller 수정]

public interface Controller {
	public ModelAndView execute(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException;
}
public class InsertCtrl implements Controller{
	@Override
	public ModelAndView execute(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException {
		System.out.println("InsertCtrl execute");
		ModelAndView mv = new ModelAndView(false, "greeting.jsp");
		return mv;
	}
}
public class SelectCtrl implements Controller{
	@Override
	public ModelAndView execute(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException {
		System.out.println("SelectCtrl execute");
		ModelAndView mv = new ModelAndView(true, "greeting.jsp");
		return mv;
		
	}
}

- 리다이렉션 방법 차이 확인

sendRedirect와 Forward의 request, response를 하는 방법 차이

[Front  Controller 수정]

protected void requestProc(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException {
		String uri = request.getRequestURI();
		System.out.println("client uri : " + uri);
		
		BeanFactory factory = BeanFactory.getInstance();
		Controller ctrl = factory.getBean(uri);
		
		ModelAndView mv = ctrl.execute(request, response);
		if(mv.isSend()) {
        	//forward로 처리
			RequestDispatcher view = request.getRequestDispatcher(mv.getPath());
			view.forward(request, response);
		}else {
        	//sendRedirect로 처리
			response.sendRedirect(mv.getPath());
		}
	}

forward: ~/select.inc - select로 접근시(true)
sendRedirect: ~/insert.inc - insert로 접근시(false)

결론부터 말하자면, 우리는 앞으로 Forward를 이용해 리다이렉션할 것이다.

[분기방식에 따라 데이터를 가져올 수도 못 가져올 수도 있다.]

public class SelectCtrl implements Controller{
	@Override
	public ModelAndView execute(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException {
		System.out.println("SelectCtrl execute");
		ModelAndView mv = new ModelAndView(true, "greeting.jsp");
		request.setAttribute("msg", "data");
		return mv;
		
	}
}
public class InsertCtrl implements Controller{
	@Override
	public ModelAndView execute(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException, IOException {
		System.out.println("InsertCtrl execute");
		ModelAndView mv = new ModelAndView(false, "greeting.jsp");
		request.setAttribute("msg", "data");
		return mv;
	}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div align="center">안녕하세요, 반갑습니다.</div>
	<hr/>
	Result :: ${msg}
</body>
</html>

forward: ~/select.inc - select로 접근시(true) - 데이터 공유가 가능
sendRedirect: ~/insert.inc - insert로 접근시(false) - 데이터 공유가 불가능