본문 바로가기
👨‍💻 2. 웹개발_Back end/2-6 Spring

[Spring] 4장 MVC 프레임워크 개발 - MVC 프레임워크 클래스 종류 및 역할 / 각 기능별 Controller 클래스 생성 및 HandlerMapping 클래스에 객체 등록

by 달님🌙 2021. 10. 29.
반응형

 

실습 코드 참조

 

moonhy7/SpringFramework: Spring Framework 실습 코드 정리 (github.com)

 

GitHub - moonhy7/SpringFramework: Spring Framework 실습 코드 정리

Spring Framework 실습 코드 정리. Contribute to moonhy7/SpringFramework development by creating an account on GitHub.

github.com

 

 

4.1절 MVC 프레임워크 구조

 

1. Spring MVC Controller

 

- 하나의 서블릿으로 Controller를 구현하면 클라이언트의 모든 요청을 하나의 서블릿이 처리하기 때문에 수많은 분기 처리 로직이 생겨 개발과 유지보수가 어렵다.

- 특정 기능을 수정하려고 할 때 코드를 찾는게 어렵고 새로운 기능을 추가할 때 역시 분기 처리 로직은 계속 늘어나므로 복잡도는 계속 증가하게 된다.

- 최종적으로는 Spring MVC 프레임워크를 사용하여 제공되는 효율적인 Controller를 사용할 예정이다. 

- 하지만 이는 기능과 구조가 복잡하기 때문에 이와 동일한 구조를 직접 구현해보면서 Spring MVC 구성 요소와 동작 원리를 이해해보자

 

2. MVC 프레임워크 구조

 

3. MVC 프레임워크 클래스 역할

 

 

 

4.2절 MVC 프레임워크 구현

 

1. Controller 인터페이스 작성 ( _053_BoardWeb_MVC_Interface )

 

- DispatcherServlet : 클라이언트의 요청을 가장 먼저 받아들이는 Front Controller로서, 실질적인 요청 처리는 각 Controller가 담당한다.

- 클라이언트의 요청을 받은 DispatcherServlet은 HandlerMapping을 통해 Controller 객체를 검색하고 검색된 Controller를 실행한다.

- 이때 어떤 Controller 객체가 검색되더라도 같은 코드로 실행하려면 모든 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);
}

 

2. LoginController 구현

 

- Controller 인터페이스를 구현한 LoginController 클래스 작성

- DispatcherServlet 클래스에서 /login.do에 해당하는 소스를 복사해온다.

- 다만 Controller 인터페이스의 handleRequest() 메소드를 재정의했으므로 로그인 처리 기능의 마지막은 이동할 화면을 리턴하는 것으로 처리한다.

- handleRequest() 메소드가 확장자 없는 문자열을 리턴하면 자동으로 .jsp 확장자가 붙어서 처리되기때문에 login.jsp가 아니라 그냥 login이다. (ViewResolver 클래스에서 자세히 나옴) 

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. 사용자 입력 정보 추출(login.jsp에서 전송한 id, password 받기)
		String id = request.getParameter("id");
		String password = request.getParameter("password");
		
		//2. DB연동 처리(UserDAO의 메소드 호출)
		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";
		}
	}
}

 

3. HandlerMapping 클래스 작성

 

- HandlerMApping은 모든 Controller 객체를 저장하고 있다가 클라이언트의 요청이 들어오면 요청을 처리할 특정 Controller를 검색하는 기능을 제공한다.

- HandlerMapping 객체는 DispatcherServlet이 사용하는 객체이므로 DispatcherServlet이 생성되고 init() 메소드가 호출될 때 단 한 번 생성된다.

- HandlerMapping은 Map 타입의 컬렉션을 멤버변수로 가지고 있으면서 게시판 프로그램에 필요한 모든 Controller 객체들을 등록하고 관리한다.

- getController() 메소드는 매개변수로 받은 path에 해당하는 Controller 객체를 HashMap 컬렉션으로부터 검색하여 리턴한다.

