[JSP] 홈페이지 만들기 (2) : MVC 패턴

·2023년 11월 14일
0

jsp

목록 보기
14/18
post-thumbnail

2. MVC 패턴

(1) MVC 패턴이란?

내가 지금까지 만들었던 jsp 프로젝트 MyHome 은 Model1이다.
jsp 파일과 파일로 값을 옮길 때 page로만 값을 이동시키고, 한 번에 눈에 들어오는 디자인이 아니다. 이렇게 홈페이지를 구성하면 나중에 코드 복잡도가 높아져 코드 작성, 수정 및 유지보수 과정에서 매우매우매우 개고생하게 된다. (마치 나의 OzPcServer 처럼...)

그런데 만약 servlet 에서 모든 request 와 reponse 를 관리하고, 값을 보내주고 받아오는 기능을 다 해 준다면?

훨씬 쉽고 통일감 있는 구성이 가능하다.

📌 MVC 패턴의 정의

MVC는 Model-View-Controller의 약자로, 소프트웨어 개발에서 사용되는 설계 패턴 중 하나이다. 이 패턴은 소프트웨어를 세 가지 주요 구성 요소로 나누어 개발하고 유지보수하는 데 도움이 된다.

⭐ Model (모델):

  • 데이터와 데이터 처리를 담당한다.
  • 데이터의 상태를 관리하고 데이터의 변경을 감지하여 관련된 뷰와 컨트롤러에 알린다.
  • 주로 비즈니스 로직, 데이터베이스 연동 등의 역할을 수행한다.

⭐ View (뷰):

  • 사용자에게 보여지는 부분을 담당한다.
  • 모델의 데이터를 시각적으로 표현하며, 사용자 인터페이스를 통해 사용자와 상호 작용한다.
  • 모델의 변경 사항을 감지하고 해당 변경을 반영하여 업데이트한다.

⭐ Controller (컨트롤러):

  • 사용자 입력을 받고 해당 입력에 대한 처리를 담당한다.
  • 모델과 뷰 간의 상호 작용을 조정하고 업데이트를 관리한다.
  • 사용자의 행동에 따라 모델을 업데이트하고, 그 결과를 뷰에 반영한다.

MVC 패턴은 이러한 세 가지 구성 요소 간의 강한 결합을 피하고, 각각을 독립적으로 유지하여 소프트웨어의 확장성과 유지보수성을 향상시킨다. 이는 코드를 분리하여 각 부분이 서로 영향을 덜 주면서 독립적으로 변경될 수 있도록 해 준다.

📌 MVC 패턴 내가 아는 예로 들면?

이렇게 생각하면 너무 쉽다.

Model = dao
Controller = 서블릿
view = jsp, react, view, (프론트엔드)

(2) Servlet = Controller

그럼 이제부터 controller 에 대해 알아가 보자.
나는 Member.jsp 를 MVC 패턴대로 따라가며 구성해 보고, 그에 쓰이는 디자인 패턴과 자바 기능을 설명하고자 한다.

📌 1단계 : Command 패턴으로 comd 설정하기

MemberServlet.java

package member;

import java.io.IOException;

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

public class MemberServlet extends HttpServlet{

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setCharacterEncoding("EUC-KR");
		resp.setContentType("text/html; charset=EUC-KR");
		
		// 클라이언트의 요청 URL을 가져옴
        String url = req.getRequestURI();
        // 현재 웹 어플리케이션의 컨텍스트(경로)를 가져옴
        String path = req.getContextPath();
        // 요청 URL에서 컨텍스트를 제외한 부분을 가져와서 cmd에 저장
        String cmd = url.substring(path.length());
        // substring 메서드는 문자열에서 특정 범위의 문자열을 추출하는 데 사용되는 
        // Java의 문자열 메서드 중 하나입니다. 
        // 이 메서드는 원본 문자열에서 시작 인덱스부터 끝 
        // 인덱스 전까지의 부분 문자열을 반환합니다.
        
        
		MemberCommandFactory factory = MemberCommandFactory.getInstance();
		CommandIf cmdIf = factory.createCommand(cmd);
		String nextPage = (String)cmdIf.processCommand(req, resp);
		RequestDispatcher view = req.getRequestDispatcher(nextPage);
		view.forward(req, resp);		
	}
	
}

값이 들어오면 무조건 이쪽으로 오게 하는 서블릿 페이지이다. 이 서블릿 페이지를 어떻게 관리하느냐?

⭐ Command 패턴

