본문 바로가기

개발 패턴/MVC

[개발패턴] <MVC2> Web MVC2 PATTERN NO Spring

M

  • DTO > 테이블
  • DAO 인자를 DTO
  • boolean DTO AL
  • 결합도를 낮추기 위함

V

  • 사용자 편의성 UI/UX
  • 유효성 검사
  • 안내
  • 웹 접근성 표준 지침

C

  • MVC1에서는 controller.jsp에서 action 파라미터를 받아서 if 분기처리하여 코드를 작성한다.
  • 문제점
    • 1) 하나의 기능을 수정한다 해도, 전체 프로그램이 동작하지 않는다.
      • 응집도가 낮아서 문제인 상황이다.
      • 기능별로 묶어놔야 하는 상황이다.
    • 2).jsp는 V를 의미함
      •  C는 JAVA 코드를 사용한다.
      • .java 페이지를 활용하는 것이 바람직하다.
  • 대안
    • MVC2 사용
      • controller.jsp를 controller.java로 변경한다.
      • 각각의 if문 내부의 기능들을 클래스화(모듈화, 컴포넌트화)
        • 응집도가 높아짐 == 유지보수가 용이해짐
      • jsp의 내부객체를 사용해야하기 때문에 .java파일이 아닌 Servlet파일로 생성
        • Servlet 파일은 패키지와 클래스명이 같아서는 안된다.
        • url mapping에 Servlet이 반응 할 키워드를 적어야한다. 
          • *do로 지정할 경우, 경로를 지정할 때 .do를 붙여준다.
          • ex) /main.do, /join.do

Servlet 작성

  • Servlet은 무겁기 때문에 경량화를 위해 Servlet은 단 하나만 생성한다.
  • FrontController 패턴을 사용한다.
    • 프론트 컨트롤러가 요청에 맞는 컨트롤러를 찾아서 호출하는 패턴이다.  
    •  모든 컨트롤러의 앞 단에서 서블릿 하나로 클라이언트의 모든 요청을 받는다.
  • url mapping을 *.do로 정했기 때문에 @WebServlet("*.do")라는 어노테이션이 붙는다.
package controller;

@WebServlet("*.do")
public class FrontController extends HttpServlet {

 

 

  • 방식이 GET이던 POST던 공통으로 로직을 불러올 수 있도록 수정한다.
    • doAction하나로 통일
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 {
                                            
                      
}

 

 

  • doAction에 controller 로직 작성
private void doAction(HttpServletRequest request, HttpServletResponse response) 
						throws ServletException, IOException {

		// controller.jsp 의 코드를 옮겨올예정!

		String uri = request.getRequestURI();
		String cp = request.getContextPath();
		String action = uri.substring(cp.length());
		System.out.println(action);

		if (action.equals("/main.do")) { // ◀ if(action.equals("main")){

			ActionForward forward = new MainAction().execute(request, response);

		} else if (action.equals("/join.do")) {

		} else if (action.equals("/joinPage.do")) {

		} else if (action.equals("/logout.do")) {

		} else if (action.equals("/testPage.do")) {

		} else if (action.equals("/mypage.do")) {

		} else if (action.equals("/loginPage.do")) {

		} else if (action.equals("/login.do")) {

		} else if (action.equals("/replySelectOne.do")) {

		} else if (action.equals("/replyInsert.do")) {

		} else if (action.equals("/replyUpdate.do")) {

		} else if (action.equals("/replyDelete.do")) {

		} else if (action.equals("/changeName.do")) {

		} else if (action.equals("/memberDelete.do")) {

		} else {

		}
	}

메서드명을 일괄적으로 강제하기 위한 인터페이스

  • FrontController 에서 기능 클래스를 호출할때에 메서드명을 일괄적으로 강제하고싶어서 인터페이스 사용한다.
package controller;

import java.io.IOException;

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

public interface Action {

	void execute(HttpServletRequest request, HttpServletResponse response) 
    						throws ServletException, IOException;

}

 

 

