Learn/KH정보교육원

[KH정보교육원 당산] 71일 (model2 -> MVC 아키텍쳐)

Dahoon06 2021. 6. 22. 16:18
728x90
반응형

model1, 2는 기존에 해왔던 실습 예제와 똑같은 방식이다.

 

간단한 게시판 만들기 코드를

model1으로 시작해서 그 코드를 가지고 model2로 바꿔본 후에 Spring 이 어떤식으로 구동하는지 알기 위하여

필요한 클래스를 직접 만들어서 그 구조를 익혀보자.

 

먼저 클라이언트가 요청을 하게 되면 그 요청을 DispatcherServlet에서 받게 된다.

DispatcherServlet은 다시 Controller에게 요청을 하는데 이때 HandlerMapping클라이언트가 요청을 처리할 Controller를 매핑하고 ViewResolver 클래스를 통하여 JSP경로를 완성시킨다.

 

DispatcherServlet

@WebServlet(name = "action", urlPatterns = { "/*do" })
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");
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		process(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		process(request, response);
	}

	private void process(HttpServletRequest request, HttpServletResponse response) throws IOException {
		// 클라이언트 요청 path(경로) 정보 추출
		String uri = request.getRequestURI();
		String path = uri.substring(uri.lastIndexOf("/"));
		// lastIndexOf("/") => 지정한  "/" 중, 맨 마지막 "/" 의 인덱스 부터 맨마지막 까지 값을 꺼냄

		//핸들러를 통해 paht에 해당하는 controller 검샥
		Controller ctrl = handlerMapping.getController(path);
		//검색된 컨트롤러 실행
		String viewName = ctrl.handleRequest(request, response);

		// 클라이언트 요청 path에 따라 적절히 분기 처리
		//viewResolver를 통하여 해당 화면 검색
		String view = null;
		
			if (!viewName.contains(".do")) {
				view = viewResolver.getView(viewName);
			} else {
				view = viewName;
			}
			
			response.sendRedirect(view);
		
	}

 

~~Controller 클래스가 생성될 때마다 HandlerMapping에 등록 시켜줘야하며

~~Controller 클래스들은 Controller 인터페이스를 구현 받는다.

 

Controller 인터페이스

public interface Controller {
	String handleRequest(HttpServletRequest request, HttpServletResponse response);
}

 

경로를 설정하기 위해

ViewResolver 클래스

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

 

 

최종적인 HandlerMapping 클래스는 이러한 구조가 된다.

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

 

 

model2에서는 DispatcherServlet 클래스에서

모든 일처리(if(command.equals("login"){ } 이러한 구조)를 했다면

MVC 구조에서는 각각의 컨트롤러에서 해당하는 일들을 처리한다.

 

ex) 게시글 등록 컨트롤러

public class InsertBoardController implements Controller {

	@Override
	public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
		System.out.println("게시글 등록");
		//request.setCharacterEncoding("UTF-8");

		String title = request.getParameter("title");
		String content = request.getParameter("content");
		String writer = request.getParameter("writer");
		
		BoardVO vo = new BoardVO();
		vo.setTitle(title);
		vo.setWriter(writer);
		vo.setContent(content);
		
		BoardDAO dao = new BoardDAO();
		int result = dao.insertBoard(vo);
		
		if(result == 1){
			return "getBoardList.do";
		} else {
			return "error";
		}
		
	}

}

model2에서는 경로 설정을 위하여 response.redirect를 사용하여 페이지 이동이 이루어졌다면

MVC에서는 ViewResolver 클래스의 값설정과 web.xml에 등록되었있는 Servlet 매핑의 경로

를 통하여 페이지 전환이 이루어지게된다. 

 

web.xml

더보기

<servlet>
     <description>DispatcherServlet.java</description>
     <display-name>action</display-name>
     <servlet-name>action</servlet-name>
     <servlet-class>com.jdh.spring.view.servlet.DispatcherServlet</servlet-class>

</servlet>
<servlet-mapping>
     <servlet-name>action</servlet-name>
     <url-pattern>*.do</url-pattern>
</servlet-mapping>

 

DispathcerServlet -> Controller -> 이때 반환 타입이 String 타입 -> DispathcerServlet

 

DispathcerServlet에서의 init() 메서드가 실행되어 경로를 완성 시킨다.

 

 


MVC 아키텍처 -> Spring이 제공하는 MVC

 

MVC아키텍처에서는 경로값을 String타입으로 반환받았는데 Spring에서는 ModelAndView를 통하여 반환 받는다.

 

MVC 아키텍처 구조를 알아보기 위해서 DispathcerServlet 클래시를 직접 만들어서 사용해봤다.

