실습 코드 참조
moonhy7/SpringFramework: Spring Framework 실습 코드 정리 (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 인젝션에 의해 자동으로 사용자 입력값이 저장된다.
댓글