Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

5주차 과제- 고양이 장난감가게 만들기 (심화) #75

Merged
merged 40 commits into from
Sep 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
913016f
gradle DozerMapper 추가
jdalma Aug 29, 2022
8fb107b
DozerMapper 적용
jdalma Aug 29, 2022
9ad7692
ddl-auto: create로 수정
jdalma Aug 29, 2022
6f398d4
out폴더 무시
jdalma Aug 29, 2022
398c728
UserController 유닛 테스트 작성
jdalma Aug 29, 2022
8079515
ProductService 주석 추가
jdalma Aug 29, 2022
21a2fcb
메서드 파라미터 타입 수정
jdalma Aug 29, 2022
36be2a5
변수 네이밍 수정
jdalma Aug 29, 2022
a189482
User 테스트 데이터 클래스 추가
jdalma Aug 29, 2022
9ac5972
User 도메인 password필드 직렬화 방지
jdalma Aug 29, 2022
e92a0a9
UserController @RequestBody 추가
jdalma Aug 29, 2022
f6a6cb8
UserControllerTest 반복되는 코드 제거
jdalma Aug 29, 2022
8c9ac91
UserSerivce 테스트 코드 작성 중
jdalma Aug 29, 2022
aec0ada
Update app/src/main/java/com/codesoom/assignment/application/ProductS…
jdalma Aug 30, 2022
bfc1bbb
Update app/src/main/java/com/codesoom/assignment/application/ProductS…
jdalma Aug 30, 2022
32c11e1
Update app/src/main/java/com/codesoom/assignment/application/UserServ…
jdalma Aug 30, 2022
2e654f4
ProductService 주석 수정
jdalma Aug 30, 2022
9212001
ProductNotFound -> ResourceNotFound 커스텀 예외 변경
jdalma Aug 30, 2022
0be1625
AllArgsConstructor 제거
jdalma Aug 30, 2022
9d8a363
Product 엔티티 AllArgsConstructor 제거
jdalma Aug 30, 2022
a3e6132
User 엔티티 update 메서드 추가
jdalma Aug 30, 2022
3385770
예외 메세지 수정
jdalma Aug 30, 2022
7ccaeff
User 테스트 코드 작성
jdalma Aug 30, 2022
5bad14b
테스트를 작성하지 않은 부분은 fail()
jdalma Aug 31, 2022
7633d28
findProduct 메서드 주석 추가
jdalma Aug 31, 2022
40039a5
Builder어노테이션 생성자로 이동
jdalma Aug 31, 2022
5fefb1b
ProductController 주석 추가
jdalma Aug 31, 2022
c2367ef
updateProduct 메서드 주석 수정
jdalma Aug 31, 2022
f2cea5e
UserService 클래스 분리
jdalma Aug 31, 2022
1258380
UserService 분리로 인한 수정
jdalma Aug 31, 2022
b6aff67
불필요한 주석 제거
jdalma Sep 1, 2022
5431692
User 도메인 필드 검증 어노테이션 추가
jdalma Sep 1, 2022
5c93236
UserController 주석 및 테스트 코드 작성
jdalma Sep 1, 2022
6720c2b
Update app/src/main/java/com/codesoom/assignment/controllers/ProductC…
jdalma Sep 1, 2022
180aabd
Update app/src/test/java/com/codesoom/assignment/controllers/UserCont…
jdalma Sep 2, 2022
979a3e0
user spec으로 인해/user를 /users로 변경
jdalma Sep 2, 2022
23a10fb
User 엔티티 필수 입력 값 테스트 코드 추가
jdalma Sep 2, 2022
2bf7346
user spec에 의한 DTO 추가
jdalma Sep 2, 2022
5d890ea
User update 메서드 수정
jdalma Sep 2, 2022
85dea3b
UserController DTO 추가로 JavaDoc 수정
jdalma Sep 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
/app/out/
4 changes: 4 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ dependencies {
// Spring Developer Tools
developmentOnly 'org.springframework.boot:spring-boot-devtools'

// DozerMapper
// DTO와 Domain을 매핑해주는 역할
implementation 'com.github.dozermapper:dozer-core:6.4.0'
Comment on lines +67 to +69
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dozermapper github repository에 방문해 보세요. 어떤 문제가 있다는 것을 알 수 있을 텐데, 어떤 문제인지 확인해서 글로 작성해 보세요. dozermapper 를 제거해야 할 지에 대해서도 생각해 보시고, 제거한다면 어떤 대안이 있는지도 글에 함께 적어 보세요.


// Spring Boot Test
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/com/codesoom/assignment/App.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.codesoom.assignment;

import com.github.dozermapper.core.DozerBeanMapperBuilder;
import com.github.dozermapper.core.Mapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class App {
Expand All @@ -12,4 +15,9 @@ public String getGreeting() {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}

@Bean
public Mapper dozerMapper(){
return DozerBeanMapperBuilder.buildDefault();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.codesoom.assignment;

public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(Long id) {
super("식별자에 해당하는 자원이 존재하지 않습니다. : " + id);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.codesoom.assignment.application;

import com.codesoom.assignment.ProductNotFoundException;
import com.codesoom.assignment.ResourceNotFoundException;
import com.codesoom.assignment.domain.Product;
import com.codesoom.assignment.domain.ProductRepository;
import com.codesoom.assignment.dto.ProductData;
import com.github.dozermapper.core.Mapper;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
Expand All @@ -12,43 +13,64 @@
@Service
@Transactional
public class ProductService {
private final Mapper mapper;
private final ProductRepository productRepository;

public ProductService(ProductRepository productRepository) {
public ProductService(Mapper dozerMapper , ProductRepository productRepository) {
this.mapper = dozerMapper;
this.productRepository = productRepository;
}

/**
* 모든 상품들을 반환한다.
*/
public List<Product> getProducts() {
return productRepository.findAll();
}

/**
* 상품을 찾아 반환한다.
*
* @param id 찾으려는 상품의 식별자
* @return 식별자에 해당하는 상품
* @throws ResourceNotFoundException 식별자에 해당하는 상품이 없는 경우
*/
public Product getProduct(Long id) {
return findProduct(id);
}

/**
* 상품을 저장한다.
*
* @param productData 저장할 상품의 DTO
* @return 저장한 상품
*/
public Product createProduct(ProductData productData) {
Product product = Product.builder()
.name(productData.getName())
.maker(productData.getMaker())
.price(productData.getPrice())
.imageUrl(productData.getImageUrl())
.build();
Product product = mapper.map(productData, Product.class);
return productRepository.save(product);
}

/**
* 식별자에 해당하는 상품을 수정한다.
*
* @param id 수정하려는 상품의 식별자
* @param productData 수정할 정보 상품의 DTO
* @return 수정 후 저장된 상품
* @throws ResourceNotFoundException 식별자에 해당하는 상품이 없는 경우
*/
public Product updateProduct(Long id, ProductData productData) {
Product product = findProduct(id);

product.change(
productData.getName(),
productData.getMaker(),
productData.getPrice(),
productData.getImageUrl()
);

product.change(mapper.map(productData , Product.class));
return product;
}

/**
* 식별자에 해당하는 상품을 삭제한다
*
* @param id 삭제하려는 상품의 식별자
* @return 식별자에 해당하는 상품
* @throws ResourceNotFoundException 식별자에 해당하는 상품이 없는 경우
*/
public Product deleteProduct(Long id) {
Product product = findProduct(id);

Expand All @@ -57,8 +79,15 @@ public Product deleteProduct(Long id) {
return product;
}

/**
* 식별자에 해당하는 상품을 조회한다
*
* @param id 조회할 상품의 식별자
* @return 식별자에 해당하는 상품
* @throws ResourceNotFoundException 식별자에 해당하는 상품이 없는 경우
*/
private Product findProduct(Long id) {
return productRepository.findById(id)
.orElseThrow(() -> new ProductNotFoundException(id));
.orElseThrow(() -> new ResourceNotFoundException(id));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.codesoom.assignment.application;

import com.codesoom.assignment.ResourceNotFoundException;
import com.codesoom.assignment.domain.User;
import com.codesoom.assignment.domain.UserRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional
public class UserCommandService {

private UserRepository repository;

public UserCommandService(UserRepository repository) {
this.repository = repository;
}

public User save(User user){
return repository.save(user);
}

public User update(User beforeUser , User user){
return beforeUser.update(user);
}

public User delete(User user){
repository.delete(user);
return user;
Comment on lines +29 to +31
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

만약 삭제가 실패했다면 실패했다는 사실을 호출자에게 어떤 식으로 알릴 수 있을까요? 지금은 User를 그대로 리턴하고만 있기 때문에 알 수 없을 것입니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Controller에서 query.findUser가 식별자에 해당하는 정보가 없으면 예외를 던지게 되어 있습니다

@DeleteMapping("{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(@PathVariable Long id){
    command.delete(query.findUser(id));
}

어떤 상황이 더 있을까요??

Copy link
Collaborator

@johngrib johngrib Sep 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예외를 던진다면 delete 메소드 위에 JavaDoc으로 @throws를 작성해 주도록 합시다. 한 번에 알아볼 수 있도록 해주는 것이 필요해요. 한편 findUser가 예외를 던지도록 하는 것이 과연 바람직한 것인지에 대해서도 생각할 수 있겠죠. 만약 검색엔진에서 어떤 것을 검색했는데 "검색 결과가 0 입니다" 라고 결과가 나오는 것과 예외가 던져지는 것을 두고 상상해볼 수도 있을 겁니다. 지금은 예외를 Goto 처럼 쓰고 있는 셈인데 (이것이 꼭 나쁘다는 것은 아닙니다) 어떻게 해야 코드를 읽는 사람에게 빨리 파악할 수 있도록 도와줄 수 있는지도 고민해야 해요

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.codesoom.assignment.application;

import com.codesoom.assignment.ResourceNotFoundException;
import com.codesoom.assignment.domain.User;
import com.codesoom.assignment.domain.UserRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional(readOnly = true)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QueryService 에 잘 어울리는 애노테이션입니다.

public class UserQueryService {

private UserRepository repository;

public UserQueryService(UserRepository repository) {
this.repository = repository;
}

public List<User> findAll(){
return repository.findAll();
}

public User findUser(Long id) {
return repository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException(id));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.codesoom.assignment.controllers;

import com.codesoom.assignment.ProductNotFoundException;
import com.codesoom.assignment.ResourceNotFoundException;
import com.codesoom.assignment.dto.ErrorResponse;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
Expand All @@ -12,7 +12,7 @@
public class NotFoundErrorAdvice {
@ResponseBody
@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler(ProductNotFoundException.class)
@ExceptionHandler(ResourceNotFoundException.class)
public ErrorResponse handleProductTaskNotFound() {
return new ErrorResponse("Product not found");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package com.codesoom.assignment.controllers;

import com.codesoom.assignment.ResourceNotFoundException;
import com.codesoom.assignment.application.ProductService;
import com.codesoom.assignment.domain.Product;
import com.codesoom.assignment.dto.ProductData;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

/**
* 상품을 조회, 생성, 삭제한다.
*/
@RestController
@RequestMapping("/products")
public class ProductController {
Expand All @@ -18,22 +23,48 @@ public ProductController(ProductService productService) {
this.productService = productService;
}

/**
* 모든 상품들을 반환한다.
*/
@GetMapping
public List<Product> list() {
return productService.getProducts();
}

/**
* 식별자에 해당하는 상품을 조회한다.
*
* @param id 찾으려는 상품의 식별자
* @return 식별자에 해당하는 상품
* @throws ResourceNotFoundException 식별자에 해당하는 상품이 없는 경우
*/
@GetMapping("{id}")
public Product detail(@PathVariable Long id) {
return productService.getProduct(id);
}

/**
* 상품 정보를 저장한다.
*
* @param productData 저장할 정보
* @return 생성된 상품
* @throws MethodArgumentNotValidException 필수 정보가 비어있는 경우
*/
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Product create(@RequestBody @Valid ProductData productData) {
return productService.createProduct(productData);
}

/**
* 식별자에 해당하는 상품을 전달받은 상품으로 수정한다.
*
* @param id 수정할 상품의 식별자
* @param productData 수정할 정보
* @return 수정된 상품
* @throws MethodArgumentNotValidException 필수 정보가 비어있는 경우
* @throws ResourceNotFoundException 식별자에 해당하는 상품이 없는 경우
Comment on lines +65 to +66
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋습니다.

*/
@PatchMapping("{id}")
public Product update(
@PathVariable Long id,
Expand All @@ -42,6 +73,12 @@ public Product update(
return productService.updateProduct(id, productData);
}

/**
* 식별자에 해당하는 상품을 삭제한다.
*
* @param id 삭제할 상품의 식별자
* @throws ResourceNotFoundException 식별자에 해당하는 상품이 없는 경우
*/
@DeleteMapping("{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void destroy(@PathVariable Long id) {
Expand Down