Day 71 : MVC 프레임워크 개발
1. MVC 프레임워크 구조
클래스 | 기능 |
DispatcherServlet | 유일한 서블릿 클래스로서 모든 클라이언트의 요청을 가장 먼저 처리하는 Front Controller → 새로운 기능이 추가되더라도 DispatcherServlet 클래스의 소스는 변경할 필요가 없도록 개발해야 함 |
HandlerMapping | 클라이언트의 요청을 처리할 Controller 매핑 |
Controller | 실질적인 클라이언트의 요청 처리 |
ViewResolver | Controller가 리턴한 View 이름으로 실행될 JSP 경로 완성 |
※ 클라이언트의 요청을 받은 DispatcherServlet은 HandlerMapping을 통해 Controller 객체를 검색하고, 검색된 Controller를 실행 → 이 때, 어떤 Controller가 검색되더라도 같은 코드로 실행하려면 모든 Controller의 최상위 인터페이스가 필요
2. MVC 프레임워크 구현
① Controller 인터페이스 작성 (최상위 인터페이스)
package com.springbook.view.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface Controller {
String handleRequest(HttpServletRequest request, HttpServletResponse response);
}
② LoginController 구현
package com.springbook.view.user;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.springbook.biz.user.UserVO;
import com.springbook.biz.user.impl.UserDAO;
import com.springbook.view.controller.Controller;
public class LoginController implements Controller {
@Override
public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
System.out.println("로그인 처리");
// 1. 사용자 입력 정보 추출
String id = request.getParameter("id");
String password = request.getParameter("password");
// 2. DB 연동 처리
UserVO vo = new UserVO();
vo.setId(id);
vo.setPassword(password);
UserDAO userDAO = new UserDAO();
UserVO user = userDAO.getUser(vo);
// 3. 화면 네비게이션
if (user != null) {
return "getBoardList.do"; //메소드 재정의이기 때문에 리다이렉트가 아니라 리턴하는 것으로 처리
} else {
return "login"; //handleRequest 메소드는 확장자가 없는 문자열을 리턴하면 자동으로 .jsp 확장자가 붙음
}
}
}
③ HandlerMapping 클래스 작성
: 모든 Controller 객체들을 저장하고 있다가, 클라이언트의 요청이 들어오면 요청을 처리할 특정 Controller를 검색하는 기능 제공 → DispatcherServlet이 사용하는 객체 (init() 메소드 호출 시 단 한 번 생성)
package com.springbook.view.controller;
import java.util.HashMap;
import java.util.Map;
import com.springbook.view.user.LoginController;
public class HandlerMapping {
private Map<String, Controller> mappings;
public HandlerMapping() {
mappings = new HashMap<String, Controller>();
mappings.put("/login.do", new LoginController());
}
public Controller getController(String path) {
return mappings.get(path); //path에 해당하는 Controller 객체를 HashMap 컬렉션으로부터 검색하여 리턴
}
}
④ ViewResolver 클래스 작성
: Controller가 리턴한 View 이름에 접두사(prefix)와 접미사(suffix)를 결합하여 최종으로 실행될 View 경로와 파일명을 완성 → DispatcherServlet의 init() 메소드 호출 시 생성
package com.springbook.view.controller;
public class VIewResolver {
public String prefix; //접두사
public String suffix; //접미사
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
public String getView(String viewName) {
return prefix + viewName + suffix;
}
}
⑤ DispatcherServlet 수정
package com.springbook.view.controller;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.springbook.biz.board.BoardVO;
import com.springbook.biz.board.impl.BoardDAO;
import com.springbook.biz.user.UserVO;
import com.springbook.biz.user.impl.UserDAO;
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private HandlerMapping handlerMapping;
private ViewResolver viewResolver;
@Override
public void init() throws ServletException {
handlerMapping = new HandlerMapping();
viewResolver = new ViewResolver();
viewResolver.setPrefix("./");
viewResolver.setSuffix(".jsp");
}
public DispatcherServlet() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
process(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
request.setCharacterEncoding("EUC-KR");
process(request, response);
}
private void process(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 1. 클라이언트의 요청 path 정보를 추출한다.
String uri = request.getRequestURI();
String path = uri.substring(uri.lastIndexOf("/"));
System.out.println(path);
//2. HandlerMapping을 통해 path에 해당하는 Controller를 검색한다.
Controller ctrl = handlerMapping.getController(path);
//3. 검색된 Controller를 실행한다. (로직 처리 후 이동할 화면 정보 리턴)
String viewName = ctrl.handleRequest(request, response);
//4. ViewResolver를 통해 viewName에 해당하는 화면을 검색한다.
String view = null;
if(!viewName.contains(".do")) {
view = viewResolver.getView(viewName);
} else {
view = viewName;
}
//5. 검색된 화면으로 이동
response.sendRedirect(view);
}
}
3. MVC 프레임워크 구현
① 글 목록 검색 구현
package com.springbook.view.board;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.springbook.biz.board.BoardVO;
import com.springbook.biz.board.impl.BoardDAO;
import com.springbook.view.controller.Controller;
public class GetBoardListController implements Controller {
@Override
public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
System.out.println("글 목록 검색 처리");
// 1. 사용자 입력 정보 추출(검색 기능은 나중에 구현)
// 2. DB 연동 처리
BoardVO vo = new BoardVO();
BoardDAO boardDAO = new BoardDAO();
List<BoardVO> boardList = boardDAO.getBoardList(vo);
// 3. 검색 결과를 세션에 저장하고 목록 화면으로 이동한다.
HttpSession session = request.getSession();
session.setAttribute("boardList", boardList);
return "getBoardList"; //확장자 없이 리턴하는 이유는 ViewResolver를 이용하여 View 이름을 완성하기 때문이다.
}
}
- HandlerMapping 클래스에 객체 등록
package com.springbook.view.controller;
import java.util.HashMap;
import java.util.Map;
import com.springbook.view.board.GetBoardListController;
import com.springbook.view.user.LoginController;
public class HandlerMapping {
private Map<String, Controller> mappings;
public HandlerMapping() {
mappings = new HashMap<String, Controller>();
mappings.put("/login.do", new LoginController());
mappings.put("/getBoardList.do", new GetBoardListController());
}
public Controller getController(String path) {
return mappings.get(path); //path에 해당하는 Controller 객체를 HashMap 컬렉션으로부터 검색하여 리턴
}
}
② 글 상세 보기 구현
package com.springbook.view.board;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.springbook.biz.board.BoardVO;
import com.springbook.biz.board.impl.BoardDAO;
import com.springbook.view.controller.Controller;
public class GetBoardController implements Controller {
@Override
public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
System.out.println("글 상세 조회 처리");
// 1. 검색할 게시글 번호 추출
String seq = request.getParameter("seq");
// 2. DB 연동 처리
BoardVO vo = new BoardVO();
vo.setSeq(Integer.parseInt(seq));
BoardDAO boardDAO = new BoardDAO();
BoardVO board = boardDAO.getBoard(vo);
// 3. 검색 결과를 세션에 저장하고 목록 화면으로 이동한다.
HttpSession session = request.getSession();
session.setAttribute("board", board);
return "getBoard";
}
}
- HandlerMapping 클래스에 객체 등록
package com.springbook.view.controller;
import java.util.HashMap;
import java.util.Map;
import com.springbook.view.board.GetBoardController;
import com.springbook.view.board.GetBoardListController;
import com.springbook.view.user.LoginController;
public class HandlerMapping {
private Map<String, Controller> mappings;
public HandlerMapping() {
mappings = new HashMap<String, Controller>();
mappings.put("/login.do", new LoginController());
mappings.put("/getBoardList.do", new GetBoardListController());
mappings.put("/getBoard.do", new GetBoardController());
}
public Controller getController(String path) {
return mappings.get(path); //path에 해당하는 Controller 객체를 HashMap 컬렉션으로부터 검색하여 리턴
}
}
③ 글 등록 구현
package com.springbook.view.board;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.springbook.biz.board.BoardVO;
import com.springbook.biz.board.impl.BoardDAO;
import com.springbook.view.controller.Controller;
public class InsertBoardController implements Controller {
@Override
public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
System.out.println("글 등록 처리");
// 1. 사용자 입력 정보 추출
// request.setCharacterEncoding("EUC-KR");
String title = request.getParameter("title");
String writer = request.getParameter("writer");
String content = request.getParameter("content");
// 2. DB 연동 처리
BoardVO vo = new BoardVO();
vo.setTitle(title);
vo.setWriter(writer);
vo.setContent(content);
BoardDAO boardDAO = new BoardDAO();
boardDAO.insertBoard(vo);
// 3. 화면 네비게이션
return "getBoardList.do";
}
}
- HandlerMapping 클래스에 객체 등록
package com.springbook.view.controller;
import java.util.HashMap;
import java.util.Map;
import com.springbook.view.board.GetBoardController;
import com.springbook.view.board.GetBoardListController;
import com.springbook.view.board.InsertBoardController;
import com.springbook.view.user.LoginController;
public class HandlerMapping {
private Map<String, Controller> mappings;
public HandlerMapping() {
mappings = new HashMap<String, Controller>();
mappings.put("/login.do", new LoginController());
mappings.put("/getBoardList.do", new GetBoardListController());
mappings.put("/getBoard.do", new GetBoardController());
mappings.put("/insertBoard.do", new InsertBoardController());
}
public Controller getController(String path) {
return mappings.get(path); //path에 해당하는 Controller 객체를 HashMap 컬렉션으로부터 검색하여 리턴
}
}
④ 글 수정 구현
package com.springbook.view.board;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.springbook.biz.board.BoardVO;
import com.springbook.biz.board.impl.BoardDAO;
import com.springbook.view.controller.Controller;
public class UpdateBoardController implements Controller {
@Override
public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
System.out.println("글 수정 처리");
// 1. 사용자 입력 정보 추출
// request.setCharacterEncoding("EUC-KR");
String title = request.getParameter("title");
String content = request.getParameter("content");
String seq = request.getParameter("seq");
// 2. DB 연동 처리
BoardVO vo = new BoardVO();
vo.setTitle(title);
vo.setContent(content);
vo.setSeq(Integer.parseInt(seq));
BoardDAO boardDAO = new BoardDAO();
boardDAO.updateBoard(vo);
// 3. 화면 네비게이션
return "getBoardList.do";
}
}
- HandlerMapping 클래스에 객체 등록
package com.springbook.view.controller;
import java.util.HashMap;
import java.util.Map;
import com.springbook.view.board.GetBoardController;
import com.springbook.view.board.GetBoardListController;
import com.springbook.view.board.InsertBoardController;
import com.springbook.view.board.UpdateBoardController;
import com.springbook.view.user.LoginController;
public class HandlerMapping {
private Map<String, Controller> mappings;
public HandlerMapping() {
mappings = new HashMap<String, Controller>();
mappings.put("/login.do", new LoginController());
mappings.put("/getBoardList.do", new GetBoardListController());
mappings.put("/getBoard.do", new GetBoardController());
mappings.put("/insertBoard.do", new InsertBoardController());
mappings.put("/updateBoard.do", new UpdateBoardController());
}
public Controller getController(String path) {
return mappings.get(path); //path에 해당하는 Controller 객체를 HashMap 컬렉션으로부터 검색하여 리턴
}
}
⑤ 글 삭제 구현
package com.springbook.view.board;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.springbook.biz.board.BoardVO;
import com.springbook.biz.board.impl.BoardDAO;
import com.springbook.view.controller.Controller;
public class DeleteBoardController implements Controller {
@Override
public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
System.out.println("글 삭제 처리");
// 1. 사용자 입력 정보 추출
String seq = request.getParameter("seq");
// 2. DB 연동 처리
BoardVO vo = new BoardVO();
vo.setSeq(Integer.parseInt(seq));
BoardDAO boardDAO = new BoardDAO();
boardDAO.deleteBoard(vo);
// 3. 화면 네비게이션
return "getBoardList.do";
}
}
- HandlerMapping 클래스에 객체 등록
package com.springbook.view.controller;
import java.util.HashMap;
import java.util.Map;
import com.springbook.view.board.DeleteBoardController;
import com.springbook.view.board.GetBoardController;
import com.springbook.view.board.GetBoardListController;
import com.springbook.view.board.InsertBoardController;
import com.springbook.view.board.UpdateBoardController;
import com.springbook.view.user.LoginController;
public class HandlerMapping {
private Map<String, Controller> mappings;
public HandlerMapping() {
mappings = new HashMap<String, Controller>();
mappings.put("/login.do", new LoginController());
mappings.put("/getBoardList.do", new GetBoardListController());
mappings.put("/getBoard.do", new GetBoardController());
mappings.put("/insertBoard.do", new InsertBoardController());
mappings.put("/updateBoard.do", new UpdateBoardController());
mappings.put("/deleteBoard.do", new DeleteBoardController());
}
public Controller getController(String path) {
return mappings.get(path); //path에 해당하는 Controller 객체를 HashMap 컬렉션으로부터 검색하여 리턴
}
}
⑥ 로그아웃 구현
package com.springbook.view.user;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.springbook.view.controller.Controller;
public class LogoutController implements Controller {
@Override
public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
System.out.println("로그아웃 처리");
// 1. 브라우저와 연결된 세션 객체를 강제 종료한다.
HttpSession session = request.getSession();
session.invalidate();
// 2. 세션 종료 후, 메인 화면으로 이동한다.
return "login";
}
}
- HandlerMapping 클래스에 객체 등록
package com.springbook.view.controller;
import java.util.HashMap;
import java.util.Map;
import com.springbook.view.board.DeleteBoardController;
import com.springbook.view.board.GetBoardController;
import com.springbook.view.board.GetBoardListController;
import com.springbook.view.board.InsertBoardController;
import com.springbook.view.board.UpdateBoardController;
import com.springbook.view.user.LoginController;
import com.springbook.view.user.LogoutController;
public class HandlerMapping {
private Map<String, Controller> mappings;
public HandlerMapping() {
mappings = new HashMap<String, Controller>();
mappings.put("/login.do", new LoginController());
mappings.put("/getBoardList.do", new GetBoardListController());
mappings.put("/getBoard.do", new GetBoardController());
mappings.put("/insertBoard.do", new InsertBoardController());
mappings.put("/updateBoard.do", new UpdateBoardController());
mappings.put("/deleteBoard.do", new DeleteBoardController());
mappings.put("/logout.do", new LogoutController());
}
public Controller getController(String path) {
return mappings.get(path); //path에 해당하는 Controller 객체를 HashMap 컬렉션으로부터 검색하여 리턴
}
}