todoApp 만들기

ggujunhee·2021년 12월 15일
0

return하는 종류는 2가지

  1. 내부이동하는 주소.("/model2-todo.home.hta")
  2. 재요청하는 주소. ("redirect:/model2-todo.home.hta")

map을 사용하면 FrontController의 if문을 없앨수있다.

FrontController_if.ver


@WebServlet("*.hta")
public class FrontControllerServlet extends HttpServlet {

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		// 웹 애플리케이션의 ContextPath를 조회한다.
		// ContextPath는 웹 애플리케이션을 식별하는 이름이다.
		// 특별히 지정하지않으면 프로젝트이름이 contextPath가 된다.
		// Tomcat에 배포된 여러 웹애플리케이션은 서로 다른 contextPath를 가지며, contextPath가 웹 애플리케이션 프로젝트를 구분하는 식별자가 된다.
		String contextPath = request.getContextPath();
		
		// 클라이언트의 요청URI를 조회한다.
		String requestURI = request.getRequestURI();
		requestURI = requestURI.replace(contextPath, "");
		System.out.println("요청URI [" + requestURI + "]");
		
		// 요청URI에 해당하는 컨트롤러 객체를 생성하고 실행시킨다.
		try {
			if ("/home.hta".equals(requestURI)) {
				new HomeController().execute(request, response);

			} else if ("/registerform.hta".equals(requestURI)) {
				new RegisterFormController().execute(request, response);
				
			} else if ("/register.hta".equals(requestURI)) {
				new RegisterController().execute(request, response);
				
			} else if ("/loginform.hta".equals(requestURI)) {
				new LoginFormController().execute(request, response);
				
			} else if ("/login.hta".equals(requestURI)) {
				new LoginController().execute(request, response);
				
			} else if ("/logout.hta".equals(requestURI)) {
				new LogoutController().execute(request, response);
				
			} else if ("/el1.hta".equals(requestURI)) {
				new ElSampleController1().execute(request, response);
				
			} else if ("/el2.hta".equals(requestURI)) {
				new ElSampleController2().execute(request, response);
				
			} else if ("/el3.hta".equals(requestURI)) {
				new ElSampleController3().execute(request, response);
			
			} else if ("/jstl1.hta".equals(requestURI)) {
				new JstlCotroller1().execute(request, response);

			} else if ("/jstl2.hta".equals(requestURI)) {
				new JstlCotroller2().execute(request, response);
				
			} else if ("/jstl3.hta".equals(requestURI)) {
				new JstlCotroller3().execute(request, response);
				
			} else if ("/jstl4.hta".equals(requestURI)) {
				new JstlCotroller4().execute(request, response);
				
			} else if ("/jstl5.hta".equals(requestURI)) {
				new JstlCotroller5().execute(request, response);
				
			}
		} catch (Exception e) {
			throw new ServletException(e);
		}
	}
}

FrontControllerServlet.java

@WebServlet("*.hta")
public class FrontControllerServlet extends HttpServlet {

	private static final long serialVersionUID = 339661543186959731L;
	private Map<String, Controller> controllers = new HashMap<>();
	
	public void init() throws ServletException {
		controllers.put("/home.hta", new HomeController());
		controllers.put("/loginform.hta", new LoginFormController());
		controllers.put("/login.hta", new LoginController());
		controllers.put("/logout.hta", new LogoutController());
		controllers.put("/todo/list.hta", new TodoListController());
		controllers.put("/todo/detail.hta", new TodoDetailController());
		controllers.put("/todo/form.hta", new TodoFormController());
		controllers.put("/todo/insert.hta", new TodoInsertController());
		controllers.put("/todo/update.hta", new TodoUpdateController());
	}
	
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		try {
			String requestURI = request.getRequestURI().replace(request.getContextPath(), "");
			Controller controller = controllers.get(requestURI);
			if (controller == null) {
				throw new RuntimeException("요청 URI에 대응되는 컨트롤러가 존재하지 않습니다.");
			}
			String path = controller.execute(request, response);
			if (path == null) {
				throw new RuntimeException("내부이동 혹은 재요청할 경로가 null입니다.");
			}
			if (path.startsWith("redirect:")) {
				response.sendRedirect(path.replace("redirect:", ""));
			} else {
				path = "/WEB-INF/views/" + path;
				request.getRequestDispatcher(path).forward(request, response);
			}
			
		} catch (Exception e) {
			throw new ServletException(e);
		}
	}
}

Untitled