  • execute기능에서는 경로와 방식(리다이렉트, 포워드) 두 가지를 리턴해줘야하기 때문에 자료형을 만들어줄 필요가 있다.
package controller;

public class ActionForward {

	private String path; // 어디로 가야하는지 == 경로
	private boolean redirect; // 어떻게 갈지 == 리다이렉트 or 포워드
	
	public ActionForward() {
		
	}

	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;
	}

}

 

 

  • execute의 자료형을 ActionForward로 지정한다.
package controller;

import java.io.IOException;

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

public interface Action {

	ActionForward execute(HttpServletRequest request, HttpServletResponse response) 
    						throws ServletException, IOException;

}

기능 클래스 제작

  • 메서드명을 통일하기 위해 만든 Action 인터페이스를 implements한다.
public class MainAction implements Action{

 

 

  • 메서드 오버라이딩한다.
@Override
public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
						throws ServletException, IOException {

 

 

  • 기능을 기술한다.
public class MainAction implements Action{

	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
							throws ServletException, IOException {
                        
		ActionForward forward = new ActionForward();
		forward.setPath("/main.jsp");
		forward.setRedirect(false); // false = pageContext.forward("main.jsp");
  					    // true = sendRedirect
		
		request.setCharacterEncoding("UTF-8");
		
		ReplyDAO rDAO = new ReplyDAO();
		ReplyDTO rDTO = new ReplyDTO();
		ArrayList<ReplyDTO> rdatas=rDAO.selectAll(rDTO);
		request.setAttribute("rdatas", rdatas);
		
		MemberDAO mDAO=new MemberDAO();
		MemberDTO mDTO=new MemberDTO();
		ArrayList<MemberDTO> mdatas=mDAO.selectAll(mDTO);
		request.setAttribute("mdatas", mdatas);
		
		return forward;
	}

}

 


전체 흐름

  • 인덱스 페이지에서 main.do 호출
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	response.sendRedirect("main.do");
	// controller.jsp?action=main
	// .do 가 이미 C 를 호출
	// 파라미터를 절약하기위해 main.do 로 호출
%>

 

 

  • FrontController에서 if문으로 main.do를 찾아 로직 수행
private void doAction(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// controller.jsp 의 코드를 옮겨올예정!

		String uri = request.getRequestURI();
		String cp = request.getContextPath();
		String action = uri.substring(cp.length());
		System.out.println(action);

		ActionForward forward = null;
		
		if (action.equals("/main.do")) { ←←←←←←
			
			forward = new MainAction().execute(request, response); ←←←←←←
			
		} else if (action.equals("/join.do")) {
			
			forward = new JoinAction().execute(request, response);

 

 

  • MainAction의 execute 로직을 수행
  • 경로와 방식(리다이렉트, 포워드)를 반환한다.
public class MainAction implements Action{

	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
            
		ActionForward forward=new ActionForward();
        
		forward.setPath("/main.jsp"); ←←←←←← 이동 경로 지정
        
		forward.setRedirect(false); ←←←←←← 방식 지정
		
		request.setCharacterEncoding("UTF-8");
		
		ReplyDAO rDAO=new ReplyDAO();
		ReplyDTO rDTO=new ReplyDTO();
		ArrayList<ReplyDTO> rdatas=rDAO.selectAll(rDTO);
		request.setAttribute("rdatas", rdatas); 
		
		MemberDAO mDAO=new MemberDAO();
		MemberDTO mDTO=new MemberDTO();
		ArrayList<MemberDTO> mdatas=mDAO.selectAll(mDTO);
		request.setAttribute("mdatas", mdatas);
		
		return forward; ←←←←← 값 반환
     
	}

}

 

 

  • 반환 받은 값으로 포워딩
if (forward.isRedirect()) {
			
	response.sendRedirect(forward.getPath());
			
	} else {
			
		RequestDispatcher dispatcher = request.getRequestDispatcher(forward.getPath());
			
		dispatcher.forward(request, response);
				
	}
        
 }