스프링(5) - 도서 구매 프로젝트(2)
👩💻 컨트롤러란?
- 사용자 요청은 제일 먼저 디스패처 서블릿으로 전달되는데, 사실디스패처 서블릿은 요청을 전달받는 창구 역할만 할 뿐 실제로는 컨트롤러(Controller)가 요청을 처리함
- 웹 요청을 전달받아 그 내용을 해석한 후 요청을 처리할 수 있는 메서드를 호출한다.
- 해당 요청을 처리하고 나서 사용자에게 결과를 반환한다.
💚 컨트롤러 구현과정
1. 컨트롤러 정의
- 컨트롤러로 사용할 자바 클래스에 @Controller를 선언한다.
- 해당 컨트롤러와 의존 관계에 있는 모든 자바 클래스를 빈 객체로 등록하는 단계
컨트롤러 정의 구현
package com.springmvc.JAVA;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller // @Controller : 웹 요청 URL에 대해서 디스패처 서블릿이 컨트롤러임을 인식할 수 있도록 알려주는 것
public class Example01Controller {
@RequestMapping(value="/exam01", method=RequestMethod.GET)
public void requestMethod() {
System.out.println("@Controller 예제입니다");
}
}
2. 요청 매핑 경로 설정
-@ReqeustMapping(value='/요청url', method=RequestMethod.겟이나 포스트 중 하나 선택)
- 위의 예시의
@RequestMapping(value="/exam01", method=RequestMethod.GET)
부분임
- 'http://localhost:8080/JAVA/exam01'을 띄어주게 만든다.
🐤 형태
@RequestMapping(value="웹 요청 URL", method=RequestMethod.HTTP 요청 방식, ...)
🐤 속성
🐤 클래스 수준의 요청 매핑 경로 설정
- 웹에서 사용자가 요청한 URL에 매핑되는 @RequestMapping이 컨트롤러에 선언될 경우에 사용됨
- 기본 매핑 경로를 설정하지 않은 @RequestMapping만 선언된 요청 처리 메서드가 사용된다.
package com.springmvc.chap05;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping(value="/exam02", method=RequestMethod.GET) //클래스에 매핑된 @RequestMapping
public class Example02Controller {
@RequestMapping //메서드에 매핑된 @RequestMapping
public void requestMethod() {
System.out.println("@RequestMapping 예제입니다.");
System.out.println("웹 요청 URL은 /exam02 입니다.");
}
}
🐤 메서드 수준의 요청 매핑 경로 설정
- 웹 요청 URL이 http://localhost:8080/.../JAVA이면 컨트롤러인 Example03Controller 클래스의 requestMethod() 메서드에 매핑되어 요청을 처리한다.
package com.springmvc.JAVA;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class Example03Controller {
@RequestMapping(value="/JAVA", method=RequestMethod.GET)
public void requestMethod() {
System.out.println("@RequestMapping 예제입니다.");
System.out.println("웹 요청 URL은 /JAVA 입니다.");
}
}
- 웹에서 사용자가 요청한 URL에 대해 컨트롤러 안의 어떤 메서드를 처리할지 선언하여 사용하는 경우에 쓰임
- 메서드 수준의 @ReqeustMapping은 단순화가 가능하다.
📌 단순화 종류
📌 구현 예시
package com.springmvc.JAVA;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/home")
public class ExampleController {
@GetMapping("/Example")
public void requestMethod() {
System.out.println("@RequestMapping 예제입니다.");
System.out.println("웹 요청 URL은 /home/Example 입니다.");
}
}
3. 요청 처리 메서드 구현
- 사용자의 요청을 처리하는 메서드를 구현함
public void requestMethod() {
System.out.println("@Controller 예제입니다");
}
- 에서 public void request() {}이다.
- 요청 처리 메서드 형태
4. 뷰(&모델) 반환
- 처리된 결과를 반환하도록 메서드 안에 뷰나 뷰 이름을 포함한 모델을 넣어서 return한다.
- 위의 예시의 System.out.println("@Controller 예제입니다.") 부분으로, 웹 요청 URL에 대한 응답(@Controller 예제입니다.)를 반환한다.
💚 스프링 MVC 설정 파일(servlet-context.xml) 등록하기에 자바클래스를 빈 객체로 등록하기
- . 웹에서 사용자 요청이 들어오면 디스패처 서블릿은 @Controller가 선언된 컨트롤러 여러 개를 스캔하고 스패처 서블릿이 모든 컨트롤러를 인식할 수 있도록 컨트롤러와 컨트롤러와 의존 관계에 있는 자바 클래스들을 스프링 MVC 설정 파일(servlet-context.xml)에 빈 객체로 등록해야 함
🐤 컴포넌트 스캔(<context:component-scan>)
- 하나씩 MVC 설정파일에 자바 클래스를 등록하기 번거로우므로 @Controller가 선언된 컨트롤러를 빈 객체로 자동으로 등록할 뿐만 아니라 의존 관계에 있는 자바 클래스도 빈 객체로 자동 등록해줄 수 있게 함
- 형식
<context:component-scan base-package="패키지 이름"/>
- 컴포넌트(@Controller, @Autowired) 자동 인식 기능을 지원한다.
- <context:component-scan> 요소의 base-package 속성에 공통 패키지 com.springmvc.*를 설정하면 설정된 패키지 하위에 있는 컨트롤러 및 의존 관계에 있는 자바 클래스를 검색하여 빈 객체로 자동으로 등록해준다. (다른 패키지 경로에 있는 친구들을 자동으로 검색하여 빈 객체로 등록시켜주는 것)
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
...
<context:component-scan base-package="com.springmvc.*"/> // 컨트롤러의 빈 객체 등록
</beans:beans>
📍 컴포넌트 스캔(<context:component-scan>)이 없다면...?
- 스프링 MVC 환경 설정 파일 servlet-context.xml에 컨트롤러 및 의존 관계에 있는 자바 클래스를 빈 객체로 하나씩 직접 등록해야 한다.
- 겁나 인생 복잡해지고 피곤해짐....BUT 굳이 컴포넌트 스캔 없이 코드를 작성해봤다.
<beans:bean class="com.springmvc.controller.HomeController"/>
<beans:bean id="bookRepositoryImpl" class="com.springmvc.repository.BookRepositoryImpl"/>
<beans:bean id="bookServiceImpl" class="com.springmvc.service.BookServiceImpl">
<beans:property name="bookRepository" ref="bookRepositoryImpl"/>
</beans:bean>
<beans:bean class="com.springmvc.controller.BookController">
<beans:property name="bookService" ref="bookServiceImpl"/>
</beans:bean>
- 트롤러와 의존 관계에 있는 클래스의 프로퍼티에 선언된 @Autowired를 인식할 수 없기 때문에 다음과 같이 프로퍼티의 Setter() 메서드도 모두 작성해야한다. ➡ Autowired로 참조가 불가능하기 때문에 참조를 할 수 있도록 Setter을 써서 외부 패키지의 내용들을 가져와야함
✍ BookController.java
private BookService bookService;
public void setBookService(BookService bookService) {
this.bookService = bookService;
}
✍ BookService.java
private BookRepository bookRepository;
public void setBookRepository(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
🔗 BookController 만들기
BookController.java
- 요청 매핑 경로가 /books/all인 requestAllBooks() 메서드에 ModelAndView 객체를 사용하여 모델과 뷰를 처리해준다.
package com.springmvc.controller;
...
import org.springframework.web.bind.annotation.GetMapping; // 추가
import org.springframework.web.servlet.ModelAndView; // 추가
...
@Controller
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@GetMapping
public String requestBookList(Model model) {
List<Book> list = bookService.getAllBookList();
model.addAttribute("bookList", list);
return "books";
}
@GetMapping("/all")
public String requestAllBooks(Model model) {
// List<Book> list = bookService.getAllBookList();
// modelAndView.addObject("bookList", list);//model.addAttribute("bookList", list);
// model.AndView.setViewName("books");
return modelAndView;//return "books";
}
}
@GetMapping
- 사용자의 웹 요청 URL이 /books인 경우 reqeustBookList()가 처리할 수 있도록 매핑하는 것
- @RequestMapping과 같은 기능을 한다.
@GetMapping("/all")
- 사용자의 웹 요청 URL이 /books/all인 경우 requestAllBooks() 메서드가 처리할 수 있도록 매핑해준다.
- @RequestMapping(value="/all", method=RequestMethod.GET) 또는 @RequestMapping("/all")과 같은 말이다.
@RequestMapping(value="/books", method=RequestMethod.GET)
- 요청 매핑 경로를 books로 지정한다.
-요청 처리 메서드를 정의해준다.
요청 처리 메서드 형태
- 사용자의 요청을 처리하는 메서드
@RequestMapping에 설정된 요청 매핑 경로에 따라서 호출됨
@RequestMapping(...)
public String 메서드 이름() {
// 모델(객체)에 응답 데이터 저장
return "뷰 이름";
}
모델 : 사용자의 웹 요청을 처리한 결과 데이터를 관리하고 전달한다.
뷰 : 처리된 결과 데이터를 웹 브라우저에 출력하는 웹 페이지 역할을 함
응답 데이터를 저장하는 모델 유형들(모델 클래스)
Model 인터페이스를 이용한 메서드 작성
- Model 인터페이스는 사용자 요청에 대한 처리 결과를 뷰에 보여 주는 데 필요한 데이터를 Model 객체의 addAttribute() 메서드에 담아 전달함 : 데이터를 ModelAtrribute에 담아서 뷰에 전달함
Model addAttribute(String attributeName, Object attributeValue)
// 역할: 제공된 이름으로 제공된 속성을 등록합니다.
// 매개변수:
// attributeName: 모델 속성 이름(null이 될 수 없음)
// attributeValue: 모델 속성 값(null이 될 수 있음)
Model 인터페이스 구현 예시
- 요청 처리 메서드 requestMethod()에 Model 객체를 사용하여 모델 속성 이름 data와 data2에 뷰로 전송할 값을 각각 저장한다.
- 뷰 이름을 webpage05로 반환하면 webpage05.jsp 파일을 웹 브라우저에 출력한다. = url은 /exam05로 들어가게 됨. 페이지 이름은 webpage05.jsp 가 됨
Model Interface가 반환한 뷰 페이지 webpage05.jsp
<%@ page contentType="text/html; charset=utf-8" %>
<html>
<head>
<title>chap05</title>
</head>
<body>
<p>${data}
<p>${data2}
</body>
</html>
ModelMap 인터페이스
- Model 인터페이스와 동일함
- 사용자 요청에 대한 처리 결과를 뷰에 보여주는 데 필요한 데이터를 Model 객체의 addAtrribute() 메서드에 담아서 전달한다.
ModelMap addAttribute(String attributeName, Object attributeValue)
- 지정된 이름(attributeName)과 속성(attributeValue)을 등록한다.
- 매개변수:
attributeName: 모델 속성의 이름(null이 될 수 없음)
attributeValue: 모델 속성의 값(null이 될 수 있음)
package com.springmvc.chap05;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/home")
public class Example06Controller {
@GetMapping("/exam06")
public String requestMethod(ModelMap model) {
model.addAttribute("data", "ModelMap 예제입니다");
model.addAttribute("data2", "웹 요청 URL은 /home/exam06 입니다");
return "webpage05";
ModelAndView 클래스를 사용한 메서드 작성
- ModelAndView 클래스는 모델과 뷰를 합쳐놓은 것
- 사용자 요청에 대한 처리 결과 데이터를 ModelAndView 객체의 addObject() 메서드에 담아 전달하고 setViewName() 메서드로 뷰 이름을 설정해준다.
ModelAndView addObject() 메서드
ModelAndView addObject(String attributeName, Object attributeValue)
역할 : 지정한 이름(attributeName)으로 제공된 속성(attributeValue)을 등록한다(addObject).
매개변수
attributeName : 모델 속성의 이름
atrributeValue : 모델 속성의 값
void setViewName() 메서드
void setViewName(String viewName)
- ModelAndView를 위한 뷰 이름을 설정한다
viewName : 뷰 이름 매개변수
ModelAndView 요청 처리 메서드 결과 페이지
- 사용자의 웹 요청 URL http://localhost:8080/chap05/home/exam07에 대한 응답으로 웹 브라우저에 webpage05 페이지를 출력하는 과정
모델(뷰) 클래스 유형
RequestBookList 요청 처리 메서드 예시
public String requestBookList(Model model) {
List<Book> list = bookService.getAllBookList(); //도서 목록을 bookService으로부터 가져와준다.
model.addAttribute("bookList", list); //도서 목록을 booklist에 저장한다.
return "books"; //뷰이름 books로 반환한다.
}
model.addAttribute("현재 모델 변수 이름", 저장대상)
- 모델로 설정하여 books로 반환될 booklist에 외부에서 가져온(getBookList)를 넣어준다.