인프런 커뮤니티 질문&답변
상품 등록, 수정 구현 방법에 대해서 궁금합니다.
해결된 질문
작성
·
438
1
안녕하세요 강사님! 항상 훌륭한 강의 감사드립니다.
다름이 아니라 Book뿐만 아니라 Food, Movie 등 여러 Item도 등록 및 수정을 구현해보고 있습니다.
궁금한점은 제가 구현하는 방식이 item 종류에 따라 Controller에 메서드를 구현, ItemService에서 if-else 문을 통해 SaveForm, UpdateForm의 타입을 판단하여 다운캐스팅을 통해 save, update를 실행하도록 하였습니다.
허나 이 방식은 Item의 종류가 증가하게 될때마다 메서드와 if문이 추가되기때문에 코드가 복잡하고 가독성이 떨어진다는 느낌이 들었습니다.
이 방식을 개선할 수 있는 방법이 무엇이 있는지 궁금합니다.
[Save & Update Form]
각 Item들은 ItemSaveForm, ItemUpdateForm을 상속
[ add & edit Item ]
@GetMapping("/addBook")
public String addBookForm(Model model) {
Book book = Book.createEmptyBook();
model.addAttribute("book", book);
return VIEW_PATH + "book/addForm";
}
@PostMapping("/addBook")
public String addBookForm(@Validated @ModelAttribute("book") BookSaveForm form, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
//특정 필드 예외가 아닌 전체 예외
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 VIEW_PATH + "book/addForm";
}
Long savedId = itemService.save(form);
redirectAttributes.addAttribute("itemId", savedId);
redirectAttributes.addAttribute("status", true);
return "redirect:/manager/items/{itemId}";
}
@GetMapping("/addFood")
public String addFoodForm(Model model) {
Food food = Food.createEmptyFood();
model.addAttribute("food", food);
return VIEW_PATH + "food/addForm";
}
@PostMapping("/addFood")
public String addFoodForm(@Validated @ModelAttribute("food") FoodSaveForm form, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
//특정 필드 예외가 아닌 전체 예외
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 VIEW_PATH + "food/addForm";
}
Long savedId = itemService.save(form);
redirectAttributes.addAttribute("itemId", savedId);
redirectAttributes.addAttribute("status", true);
return "redirect:/manager/items/{itemId}";
}
@GetMapping("/{itemId}/edit/book")
public String editBookForm(@PathVariable Long itemId, Model model) {
Item item = itemService.findItem(itemId);
model.addAttribute("book", item);
return VIEW_PATH + "book/editForm";
}
@PostMapping("/{itemId}/edit/book")
public String editBook(@PathVariable Long itemId, @Validated @ModelAttribute("book") BookUpdateForm 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 VIEW_PATH + "book/editForm";
}
itemService.update(itemId, form);
return "redirect:/manager/items/{itemId}";
}
@GetMapping("/{itemId}/edit/food")
public String editFoodForm(@PathVariable Long itemId, Model model) {
Item item = itemService.findItem(itemId);
model.addAttribute("food", item);
return VIEW_PATH + "food/editForm";
}
@PostMapping("/{itemId}/edit/food")
public String editFood(@PathVariable Long itemId, @Validated @ModelAttribute("food") FoodUpdateForm 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 VIEW_PATH + "food/editForm";
}
itemService.update(itemId, form);
return "redirect:/manager/items/{itemId}";
}
Item이 추가될때마다 add, edit 메서드를 구현해야함
[ItemService]
public Long save(ItemSaveForm form) {
if (form instanceof BookSaveForm) {
Book book = Book.createBook(form.getItemName(), form.getPrice(), form.getQuantity(), ((BookSaveForm) form).getAuthor());
itemRepository.save(book);
return book.getId();
} else if (form instanceof FoodSaveForm) {
Food food = Food.createFood(form.getItemName(), form.getPrice(), form.getQuantity(), ((FoodSaveForm) form).getFoodType());
itemRepository.save(food);
return food.getId();
} else if (form instanceof MovieSaveForm) {
Movie movie = Movie.createMovie(form.getItemName(), form.getPrice(), form.getQuantity(), ((MovieSaveForm) form).getGenre());
itemRepository.save(movie);
return movie.getId();
}
return null;
}
public Long update(Long itemId, ItemUpdateForm form) {
if (form instanceof BookUpdateForm) {
Book book = (Book) itemRepository.findById(itemId).get();
book = Book.updateBook(book, (BookUpdateForm) form);
} else if (form instanceof FoodUpdateForm) {
Food food = (Food) itemRepository.findById(itemId).get();
food = Food.updateFood(food, (FoodUpdateForm) form);
} else if (form instanceof MovieUpdateForm) {
Movie movie = (Movie) itemRepository.findById(itemId).get();
movie = Movie.updateMovie(movie, (MovieUpdateForm) form);
}
return itemId;
}
ItemType에 따라 다운캐스팅하여 save, update 실행
퀴즈
회원 가입 시 화면 입력 데이터를 엔티티 객체 대신 별도의 Form 객체로 받는 주된 이유는 무엇일까요?
데이터베이스 성능을 최적화하기 위해서
화면 종속적인 데이터나 유효성 검증 로직을 분리하기 위해서
JPA 영속성 컨텍스트와 직접적인 관계를 맺기 위해서
코드의 자동 생성 기능을 활용하기 위해서
답변 2
1
0
주말에 쉬셔야 하시는데 답변 달아주셔서 감사드립니다.ㅠㅠ
서비스를 각각 별도로 분리해라는 뜻이 Controller(add)-Service(save), Controller(edit)-Service(update)로 분리해라는 의미일까요?
그렇다면 클래스가 분리되니 클래스당 코드 양은 줄일 수 있을것 같습니다.
다만, Service의 save, update 로직은 if-else 문은 결국 저런 형태로 구현해야한다는 말씀이신지 궁금합니다.






ItemService를 분리해서 BookService, FoodService 등으로 분리하는게 더 좋은 판단입니다.
실제로 해당 상품군으로 로직도 많이 다를 수 있습니다.
감사합니다.