하나의 서블릿이나, JSP로 처리하던 것을 컨트롤러와 뷰의 영역으로 역할을 나눈 것을 말한다.
MVC패턴을 사용한다.
서블릿을 컨트롤러로 사용하고, JSP를 뷰로 사용해서 MVC패턴을 적용한다.
Model은 HttpServletRequest 객체를 사용한다. request는 내부에 데이터 저장소를 가지고 있는데,
request.setAttribute() , request.getAttribute() 를 사용하면 데이터를 보관하고, 조회할 수 있다.
package hello.servlet.web.servletmvc;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@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); // 다른 서블릿이나 JSP로 이동할 수 있는 기능, 서버 내부에서 호출이 발생한다.
}
}
MVC 패턴 한계
Front Controller Servlet하나로 클라이언트 요청을 받는다.
프론트 컨트롤러가 요청에 맞는 컨트롤러를 찾아서 호출
DispatcherServlet = FrontController 패턴으로 구현
프론트 컨트롤러 ControllerV1
클라이언트 HTTP요청 -> Front Controller -> Controller
-> 컨트롤러에서 JSP forward -> JSP -> HTML응답
ControllerV1 서블릿과 비슷한 모양의 컨트롤러 인터페이스 도입
로직의 일관성을 가져간다.
MemberFormControllerV1 extends ControllerV1 회원 등록 컨트롤러
String viewPath = "/WEB-INF/views/new-form.jsp"; // jsp를 호출하는 것이다.
RequestDispatcher는 클라이언트로부터 최초 들어온 요청을 jsp/servlet내에서 원하는 자원으로 요청을 넘기는 역할을 수행, 특정 자원에 처리를 요청하고 처리 결과를 얻어오는 기능을 수행하는 클래스이다. .
/a.jsp 로 들어온 요청을 dispatcher를 통해 /b.jsp로 요청을 보낼 수 있다.
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
1) dispatcher.forward() 대상 자원으로 제어를 넘기는 역할
HTTP 리다이렉트 방식과는 달리 하나의 HTTP 요청 범위 안에서 동작이 ㅣ루어진다.
2) dispatcher.include() 두 가지 방법이 있다.
https://dololak.tistory.com/506 이 글에서 참고하기
1) RequestDispatcher를 통한 제어 이동
브라우저 -> a/.jsp 서버 a.jsp -> b.jsp(forward /b.jsp) -> 브라우저
현재 처리중인 서블릿이 속해 있는 웹 어플리케이션 범위 내에서 요청을 제어할 수 있다.
2) HttpServletResponse sendRedirect()
브라우저 -> /a.jsp 서버 -> redirect/b.jsp -> 브라우저 -> 서버 /b.jsp
HTTP 리다이렉션을 이용하기 때문에 하나의 요청 범위 안에서 처리하는 것이 아니라 브라우저에게 Response 후 재요청한다.
MemberSaveControllerV1회원 저장 컨트롤러
String usernmae=request.getParameter("username");
HTTP 요청의 매개변수를 가져오는데 사용되는 메서드이다.
HTTP GET OR POST요청에서 서버로 전송할때 매개변수를 함께 전송,
request.getParameter()를 사용하여 매개변수 값을 가져올 수 있다.
request.setAttribute("member", member);
각각의 기본 객체가 존재하는 동안에 사용될 수 있다. jsp페이지 사이에서 정보를 주고 받거나 공유하기 위한 목적으로 사용된다.
MemberListController 회원 목록 컨트롤러
MVC 프레임워크 만들기 5page
public FrontControllerServletV1() {
controllerV1Map.put("/front-controller/v1/members/new-form", new MemberFormControllerV1());
controllerV1Map.put("/front-controller/v1/members/save", new MemberSaveControllerV1());
controllerV1Map.put("/front-controller/v1/members", new MemberListControllerV1());
}
하위 모든 요청은 서블릿에서 받아들인다.
/front-controller/v1, /front-controller/v1/a
MyView
뷰 객체는 이후 다른 버전에서도 함께 사용하므로 패키지 위치를 frontcontroller에 두었다.
1) 컨트롤러에서 HttpServletRequest, HttpServletResponse이 필요한가?
요청 파라미터 정보는 자바의 Map으로 대신 넘기도록 하면 지금 구조에서 컨트롤러가 서블릿 기술을 몰라도 동작할 수 있다.
request객체를 Model로 사용하는 대신에 별도의 Model 객체를 만들어서 반환한다.
2) 뷰 이름 중복 제거
컨트롤러에서 뷰 이름 중복이 있다.
뷰의 논리 이름을 반환하고, 실제 물리 위치의 이름은 프론트 컨트롤러에서 처리하도록 한다.
/WEB-INF/views/new-form.jsp -> new-form 이런식으로 고쳐준다.
request.setAttribute()를 통해 저장하고 뷰에 전달한다.
ModelView 다른 버전에서 사용하므로 패키지를 frontcontroller에 둔다.
ModelView
서블릿의 종속성을 제거하기 위해 Model을 직접 만들고, 추가로 View 이름까지 전달하는 객체를 만들어보자. model은 단순히 map으로 되어 있으므로 컨트롤러에서 뷰에 필요한 데이터를 key, value로 넣어주면 된다.
Controller는 서블릿 기술을 전혀 사용하지 않는다.
ModelView process(Map<String, String> paramMap); 담아서 호출하면 된다.
MyView view=viewResolver(viewName)
컨트롤러가 반환한 논리 뷰 이름을 실제 물리 뷰 경로로 변경한다. 실제 물리 경로가 있는 MyView 객체를 반환한다.
view.render(mv.getModel(), request, response)
뷰 객체를 통해서 HTML화면을 렌더링 한다.
뷰 객체의 render()는 모델 정보도 함께 받는다.
JSP는 request.getAttribute()로 데이터를 조회하기 때문에, 모델의 데이터를 꺼내서
request.setAttribute()로 담아둔다.
JSP로 포워드 해서 JSP를 렌더링 한다.
ModelView 객체를 생성하고 반환하는 부분이 번거롭다. 실제 개발하는 개발자가 단순하고 편리하게 사용할 수 있어야 한다. -> ViewName만 반환하도록 한다.
boolean supports(Object handler)
handler는 컨트롤러를 말한다.
어댑터가 해당 컨트롤러를 처리할 수 있는지 판단하는 메서드이다.
ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
어댑터는 실제 컨트롤러를 호출하고, 결과로 ModelView를 반환한다.
실제 컨트롤러가 ModelView를 반환하지 못하면, 어댑터가 ModelView를 직접 생성해서라도 반환해야 한다. 이전에는 프론트 컨트롤러가 실제 컨트롤러를 호출했지만 이제는 이 어댑터를 통해서 실제 컨트롤러가 호출 된다.
컨트롤러 -> 핸들러
이제는 어댑터를 사용하기 때문에, 컨트롤러 뿐만 아니라 어댑터가 지원하기만 하면, 어떤 것이라도 URL에 매핑해서 사용할 수 있다