코딩항해기
[JSP] Controller - 심화 (싱글톤패턴 : 핸들러맵핑 적용) 본문
전의 게시물에서 작성했던 Controller 버전을 살펴보면, if문으로 분기를 나누는 기능 부분이 있다.
ActionForward forward=null;
if(command.equals("/main.do")) {
MainAction mainAction=new MainAction();
forward = mainAction.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);
}
else if(command.equals("/board.do")) {
forward = new BoardAction().execute(request, response);
}
이 부분을 보면 매번 new 연산자를 사용해서 Action을 수행하고 있다. 즉, 하나의 요청 당 한 개의 new 연산자가 사용돼서 객체가 요청 개수 만큼 무한히 힙 메모리에 쌓이고 있다.
즉, 싱글톤 패턴이 깨진 상황이다.
싱글톤 패턴
new를 절약하는 패턴 중 하나로, 한 번 new해서 존재하는 객체가 있다면 해당 객체를 계속 재사용하는 패턴이다.
그럼 싱글톤 패턴을 지키기 위해 어떤 방법을 쓰면 좋을까?
싱글톤 패턴의 핸들러 맵핑을 사용할 수 있다.
핸들러 맵핑
싱글톤 패턴을 유지시키는 장치 중 하나로 가장 대표적인 장치이다.
그럼, 핸들러 맵핑을 만들어보자.
핸들러 맵핑은 Map을 필드 값으로 가지며, 요청에 따라 맞는 기능을 반환한다.
전 게시물을 기준으로 설명하면, if문 조건을 key값으로 받아 new Action()객체를 반환하는 것이다.
public class HandlerMapper {
private Map<String, Action> mapper; //요청에 대해 기능을 반환
public HandlerMapper() {
this.mapper = new HashMap<>();
//요청값과 그에 따른 Action을 작성한다.
this.mapper.put("/main.do", new MainAction());
this.mapper.put("/login.do", new LoginAction());
this.mapper.put("/joinPage.do", new JoinPageAction());
this.mapper.put("/join.do", new JoinAction());
this.mapper.put("/logout.do", new LogoutAction());
this.mapper.put("/board.do", new BoardAction());
}
//바로 value값을 반환한다.
public Action getMapper(String command) {
return this.mapper.get(command);
}
}
새로운 기능이 생기면 if문 분기로 나누는 것이 아니라 핸들러 맵핑 기본 생성자에 키와 밸류로 추가하면 된다.
그럼 FrontController는 어떻게 바뀔까?
@WebServlet("*.do")
public class frontController extends HttpServlet {
private static final long serialVersionUID = 1L; //직렬화 코드
private HandlerMapper mappings;
public frontController() {//기본생성자(웹에서는 기본생성자 사용)
super();
this.mappings = new HandlerMapper();//한 번만 핸들러 맵핑 객체를 만든다.
}
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);
}
//get으로 오든 post로 오든 실행할 기능
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. 요청을 수행
//핸들러 맵핑으로 싱글톤 패턴이 지켜진 코드
Action action = mappings.getMapper(command);
ActionForward forward = action.execute(request, response);
//기존 코드
// ActionForward forward=null;
// if(command.equals("/main.do")) {
// MainAction mainAction=new MainAction();
// forward = mainAction.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);
// }
// else if(command.equals("/board.do")) {
// forward = new BoardAction().execute(request, response);
// }
// 3. 응답(페이지 이동 등)
// 1) 전달할 데이터가 있니? 없니? == 포워드? 리다이렉트?
// 2) 어디로 갈까? == 경로
if(forward == null) {
// command 요청이 없는 경우
System.out.println("error 발생");
forward = new ActionForward();
forward.setRedirect(true);
forward.setPath("error/error.jsp");
}
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();
}
}
}
}
주석 처리된 부분이 기존 코드고, 위의 두 줄의 코드가 핸들러 맵핑을 통해 변경된 코드다.
Action 인터페이스를 통해 메서드 명이 통일되어있기 때문에 나누어 쓸 필요없이 알맞게 반환된 객체의 메서드를 바로 호출할 수 있다.
'JSP' 카테고리의 다른 글
[JSP] 입력받은 이미지 파일 저장하기 (0) | 2024.08.27 |
---|---|
[JSP] DB에서 이미지 파일 경로 받아서 화면에 띄우기 (0) | 2024.08.27 |
[JSP] Controller Servlet (0) | 2024.08.19 |
[JSP] 내장 객체 (request, session, application) (0) | 2024.08.17 |
[JSP] xml 파일로 error 페이지 설정하기 (0) | 2024.08.14 |