Untitled

  1. init 메서드에서 requestURI들을 Mapper에 저장한다.
  2. service 메서드에서 주소창에서 받아온 uri를 담은 변수로 controllers mapper에 저장한 값을 불러온다.
  3. 만약 controller가 null이면 (해당 파일이 없다면) 예외처리함.
  4. controller 를 실행시켜 string형태의 path를 반환받음.
  5. 만약 controller를 실행했을 때 반환받은 path가 null이면(해당 파일이 없다면) 예외처리함.
  6. 만약 controller의 반환된 path가 redirect(재요청)로 시작했다면 (startsWith) 그곳으로 sendRedirect시킴.
  7. 앞의 조건이 성립안될 시 WEB-INF/views/ 뒤에 path(return받은 jsp 파일명)를 붙여 내부이동시킴.

로그인화면 넘어가기.

Untitled

  • FrontController의 요청객체가 LoginFormController와 loginform.jsp에도 넘어감
  • 그래서 loginform.jsp에서 param.error를 사용할 수 있음.

로그인,로그아웃하기

Untitled

Untitled

등록,수정,삭제는 내부이동 할 필요가 없어서 재요청 URL만 보내면 됨.

왜냐하면 기능을 수행할때 보여줄 것이 없기 때문

Untitled

  • 개발 순서
    • loginController
    1. 요청객체에서 요청파라미터(id, password)를 조회한다.
    2. UserDao의 getUserById(id)를 실행해서 사용자정보를 조회한다.
    3. 사용자정보가 null이면 "redirect:/model2-todo/loginform.hta?error=notfound"을 반환한다.
    4. 비밀번호가 일치하지 않으면 "redirect:/model2-todo/loginform.hta?error=mismatch"를 반환한다.
    5. 사용자가 존재하고, 비밀번호가 일치하면 HttpSession객체를 획득해서 HttpSession객체 에 사용자정보를 "loginUser"라는 속성명으로 저장한다.
    6. 홈페이지를 재요청하는 URL("redirect:/model2-todo/home.hta")을 반환한다.
    • loginform.jsp
      • c:if로 조건걸어 error종류마다(id없음 or 비밀번호불일치) 다른 alert를 보여주기.
    • navbar.jsp
      • 로그인폼에서 c:if로 조건걸어 로그인한 사람한테만 로그인했을 때 할 수 있는 메뉴들을 보여줌.
    • logout.jsp
      • HttpSession객체를 획득(request.getSession())해서 session객체를 폐기(session.invalidate())시킨다.
      • 홈화면을 요청하는 재요청URL을 응답으로 보낸다.

일반 model1방식과 달라진 점은 직접 responseRedirect를 하는 것이 아니라 어디로 이동해야할 지 주소를 반환해야한다는 것.

이동하는 방법도 2가지라는 점. 1) 내부이동 2) 재요청redirect

loginController

public class LoginController implements Controller {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		String id = request.getParameter("id");
		String password = request.getParameter("password");
		User user = UserDao.getInstance().getUserById(id);
		if (user == null) {
			return "redirect:/model2-todo/loginform.hta?error=notfound";
		}
		if (!user.getPassword().equals(password)) {
			return "redirect:/model2-todo/loginform.hta?error=mismatch";
		}
		HttpSession session = request.getSession();
		session.setAttribute("loginUser", user);
		
		return "redirect:/model2-todo/home.hta";
	}
}

loginform.jsp

<div class="col-8">
			<c:if test="${param.error eq 'notfound'}">
			<div class="alert alert-danger mb-3">
				<strong>아이디 오류</strong> 아이디에 해당하는 사용자가 존재하지 않습니다.
			</div>
			</c:if>
			<c:if test="${param.error eq 'mismatch' }">
			<div class="alert alert-danger mb-3">
				<strong>비밀번호 오류</strong> 비밀번호가 일치하지 않습니다.
			</div>
			</c:if>

로그인폼에서 c:if로 조건걸어 error종류마다 다른 alert를 보여주기.

navbar.jsp

<div class="collapse navbar-collapse" id="navbarSupportedContent">
			<ul class="navbar-nav me-auto mb-2 mb-lg-0">
				<li class="nav-item"><a class="nav-link" href="/model2-todo/home.hta"></a></li>
				<c:if test="${not empty loginUser }">
					<li class="nav-item"><a class="nav-link" href="/model2-todo/todo/list.hta">일정 목록</a></li>
					<li class="nav-item"><a class="nav-link" href="/model2-todo/todo/form.hta">일정 등록</a></li>
				</c:if>		
			</ul>
			<ul class="navbar-nav">
			<c:if test="${empty loginUser }">
				<li class="nav-item"><a class="nav-link" href="/model2-todo/loginform.hta">로그인</a></li>
			</c:if>
			<c:if test="${not empty loginUser }">
				<li class="nav-item"><a class="nav-link" href="/model2-todo/logout.hta"><strong>홍길동</strong>님 로그아웃</a></li>
			</c:if>
			</ul>
		</div>

