검색결과 리스트
@Data에 해당되는 글 2건
- 2022.05.29 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 27
- 2022.05.22 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 23
글
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 27
인프런 강의 38일차.
- 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 1 (김영한 강사님)
- 서블릿, JSP, MVC 패턴
- 서블릿으로 1차 구현
-> 서블릿으로 구현했을 때 불편한 점 개선을 위해 JSP로 2차 구현
-> JSP로도 불편한 점을 개선하기 위해 MVC 패턴으로 3차 구현
- 스프링 프로젝트 시작
-> 스프링 기본기능 이해
-> 스프링 MVC 웹페이지 만들기
5. 스프링 MVC - 웹 페이지 만들기
5.1 프로젝트 생성 (스프링 부트 스타터 사이트로 이동해서 스프링 프로젝트 생성)
> 스프링 프로젝트 생성 (https://start.spring.io)
- 프로젝트 선택 Project: Gradle Project
- Language: Java
- Spring Boot: 2.7.0
- Group: hello
- Artifact: item-service
- Name: item-service
- Package name: hello.itemservice
- Packaging: Jar
- Java: 11
- Dependencies: Spring Web, Thymeleaf, Lombok
> 파일 오픈 시 build.gradle을 선택하자
5.2 요구사항 분석
> 상품을 관리할 수 있는 화면을 만들어보자!
* 상품 도메인 모델
- 상품 ID
- 상품명
- 가격
- 수량
* 상품 관리 기능
- 상품 목록
- 상품 상세
- 상품 등록
- 상품 수정
> 요구사항이 정리되고 디자이너, 웹 퍼블리셔, 백엔드 개발자가 업무를 나누어 진행한다.
> 디자이너 : 요구사항에 맞도록 디자인하고, 디자인 결과물을 웹 퍼블리셔에게 넘겨준다.
> 웹 퍼블리셔 : 다자이너에서 받은 디자인을 기반으로 HTML, CSS를 만들어 개발자에게 제공한다.
> 백엔드 개발자 : 디자이너, 웹 퍼블리셔를 통해서 HTML 화면이 나오기 전까지 시스템을 설계하고, 핵심 비즈니스 모델을 개발한다. 이후 HTML이 나오면 이 HTML을 뷰 템플릿으로 변환해서 동적으로 화면을 그리고, 또 웹 화면의 흐름을 제어한다
* 참고
> React, Vue.js 같은 웹 클라이언트 기술을 사용하고, 웹 프론트엔드 개발자가 별도로 있으면, 웹 프론트엔드 개발자가 웹 퍼블리셔 역할까지 포함해서 하는 경우도 있다.
> 웹 클라이언트 기술을 사용하면, 웹 프론트엔드 개발자가 HTML을 동적으로 만드는 역할과 웹 화면의 흐름을 담당한다. 이 경우 백엔드 개발자는 HTML 뷰 템플릿을 직접 만지는 대신에, HTTP API를 통해 웹 클라이언트가 필요로 하는 데이터와 기능을 제공하면 된다.
5.3 상품 도메인 개발
package hello.itemservice.domain.item;
import lombok.Data;
/**
* @Data는 도메인 상황에서 예측하지 못한 동작을 수행할 수 있다.
* 그러므로 필요에 따라 @Getter, @Setter를 사용하는 것을 추천한다.
* 일반적으로 데이터만 왔다갔다 하는 객체(DTO) 대상으로는 @Data를 써도 무방하다.
* Item 클래스에서는 예제이므로 @Data를 사용.
*/
@Data
public class Item {
private Long id;
private String itemName;
private Integer price; //price가 null일 수도 있으니 Integer를 사용
private Integer quantity; //quantity가 null일 수도 있으니 Integer를 사용
public Item() {
}
public Item(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
- domain.item.Item.java
- Item 객체 선언
package hello.itemservice.domain.item;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//@Repository를 사용했기 때문에 Component Scan 대상이 됨
@Repository
public class ItemRepository {
//일반적으로 싱글톤이기 때문에 static을 사용하지 않아도 되나, new ItemRepository() 할 경우를 대비하기 위해 static으로 선언함.
//실무에서는 HashMap을 사용할 시 멀티쓰레드 환경에서 동시에 접근이 불가능하다.. 만약 HashMap을 사용하고 싶다면 ConcurrentHashMap을 사용해야한다.
private static final Map<Long, Item> store = new HashMap<>(); //static 사용
private static long sequence = 0L; //static 사용
public Item save(Item item) {
item.setId(++sequence);
store.put(item.getId(), item);
return item;
}
public Item findById(Long id) {
return store.get(id);
}
public List<Item> findAll() {
return new ArrayList<>(store.values());
}
public void update(Long itemId, Item updateParam) {
//정석대로라면 Item 객체의 멤버 중 id가 사용되지 않기 때문에 따로 ItemPramDto 등으로 선언해서 기존 객체와 구분해서 사용해주어야 한다.(귀찮아도 명확성을 위해 선언해주는 것이 설계상 좋다)
//안그러면 개발자가 setId, getId 등은 사용할 수 있는데 왜 안했지?라고 헷갈리거나 데이터 변조가 가능함.
Item findItem = findById(itemId);
findItem.setItemName(updateParam.getItemName());
findItem.setPrice(updateParam.getPrice());
findItem.setQuantity(updateParam.getQuantity());
}
public void clearStore() {
store.clear();
}
}
- domain.item.ItemRepository.java
- ItemRepository 사용
package hello.itemservice.domain.item;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
class ItemRepositoryTest { //public class ItemRepositoryTest 이지만 JUnit5이상에서 public 생략이 가능하게 됨.
ItemRepository itemRepository = new ItemRepository();
@AfterEach
void afterEach() {
itemRepository.clearStore();
}
@Test
void save() {
//given
Item item = new Item("itemA", 10000, 10);
//when
Item savedItem = itemRepository.save(item);
//then
Item findItem = itemRepository.findById(item.getId());
assertThat(findItem).isEqualTo(savedItem);
}
@Test
void findById() {
}
@Test
void findAll() {
//given
Item item1 = new Item("item1", 10000, 10);
Item item2 = new Item("item2", 20000, 20);
itemRepository.save(item1);
itemRepository.save(item2);
//when
List<Item> result = itemRepository.findAll();
//then
assertThat(result.size()).isEqualTo(2);
assertThat(result).contains(item1, item2);
}
@Test
void updateItem() {
//given
Item item = new Item("item1", 10000, 10);
Item savedItem = itemRepository.save(item);
Long itemId = savedItem.getId();
//when
Item updateParam = new Item("item2", 20000, 30);
itemRepository.update(itemId, updateParam);
Item findItem = itemRepository.findById(itemId);
//then
assertThat(findItem.getItemName()).isEqualTo(updateParam.getItemName());
assertThat(findItem.getPrice()).isEqualTo(updateParam.getPrice());
assertThat(findItem.getQuantity()).isEqualTo(updateParam.getQuantity());
}
@Test
void clearStore() {
}
}
- domain.item.ItemRepositoryTest.java
- ItemRepository를 테스트하기위한 Test클래스
* HTML을 편리하게 개발하기 위해 부트스트랩 사용
- 부트스트랩(Bootstrap)은 웹사이트를 쉽게 만들 수 있게 도와주는 HTML, CSS, JS 프레임워크이다. 하나의 CSS로 휴대폰, 태블릿, 데스크탑까지 다양한 기기에서 작동한다. 다양한 기능을 제공하여 사용자가 쉽게 웹사이트를 제작, 유지, 보수할 수 있도록 도와준다.
- 부트스트랩 공식 사이트 : https://getbootstrap.com
- 부트스트랩을 다운로드 받고 압축을 풀자 : https://getbootstrap.com/docs/5.0/getting-started/download/
- Compiled CSS and JS 항목을 다운로드하자.
- 압축을 출고 bootstrap.min.css 를 복사해서 resources/static/css/bootstrap.min.css 폴더에 추가하자
- /resources/static/css/bootstrap.min.css (부트스트랩 다운로드)
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link href="../css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container" style="max-width: 600px">
<div class="py-5 text-center">
<h2>상품 목록</h2>
</div>
<div class="row">
<div class="col">
<button class="btn btn-primary float-end"
onclick="location.href='addForm.html'" type="button">상품
등록</button>
</div>
</div>
<hr class="my-4">
<div>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>상품명</th>
<th>가격</th>
<th>수량</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="item.html">1</a></td>
<td><a href="item.html">테스트 상품1</a></td>
<td>10000</td>
<td>10</td>
</tr>
<tr>
<td><a href="item.html">2</a></td>
<td><a href="item.html">테스트 상품2</a></td>
<td>20000</td>
<td>20</td>
</tr>
</tbody>
</table>
</div>
</div> <!-- /container -->
</body>
</html>
- /resources/static/html/items.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link href="../css/bootstrap.min.css" rel="stylesheet">
<style>
.container {
max-width: 560px;
}
</style>
</head>
<body>
<div class="container">
<div class="py-5 text-center">
<h2>상품 상세</h2>
</div>
<div>
<label for="itemId">상품 ID</label>
<input type="text" id="itemId" name="itemId" class="form-control"
value="1" readonly>
</div>
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" name="itemName" class="form-control"
value="상품A" readonly>
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" name="price" class="form-control"
value="10000" readonly>
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" name="quantity" class="form-control"
value="10" readonly>
</div>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-primary btn-lg"
onclick="location.href='editForm.html'" type="button">상품 수정</button>
</div>
<div class="col">
<button class="w-100 btn btn-secondary btn-lg"
onclick="location.href='items.html'" type="button">목록으로</button>
</div>
</div>
</div> <!-- /container -->
</body>
</html>
- /resources/static/html/item.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link href="../css/bootstrap.min.css" rel="stylesheet">
<style>
.container {
max-width: 560px;
}
</style>
</head>
<body>
<div class="container">
<div class="py-5 text-center">
<h2>상품 등록 폼</h2>
</div>
<h4 class="mb-3">상품 입력</h4>
<form action="item.html" method="post">
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" name="itemName" class="formcontrol" placeholder="이름을 입력하세요">
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" name="price" class="form-control"
placeholder="가격을 입력하세요">
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" name="quantity" class="formcontrol" placeholder="수량을 입력하세요">
</div>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-primary btn-lg" type="submit">상품
등록</button>
</div>
<div class="col">
<button class="w-100 btn btn-secondary btn-lg"
onclick="location.href='items.html'" type="button">취소</button>
</div>
</div>
</form>
</div> <!-- /container -->
</body>
</html>
- /resources/static/html/addForm.html
<html>
<head>
<meta charset="utf-8">
<link href="../css/bootstrap.min.css" rel="stylesheet">
<style>
.container {
max-width: 560px;
}
</style>
</head>
<body>
<div class="container">
<div class="py-5 text-center">
<h2>상품 수정 폼</h2>
</div>
<form action="item.html" method="post">
<div>
<label for="id">상품 ID</label>
<input type="text" id="id" name="id" class="form-control" value="1"
readonly>
</div>
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" name="itemName" class="formcontrol" value="상품A">
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" name="price" class="form-control"
value="10000">
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" name="quantity" class="formcontrol" value="10">
</div>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-primary btn-lg" type="submit">저장
</button>
</div>
<div class="col">
<button class="w-100 btn btn-secondary btn-lg"
onclick="location.href='item.html'" type="button">취소</button>
</div>
</div>
</form>
</div> <!-- /container -->
</body>
</html>
- /resources/static/html/editForm.html
* 참고
> /resources/static 에 넣어두었기 때문에 스프링 부트가 정적 리소스를 제공한다. (http://localhost:8080/html/items.html)
> 그런데 정적 리소스여서 해당 파일을 탐색기를 통해 직접 열어도 동작하는 것을 확인할 수 있다.
> 정적 리소스가 공개되는 /resources/static 폴더에 HTML을 넣어두면, 실제 서비스에서도 공개된다. 서비스를 운영한다면 지금처럼 공개할 필요없는 HTML을 두는 것은 주의하자
'Spring 정리' 카테고리의 다른 글
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 1 (0) | 2022.05.30 |
---|---|
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 28 (1) | 2022.05.29 |
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 26 (0) | 2022.05.27 |
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 25 (0) | 2022.05.26 |
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 24 (0) | 2022.05.22 |
설정
트랙백
댓글
글
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 23
인프런 강의 37일차.
- 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 1 (김영한 강사님)
- 서블릿, JSP, MVC 패턴
- 서블릿으로 1차 구현
-> 서블릿으로 구현했을 때 불편한 점 개선을 위해 JSP로 2차 구현
-> JSP로도 불편한 점을 개선하기 위해 MVC 패턴으로 3차 구현
- 스프링 프로젝트 시작
-> 스프링 기본기능 이해
-> 스프링 MVC 웹페이지 만들기
4. 스프링 MVC - 기본 기능
4.5 HTTP 요청 파라미터 - 쿼리 파라미터, HTML Form
> HTTP 요청 데이터 조회 - 개요
- 서블릿에서 학습했던 HTTP 요청 데이터를 조회 하는 방법을 다시 떠올려보자.
- 그리고 서블릿으로 학습했던 내용을 스프링이 얼마나 깔끔하고 효율적으로 바꾸어주는지 알아보자.
- HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전달하는 방법을 알아보자.
> 클라이언트에서 서버로 요청 데이터를 전달할 때는 주로 다음 3가지 방법을 사용한다
- GET - 쿼리 파라미터
/url?username=hello&age=20
메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달
예) 검색, 필터, 페이징등에서 많이 사용하는 방식
- POST - HTML Form
content-type: application/x-www-form-urlencoded
메시지 바디에 쿼리 파리미터 형식으로 전달 username=hello&age=20
예) 회원 가입, 상품 주문, HTML Form 사용
- HTTP message body에 데이터를 직접 담아서 요청
HTTP API에서 주로 사용, JSON, XML, TEXT
데이터 형식은 주로 JSON 사용
POST, PUT, PATCH
> 스프링으로 요청 파라미터를 조회하는 방법
package hello.springmvc.basic.request;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@Controller
public class RequestParamController {
@RequestMapping("/request-param-v1")
public void requestParamV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
log.info("username={}, age={}", username, age);
response.getWriter().write("ok");
}
}
- hello.springmvc.basic.request.RequestParamController.java
- HTTP get/post 호출 처리
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/request-param-v1" method="post">
username: <input type="text" name="username" />
age: <input type="text" name="age" />
<button type="submit">전송</button>
</form>
</body>
</html>
- resources/static/basic/hello-form.html
- HTTP post 호출을 하기 위한 샘플 html
- Jar 를 사용하면 webapp 경로를 사용할 수 없다. 이제부터 정적 리소스도 클래스 경로에 함께 포함해야 한다.
4.6 HTTP 요청 파라미터 - @RequestParam
> 스프링이 제공하는 @RequestParam 을 사용하면 요청 파라미터를 매우 편리하게 사용할 수 있다.
/**
* @RequestParam 사용
* - 파라미터 이름으로 바인딩
* @ResponseBody 추가
* - View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력
*/
@ResponseBody
@RequestMapping("/request-param-v2")
public String requestParamV2(
@RequestParam("username") String memberName,
@RequestParam("age") int memberAge) {
log.info("username={}, age={}", memberName, memberAge);
return "ok"; //String 반환일 경우 ViewResolver를 호출하는 것이지만 ResponseBody Annotation을 추가함으로써 REST API 호출로 변경할 수 있다.
}
- requestParamV2
- @RequestParam : 파라미터 이름으로 바인딩
- @ResponseBody : View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력
- @RequestParam의 name(value) 속성이 파라미터 이름으로 사용된다.
- @RequestParam("username") String memberName -> request.getParameter("username")
/**
* @RequestParam 사용
* HTTP 파라미터 이름이 변수 이름과 같으면 @RequestParam(name="xx") 생략 가능
*/
@ResponseBody
@RequestMapping("/request-param-v3")
public String requestParamV3(
@RequestParam String username,
@RequestParam int age) {
log.info("username={}, age={}", username, age);
return "ok";
}
- requestParamV3
- HTTP 파라미터 이름이 변수 이름과 같으면 @RequestParam(name="xx") 생략 가능
/**
* @RequestParam 사용
* String, int 등의 단순 타입이면 @RequestParam 도 생략 가능
*/
@ResponseBody
@RequestMapping("/request-param-v4")
public String requestParamV4(String username, int age) {
log.info("username={}, age={}", username, age);
return "ok";
}
- requestParamV4
- String , int , Integer 등의 단순 타입이면 @RequestParam 도 생략 가능
* @RequestParam 애노테이션을 생략하면 스프링 MVC는 내부에서 required=false 를 적용한다.
- @RequestParam을 생략하지 않음으로써 명확하게 요청 파리미터에서 데이터를 읽는 다는 것을 표현하기도 한다.
/**
* @RequestParam.required
* /request-param -> username이 없으므로 예외
*
* 주의!
* /request-param?username= -> 빈문자로 통과
*
* 주의!
* /request-param
* int age -> null을 int에 입력하는 것은 불가능, 따라서 Integer 변경해야 함(또는 다음에 나오는
defaultValue 사용)
*/
@ResponseBody
@RequestMapping("/request-param-required")
public String requestParamRequired(
@RequestParam(required = true) String username,
@RequestParam(required = false) Integer age) {
log.info("username={}, age={}", username, age);
return "ok";
}
- requestParamRequired (파라미터 필수 여부)
- @RequestParam.required : 파라미터 필수 여부. 기본값이 파라미터 필수( true )이다.
- /request-param 요청 : username 이 없으므로 400 예외가 발생한다.
- 파라미터 이름만 사용 : /request-param?username= 파라미터 이름만 있고 값이 없는 경우 빈문자로 통과
- 기본형(primitive)에 null 입력 : /request-param 요청 @RequestParam(required = false) int age
- null 을 int 에 입력하는 것은 불가능(500 예외 발생). null 을 받을 수 있는 Integer 로 변경 혹은 defaultValue 사용
/**
* @RequestParam
* - defaultValue 사용
*
* 참고: defaultValue는 빈 문자의 경우에도 적용
* /request-param?username=
*/
@ResponseBody
@RequestMapping("/request-param-default")
public String requestParamDefault(
@RequestParam(required = true, defaultValue = "guest") String username,
@RequestParam(required = false, defaultValue = "-1") int age) {
log.info("username={}, age={}", username, age);
return "ok";
}
- requestParamDefault (기본 값 적용)
- 파라미터에 값이 없는 경우 defaultValue 를 사용하면 기본 값을 적용할 수 있다. 기본 값이 있기 때문에 required 는 의미가 없다
- defaultValue 는 빈 문자의 경우에도 설정한 기본 값이 적용된다. (e.g. /request-param?username=)
/**
* @RequestParam Map, MultiValueMap
* Map(key=value)
* MultiValueMap(key=[value1, value2, ...] ex) (key=userIds, value=[id1, id2])
*/
@ResponseBody
@RequestMapping("/request-param-map")
public String requestParamMap(@RequestParam Map<String, Object> paramMap) {
log.info("username={}, age={}", paramMap.get("username"),
paramMap.get("age"));
return "ok";
}
- requestParamMap (파라미터를 Map으로 조회하기)
- 파라미터를 Map, MultiValueMap으로 조회할 수 있다
- @RequestParam Map : Map(key=value)
- @RequestParam MultiValueMap : MultiValueMap(key=[value1, value2, ...] ex) (key=userIds, value=[id1, id2])
- 파라미터의 값이 1개가 확실하다면 Map 을 사용해도 되지만, 그렇지 않다면 MultiValueMap 을 사용하자.
4.7 HTTP 요청 파라미터 - @ModelAttribute
> 실제 개발을 하면 아래와 같이 요청 파라미터를 받아서 필요한 객체를 만들고 그 객체에 값을 넣어주어야 한다.
@RequestParam String username;
@RequestParam int age;
HelloData data = new HelloData();
data.setUsername(username);
data.setAge(age);
- 스프링은 이 과정을 완전히 자동화해주는 @ModelAttribute 기능을 제공한다
package hello.springmvc.basic;
import lombok.Data;
@Data
public class HelloData {
private String username;
private int age;
}
- @Data Annotation의 역할 : 롬복에서 제공해주는 @Data의 경우 @Getter , @Setter , @ToString , @EqualsAndHashCode , @RequiredArgsConstructor 를 자동으로 적용해준다.
/**
* @ModelAttribute 사용
* 참고: model.addAttribute(helloData) 코드도 함께 자동 적용됨, 뒤에 model을 설명할 때
자세히 설명
*/
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@RequestParam String username, @RequestParam int age) {
HelloData helloData = new HelloData();
helloData.setUsername(username);
helloData.setAge(age);
log.info("username={}, age={}", helloData.getUsername(),
helloData.getAge());
log.info("hellodata={}", helloData); //객체를 log에 찍을 경우 @Data에서 ToString으로 변환해준다.
return "ok";
}
@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@ModelAttribute HelloData helloData) {
//@ModelAttribute HelloData helloData의 경우 @RequestParam String username, @RequestParam int age와 동일한 역할을 한다.
log.info("username={}, age={}", helloData.getUsername(),
helloData.getAge());
return "ok";
}
- @ModelAttribute 적용
- HelloData 객체가 생성되고, 요청 파라미터의 값도 모두 들어가 있다
- 스프링MVC는 @ModelAttribute 가 있으면 다음을 실행한다.
- HelloData 객체를 생성한다 -> 요청 파라미터의 이름으로 HelloData 객체의 프로퍼티를 찾는다 -> 해당 프로퍼티의 setter를 호출해서 파라미터의 값을 입력(바인딩) 한다.
- 예) 파라미터 이름이 username 이면 setUsername() 메서드를 찾아서 호출하면서 값을 입력한다
> 프로퍼티
- 객체에 getUsername() , setUsername() 메서드가 있으면, 이 객체는 username 이라는 프로퍼티를 가지고 있다.
- username 프로퍼티의 값을 변경하면 setUsername() 이 호출되고, 조회하면 getUsername() 이 호출된다
class HelloData {
getUsername();
setUsername();
}
> 바인딩 오류
- age=abc 처럼 숫자가 들어가야 할 곳에 문자를 넣으면 BindException 이 발생한다.
/**
* @ModelAttribute 생략 가능
* String, int 같은 단순 타입 = @RequestParam
* argument resolver 로 지정해둔 타입 외 = @ModelAttribute
*/
@ResponseBody
@RequestMapping("/model-attribute-v2")
public String modelAttributeV2(HelloData helloData) {
log.info("username={}, age={}", helloData.getUsername(),
helloData.getAge());
return "ok";
}
- @ModelAttribute 생략
- @ModelAttribute 는 생략할 수 있다. 그런데 @RequestParam 도 생략할 수 있으니 혼란이 발생할 수 있다
- 스프링은 해당 생략시 다음과 같은 규칙을 적용한다.
- String , int , Integer 같은 단순 타입 = @RequestParam
- 나머지 = @ModelAttribute (argument resolver 로 지정해둔 타입 외)
'Spring 정리' 카테고리의 다른 글
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 25 (0) | 2022.05.26 |
---|---|
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 24 (0) | 2022.05.22 |
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 22 (0) | 2022.05.15 |
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 21 (0) | 2022.05.15 |
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 20 (0) | 2022.04.03 |