5. 페이지 컨트롤러 객체들을 준비
페이지 컨트롤러도 MemberDao 객체처럼 ContextLoaderListener 클래스에서 준비한다. spms.listeners.ContextLoaderListener 클래스를 다음과 같이 변경한다.
package spms.listeners;
import javax.naming.InitialContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
//import javax.servlet.annotation.WebListener;
import javax.servlet.annotation.WebListener;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import spms.controls.LogInController;
import spms.controls.LogOutController;
import spms.controls.MemberAddController;
import spms.controls.MemberDeleteController;
import spms.controls.MemberListController;
import spms.controls.MemberUpdateController;
import spms.dao.MemberDao;
//리스너의 배치 : @WebListener 어노테이션 사용
@WebListener
public class ContextLoaderListener implements ServletContextListener {
BasicDataSource ds;
@Override
public void contextInitialized(ServletContextEvent event) {
try {
//DB 커넥션 객체 준비
ServletContext sc = event.getServletContext();
//InitialContext 객체 생성 - 톰캣 서버에서 자원 찾기 위함
InitialContext initialContext = new InitialContext();
//lookup() 메서드로 JNDI 이름으로 등록된 서버 자원 찾을 수 있다.
//lookup() 메서드 매개변수는 서버 자원의 JNDI 이름
DataSource ds = (DataSource)initialContext.lookup("java:comp/env/jdbc/studydb");
//MemberDao 객체 준비하여 ServletContext에 보관
MemberDao memberDao = new MemberDao();
memberDao.setDataSource(ds); //DAO에 DataSource 객체 주입
//sc.setAttribute("memberDao", memberDao); //memberDao 객체를 별도로 꺼내서 사용할 일 없기 때문에 ServletContext에 저장하지 않는다.
//페이지 컨트롤러 객체를 ServletContext에 저장시, 서블릿 요청 URL을 키값으로 하여 저장
sc.setAttribute("/auth/login.do", new LogInController().setMemberDao(memberDao));
sc.setAttribute("/auth/logout.do", new LogOutController());
sc.setAttribute("/member/list.do", new MemberListController().setMemberDao(memberDao));
sc.setAttribute("/member/add.do", new MemberAddController().setMemberDao(memberDao));
sc.setAttribute("/member/update.do", new MemberUpdateController().setMemberDao(memberDao));
sc.setAttribute("/member/delete.do", new MemberDeleteController().setMemberDao(memberDao));
} catch(Throwable e) {
e.printStackTrace();
}
}
@Override
public void contextDestroyed(ServletContextEvent event) {}
}
MemberDao 객체는 별도로 꺼내서 사용할 일이 없기 때문에 ServletContext에 저장하지 않는다.
//sc.setAttribute("memberDao", memberDao); //memberDao 객체를 별도로 꺼내서 사용할 일 없기 때문에 ServletContext에 저장하지 않는다.
- 페이지 컨트롤러 객체를 준비
페이지 컨트롤러 객체를 생성하고 나서 MemberDao 객체가 필요한 객체에 대해서는 셋터 메서드를 호출하여 주입해 준다.
new LogInController().setMemberDao(memberDao)
이렇게 생성된 페이지 컨트롤러를 ServletContext에 저장한다. 단, 저장할 때 서블릿 요청 URL을 키(key)로 하여 저장한다. 프런트 컨트롤러에서 ServletContext에 보관된 페이지 컨트롤러를 꺼낼 때 이 서블릿 요청 URL을 사용할 것이다.
sc.setAttribute("/auth/login.do", new LogInController().setMemberDao(memberDao));
LogOutController 클래스는 MemberDao 객체가 필요 없기 때문에 셋터 메서드를 호출하지 않았다.
sc.setAttribute("/auth/logout.do", new LogOutController());
나머지 페이지 컨트롤러도 LogInController의 경우와 동일하게 준비한다.
//페이지 컨트롤러 객체를 ServletContext에 저장시, 서블릿 요청 URL을 키값으로 하여 저장
sc.setAttribute("/auth/login.do", new LogInController().setMemberDao(memberDao));
sc.setAttribute("/auth/logout.do", new LogOutController());
sc.setAttribute("/member/list.do", new MemberListController().setMemberDao(memberDao));
sc.setAttribute("/member/add.do", new MemberAddController().setMemberDao(memberDao));
sc.setAttribute("/member/update.do", new MemberUpdateController().setMemberDao(memberDao));
sc.setAttribute("/member/delete.do", new MemberDeleteController().setMemberDao(memberDao));
6. 프런트 컨트롤러의 변경
페이지 컨트롤러 객체를 ContextLoaderListener 클래스에서 준비했기 때문에 프런트 컨트롤러를 변경해야 한다. spms.servlets.DispatcherServlet 클래스를 다음과 같이 변경한다.
package spms.servlets;
import java.io.IOException;
import java.util.HashMap;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import spms.controls.Controller;
import spms.controls.LogInController;
import spms.controls.LogOutController;
import spms.controls.MemberAddController;
import spms.controls.MemberDeleteController;
import spms.controls.MemberListController;
import spms.controls.MemberUpdateController;
import spms.vo.Member;
@SuppressWarnings("serial")
@WebServlet("*.do") //프런트 컨트롤러의 배치
public class DispatcherServlet extends HttpServlet {//서블릿이기 때문에 HttpServlet 상속
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset=UTF-8");
String servletPath = request.getServletPath(); //서블릿 경로 추출
try {
ServletContext sc = this.getServletContext();
//페이지 컨트롤러에게 전달할 Map 객체 준비
HashMap<String,Object> model = new HashMap<String,Object>();
//model.put("memberDao", sc.getAttribute("memberDao")); //memberDao 객체는 더이상 Map 객체에 담을 필요 없음.
model.put("session", request.getSession()); //로그인 및 로그아웃 페이지 컨트롤러에서 사용할 세션 객체
//String pageControllerPath = null;
//인터페이스 타입의 참조 변수 선언 - Controller의 구현체 클래스들 객체 주소 저장 위함
//Controller pageController = null;
//ServletContext에서 페이지 컨트롤러 꺼낼 때 서블릿 URL 사용
Controller pageController = (Controller)sc.getAttribute(servletPath);
//페이지 컨트롤러로 위임
//조건문 변경 : 페이지 컨트롤러가 사용할 데이터를 준비하는 부분 외 제거
/*if("/member/list.do".equals(servletPath)) {
//pageControllerPath = "/member/list";
//pageController = new MemberListController();
}else*/
if("/member/add.do".equals(servletPath)) {
//pageControllerPath = "/member/add";
//pageController = new MemberAddController();
if(request.getParameter("email") != null) {
//요청 매개변수로부터 VO 객체 준비
/*request.setAttribute("member", new Member().setEmail(request.getParameter("email"))
.setPassword(request.getParameter("password"))
.setName(request.getParameter("name")));*/
//Map 객체에 VO 객체 준비
model.put("member", new Member().setEmail(request.getParameter("email"))
.setPassword(request.getParameter("password"))
.setName(request.getParameter("name")));
}
}else if("/member/update.do".equals(servletPath)) {
//pageControllerPath = "/member/update";
//pageController = new MemberUpdateController();
if(request.getParameter("email") != null) {
//요청 매개변수로부터 VO 객체 준비
/*request.setAttribute("member", new Member().setNo(Integer.parseInt(request.getParameter("no")))
.setEmail(request.getParameter("email"))
.setName(request.getParameter("name")));*/
//Map 객체에 VO 객체 준비
model.put("member", new Member().setNo(Integer.parseInt(request.getParameter("no")))
.setEmail(request.getParameter("email"))
.setName(request.getParameter("name")));
}else {
model.put("no", new Integer(request.getParameter("no")));
}
}else if("/member/delete.do".equals(servletPath)) {
//pageControllerPath = "/member/delete";
//pageController = new MemberDeleteController();
model.put("no", new Integer(request.getParameter("no")));
}else if("/auth/login.do".equals(servletPath)) {
//pageControllerPath = "/auth/login";
//pageController = new LogInController();
if(request.getParameter("email") != null) {
model.put("loginInfo", new Member().setEmail(request.getParameter("email"))
.setPassword(request.getParameter("password")));
}
}/*else if("/auth/logout.do".equals(servletPath)) {
//pageControllerPath = "/auth/logout";
//pageController = new LogOutController();
}*/
//페이지 컨트롤러로 실행 위임
/*RequestDispatcher rd = request.getRequestDispatcher(pageControllerPath);
rd.include(request, response);*/
//페이지 컨트롤러 실행
String viewUrl = pageController.execute(model); //뷰 URL 반환받음
//Map 객체에 저장된 값을 ServletRequest에 복사
for(String key : model.keySet()) {//keySet() : key값 가져옴
request.setAttribute(key, model.get(key)); //model.get(key) : value값 가져옴
}
//JSP로 위임
/*String viewUrl = (String)request.getAttribute("viewUrl");
if(viewUrl.startsWith("redirect:")) {
response.sendRedirect(viewUrl.substring(9));
return;
}else {
rd = request.getRequestDispatcher(viewUrl);
rd.include(request, response);
}*/
//JSP로 실행 위임
if(viewUrl.startsWith("redirect:")) {
response.sendRedirect(viewUrl.substring(9));
return;
}else {
RequestDispatcher rd = request.getRequestDispatcher(viewUrl);
rd.include(request, response);
}
} catch (Exception e) {//오류 처리
e.printStackTrace();
request.setAttribute("error", e);
RequestDispatcher rd = request.getRequestDispatcher("/Error.jsp");
rd.forward(request, response);
}
}
}
MemberDao 객체는 더 이상 Map 객체에 담을 필요가 없어서 제거하였다.
//model.put("memberDao", sc.getAttribute("memberDao")); //memberDao 객체는 더이상 Map 객체에 담을 필요 없음.
- ServletContext에서 페이지 컨트롤러 꺼내기
페이지 컨트롤러는 ServletContext 보관소에 저장되어 있다. 이 보관소에서 페이지 컨트롤러를 꺼낼 때는 서블릿 URL을 사용한다.
//ServletContext에서 페이지 컨트롤러 꺼낼 때 서블릿 URL 사용
Controller pageController = (Controller)sc.getAttribute(servletPath);
- 조건문 변경
if ~ else 조건문에서 페이지 컨트롤러가 사용할 데이터를 준비하는 부분을 제외하고는 모두 제거하였다. 다음 강의에서는 이 부분도 자동화시킬 것이다.
//페이지 컨트롤러로 위임
//조건문 변경 : 페이지 컨트롤러가 사용할 데이터를 준비하는 부분 외 제거
/*if("/member/list.do".equals(servletPath)) {
//pageControllerPath = "/member/list";
//pageController = new MemberListController();
}else*/
if("/member/add.do".equals(servletPath)) {
//pageControllerPath = "/member/add";
//pageController = new MemberAddController();
if(request.getParameter("email") != null) {
//요청 매개변수로부터 VO 객체 준비
/*request.setAttribute("member", new Member().setEmail(request.getParameter("email"))
.setPassword(request.getParameter("password"))
.setName(request.getParameter("name")));*/
//Map 객체에 VO 객체 준비
model.put("member", new Member().setEmail(request.getParameter("email"))
.setPassword(request.getParameter("password"))
.setName(request.getParameter("name")));
}
}else if("/member/update.do".equals(servletPath)) {
//pageControllerPath = "/member/update";
//pageController = new MemberUpdateController();
if(request.getParameter("email") != null) {
//요청 매개변수로부터 VO 객체 준비
/*request.setAttribute("member", new Member().setNo(Integer.parseInt(request.getParameter("no")))
.setEmail(request.getParameter("email"))
.setName(request.getParameter("name")));*/
//Map 객체에 VO 객체 준비
model.put("member", new Member().setNo(Integer.parseInt(request.getParameter("no")))
.setEmail(request.getParameter("email"))
.setName(request.getParameter("name")));
}else {
model.put("no", new Integer(request.getParameter("no")));
}
}else if("/member/delete.do".equals(servletPath)) {
//pageControllerPath = "/member/delete";
//pageController = new MemberDeleteController();
model.put("no", new Integer(request.getParameter("no")));
}else if("/auth/login.do".equals(servletPath)) {
//pageControllerPath = "/auth/login";
//pageController = new LogInController();
if(request.getParameter("email") != null) {
model.put("loginInfo", new Member().setEmail(request.getParameter("email"))
.setPassword(request.getParameter("password")));
}
}/*else if("/auth/logout.do".equals(servletPath)) {
//pageControllerPath = "/auth/logout";
//pageController = new LogOutController();
}*/
구조를 개선하고 나서 제대로 동작하는지 테스트해본다.
톰캣 서버를 재시작한 후, 웹 브라우저에서 http://localhost:9999/web06/member/list.do를 요청한다. 회원 목록 외에 로그인, 로그아웃, 회원 등록, 변경, 삭제까지 모두 테스트한다.
참고도서 : https://freelec.co.kr/book/1674/
[열혈강의] 자바 웹 개발 워크북
[열혈강의] 자바 웹 개발 워크북
freelec.co.kr
'교재 실습 > 자바 웹 개발 워크북' 카테고리의 다른 글
| 85. 리플랙션 API를 이용하여 프런트 컨트롤러 개선하기 (1) (0) | 2022.08.03 |
|---|---|
| 84. DI를 이용한 빈 의존성 관리 (3) (0) | 2022.08.02 |
| 82. DI를 이용한 빈 의존성 관리 (1) (0) | 2022.07.31 |
| 81. 페이지 컨트롤러의 진화 (3) (0) | 2022.07.30 |
| 80. 페이지 컨트롤러의 진화 (2) (0) | 2022.07.28 |
댓글