FrontController는 모든 요청을 받는 방식을 말한다.
controller.jsp는 무조건 필요한데 HTML을 사용하지 않기 때문에 java라고 볼 수 있다.
그런데 .jsp는 컴파일하면 Servlet이 됨. 이것을 FrontController
프론트단에서 사용자들이 하는 모든 요청이 이곳으로 와줬으면 좋겠다~ 하는 관리를
톰캣(Server) 설정을 해주어야 한다.
톰캣(Server)은 서버도 제공해 주지만, 이러한 설정 역할을 해준다.
톰캣(Server)에게 설정을 제공하는 방법
1) xxx.xml (설정파일) 등록
: 톰캣의 경우 web.xml 파일.
2) @ (어노테이션, 애너테이션) 등록
1)번의 경우 .xml이 다루기 어렵고, 스키마가 무겁다는 단점이 있기 때문에,
간략하고 가독성이 좋은 2) 번의 방식을 사용한다.
사용법은 Servlet 위쪽에 애너테이션을 작성해 준다.
위와 같이 @WebServlet("*.do") 을 작성해 주면
xxxx.do로 끝나는 규칙이 있으면 이 페이지로 보내준다!
이 @어노테이션의 위치는 반드시 해당 클래스의 위쪽에 달아줘야 한다.
▼ 사용 예시
@WebServlet("*.do")
// 톰캣(server)이 구동될때, xxx.do로 끝나는 요청에 대하여 FC를 호출하게됨
public class FrontController extends HttpServlet {
private static final long serialVersionUID = 1L;
public FrontController() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
private void doAction(HttpServletRequest request, HttpServletResponse response) {
// 1. 사용자가 무슨 요청을 했는지 추출 및 확인
String uri=request.getRequestURI();
String cp=request.getContextPath();
String command=uri.substring(cp.length());
System.out.println("command : "+command);
// 2. 요청을 수행
if(command.equals("/main.do")) {
BoardDAO boardDAO=new BoardDAO();
BoardDTO baodrDTO=new BoardDTO();
ArrayList<BoardDTO> datas=boardDAO.selectAll(boardDTO);
request.setAttribute("datas", datas);
}
else if(command.equals("/login.do")) {
MemberDAO memberDAO = new MemberDAO();
MebmerDTO memberDTO = new MemberDTO();
memberDTO.setMid(request.getParameter("mid"));
memberDTO.setPassword(request.getParameter("passowrd"));
memberDTO = mebmerDAO.selectOne(memberDTO);
if(memberDTO != null){
session.setAttrubute("loginInfo", memberDTO.getMid());
}
}
else if(command.equals("/join.do")) {
}
else if(command.equals("/logout.do")) {
}
else {
// 등록되지않은 요청입니다.
}
// 3. 응답(페이지 이동 등)
// 1) 전달할 데이터가 있니? 없니? == 포워드? 리다이렉트?
// 2) 어디로 갈까? == 경로
if(forward == null) {
// command 요청이 없는 경우
}
else {
if(forward.isRedirect()) {
try {
response.sendRedirect(forward.getPath());
} catch (IOException e) {
e.printStackTrace();
}
}
else {
RequestDispatcher dispatcher=request.getRequestDispatcher(forward.getPath());
try {
dispatcher.forward(request, response);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
doGet / doPost 어느 방식으로 오던 다 무언가를 수행해야 하기 때문에,
doGet과 doPost에 도달하면 doAction 을 수행할 수 있도록 코드를 작성해 준다.
🍀doAction의 3단계
1. 사용자가 무슨 요청을 했는지 추출 및 확인
2. 요청을 수행
3. 응답 (페이지 이동 등)
String uri=request.getRequestURI(); >> 무슨 요청을 했는지 URI로 확인을 해주는 역할을 한다.
(ex. /day034/main.do)
String cp=request.getContextPath(); >> 현재 웹 애플리케이션의 기본 경로를 나타낸다.
(ex. /day034)
String command=uri.substring(cp.length());
>> uri의 길이를 subgstring를 사용하여 cp.length는 길이부터 자른다는 것을 의미한다.
>> 해당 코드를 사용할 경우 command에는 /main.do 가 들어가게 된다.
이때 변수를 저장하는 곳을 command 또는 action 이라고 한다.
(command? == action No. - 메뉴 번호를 의미한다)
이 Servlet을 사용하여 모든 요청을 받아주고. 응답을 수행한다.
따라서 기존에 사용하던 controller.jsp 파일은 필요하지 않고,
처음 페이지인 index.jsp 도 요청을 controller.jsp action 파라미터 값으로 보내지 않는다.
▼ index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
// 기존에 사용하던 방식
// response.sendRedirect("controller.jsp?action=main");
// FrontController로 보내주는 방식 xxx.do
response.sendRedirect("main.do");
%>
기존에는 파라미터 방식으로 들고 다녀야 하니 무겁고 가독성이 떨어진다.
현재의 방식(xxx.do로 보내주는 방식)으로 바꿔주면 가독성이 올라가고, 파라미터가 0개라 가벼워진다!
또한 기존의 controller.jsp 에서는 DAO DTO 수만큼 <jsp:useBean> 선언해서 사용했는데,
이렇게 되면 필요 없는 기능에서도 new가 사용된다.
FrontController에서는 기능별로 요청을 따로 수행하기 때문에 훨씬 더 경제적이다.
(필요 없는 곳에서는 new를 사용하지 않는다 == 힙 메모리 영역을 사용하지 않는다.)
위의 FrontController 코드는 응집도가 낮은 상태.
응집도가 낮다 == 서로 관련 없는 코드들이 한 곳에 저장되어 있다
이러한 것의 단점은
1) 공동 작업이 어렵다.
2) 코드 작업 중에는 해당 페이지 내용 전부 접근 불가
따라서 한 가지 기능을 수정하면 다른 기능도 모두 사용이 불가하다.
--> 가용성이 낮아져서 사용자가 이용을 못하는 경우에는, 반드시 그 사실을 고지해야 한다.
이러한 단점들 때문에 응집도를 높여야 한다.
응집도를 높이기 위해 xxxAction.java 클래스 만들어서 관리해 준다.
xxxAction.java == POJO (가벼움!)
상대적으로 무거운 NOT POJO인 Servlet은 적으면 좋기 때문에, FrontController만 있으면 된다.
xxxAction.java 로 클래스를 나눠주면 응집도를 높여주고, 가용성도 좋아진다!
▼ mainAction.java
public void execute() {
BoardDAO boardDAO=new BoardDAO();
BoardDTO boardDTO=new BoardDTO();
ArrayList<BoardDTO> datas=boardDAO.selectAll(boardDTO);
request.setAttribute("datas", datas);
}
자바 파일에서 기능을 수행하는 코드를 작성해 준다.
execute 메서드는, 외부의 요청정보를 받아와서 수행해야 하기 때문에 인자값으로 request와 response를 넣어준다.
xxxAction 파일이 여러 개 이기 때문에, 동일한 메서드명과 인자를 모두 같은 이름으로 사용하고 싶다.
==> 인터페이스를 이용한다!
▼ Action.java (인터페이스)
package controller.common;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public interface Action {
ActionForward execute(HttpServletRequest request, HttpServletResponse response);
}
그리고 xxxAction.java에서의 값들은 결국 반환이 필요한데,
1. 어떻게 갈지? (포워드 or 리다이렉트)
2. 어디로 갈지? (경로)
의 반환이 필요하다.
java에서 반환 시 2개 이상의 반환이 필요할 때 DTO 파일에 담아서 반환한다.
따라서 DTO 같은 클래스 파일을 하나 만들어준다.
▼ ActionForward.java
package controller.common;
public class ActionForward {
private boolean redirect; // 어떻게 갈지? == 방식
private String path; // 어디로 갈지? == 경로
public boolean isRedirect() {
return redirect;
}
public void setRedirect(boolean redirect) {
this.redirect = redirect;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
▼ 수정한 mainAction.java
package controller.board;
import java.util.ArrayList;
import controller.common.Action;
import controller.common.ActionForward;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import model.dao.BoardDAO;
import model.dto.BoardDTO;
public class MainAction implements Action {
@Override
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) {
BoardDAO boardDAO=new BoardDAO();
BoardDTO boardDTO=new BoardDTO();
ArrayList<BoardDTO> datas=boardDAO.selectAll(boardDTO);
request.setAttribute("datas", datas);
ActionForward forward=new ActionForward();
forward.setRedirect(false); // 포워드 방식
forward.setPath("main.jsp");
return forward;
}
}
인터페이스를 활용하므로, implements Action을 사용하고,
ActionForward 타입으로 반환해 준다.
forward.setRedirect에는
- 반환할 값이 있다면 : 포워드 방식 false
- 반환할 값이 없다면 : 리다이렉트 방식 true를 입력한다.
▼ FrontController 수정
ActionForward forward=null;
//모든 ACtion들이 forward를 받아서 쓸 예정이라, 위쪽에 선언
if(command.equals("/main.do")) {
MainAction mainAction=new MainAction();
forward = mainAction.execute(request, response);
}
else if(command.equals("/bodrd.do")) {
BoardAction boardAction=new BoardAction();
forward = boardAction.execute(request, response);
}
else if(command.equals("/login.do")) {
LoginAction loginAction=new LoginAction();
forward = loginAction.execute(request, response);
}
else if(command.equals("/joinPage.do")) {
JoinPageAction joinPageAction=new JoinPageAction();
forward = joinPageAction.execute(request, response);
}
else if(command.equals("/join.do")) {
JoinAction joinAction=new JoinAction();
forward = joinAction.execute(request, response);
}
else if(command.equals("/logout.do")) {
LogoutAction logoutAction=new LogoutAction();
forward = logoutAction.execute(request, response);
}
🍀정리
- View는 이제 .jsp 페이지로 바로 보내는 것이 아니라, 무조건 Controller를 거쳐 액션명.do로 요청을 보낸다.
- 액션명.do로 요청을 보내면 Servlet을 타고 요청이 해당 페이지로 가는데, 이건 @ 어노테이션 덕분이다.
: 그래서 서버가 늘어나거나 처리해야 할 요청이 많아지면 FrontController2를 만들 수 있음.
이때 어노테이션을 @("*.mem") 식으로 처리할 수 있다.
'WEB > 백' 카테고리의 다른 글
[WEB] 이미지(파일) 업로드 (5) | 2024.09.02 |
---|---|
[WEB] 핸들러맵핑 (0) | 2024.08.26 |
[WEB] xml 파일 (0) | 2024.08.25 |
[WEB] 커스텀 태그 (0) | 2024.08.25 |
[WEB] JSTL (0) | 2024.08.25 |