- HashMap에 등록된 정보를 보면 Controller 객체가 어떤 .do 요청과 매핑되어 있는지 확인할 수 있다. 

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("/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);
	}
}

 

4. ViewResolver 클래스 작성

 

- ViewResolver 클래스는 Controller가 리턴한 View 이름에 접두사(prefix)와 접미사(suffix)를 결합하여 최종으로 실행될 View 경로와 파일명을 완성한다.

- ViewResolver도 HandlerMapping과 마찬가지로 DispatcherServlet의 init() 메소드가 호출될 때 생성된다.

- ViewResolver는 setPrefix()와 setSuffix() 메소드로 접두사와 접미사를 초기화한다.

- 그리고 getView() 메소드가 호출될 때 viewNAme 앞에 prefix를 결합하고 뒤에는 suffix를 결합하여 리턴한다. 

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;
	}
}

 

5. DispatcherServlet 수정

 

- DispatcherServlet은 Front Controller 기능의 클래스로서 Controller 구성 요소 중 가장 중요한 역할을 수행한다.

- 수정을 시작하기에 앞서 이전 코드의 복사본을 만들어놓고 나중에 구체적인 Controller 클래스 구현에서 재사용하자.

- 수정된 DispatcherServlet 클래스에는 init() 메소드가 재정의되어있는데 HandlerMapping와 ViewResolver 객체를 초기화하기 위해 자동으로 실행된다.

- process() 메소드를 보면 클라이언트의 요청 path 정보 추출 코드를 제외한 나머지가 모두 수정되었다.

- 먼저 path에 해당하는 Controller를 검색하기 위해 HandlerMapping 객체의 getController() 메소드를 호출한다.

- 그리고 나서 검색된 Controller의 handlerRequest() 메소드를 호출하여 요청에 해당하는 로직을 처리하고 나면 이동할 화면 정보가 리턴된다.

- 마지막으로 Controller가 리턴한 View 이름을 이용하여 실행될 View를 찾아 해당 화면으로 이동한다.

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;

/**
 * Servlet implementation class DispatcherServlet
 */
public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private HandlerMapping handlerMapping;
	private ViewResolver viewResolver;
	
	public void init() throws ServletException {
		handlerMapping = new HandlerMapping();
		viewResolver = new ViewResolver();
		viewResolver.setPrefix("./");
		viewResolver.setSuffix(".jsp");
	}
	
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		process(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//클라이언트에서 전송하는 데이터가 한글일 경우 깨짐 방지
		request.setCharacterEncoding("UTF-8");
		process(request, response);
	}
	
	private void process(HttpServletRequest request, HttpServletResponse response) throws IOException {
		//1. 클라이언트 요청  path 정보를 추출한다.
		String uri = request.getRequestURI();
		//  http://localhost:9900/biz/login.do
		String path = uri.substring(uri.lastIndexOf("/"));
		//  /login.do
		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);
	}
}

 

6. 로그인 기능의 처리 순서

① 클라이언트가 로그인 버튼을 클릭하여 /login.do 요청을 전송하면 DispatcherServlet이 요청을 받는다.

② DispatcherServlet은 HandlerMapping 객체를 통해 로그인 요청을 처리할 LoginController를 검색하고,

③ 검색된 LoginController의 handleRequest() 메소드를 호출하면 로그인 로직이 처리된다.

④ 로그인 처리 후에 이동할 화면 정보가 리턴되면

⑤ DispatcherServlet은 ViewResolver를 통해 접두사와 접미사가 붙은 JSP 파일의 이름과 경로를 리턴받는다.

⑥ 그리고 최종적으로 JSP를 실행하고 실행 결과가 브라우저에 응답된다.

 

 

4.3절 MVC 프레임워크 적용

 

1. 글 목록 검색 구현

 

1) GetBoardListController 

- Controller 인터페이스를 구현한 GetBoardListController 클래스로서 DispatcherServlet에서 글 목록 검색 소스를 복사해서 구현함

