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

[Spring] 넷째 날 1장 어노테이션 기반 MVC 개발 - POJO 스타일을 고려한 어노테이션 설정(@Controller , @RequestMapping) 및 Command 객체를 이용하여 코드 간략화

by 달님🌙 2021. 11. 1.
반응형

 

실습 코드 참조

 

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

 

 

1.1절 어노테이션 관련 설정 ( _056_BoardWeb_Spring_MVC_Anotation )

 

1) 어노테이션 설정 이유

- 스프링은 어노테이션 기반 설정을 제공함으로써 과도한 XML 설정으로 인한 문제를 해결한다.

- 스프링 MVC도 스프링 설정 파일에 HandlerMapping, Controller, ViewResolver 같은 여러 클래스를 등록해야 하므로 어노테이션을 최대한 활용하여 XML 설정을 최소화할 필요가 있다.

 

2) presentation-layer.xml

- 먼저, context 네임스페이스 추가하기

- HandlerMapping, Controller, ViewResolver 클래스에 대한 <bean> 등록 모두 삭제하고 <context:component-scan> 엘리먼트로 대체한다.

- 모든 Controller 클래스가 스캔 범위에 포함되도록 가장 상위 패키지로 base-package를 설정한다.

- 어노테이션 활용을 위해 ViewResolver 설정 삭제하고 getBoard.jsp와 getBoardList.jsp 파일의 위치도 webapp 폴더 밑으로 돌려 놓는다.

 

1.2절 @Controller 사용하기

 

1) @Controller

public class InsertBoardController implements Controller {
 @Override 
 public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
	 System.out.println("글 등록 처리");
		...
	}
}

- 어노테이션을 사용하면 컨트롤러 클래스 모두 일일이 <bean> 등록할 필요 없이 @Controller를 붙이면 된다.

- 스프링 설정 파일에서 <ontext:component-scan>로 스프링 컨테이너가 컨트롤러 객체들을 자동으로 생성해준다.

- @Controller는 단순히 객체를 생성하는 것에 그치지 않고 DispatcherServlet이 인식하는 Controller 객체로 만들어준다.

- 그리고 handleRequest() 메소드를 반드시 재정의하여 DispatcherServlet이 모든 Controller의 handleRequest() 메소드를 호출할 수 있도록 한다.

 

2) 바뀐  Controller

- 위 처럼 구현한 Controller는 스프링 프레임워크가 지향하는 POJO 스타일의 클래스가 아니다.

- POJO : Plain Old Java Object

- POJO 스타일로 구현하려면 우선 implements Controller를 제거하고 @Controller를 선언한다.

- 스프링 컨테이너가 @Controller가 선언된 객체를 자동으로 Controller 객체로 인식한다.

- 메소드 이름과 리턴타입, 매개변수를 변경해준다.

 

package com.springbook.view.board;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.springbook.biz.board.BoardVO;
import com.springbook.biz.board.impl.BoardDAO;

@Controller	//presentation-layer.xml에 Controller 등록 부분과 같은 역할
public class InsertBoardController {
	 @RequestMapping(value="/insertBoard.do")	//presentation-layer.xml에 HandlerMapping 등록 부분과 같은 역할
	 //@RequestMapping : HandlerMapping 등록, 메소드 타입에 상관없이 호출 시 무조건 실행
	 //메소드 타입에 따라 @GetMapping, @PostMapping으로도 사용이 가능하며 예를 들어, PostMapping일 땐 post 메소드가 매핑되는 방식
	 
	 //Command 객체 : 사용자가 전송한 데이터를 매핑한 VO를 바로 생성
	 //				사용자 입력 값이 많아지면 코드가 길어지기 때문에 간략화 가능
	 // 			사용자 입력 input의 name 속성과 VO 멤버변수의 이름을 매핑해주는 것이 중요하다.
	 // 			그래야 BoardVO 클래스의 멤버변수가 insertBoard에 해당 변수에 자동으로 매핑이 된다. 
	 public void insertBoard(BoardVO vo) {	//VO 객체를 바로 가져옴
		 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);
	 }
}

 

 

1.3절 @RequestMapping 사용하기

 

- @RequestMapping를 이용하여 HandlerMapping 설정을 대체한다.

- 메소드 타입에 상관없이 호출 시 무조건 실행된다.

- value 속성은 생략할 수 있다.

@Controller
public class InsertBoardController {
 @RequestMapping(value="/insertBoard.do") 
 public void insertBoard(HttpServletRequest request) {
	 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);
 }
}

 

