본문 바로가기
교재 실습/자바 웹 개발 워크북

83. DI를 이용한 빈 의존성 관리 (2)

by jint 2022. 8. 1.

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

댓글