다양한 방법이 있을겁니다. 문자열로 “상품 등록에 실패했습니다” 등의 안내 문구를 리턴할 수도 있고, 실패했다는 메세지를 담은 객체를 만들어서 json으로 전달할 수도 있습니다. 혹은 Exception을 만들어서 throw할 수도 있습니다. 자유롭게 구현해보세요!
처음에는 Exception
을 CheckedException
으로 만들었는데, 호석님이 에러를 던지다 보면 controller
까지 에러 throw
코드가 넘어가게 되고, 이것은 메서드 모양을 변형시키는 것이라고 하셨다. 그리고 요즘은 CheckedException
을 잘 안쓴다고 해서 내가 만든 Exception
들이 RuntimeException
을 상속받게 만들었다!
@PostMapping("/save")
public Long save(@RequestBody SaveProductRequest saveProductRequest) {
return productService.save(saveProductRequest);
}
// 저장 메서드
public Long save(SaveProductRequest saveProductRequest) {
//상품명 중복 검사
checkProductDuplicate(saveProductRequest.getName());
return productRepository.save(saveProductRequest.getName(), saveProductRequest.getPrice());
}
// 중복 검사 메서드 (이미 존재하는 상품인지 확인하고, 있다면 에러를 throw한다)
private void checkProductDuplicate(String name) {
if (isExistedProduct(name)) {
throw new DuplicateNameException(); //UnCheckedException으로 구현함
}
}
// 이미 존재하는지 확인하는 메서드
private boolean isExistedProduct(String name) {
return productRepository.findOneByName(name).isPresent();
}
public Long save(String name, Long price) {
Product saveProduct = Product.createProduct(sequence++, name, price);
products.add(saveProduct);
return saveProduct.getId();
}
시퀀스 값을 하나 증가시켜 products
라는 ArrayList에 추가한다.
(controller는 service에게 위임하는 역할만 하도록 했고, 아래 코드는 모두 service 계층에서 구현된 메서드들이다.)
public ProductResponse findOneByName(String name, String monetaryUnit) {
// 없는 상품명으로 조회했는지 확인
checkProductNotFound(name);
Product findProduct = productRepository.findOneByName(name).get();
ProductResponse productResponse = ProductResponse.from(findProduct);
return getProductResponse(monetaryUnit, productResponse);
}
//존재하는 상품인지 확인하는 메서드 (없는 상품이면 에러를 throw한다)
private void checkProductNotFound(String name) {
if (!isExistedProduct(name)) {
throw new ProductNotFoundException(); //UnCheckedException으로 구현함
}
monetaryUnit
을 쿼리 파라미터로 받아서 service
계층에 전달한다.service
에서는 비즈니스 로직을 처리하고, controller
에 반환할 때 ProductResponse
dto
로 반환하게 되는데, 이건 monetaryUnit
가 dollar
면 dollar로 바꿔서 반환하고, won
이면 그대로 반환하게 만들었다.private ProductResponse getProductResponse(String monetaryUnit, ProductResponse productResponse) {
if (monetaryUnit != null && monetaryUnit.equals("dollar")){
productResponse.setMonetaryUnit(MonetaryUnit.DOLLAR);
productResponse.setPrice(changeToDollar(productResponse.getPrice()));
return productResponse;
}
productResponse.setMonetaryUnit(MonetaryUnit.WON);
return productResponse;
}
여기서 원화를 달러로 바꾸는 changeToDollar()
라는 메서드가 있는데, 나는 그냥won/1300
으로 개발자스럽지 않게 수동으로 바꾸도록 했다... (추후 수정이 필요할 것 같다. )상품을 등록할 때와 조회할 때 모두 ‘실패’가 발생 하는데요. 실패가 발생했을 때는 ‘실패사유’ 등을 공통적으로 전달해야 합니다. 실패에 대한 interface를 만들어서 등록과 조회에서의 각 실패를 구현해보세요.
이건 아직 공부를 덜 해서 공부를 더 하고 블로그 글 수정하겠습니다...⭐
@ExceptionHandler
, @RestControllerAdvice
꼭 찾아보기!!!
Exception
을 만드는 고민을 해본 것 같다. day1
에서는 텅텅 빈 자바 프로젝트였고, day4
는 스프링 프로젝트여서 브랜치 별로 커밋하는 게 좀 헷갈린다. 커밋을 해두긴 했는데 잘 할 건지 모르겠다(?) 프로젝트 안에 프로젝트가 있는 느낌이랄까...dto
는 거의 setter
를 열어둔다. 근데 호석님이 setter
를 롬복으로 만들지 말고 직접 이름을 지정해서 만들라고
조언해주셨다. 어떤 값이 변경된다면 setA()
보다 changeX()
가 더 직관적인 이름이라고도 해주셔서 나의 무분별한 setter
사용을 반성했다. 정석의 코드(혹은 사용기술)
이 궁금합니다!! :)