MVC 패턴에서 Controller 역할을 하는 Servlet 파일.
Spring 구조를 결정짓는 요소. 스프링에서 사용한다.
여태까지는 JSP를 사용해서 Controller 코드를 작성해왔지만, 이제 JSP는 오직 VIEW의 역할을 하도록 만들 것이다
(JSTL, EL 등 사용)
FrontController 란 ?
---> VIEW에 JAVA가 없도록 하자!
즉, JSTL, EL, 커스텀 태그 등으로만 구성될 것
■ 여태까지의 controller.jsp
□ 컴파일 후 .java (not POJO, Servlet)로 변환됨
□ 어짜피 서블릿으로 변환될 거 처음부터 서블릿으로 만들자고 생각
□ 서블릿으로 만든 컨트롤러를 "FrontController"라고 한다. (여러 요청을 경로에 맞게 보내주는 역할)
□ ActionFactory에 있는 액션명들을 (원래는 "controller.jsp?action=?" 이런 식으로 사용) ~.do로 바꿔준다.
--->> 액션마다 controller.jsp?action=? 를 제거함으로써 파라미터 개수를 1개 줄일 수 있다!
■ controller.jsp를 제거하고 FrontController로 교체 & VIEW에서 모든 자바 코드 삭제
--> 온전한 스프링 형태의 MVC 패턴이 된다!
String commnad = request.getParameter("action")
원래 controller.jsp에서 쓰이던 이 코드는 action의 파라미터를 가져오는 것이므로 요청 자체를 가져올 수 있도록 아래와 같이 수정한다.
※ action = "LOGIN" 이것이 파라미터!
String command = request.getRequestURI();
command = command.replace("day037", "");
main.do 등의 요청이 도착하는 곳.
요청값이 프로젝트명과 함께 들어오므로 ~.do 만 갖기 위해 replace로 프로젝트명을 제거한다.
[ FrontControllerDo ] 서블릿 코드
package controller.common;
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("*.do")
public class FrontControllerDo extends HttpServlet {
private static final long serialVersionUID = 1L;
private ActionFactory factory;
public FrontControllerDo() {
super();
factory = new ActionFactory();
}
private void doAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String command = request.getRequestURI();
System.out.println("CTRL 로그 : action ["+command+"]");
command = command.replace("/honeyComboFactory/", "");
System.out.println("COMMAND ["+command+"]");
Action action = factory.getAction(command);
System.out.println("ACTION ["+action+"]");
ActionForward forward = action.execute(request);
if(forward == null) {
System.out.println("에러 페이지");
response.sendRedirect("error/errorPage.jsp");
}
if(forward.isRedirect()){
System.out.println("Redirect True");
response.sendRedirect(forward.getPath());
}
else{
System.out.println("Redirect False");
// pageContext.forward(forward.getPath());
RequestDispatcher dispatcher = request.getRequestDispatcher(forward.getPath());
dispatcher.forward(request, response);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("로그 [GET] 요청 호출됨");
doAction(request,response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("로그 [POST] 요청 호출됨");
doAction(request,response);
}
}
.do로 끝나는 요청을 이 서블릿 하나에서 받아서 처리한다.
.do로 끝나는 요청을 받아서 분석한 후, 어떤 기능(Action)을 실행할지 결정하고 결과 페이지로 이동(forward or redirect) 시켜주는 역할을 한다.
@WebServlet("*.do")
서블릿 파일을 만들어서 @WebServlet("*.do") 로 설정하면 ~ .do로 끝나는 요청을 모두 이 서블릿이 받을 수 있다.
did도 마찬가지.
public class FrontControllerDo extends HttpServlet {
HttpServlet을 상속받아서 웹 요청을 처리하는 클래스인 서블릿을 만든 것.
※ HttpServlet : 자바에서 요청과 응답을 처리하는 클래스의 부모.
보통 서블릿은 이 클래스를 상속받아서 만드며, 쉽게 말하자면 웹 요청을 처리할 수 있는 자바 클래스의 기본틀이다.
private ActionFactory factory;
ActionFactory라고 요청(command)에 따라 어떤 Action을 실행해줄지 결정하는 클래스가 존재한다.
해당 클래스를 선언해야 프론트 컨트롤러에서 해당 클래스를 참고하여 행동을 결정할 수 있다.
ex. /login.do 요청일 시 LoginAction 객체를 리턴
public FrontControllerDo() {
super();
factory = new ActionFactory();
}
factory도 생성자 안에서 함께 선언하여 서블릿 객체 시 한번만 생성되고 내내 사용할 수 있도록 함
private void doAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String command = request.getRequestURI();
System.out.println("CTRL 로그 : action ["+command+"]");
command = command.replace("/honeyComboFactory/", "");
System.out.println("COMMAND ["+command+"]");
GET/POST 어떤 요청이든 관계없이 FrontController는 doAction() 함수를 통해서 액션을 수행한다.
GET/POST 요청이 오면 실행되는 메서드이다.
전체 요청 경로를 받아온 뒤 command 부분만 추출한다.
Action action = factory.getAction(command);
System.out.println("ACTION ["+action+"]");
ActionForward forward = action.execute(request);
command에 따라 실행할 액션 클래스를 가져온 후, 액션 실행 후 그 결과를 받은 ActionForward를 받는다.
ActionFactory는 요청 문자열(command)에 따라 어떤 Action 객체를 실행할지 결정하는 역할을 하는데, 거기서 문자열을 통해 실행할 액션 객체를 가져오는 것.
action은 실제로 기능을 수행할 클래스이다. (컨트롤러 jsp를 자바 클래스로 각각 나누면서 각 action 클래스로 나누어주었다)
각 액션 클래스가 execute() 라는 메서드를 가지고 있으므로 선택한 액션마다 해당 메서드를 실행한 결과를 forward에 담는다. 실행된 결과는 각각 redirect로 보내야하는지, forward로 보내야하는지에 대한 정보를 담고 있다.
if(forward.isRedirect()){
System.out.println("Redirect True");
response.sendRedirect(forward.getPath());
}
else{
System.out.println("Redirect False");
// pageContext.forward(forward.getPath());
RequestDispatcher dispatcher = request.getRequestDispatcher(forward.getPath());
dispatcher.forward(request, response);
}
redirect가 true라면 새 요청으로 URL을 이동하고(주소 바뀜), false라면 forward 방식으로 내부 이동한다. (주소 그대로)
redirect(response.sendRedirect())는 클라이언트(브라우저)가 새로운 요청을 서버로 다시 보냈을 때 주소창(URL)이 바뀌는 것이다. 즉, 다른 웹 페이지로 새로 이동하는 것.
forward(dispatcher.forward())는 서버 내부에서 다른 JSP로 조용히 이동하는 것으로, 주소창은 그대로이고, request 객체도 그대로 전달된다.
(( 주소창이 그대로라는게 무슨뜻일까..??))
몰라서 찾아본 것들..
1. RequestDispatcher가 무엇인가?
: 서버 내부에서 다른 JSP나 서블릿으로 요청을 전달(forward) 해주는 도구.
■ forward 방식으로 이루어진다.
■ URL을 바꾸지 않고 화면만 다른 JSP로 보여주고 싶을 때 사용. request 데이터가 유지된다.
RequestDispatcher dispatcher = request.getRequestDispatcher("main.jsp");
dispatcher.forward(request, response);
main.jsp로 요청을 전달해달라고 Dispatcher에게 말하는 것.
dispatcher.forward()를 호출하면 request와 response를 그대로 main.jsp에게 넘겨준다.