인프런 - 스프링 부트와 JPA 활용1 by 김영한 을 기반으로 작성된 글입니다.
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
상품은 책으로 한정
package jpabook.jpashop.controller;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class BookForm {
private Long id;
//상품 공통 속성
private String name;
private int price;
private int stockQuantity;
//책 관련 속성
private String author;
private String isbn;
}
package jpabook.jpashop.controller;
import jpabook.jpashop.domain.item.Book;
import jpabook.jpashop.service.ItemService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
@RequiredArgsConstructor
public class ItemController {
private final ItemService itemService;
@GetMapping("/items/new")
public String createForm(Model model){
model.addAttribute("form", new BookForm());
return "items/createItemForm";
}
@PostMapping("/items/new")
public String create(BookForm form){
Book book = new Book();
book.setName(form.getName());
book.setPrice(form.getPrice());
book.setStockQuantity(form.getStockQuantity());
book.setAuthor(form.getAuthor());
book.setIsbn(form.getIsbn());
itemService.saveItem(book);
return "redirect:/";
}
}
코드는 일부만 나타내도록 하겠다
(생략)
<form th:action="@{/items/new}" th:object="${form}" method="post">
<div class="form-group">
<label th:for="name">상품명</label>
<input type="text" th:field="*{name}" class="form-control"
placeholder="이름을 입력하세요">
</div>
(생략)
👉단일 테이블 전략 사용
테이블 하나만 사용, 데이터가 저장 되었는지 구분하기 위해 간단한 데이터만 저장하였다
🔎 개인적으로 데이터 검증을 하기 위해
@Vaild
, BindingResult 코드를 추가 해보았다
public String create(@Valid BookForm form, BindingResult result){
if(result.hasErrors()){
return "items/createItemForm";
}
<input type="text" th:field="*{name}" class="form-control"
placeholder="이름을 입력하세요"
th:class="${#fields.hasErrors('name')}? 'form-control
fieldError' : 'form-control'">
에러 발생시 나타낼 스타일을 추가하고 (fieldError) 상품명, 가격, 수량에만 th:class 를 사용하였다
//상품 공통 속성
@NotEmpty(message = "책 이름을 입력해주세요")
private String name;
@NotEmpty(message = "책 가격을 입력해주세요")
private int price;
@NotEmpty(message = "책 수량을 등록해주세요")
private int stockQuantity;
📍 설명
상품명, 가격, 수량에 @NotEmpty 을 적용하였다
javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 'javax.validation.constraints.NotEmpty' validating type 'java.lang.Integer'. Check configuration for 'stockQuantity'
💡 원인
@NotEmpty
는 String 타입에서 사용하는 어노테이션이기 때문에
오류가 난 것이었다. size와 length를 검사할 수 있는 타입이 들어간다고 한다.
가격과 수량은 Integer 타입이므로 @NotNull
을 사용해준다.
추가적으로 @NotBlank
도 String 타입만 사용할 수 있다.
💡 해결
BookForm.java 코드 수정
//상품 공통 속성
@NotEmpty(message = "상품명을 입력해주세요")
private String name;
@NotNull(message = "책 가격을 1원 이상 입력해주세요")
@Min(value = 1, message = "책 가격을 1원 이상 입력해주세요")
private int price;
@NotNull(message = "책 수량을 1권 이상 입력해주세요")
@Min(value = 1, message = "책 수량을 1권 이상 입력해주세요")
private int stockQuantity;
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'form' available as request attribute
💡 원인
내가 전체적으로 코드를 추가하기 전까지는
에러가 나지 않던 코드가 에러가 나서 애를 먹었다.
form 키 값이 오타가 났나 찾아보았더니 정상적으로 써있어서 머리를 싸맸다
내가 무엇을 잘못 입력했고 해결방법은 무엇일까..?
💡 해결
ItemController.java 코드 수정
아래처럼 @ModelAttribute("form") 코드를 추가해 수정해주었다
public String create(@ModelAttribute("form") @Valid BookForm form, BindingResult result){}
제대로 데이터를 입력해서 submit 해보자
insert 성공
상품 목록 페이지는 다음 시간에 만들어보자.
일단 급한 불을 꺼두고 더 자세히 공부해 봐야겠다😅