![](http://t1.daumcdn.net/tistory_admin/static/images/xBoxReplace_250.png)
💻본 포스팅은 '스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 김영한'님의 강의를 듣고 작성되었습니다.
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 인프런 | 강의
웹 애플리케이션 개발에 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. MVC 2편에서는 MVC 1편의 핵심 원리와 구조 위에 실무 웹 개발에 필요한 모든 활용 기술들을 학습할 수 있
www.inflearn.com
[groups를 사용하지 않는 이유]
- 등록시 폼에서 전달하는 데이터가 'Item' 도메인 객체와 딱 맞지 않기 때문이다
- 수 많은 부가적인 데이터(=상품과 관련 없는)가 넘어오기 때문에 복잡한 폼의 컨트롤러까지 전달할 별도의 객체를 만들어 전달한다.
- 이것을 사용해 컨트롤러에서 폼 데이터를 전달 받고 이후 컨트롤러에서 필요한 데이터를 사용해서 Item을 생성한다.
[폼데이터 전달에 Item 도메인 객체 사용]
- 장점
- 심플하게 중간과정 없이 도메인 객체를 컨트롤러, 레포지토리까지 직접 전달해준다.
- 단점
- 매우 간단해서 간단하게 개발하는 경우에만 사용할 수 있고 수정시 검증이 중복될 수 있는 문제가 있어 groups를 사용해야 한다.
[폼 데이터 전달을 위한 별도의 객체 사용]
- 장점
- 전송하는 폼 데이터가 복잡해도 거기에 맞춘 별도의 폼 객체를 사용해 데이터를 전달받을 수 있다.
- 수정용으로 별도의 폼 객체를 만들기 때문에 검증이 중복될 일이 없다.
- 단점
- 폼 데이터를 기반으로 컨트롤러에서 Item 객체를 생성하는 변환 과정이 추가된다.
[달라지는 폼 데이터?]
- 달라지는 폼 데이터에 관해서 간단한 예시로 회원가입(등록) 회원수정(수정)의 경우를 생각해본다면 쉽다.
- 등록 시에는 주민등록, id 등을 입력 받지만 수정의 경우엔 주민등록 번호나 id를 다시 재입력 받을 필요가 없다.(수정이 불가한 항목일 경우도 있다.)
- 그렇기에 검증 로직도 달라지고 데이터 범위도 달라지게 되는 것이다.
- 다시 말해서 등록과 수정은 같아 보이지만 완전히 다른 데이터가 넘어온다고 봐야 한다.
- 그래서 결과적으로는 ItemUpdateForm이라는 별도의 객체로 데이터를 따로 전달 받는 것이 좋다. (등록 시 폼 데이터와 수정 시 넘어오는 폼 데이터를 서로 다른 객체로 받는 것을 의미한다.)
- 또한 수 많은 부가적인(약관에 대한 정보 등등..) 정보도 폼 데이터를 통해 넘어오기 때문에 폼 데이터를 하나의 객체로 사용하는 groups는 잘 사용하지 않는 것이다.
[Item 객체 수정]
[기존 Item 코드]
package hello.itemservice.domain.item;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import org.hibernate.validator.constraints.ScriptAssert;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
//@ScriptAssert(lang = "javascript", script = "_this.price * _this.quantity >= 10000")
public class Item {
@NotNull(groups = UpdateCheck.class)// 수정 요구사항 추가
private Long id;
@NotBlank(groups = {SaveCheck.class, UpdateCheck.class})
private String itemName;
@NotNull(groups = {SaveCheck.class, UpdateCheck.class})
@Range(min = 1000, max = 1000000,groups = {SaveCheck.class, UpdateCheck.class})
private Integer price;
@NotNull(groups = {SaveCheck.class, UpdateCheck.class})
@Max(value = 9999,groups = {SaveCheck.class})
private Integer quantity;
public Item() {
}
public Item(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
기존 검증을 위해서 사용했던 부분을 싹 - 다 지워줘도 된다.
[수정 후]
package hello.itemservice.domain.item;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import org.hibernate.validator.constraints.ScriptAssert;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
public class Item {
private Long id;
private String itemName;
private Integer price;
private Integer quantity;
public Item() {
}
public Item(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
[폼 데이터의 분리 작업]
[등록 폼 데이터]
package hello.itemservice.web.validation.form;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
public class ItemSaveForm {
@NotBlank
private String itemName;
@NotNull
@Range(min = 1000, max = 1000000)
private Integer price;
@NotNull
@Max(value = 9999)
private Integer quantity;
}
[수정 폼 데이터]
package hello.itemservice.web.validation.form;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
public class ItemUpdateForm {
@NotNull
private Long id;
@NotBlank
private String itemName;
@NotNull
@Range(min = 1000, max = 1000000)
private Integer price;
// 수정에서는 수량은 자유롭게 변경할 수 있다.
private Integer quantity;
}
[컨트롤러]
@PostMapping("/{itemId}/edit")
public String edit(@PathVariable Long itemId, @Validated @ModelAttribute("item") ItemUpdateForm form, BindingResult bindingResult) {
//특정 필드가 아닌 복합 룰 검증
if (form.getPrice() != null && form.getQuantity() != null) {
int resultPrice = form.getPrice() * form.getQuantity();
if (resultPrice < 10000) {
bindingResult.reject("totalPriceMin", new Object[]{10000,
resultPrice}, null);
}
}
//검증에 실패하게 될 때 다시 입력 폼으로 간다.
if (bindingResult.hasErrors()) {
log.info("errors={}", bindingResult);
return "validation/v4/editForm";
}
Item itemParam = new Item();
itemParam.setItemName(form.getItemName());
itemParam.setPrice(form.getPrice());
itemParam.setQuantity(form.getQuantity());
itemRepository.update(itemId, itemParam);
return "redirect:/validation/v4/items/{itemId}";
}
- 컨트롤러의 경우 Item 대신 수정 폼, 등록 폼에 맞게 폼 데이터 객체를 넘겨준다.
- 이때 추가적으로 폼 데이터를 Item 객체로 변환해주는 작업을 해야 한다.
[폼 객체를 Item으로 변환]
Item itemParam = new Item();
itemParam.setItemName(form.getItemName());
itemParam.setPrice(form.getPrice());
itemParam.setQuantity(form.getQuantity());
'Back-End > Spring' 카테고리의 다른 글
[Spring MVC2][로그인 처리] - 디렉토리(directory) 방향 (0) | 2022.05.13 |
---|---|
[Spring MVC2][검증2(Validation)] - Bean Validation - HTTP 메시지 컨버터 (0) | 2022.05.05 |
[Spring MVC2][검증2(Validation)] - Bean Validation - groups (0) | 2022.05.03 |
[Spring MVC2][검증2(Validation)] - Bean Validation (0) | 2022.05.03 |
[Spring MVC2][검증(Validation)] - 컨트롤러와 검증의 분리 (0) | 2022.05.02 |