- 위 설정은 아래에 있는 XML 설정 방식과 동일한 결과를 나타낸다. 

<!-- HandlerMapping 등록 -->
	<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<props>
				<prop key="/insertBoard.do">insertBoard</prop>
			</props>
		</property>
	</bean>
	
	<!-- Controller 등록 -->
	<bean id="insertBoard" class="com.springbook.view.board.InsertBoardController"></bean>

 

 

1.4절 클라이언트 요청 처리

1) insertBoardController

 - 대부분 Controller는 사용자의 입력 정보를 추출하여 VO 객체에 저장한다.

- 그리고 비즈니스 컴포넌트의 메소드를 호출할 때 VO 객체를 인자로 전달한다.

- 아래 코드의 단점 : 입력 정보가 변경될 때마다 Controller 클래스는 수정되어야함

@Controller
public class InsertBoardController {
 @RequestMapping(value="/insertBoard.do") 
 public void insertBoard(HttpServletRequest request) {
	 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);
 }
}

 

2) 해결책

- Command 객체를 이용한다.

- Command 객체 : 사용자가 전송한 데이터를 매핑한 VO를 바로 생성

- 사용자 입력 값이 많아지면 코드가 길어지기 때문에 간략화 가능

  - 사용자 입력 input의 name 속성과 VO 멤버변수의 이름을 매핑해주는 것이 중요하다.

- 그래야 BoardVO 클래스의 멤버변수가 insertBoard에 해당 변수에 자동으로 매핑이 된다. 

- 결과적으로 사용자 입력 정보 추출과 VO 객체 생성, 그리고 값 설정을 모두 컨테이너가 자동으로 처리하게 됨

package com.springbook.view.board;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.springbook.biz.board.BoardVO;
import com.springbook.biz.board.impl.BoardDAO;

@Controller	//presentation-layer.xml에 Controller 등록 부분과 같은 역할
public class InsertBoardController {
	 @RequestMapping(value="/insertBoard.do")	//presentation-layer.xml에 HandlerMapping 등록 부분과 같은 역할
	 //@RequestMapping : HandlerMapping 등록, 메소드 타입에 상관없이 호출 시 무조건 실행
	 //메소드 타입에 따라 @GetMapping, @PostMapping으로도 사용이 가능하며 예를 들어, PostMapping일 땐 post 메소드가 매핑되는 방식
	 public String insertBoard(BoardVO vo, BoardDAO boardDAO) {	//VO 객체를 바로 가져옴
		 System.out.println("글 등록 처리");
		 	boardDAO.insertBoard(vo);
			
		 	//화면 네비게이션(게시글 등록 완료 후 게시글 목록으로 이동)
			return "redirect:getBoardList.do"; //redirect를 안주면 그냥 화면만 이동되는데, redirect를 주면 주소값 까지 변경됨
	 }
}

 

3) 서블릿 컨테이너의 동작 방식

① 서블릿 컨테이너는 클라이언트의 HTTP 요청이 서버에 전달되는 순간

② HttpServletRequest 객체를 생성하고 HTTP 프로토콜에 설정된 모든 정보를 추출하여 HttpServletRequest 객체에 저장한다.

③ 그리고 이 HttpServletRequest 객체를 service() 메소드를 호출할 떄, 인자로 전달해준다.

 

4) 스프링 컨테이너 관점에서 Controller 객체의 메소드가 호출되는 과정

- 클라이언트가 서버에 insertBoard.do 요청을 전달하면 스프링 컨테이너는 @Controller가 붙은 모든 컨트롤러 객체를 생성하고 insertBoardController가 가지고 있는 insertBoard() 메소드를 실행한다.

- 이때 매개변수에 해당하는 BoardVO 객체를 스프링 컨테이너가 생성하여 전달한다.

 

① 매개변수에 해당하는 BoardVO 객체를 생성하고,

② 사용자가 입력한 파라미터 (title, writer, content) 값들을 추출하여 BoardVO 객체에 저장한다. 이때 BoardVO 클래스의 Setter 메소드들이 호출됨

③ insertBoard() 메소드를 호출할 때, 사용자 입력값들이 설정된 BoardVO 객체가 인자로 전달된다.

 

5)  파라미터 이름과 Setter 메소드 이름 일치

- Form 태그 안의 파라미터 이름과 Command 객체의 Setter 메소드 이름은 반드시 일치해야한다.

- setTitle(), setWriter(), setContent() 메소드가 있어야 Setter 인젝션에 의해 자동으로 사용자 입력값이 저장된다.

 

 

반응형

댓글