- ViewResolver를 이용하여 View 이름을 완성하기 때문에 글 목록을 출력할 JSP 이름은 확장자 없이 리턴한다.

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 연동 처리(BoardDAO의 메소드 호출)
		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";
	}
}

 

2) HandlerMapping 클래스

- GetBoardListController 객체도 HandlerMapping 클래스에 등록한다.

package com.springbook.view.controller;

import java.util.HashMap;
import java.util.Map;

import com.springbook.view.board.GetBoardListController;

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);
	}
}

 

2. 글 상세 보기 구현

 

1) GetBoardController 

- Controller 인터페이스를 구현한 GetBoardController 클래스로서 DispatcherServlet에서 글 상세 조회 소스를 복사해서 구현함

- ViewResolver를 이용하여 View 이름을 완성하기 때문에 글 목록을 출력할 JSP 이름은 확장자 없이 리턴한다.

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 연동 처리(BoardDAO의 메소드 호출)
		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";
	}
}

 

2) HandlerMapping 클래스

- GetBoardController 객체도 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;

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);
	}
}

 

3. 글 등록 구현

 

1) InsertBoardController 클래스

- Controller 인터페이스를 구현한 InsertBoardController 클래스로서 DispatcherServlet에서 글 등록 소스를 복사해서 구현함

- handlerRequest() 메소드가 글 등록 작업을 처리한 후 글 등록애 성공하면 등록된 글이 포함된 글 목록을 다시 검색해야하므로 getBoardList.do 문자열을 리턴하여 리다이렉트 처리할 것이다.

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. 사용자 입력정보 추출(insertBoard.jsp에서 전송된 정보 추출)
		String title = request.getParameter("title");
		String writer = request.getParameter("writer");
		String content = request.getParameter("content");
		
		//2. DB 연동 처리(BoardDAO의 메소드 호출)
		BoardVO vo = new BoardVO();
		vo.setTitle(title);
		vo.setWriter(writer);
		vo.setContent(content);
		
		BoardDAO boardDAO = new BoardDAO();
		boardDAO.insertBoard(vo);
		
		//3. 화면 네비게이션
		//글 등록 처리 후 글 목록 페이지로 이동
		return "getBoardList.do";
 }
}

 

2) HandlerMapping 클래스

- InsertBoardController 객체도 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;

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);
	}
}

 

 

4. 글 수정 구현

 

1) UpdateBoardController 클래스

- Controller 인터페이스를 구현한 UpdateBoardController 클래스로서 DispatcherServlet에서 글 수정 소스를 복사해서 구현함

- UpdateBoardController 역시 글 수정 성공 후에 글 목록을 다시 검색하여 목록 화면을 갱신하야하므로 getBoardList.do를 리턴한다.

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. 사용자 입력정보 추출(getBoard.jsp에서 전송된 정보 추출)
		String seq = request.getParameter("seq");
		String title = request.getParameter("title");
		String content = request.getParameter("content");
		
		//2. DB 연동 처리(BoardDAO의 메소드 호출)
		BoardVO vo = new BoardVO();
		vo.setSeq(Integer.parseInt(seq));
		vo.setTitle(title);
		vo.setContent(content);
		
		BoardDAO boardDAO = new BoardDAO();
		boardDAO.updateBoard(vo);
		
		//3. 화면 네비게이션
		//수정처리 후 글 목록 화면으로 이동
		return "getBoardList.do";
	}
}

 

2) HandlerMapping 클래스

- UpdateBoardController 객체도 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;

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);
	}
}

 

5. 글 삭제 구현

 

1) DeleteBoardController 클래스

- Controller 인터페이스를 구현한 DeleteBoardController 클래스로서 DispatcherServlet에서 글 삭제 소스를 복사해서 구현함