목적: 특정한 동작 또는 요청을 객체로 캡슐화하여 매개 변수화하고, 큐에 저장하거나 로깅하며, 실행 취소할 수 있는 연산을 지원한다.
구성 요소:
Command: 실제 요청을 나타내는 인터페이스를 정의하고, 이를 구현하는 구체적인 클래스가 있다.
Client: Command 객체를 생성하고 ConcreteCommand를 설정하여 Receiver와 연결한다.
Invoker: Command를 실행하는 객체로, ConcreteCommand에 대한 요청을 책임진다.
Receiver: 실제 동작을 수행하는 객체이다.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
	<servlet-name>front</servlet-name>
	<servlet-class>FrontAppServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>front</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet>
	<servlet-name>member</servlet-name>
	<servlet-class>member.MemberServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>member</servlet-name>
	<url-pattern>*.mem</url-pattern>
</servlet-mapping>
<servlet>
	<servlet-name>board</servlet-name>
	<servlet-class>board.BoardServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>board</servlet-name>
	<url-pattern>*.board</url-pattern>
</servlet-mapping>


</web-app>

끝에 mem 값을 갖는 그 어떤 주소이든~ 바로 MemberServlet 으로 들어오게 된다. 그래서 서블릿이 값을 관리하기 편하게 해 준다.

📌 2단계 : Singleton 패턴으로 factory instance 하나만 만들기

MemberCommandFactory factory = MemberCommandFactory.getInstance();

목적
특정 클래스가 인스턴스화될 때 하나의 인스턴스만을 생성하고, 그 인스턴스에 접근할 수 있는 전역적인 점근점을 제공합니다.
특징
생성자가 private이므로 외부에서 직접 인스턴스를 생성할 수 없습니다.
정적 메서드나 메서드로 접근할 수 있는 정적 멤버를 통해 유일한 인스턴스에 접근할 수 있습니다.
전역 상태를 피하고 객체 간에 공유된 상태를 유지할 때 유용합니다.

public class MemberCommandFactory {
	private MemberCommandFactory() {}
	private static MemberCommandFactory instance = new MemberCommandFactory();
	public static MemberCommandFactory getInstance() {
		return instance;
	}

📌 3단계 : CommandIf 로 command 패턴으로 나눠주기~

package member;

import java.io.IOException;

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

public class MemberInputCommand implements CommandIf {

	@Override
	public Object processCommand(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		return "WEB-INF/member/member_input.jsp";
	}

}

이렇게 해서 어떤 command 든 받을 수 있게 준비 완료 해 놓기
CommandIf 의 의도는 여러 사람이 같이 만들겠다는 뜻이다.
클래스 이름만 알면 밑에서 올려 보낼 수 있게 해 주는 것.

📌 4단계 : FactoryPattern 으로

다형성으로다가 여기 밑에서 구성한 걸 CommandIf로 올려 보내준다. 다형성

목적
객체 생성을 캡슐화하여 클라이언트가 생성할 구체적인 클래스를 지정하지 않고도 객체를 만들 수 있게 합니다.
종류
Factory Method 패턴: 서브클래스에서 객체를 생성하는 메서드를 정의하고, 이를 통해 객체를 생성합니다.
Abstract Factory 패턴: 여러 관련 객체의 집합을 생성할 수 있는 인터페이스를 제공하며, 이를 구현하는 여러 팩토리 클래스를 생성합니다.
Simple Factory 패턴: 하나의 팩토리 클래스에서 객체의 생성을 담당하며, 클라이언트는 팩토리 클래스를 통해 객체를 생성합니다.

package member;

public class MemberCommandFactory {
	private MemberCommandFactory() {}
	private static MemberCommandFactory instance = new MemberCommandFactory();
	public static MemberCommandFactory getInstance() {
		return instance;
	}
	
	public CommandIf createCommand(String cmd) {
		CommandIf cmdIf = null;
		if (cmd.equals("/index.mem")) {
			cmdIf = new IndexMemberCommand();
		}else if (cmd.equals("/memberSsn.mem")) {
			cmdIf = new MemberSsnCommand();
		}else if (cmd.equals("/member_check.mem")) {
			cmdIf = new MemberCheckCommand();
		}else if (cmd.equals("/member_input.mem")) {
			cmdIf = new MemberInputCommand();
		}else if (cmd.equals("/member_input_ok.mem")) {
			cmdIf = new MemberInputOkCommand();
		}
		
		return cmdIf;
	}
}

이러면 너무 쉬운 MVC 패턴 이해 완료.
이렇게 하고 나서 적용만 하면 된다.

profile
자바 백엔드 개발자 개인 위키

1개의 댓글

comment-user-thumbnail
2023년 11월 14일

정보 감사합니다.

답글 달기

관련 채용 정보