프론트 컨트롤러(FrontController)

Jan 25, 2024
프론트 컨트롤러(FrontController)
 
 
 
이전 블로그와 이어진다.
 
이전 블로그에서는 서블릿을 여러 개를 만들어서 테스트를 했다. 서블릿을 여러 개를 만들면 단점이 있다.
● 서블릿은 클라이언트의 요청이 있을 때 마다 생성되야 하기 때문에 메모리 부하가 발생할 수 있다.
● 동일한 코드가 반복될 때, 만약 서블릿이 100개가 된다면 100번의 코드 수정이 일어나야하는 단점이 있다.
 
그래서 하나의 진입점을 만들어 데이터를 요청하도록 만들기 위해 프론트 컨트롤러를 만든다.
 

1. 프론트 컨트롤러 (FrontController)

 
@WebServlet("*.do") public class DispatcherServlet extends HttpServlet { // /join.do @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 1. 공통로직 resp.setHeader("Content-Type", "text/html; charset=utf-8"); // 2. 분기 String uri = req.getRequestURI(); System.out.println(uri); if(uri.equals("/join-form.do")){ resp.sendRedirect("/user/join-form.jsp"); }else if(uri.equals("/join.do")){ resp.sendRedirect("/user/join.jsp"); }else if(uri.equals("/main.do")){ resp.sendRedirect("/board/main.jsp"); }else{ resp.setStatus(404); resp.getWriter().println("잘못된 페이지를 요청하셨어요"); } } }
 
DispatcherServlet 라는 프론트 컨트롤러를 만들었다.
이 프론트 컨트롤러는 Content-Type 의 공통 로직을 관리하고 라우팅 역할을 한다.
@WebServlet("*.do") 를 설정해 URL 식별자에 .do 를 입력하면 적절한 페이지로 리다이렉션을 한다.
 
💡
만약 @WebServlet(”/*”) 로 주소를 설정하게 되면 모든 주소가 리다이렉션 되면서 다시 DispatcherServlet 로 돌아와 무한 루프를 돌게 된다.
 
notion image
http://localhost:8080/join-form.do 를 입력하면 자동으로 리다이렉션이 된다.
 
notion image
 
 

2. 프론트 컨트롤러 강제성 부여

 
프론트컨트롤러를 이렇게 만들었을 때의 문제가 있다.
모든 요청을 프론트 컨트롤러를 통하기 위해 만들었지만 http://localhost:8080/user/join-form.jsp 를 입력하면 프론트컨트롤러를 통하지 않고 연결된다.
 
notion image
 
그래서 프론트 컨트롤러를 통해서만 접속할 수 있도록 강제성을 부여해야 한다.
 
notion image
 
우선 jsp 파일들을 WEB-INT 폴더에 넣는다.
 
notion image
WEB-INT 는 보안 폴더로 외부 브라우저에서는 접근할 수 없고, 내부 서버 내에서만 접근할 수 있다.
notion image
클라이언트가 브라우저에 /join-form.do 를 입력했을 때, 리다이렉션이 일어나면 서버에 두 번의 요청이 일어난다. 이때 요청이 서버 밖에서 이루어지기 때문에 리다이렉션된 페이지를 찾을 수가 없다.
 
이때 사용하는 메서드가 getRequestDispatcher() 이다.
 
req.getRequestDispatcher("/WEB-INF/user/join-form.jsp").forward(req,resp);
 
getRequestDispatcher() 메서드는 처음 들어온 요청을 서블릿 내에서 원하는 자원으로 요청을 전달하는 역할을 하거나, 특정 자원에 처리를 요청하고 처리 결과를 얻어오는 기능을 수행한다.
 
forward() 메서드는 요청, 응답 객체를 지정된 리소스에 전달하는 역할을 한다.
 
notion image
getRequestDispatcher() 를 사용하면 두번째 요청에서 내부에서 요청이 들어가기 때문에 WEB-INF 폴더에 접근할 수 있다.
 
 
 

3. 코드 실행

 
프론트 컨트롤러
@WebServlet("*.do") public class DispatcherServlet extends HttpServlet { // /join.do @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 1. 공통로직 System.out.println("common logic"); resp.setHeader("Content-Type", "text/html; charset=utf-8"); // 2. 분기 String uri = req.getRequestURI(); System.out.println(uri); if(uri.equals("/join-form.do")){ req.getRequestDispatcher("/WEB-INF/user/join-form.jsp").forward(req, resp); }else if(uri.equals("/join.do")){ req.getRequestDispatcher("/WEB-INF/user/join.jsp").forward(req, resp); }else if(uri.equals("/main.do")){ req.getRequestDispatcher("/WEB-INF/board/main.jsp").forward(req, resp); }else{ resp.setStatus(404); resp.getWriter().println("잘못된 페이지를 요청하셨어요"); } } }
 
메인.jsp
<html> <head> <title>Title</title> </head> <body> <h1>main page </h1> <hr> </body> </html>
 
join.jsp
<% String username = request.getParameter("username"); String password = request.getParameter("password"); String email = request.getParameter("email"); System.out.println("username :" + username); System.out.println("password :" + password); System.out.println("email :" + email); if(username.length() <3 || username.length() >10){ response.getWriter().println("<h1>username 글자수가 3~10 사이여야 합니다."); return ; } response.sendRedirect("/main.do"); %>
 
join-form.jsp
<% LocalDateTime now = LocalDateTime.now(); %> <html> <head> <title>Title</title> </head> <body> <h1>회원가입 페이지<%=now%> </h1> <hr> <form action="/join.do" method="post"> <input type="text" placeholder="username" name="username"> <input type="text" placeholder="password" name="password"> <input type="text" placeholder="email" name="email"> <button>회원가입</button> </form> </body> </html>
 
 
notion image
 
/join-form.do 를 통해서 접근할 수 있다.
 
notion image
데이터를 입력하면 메인 페이지로 넘어간다.
 
notion image
 
상태 코드 302 (리다이렉션)
 
 
notion image
프론트컨트롤러를 통하지 않으면 웹서버에 접근할 수 없다.
 
💡
지금의 패턴은 MVC 패턴 중 모델을 제외한 VC패턴이다.
M(Model) : 데이터와 비즈니스 로직을 관리
V(View) : 레이아웃과 화면을 처리
C(Controller) : 모델과 뷰로 명령을 전달
Share article

{CODE-RYU};