- DeleteBoardController 역시 글 삭제 후에 글 목록을 다시 검색하여 목록 화면을 갱신하야하므로 getBoardList.do를 리턴한다.

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.사용자 입력정보 추출(getBoard.jsp에서 전송된 정보 추출)
		String seq = request.getParameter("seq");

		//2. DB 연동 처리(BoardDAO의 메소드 호출)
		BoardVO vo = new BoardVO();
		vo.setSeq(Integer.parseInt(seq));
		
		BoardDAO boardDAO = new BoardDAO();
		boardDAO.deleteBoard(vo);
		
		//3. 화면 네비게이션
		//글 삭제 처리 후 글 목록 화면으로 이동
		return "getBoardList.do";
	}
}

 

2) HandlerMapping 클래스

- DeleteBoardController 객체도 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());
		mappings.put("/updateBoard.do", new UpdateBoardController());
		mappings.put("/deleteBoard.do", new DeleteBoardController());
	}
	
	public Controller getController(String path) {
		return mappings.get(path);
	}
}

 

6. 로그아웃 구현

 

1) LogoutController 클래스

- Controller 인터페이스를 구현한 LogoutController 클래스로서 DispatcherServlet에서 로그아웃 기능 처리 소스를 복사해서 구현함

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";
	}
}

 

2) HandlerMapping 클래스

- LogoutController 객체도 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());
		mappings.put("/updateBoard.do", new UpdateBoardController());
		mappings.put("/deleteBoard.do", new DeleteBoardController());
	}
	
	public Controller getController(String path) {
		return mappings.get(path);
	}
}

 

7. 파일 구조

 

1) 작성된 컨트롤러 클래스들의 위치

 

 

2) Controller 분리 장점

- DispatcherServlet 클래스는 유지보수 과정에서 기존의 긴을 수정하거나 추가하더라도 절대 수정되지 않음

- 예를 들어, 게시판에 회원가입 기능을 추가할 때 InsertUserController 클래스를 추가로 작성하고 HandlerMapping에  InserUserController 객체를 등록하면 된다. 

- 이 과정에서 DispatcherServlet 클래스는 전혀 수정할 필요가 없다.

- 이렇게 기능 추가나 수정에 대해서 DispatcherServlet을 수정하지 않도록 해야 프레임워크에서 DispatcherServlet을 제공할 수 있는 것이다.

 

 

4.4절 EL/JSTL 이용한 JSP 화면 처리

 

1. EL/JSTL을 이용하는 이유

 

- Model 1 아키텍처를 Model 2 (MVC)로 변환했던 이유는 JSP 파일에서 Controller 로젝에 해당하는 자바 코드를 제거하기 위함이었다.

- 하지만 MVC 아키텍처가 적용된 BoardWeb 프로젝트에서 상세 화면과 목록 화면에 해당하는 getBoard.jsp와 getBoardList.jsp 파일에 여전히 자바 코드가 남아있다.

- 이런 자바 코드 조차도 JSP 파일에서 제거하고 싶다면 JSP에 제공하는 EL과 JSTL을 이용하면 된다.

 

2. EL/JSTL이란?

 

1. EL (Expression Language)

- JSP 2.0에서 새로 추가된 스크립트 언어로서 기존의 표현식을 대체하는 표현 언어이다.

- <%= session.getAttribute("userName") %>를 EL을 이용하여 ${username}으로 표현할 수 있다.

- 따라서 JSP에 남아있던 자바 코드를 제거할 수 있게 된다.

 

2. JSTL (JSP Standard Tag Library)

- JSP로 프로그램을 개발하다 보면 Scroptlet에서 if, for, switch 등과 같은 자바 코드를 사용해야 하는데 JSTL은 JSP에서 사용해야 하는 이런 자바 코드를 태그 형태로 사용할 수 있도록 지원한다.

- 따라서 JSP에 남아있던 자바 코드를 제거할 수 있게 된다.

 

3. 상세 화면(getBoard.jsp) 수정 ( _054_BoardWeb_EL_JSTL )

 

1) 라이브러리 추가

 

2) getBoard.jsp

