Search
Duplicate
📒

[Spring Study] 04-1. MVC 패턴 등장 / 적용과 한계

상태
수정중
수업
Spring Study
주제
MVC
연관 노트
3 more properties
참고

MVC(Model View Controller)

NOTE
MVC 패턴컨트롤러(Controller)뷰(View)라는 영역으로 서로 역할을 나누는 것을 말한다.
MVC 패턴 이전 → 비즈니스 로직과 뷰 로직이 합쳐져 있다.
MVC 패턴 1 → Controller(비즈니스 로직) / View(뷰 로직)을 분리했다.
MVC 패턴 2 → 기존 Controller를 Controller는 HTTP 요청 / Service는 비즈니스 로직으로 분리
MVC 패턴2 세부내용
MVC 패턴2 흐름
Controller
HTTP 요청을 받아서 파라미터를 검증하고, 비즈니스 로직을 실행한다.
ModelView 사이의 데이터 전달 역할
자바에서 ControllerServlet을 사용하게 된다.
Model
View에 출력할 데이터를 담아둔다
Controller로 부터 View가 필요한 데이터를 담는다.
View는 화면을 렌더링 하는 일에 집중할 수 있다
View
Model에 담겨있는 데이터를 사용해서 그리는 일에만 집중한다
Service
Controller에서 넘어온 요청을 받아 알맞은 정보를 가공해서 보냄
비즈니스 로직 수행, DAO를 이용해 결과값 받음
DAO
Mysql 서버에 접근하여 SQL문을 실행할 수 있는 객체

MVC 패턴 적용

NOTE
아래와 같은 구조로 MVC 패턴을 적용해보자!
Controller
서블릿
View
JSP
Model
HttpServletRequest 객체
request는 내부에 데이터 저장소를 가지고 있다.
request.setAttribute()
request.getAttribute()

회원 등록 폼 이동

NOTE
@WebServlet(name = "mvcMemberFormServlet", urlPatterns = "/servlet-mvc/members/new-form") public class MvcMemberFormServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String viewPath = "/WEB-INF/views/new-form.jsp"; RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath); dispatcher.forward(request, response); } }
Java
복사
/WEB-INF
/WEB-INF 폴더는 외부에서 접근할 수 없도록 설정되어 있는 폴더이다
해당 폴더에 접근하려면 애플리케이션 내부적으로 즉 Servlet을 통해 접근해야 함
redirect vs foward
redirect
클라이언트에 응답이 나갔다가 클라이언트가 redirect 경로로 다시 요청한다
클라이언트가 인지할 수 있고, URL도 실제로 변경됨
foward
서버 내부에서 일어나는 호출이기 때문에 클라이언트가 알지못한다.

회원 저장

NOTE
@WebServlet(name = "mvcMemberSaveServlet", urlPatterns = "/servlet-mvc/members/save") public class MvcMemberSaveServlet extends HttpServlet { private MemberRepository memberRepository = MemberRepository.getInstance(); @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Member 저장 String username = request.getParameter("username"); int age = Integer.parseInt(request.getParameter("age")); Member member = new Member(username, age); memberRepository.save(member); // Model에 데이터를 보관 request.setAttribute("member", member); // 특정 URL로 forward String viewPath = "/WEB-INF/views/save-result.jsp"; RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath); dispatcher.forward(request, response); } }
Java
복사
ModelHttpServletRequestrequest 객체를 사용하는 것이다
request에서 setAttribute()를 사용해 데이터 저장하고 View에 전달
View에서는 request.getAttribute()를 사용해서 데이터 꺼냄

회원 목록 조회

NOTE
@WebServlet(name = "mvcMemberListServlet", urlPatterns = "/servlet-mvc/members") public class MvcMemberListServlet extends HttpServlet { private MemberRepository memberRepository = MemberRepository.getInstance(); @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 회원 목록 조회 List<Member> members = memberRepository.findAll(); // Model에 데이터를 보관 request.setAttribute("members", members); // 특정 URL로 forward String viewPath = "/WEB-INF/views/members.jsp"; RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath); dispatcher.forward(request, response); } }
Java
복사
Model 역할인 HttpServletRequest request 객체는 다양한 데이터 타입을 지원한다
List<Member> members와 같은 컬렉션 타입도 보관할 수 있다.

MVC 컨트롤러의 단점

NOTE
MVC 패턴을 적용함으로써 비즈니스 로직과 뷰 로직이 분리가 되었다. 하지만 여러 컨트롤러를 봤을 때 중복된 코드가 많고, 필요하지 않는 코드가 많이보인다
@WebServlet(name = "mvcMemberFormServlet", urlPatterns = "/servlet-mvc/members/new-form") public class MvcMemberFormServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String viewPath = "/WEB-INF/views/new-form.jsp"; RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath); dispatcher.forward(request, response); } }
Java
복사
문제점을 보기위한 예시코드

ViewPath에 중복

NOTE
String viewPath = "/WEB-INF/views/new-form.jsp";
Java
복사
각각의 컨트롤러에서는 데이터 흐름의 이동을 위한 경로 문자열을 가진다. 허나 자세히보면 아래와 같은 중복을 가지는 것을 알 수 있다.
prefix : /WEB-INF/views/
suffix : .jsp
이러한 중복은 경로가 바뀌었을 때 모든 ViewPath를 수정해야한다는 단점이 있다
JSP가 아닌 thymeleaf 같은 다른 뷰로 변경한다면 전체 코드를 변경해야 함..

포워드 중복

NOTE
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath); dispatcher.forward(request, response);
Java
복사
View이동하는 코드가 항상 중복 호출되어야 하며 그 모습 또한 동일하다
물론 이 부분을 메서드로 공통화해도 되지만, 해당 메서드도 항상 직접 호출해야 함

사용하지 않는 코드

NOTE
HttpServletRequest request, HttpServletResponse response
Java
복사
HttpServletRequest, HttpServletResponse 객체는 사용할 때도 있고, 사용하지 않을 때도 있다
HttpServletRequest, HttpServletResponse 클래스는 개발자가 직접 생성하고 다루는 대상이 아니다보니 테스트 케이스를 작성하기도 어렵다.

공통 처리가 어렵다.

NOTE
앞서 말했던 단점들은 전부 공통과 중복이라는 키워드로 설명이 가능하다
공통 기능들은 단순히 메서드로 뽑으면 될 것 같지만, 결과적으로 메서드를 호출하는 것 자체도 중복이다
이 문제를 해결하려면 컨트롤러 호출 전에 앞단에서 먼저 공통기능을 처리해야 한다
프론트 컨트롤러(Front Controller) 패턴을 도입하면 이런 문제를 깔끔하게 해결할 수 있다!