이번에는 Springframework이 제공하는 DispathcerServlet 를 사용한다.

 

먼저 web.xml 수정이 필요하다.

 

<filter>
	<filter-name>characterEncoding</filter-name>
	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	<init-param>
		<param-name>encoding</param-name>
		<param-value>UTF-8</param-value>
	</init-param>
</filter>
<filter-mapping>
	<filter-name>characterEncoding</filter-name>
	<url-pattern>*.do</url-pattern>
</filter-mapping>
	
<servlet>
	<servlet-name>action</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/config/presentation-layer.xml</param-value>
	</init-param>
</servlet>
<servlet-mapping>
	<servlet-name>action</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

servlet-class의 경로를 스프링경로로 변경!!

 

WEB-INF 폴더 안에 config폴더를 만든후에 xml파일 추가

이 xml문서에서는 HandlerMapping, controller, ViewResolver을 설정한다.

(기존에 직접 만들어서 사용했던 클래스를 이번엔 spring에서 제공해주는 클래스를 사용한다.)

 

최종 XML 문서는 이렇게 되어있다.

<!-- HandlerMapping 등록 -->
	<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<props>
				<prop key="/login.do">login</prop>
				<prop key="/getBoardList.do">getBoardList</prop>
				<prop key="/getBoard.do">getBoard</prop>
				<prop key="/insertBoard.do">insertBoard</prop>
				<prop key="/upateBoard.do">updateBoard</prop>
				<prop key="/deleteBoard.do">deleteBoard</prop>
				<prop key="/logout.do">logout</prop>
			</props>
		</property>
	</bean>
	
<!-- Controller 등록 -->
	<bean id="login" class="com.jdh.spring.view.user.LoginController" />
	<bean id="getBoardList" class="com.jdh.spring.board.controller.GetBoardListController" />
	<bean id="getBoard" class="com.jdh.spring.board.controller.GetBoardController" />
	<bean id="insertBoard" class="com.jdh.spring.board.controller.InsertBoardController" />
	<bean id="updateBoard" class="com.jdh.spring.board.controller.UpdateBoardController" />
	<bean id="deleteBoard" class="com.jdh.spring.board.controller.DeleteBoardController" />
	<bean id="logout" class="com.jdh.spring.view.user.LogoutController" />
	
<!-- ViewResolver 등록 -->
	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/board/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>
</beans>

**

HandlerMapping의 property name="mappings" <--- 유일값

HandlerMapping의 prop값은 Controller의 id값과 동일하게 설정

 

<property name="prefix" value="/WEB-INF/board/"></property>
<property name="suffix" value=".jsp"></property>

 

ViewResolver에 경로와 확장자를 설정해놨다.

WEB-INF 안에 board 디렉토리 내부의 파일을 실행하게 설정했고,(그러므로 폴더를 만들어줘야한다.)

 

컨트롤러에서의 경로를 수정해줘야한다.

 

ex) 게시글 목록불러오기 컨트롤러

import org.springframework.web.servlet.mvc.Controller;

public class GetBoardListController implements Controller {

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
		System.out.println("게시글 불러오기");
		
		ModelAndView mav = new ModelAndView();
		
		BoardVO vo = new BoardVO();
		BoardDAO dao = new BoardDAO();
		
		List<BoardVO> board = dao.getBoardList(vo);
		
		mav.addObject("board",board); // 정보 저장
		mav.setViewName("getBoardList"); //view정보 저장
		return mav;
	}

}

 

구현 받은 Controller를 보면 스프링이 제공해주는 클래스임을 알 수 있다.

게시글 목록부분에서 페이지 전환에 .jsp가 빠진것을 알 수 있다.

 

하지만 데이터를 처리하는 다른 클래스의 경우 ex)삭제, 수정 등 의 경우는 경로가 다르게 설정되었다.

 

ex) 게시글 수정

public class UpdateBoardController implements Controller {

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		int seq = Integer.parseInt(request.getParameter("seq"));
		String title = request.getParameter("title");
		String content = request.getParameter("content");
		BoardVO vo = new BoardVO();
		vo.setSeq(seq);
		vo.setTitle(title);
		vo.setContent(content);
		BoardDAO dao = new BoardDAO();
		dao.updateBoard(vo);
		ModelAndView mav = new ModelAndView();
		mav.setViewName("redirect:getBoardList.do");
		return mav;
	}

}

redirect: <- 를 통하여 xml문서에서 설정해놓은 값을 무시하고 현재 컨트롤러에서 설정한 값을 그대로 사용할 수 있다.

 

만약 redirect: 라는 접두사를 사용하지 않는다면 board/getBoardList.do.jsp라는 url형식으로 넘어가기 때문에 404에러

 

 


728x90
반응형