logout.jsp

public class LogoutController implements Controller {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		/*
		 * 1. HttpSession객체를 획득(request.getSession())해서 session객체를 폐기(session.invalidate())시킨다.
		 * 2. 홈화면을 요청하는 재요청URL을 응답으로 보낸다.
		 */
		HttpSession session = request.getSession();
		session.invalidate();
		
		return "redirect:/model2-todo/home.hta";
	}
}

일정 등록화면 요청하기

Untitled

새 일정정보 등록하기. (todo insert)

Untitled

  1. 요청객체에서 HttpSession객체를 획득한다.
  2. 세션객체에서 로그인된 사용자 정보를 조회한다.
  3. 로그인 사용자정보가 null면 "redirect:/model2-todo/loginform.hta?error=required"을 반환한다.
  4. todo/form.jsp가 제출한 값을 조회한다.
    처리예정일은 jav.util.date 타입으로 변환한다.
    DateUtils.parseDate(날짜,"yyyy-MM-dd")
  5. Todo 객체를 생성해서 조회된 값을 저장한다.
    카테고리번호, 제목, 처리예정일, 사용자번호, 내용을 todo객체에 저장한다.
  6. Todo 객체를 dao에 전달해서 저장시킨다.
  7. 화면 목록을 재요청하는 url을 응답으로 보낸다.

일정목록 화면 요청하기

Untitled

화면에 뿌리게 됨.

  • 일정목록 조회

    • HttpSession을 조회한다.
    • HttpSession에서 로그인된 사용자정보를 조회하다.
    • 사용자정보가 존재하지 않으면 로그인폼을 재요청응답한다.
    • 페이지네이션
      • 요청 페이지번호 조회, 없으면 1페이지
      • 전체 일정갯수 조회
      • Pagination객체를 생성
      • 조회시작범위, 조회종료범위를 획득한다.
      • 해당범위에 속하는 일정목록을 조회한다.
      • 요청객체에 Pagination객체를 속성으로 저장
      • 요청객체에 조회된 일정목록을 속성으로 저장
  • 일정목록 출력 →일정목록화면

  • 페이징출력 →일정목록화면

Untitled

————————————————————————————————————————————

Untitled

  • todo/detail.hta?no=2&page=1 가 frontcontroller로 전달.

  • FrontController가 하나 생겨남 → 객체가 만들어짐. 그 안에 작은 객체도 곁다리로 들어감.

  • FrontController객체에는 요청파라미터 no, page가 들어있음.

  • execute(req,res)로 TodoDetailController로 넘어감.

  • TodoDetailController

    • HttpSession객체를 획득한다.
    • HttpSession객체에서 인증된 사용자정보를 조회한다.
    • 사용자정보가 존재하지 않으면 로그인폼을 재요청하는 응답을 보낸다.
    • 요청파라미터에서 일정번호를 조회한다.
    • 일정번호에 해당하는 일정 상세정보(TodoDto)를 조회한다.
    • 전체 카테고리 목록(List)을 조회한다.
    • 전체 일정상태 목록(List)을 조회한다.
    • 요청객체에 일정상세정보를 속성으로 저장한다.
    • 요청객체에 카테고리목록 정보를 속성으로 저장한다.
    • 요청객체에 일정상태목록정보를 속성으로 저장한다
    • 내부이동할 jsp페이지(todo/detail.jsp)를 반환한다.
    • ⇒ FrontController에 속성으로 저장시킴.
  • todo/detail.jsp

    • 일정상세정보출력
      • ${todo.no} ${todo.title} ${todo.content}....
    • 카테고리목록출력
      • <c:forEach var="category" items="${categoryList}"> </c:forEach>
    • 상태목록 출력
      • <c:forEach var="status" items="${statusList}"> </c:forEach>
    • 모두 다 일정상세 화면에 출력.

Spring으로 가면 요청파라미터에서 값꺼내기,mybatis, db엑세스, controller를 만드는 방식이 훨씬 쉬워지고 간단해져서 로직구현해내는 것에만 집중할 수 있게 됨.

Untitled

profile
꾸준히 배워가는 블로그입니다.

0개의 댓글