- 게시글의 상세 정보를 출력하는 getBoard.jsp 파일에 EL을 적용하여 자바 코드를 제거한다.

- 우선 BoardVO와 BoardDAO 클래스에 대한 import 선언이 사라진다.

- 또한 세션에 저장된 BoardVO 객체를 꺼내는 자바 코드가 삭제되고 BoardVO 객체의 값을을 ${ } 구문을 이용하여 출력한다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 상세</title>
</head>
<body>
	<center>
		<h1>글 상세</h1>
		<a href="logout.do">Log-out</a>
		<form action="updateBoard.do" method="post">
			<input type="hidden" name="seq" value="${board.seq }">
			<table border="1" cellpadding="0" cellspacing="0">
				<tr>
					<td bgcolor="orange" width="70">제목</td>
					<td align="left"><input name="title" type="text" value="${board.title }"></td>
				</tr>
				<tr>
					<td bgcolor="orange">작성자</td>
					<td align="left">${board.writer }</td>
				</tr>
				<tr>
					<td bgcolor="orange">내용</td>
					<td align="left">
						<textarea name="content" cols="40" rows="10">${board.content }</textarea>
					</td>
				</tr>
				<tr>
					<td bgcolor="orange">등록일</td>
					<td align="left">${board.regDate }></td>
				</tr>
				<tr>
					<td bgcolor="orange">조회수</td>
					<td align="left">${board.cnt }</td>
				</tr>
				<tr>
					<td colspan="2" align="center">
						<input type="submit" value="글 수정">
					</td>
				</tr>
			</table>
		</form>
		<hr>
		<a href="insertBoard.jsp">글 등록</a>&nbsp;&nbsp;&nbsp;
		<a href="deleteBoard.do?seq=${board.seq }">글 삭제</a>&nbsp;&nbsp;&nbsp;
		<a href="getBoardList.do">글 목록</a>
	</center>
</body>
</html>

 

 

4. 글 목록 화면(getBoardList.jsp) 수정

 

1) getBoardList.jsp

- 게시글 목록을 출력하는 getBoardList.jsp 파일은 EL과 함께 for 루프로 처리하기 위한 JSTL도 같이 적용한다.

- 우선 getBoard.jsp 파일과 동일하게 import 선언이 모두 삭제되었다.

- 또한 JSTL 사용을 위한 taglib 지시문이 추가되었으며 for 루프는 JSTL에서 제공하는 <c:forEach> 태그로 대체되었다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 목록</title>
</head>
<body>
	<center>
		<h1>글 목록</h1>
		<h3>테스트님 환영합니다...<a href="logout.do">Log-out</a></h3>
		
		<!-- 검색 시작 -->
		<form action="getBoardList.jsp" method="post">
			<table border="1" cellpadding="0" cellspacing="0" width="700">
				<tr>
					<td align="right">
						<select name="searchCondition">
							<option value="TITLE">제목</option>
							<option value="CONTENT">내용</option>
						</select>
						<input name="searchKeyword" type="text">
						<input type="submit" value="검색">
					</td>
				</tr>
			</table>			
		</form>
		<!-- 검색 종료 -->
		
		<table border="1" cellpadding="1" cellspacing="0" width="700">
			<tr>
				<th bgcolor="orange" width="100">번호</th>
				<th bgcolor="orange" width="200">제목</th>
				<th bgcolor="orange" width="150">작성자</th>
				<th bgcolor="orange" width="150">등록일</th>
				<th bgcolor="orange" width="100">조회수</th>
			</tr>
			<c:forEach var="board" items="${boardList }">
				<tr>
					<td>${board.seq }</td>
					<td align="left"><a href="getBoard.do?seq=${board.seq }">${board.title }</a></td>
					<td>${board.writer }</td>
					<td>${board.regDate }</td>
					<td>${board.cnt }</td>
				</tr>
			</c:forEach>
		</table>
		<br>
		<a href="insertBoard.jsp">새 글 등록</a>
	</center>
</body>
</html>

 

 

반응형

댓글