-
Notifications
You must be signed in to change notification settings - Fork 112
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
전남대 BE_지연우 4주차 과제(step1,2,3) #180
base: speciling
Are you sure you want to change the base?
Changes from all commits
44ca35a
edeafe1
62cd08a
9fc04ac
1adf88e
b846a05
1fa4004
630a4fb
8cead08
11e9122
918567c
02c9456
bed2c00
ca72a61
15a677e
8ce269d
a60d11c
77d782d
3674dbb
22f50ea
b53ef61
d650025
f9d133d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,27 @@ | ||
# spring-gift-enhancement | ||
# spring-gift-enhancement | ||
## 기능 요구사항 | ||
### STEP1 | ||
- 상품에는 항상 하나의 카테고리가 있어야 한다. | ||
- 이미 등록된 카테고리만 사용 가능하다. | ||
- 상품 카테고리는 수정할 수 있다. | ||
- 관리자 화면에서 상품을 추가할 때 카테고리를 지정할 수 있다. | ||
- Admin 권한의 사용자는 새로운 카테고리를 등록할 수 있다. | ||
- Admin 권한의 사용자는 기존 카테고리의 이름을 변경할 수 있다. | ||
- Admin 권한의 사용자는 기존 카테고리를 삭제할 수 있다. | ||
- 등록된 모든 카테고리의 정보를 조회할 수 있다. | ||
|
||
### STEP2 | ||
- 상품에는 항상 하나 이상의 옵션이 있어야 한다. | ||
- 옵션 이름은 공백을 포함하여 최대 50자까지 입력할 수 있다. | ||
- 특수 문자 | ||
- 가능: ( ), [ ], +, -, &, /, _ | ||
- 그 외 특수 문자 사용 불가 | ||
- 옵션 수량은 최소 1개 이상 1억 개 미만이다. | ||
- 동일한 상품 내의 옵션 이름은 중복될 수 없다. | ||
- SELLER는 자신이 등록한 상품의 옵션을 등록, 수정, 삭제 할 수 있다. | ||
- ADMIN은 모든 상품의 옵션을 등록, 수정, 삭제 할 수 있다. | ||
- 모든 사용자는 각 상품의 옵션을 조회할 수 있다. | ||
|
||
### STEP3 | ||
- 상품 옵션의 수량을 지정된 숫자만큼 차감할 수 있다. | ||
- 위 기능의 테스트 코드를 작성한다 |
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,60 @@ | ||||||||||||||||
package gift.doamin.category.controller; | ||||||||||||||||
|
||||||||||||||||
import gift.doamin.category.dto.CategoryForm; | ||||||||||||||||
import gift.doamin.category.dto.CategoryParam; | ||||||||||||||||
import gift.doamin.category.service.CategoryService; | ||||||||||||||||
import java.util.List; | ||||||||||||||||
import org.springframework.http.HttpStatus; | ||||||||||||||||
import org.springframework.security.access.prepost.PreAuthorize; | ||||||||||||||||
import org.springframework.web.bind.annotation.DeleteMapping; | ||||||||||||||||
import org.springframework.web.bind.annotation.GetMapping; | ||||||||||||||||
import org.springframework.web.bind.annotation.PathVariable; | ||||||||||||||||
import org.springframework.web.bind.annotation.PostMapping; | ||||||||||||||||
import org.springframework.web.bind.annotation.PutMapping; | ||||||||||||||||
import org.springframework.web.bind.annotation.RequestBody; | ||||||||||||||||
import org.springframework.web.bind.annotation.RequestMapping; | ||||||||||||||||
import org.springframework.web.bind.annotation.ResponseStatus; | ||||||||||||||||
import org.springframework.web.bind.annotation.RestController; | ||||||||||||||||
|
||||||||||||||||
@RestController | ||||||||||||||||
@RequestMapping("api/categories") | ||||||||||||||||
public class CategoryController { | ||||||||||||||||
|
||||||||||||||||
private final CategoryService categoryService; | ||||||||||||||||
|
||||||||||||||||
public CategoryController(CategoryService categoryService) { | ||||||||||||||||
this.categoryService = categoryService; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
@PostMapping | ||||||||||||||||
@ResponseStatus(HttpStatus.CREATED) | ||||||||||||||||
@PreAuthorize("hasRole('ROLE_ADMIN')") | ||||||||||||||||
public void createNewCategory(@RequestBody CategoryForm categoryForm) { | ||||||||||||||||
categoryService.createCategory(categoryForm); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
@GetMapping | ||||||||||||||||
public List<CategoryParam> getAllCategories() { | ||||||||||||||||
return categoryService.getAllCategories(); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
@GetMapping("/{id}") | ||||||||||||||||
public CategoryParam getOneCategory(@PathVariable Long id) { | ||||||||||||||||
return categoryService.getCategory(id); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
@PutMapping("/{id}") | ||||||||||||||||
@ResponseStatus(HttpStatus.NO_CONTENT) | ||||||||||||||||
@PreAuthorize("hasRole('ROLE_ADMIN')") | ||||||||||||||||
public void changeCategoryName(@RequestBody CategoryForm categoryForm, @PathVariable Long id) { | ||||||||||||||||
categoryForm.setId(id); | ||||||||||||||||
categoryService.updateCategory(categoryForm); | ||||||||||||||||
} | ||||||||||||||||
Comment on lines
+49
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
이런 방식은 어떨까요? |
||||||||||||||||
|
||||||||||||||||
@DeleteMapping("/{id}") | ||||||||||||||||
@ResponseStatus(HttpStatus.NO_CONTENT) | ||||||||||||||||
@PreAuthorize("hasRole('ROLE_ADMIN')") | ||||||||||||||||
public void deleteCategory(@PathVariable Long id) { | ||||||||||||||||
categoryService.deleteCategory(id); | ||||||||||||||||
} | ||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package gift.doamin.category.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonCreator; | ||
import jakarta.validation.constraints.NotBlank; | ||
|
||
public class CategoryForm { | ||
|
||
private Long id; | ||
|
||
@NotBlank | ||
private String name; | ||
|
||
@JsonCreator | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. JsonCreator는 필요하지 않습니다~ |
||
public CategoryForm(String name) { | ||
this.name = name; | ||
} | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public void setId(Long id) { | ||
this.id = id; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package gift.doamin.category.dto; | ||
|
||
import gift.doamin.category.entity.Category; | ||
|
||
public class CategoryParam { | ||
|
||
private Long id; | ||
|
||
private String name; | ||
|
||
public CategoryParam(Category category) { | ||
this.id = category.getId(); | ||
this.name = category.getName(); | ||
} | ||
Comment on lines
+11
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 정적 팩토리 메서드 사용을 추천드립니다. |
||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package gift.doamin.category.entity; | ||
|
||
import gift.doamin.category.dto.CategoryForm; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
|
||
@Entity | ||
public class Category { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@Column(nullable = false) | ||
private String name; | ||
|
||
protected Category() { | ||
} | ||
|
||
public Category(String name) { | ||
this.name = name; | ||
} | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public void update(CategoryForm categoryForm) { | ||
this.name = categoryForm.getName(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package gift.doamin.category.exception; | ||
|
||
import org.springframework.http.HttpStatus; | ||
import org.springframework.web.server.ResponseStatusException; | ||
|
||
public class CategoryNotFoundException extends ResponseStatusException { | ||
|
||
public CategoryNotFoundException() { | ||
super(HttpStatus.BAD_REQUEST, "해당 카테고리가 존재하지 않습니다"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package gift.doamin.category.repository; | ||
|
||
import gift.doamin.category.entity.Category; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface JpaCategoryRepository extends JpaRepository<Category, Long> { | ||
|
||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,46 @@ | ||||||
package gift.doamin.category.service; | ||||||
|
||||||
import gift.doamin.category.dto.CategoryForm; | ||||||
import gift.doamin.category.dto.CategoryParam; | ||||||
import gift.doamin.category.entity.Category; | ||||||
import gift.doamin.category.exception.CategoryNotFoundException; | ||||||
import gift.doamin.category.repository.JpaCategoryRepository; | ||||||
import java.util.List; | ||||||
import org.springframework.stereotype.Service; | ||||||
|
||||||
@Service | ||||||
public class CategoryService { | ||||||
|
||||||
private final JpaCategoryRepository categoryRepository; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
이렇게 작성해도 잘 작동되게 해주세요~ |
||||||
|
||||||
public CategoryService(JpaCategoryRepository categoryRepository) { | ||||||
this.categoryRepository = categoryRepository; | ||||||
} | ||||||
|
||||||
public void createCategory(CategoryForm categoryForm) { | ||||||
categoryRepository.save(new Category(categoryForm.getName())); | ||||||
} | ||||||
|
||||||
public List<CategoryParam> getAllCategories() { | ||||||
return categoryRepository.findAll().stream().map(CategoryParam::new).toList(); | ||||||
} | ||||||
|
||||||
public CategoryParam getCategory(Long id) { | ||||||
return categoryRepository.findById(id).map(CategoryParam::new) | ||||||
.orElseThrow(CategoryNotFoundException::new); | ||||||
} | ||||||
|
||||||
public void updateCategory(CategoryForm categoryForm) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
|
||||||
Category category = categoryRepository.findById(categoryForm.getId()) | ||||||
.orElseThrow(CategoryNotFoundException::new); | ||||||
|
||||||
category.update(categoryForm); | ||||||
|
||||||
categoryRepository.save(category); | ||||||
} | ||||||
|
||||||
public void deleteCategory(Long id) { | ||||||
categoryRepository.deleteById(id); | ||||||
} | ||||||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 옵션만을 조회하는 경우는 없을까요? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package gift.doamin.product.controller; | ||
|
||
import gift.doamin.product.dto.OptionForm; | ||
import gift.doamin.product.service.OptionService; | ||
import jakarta.validation.Valid; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.web.bind.annotation.DeleteMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.PutMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.ResponseStatus; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequestMapping("/api/products/{productId}/options") | ||
public class OptionsController { | ||
|
||
private final OptionService optionService; | ||
|
||
public OptionsController(OptionService optionService) { | ||
this.optionService = optionService; | ||
} | ||
|
||
@PostMapping | ||
@ResponseStatus(HttpStatus.CREATED) | ||
public void addOption(@PathVariable Long productId, @Valid @RequestBody OptionForm optionForm) { | ||
optionService.create(productId, optionForm); | ||
} | ||
|
||
@PutMapping("/{optionId}") | ||
public void updateOption(@PathVariable Long productId, @PathVariable Long optionId, | ||
@Valid @RequestBody OptionForm optionForm) { | ||
optionService.update(productId, optionId, optionForm); | ||
} | ||
|
||
@DeleteMapping("/{optionId}") | ||
public void deleteOption(@PathVariable Long productId, @PathVariable Long optionId) { | ||
optionService.delete(productId, optionId); | ||
} | ||
Comment on lines
+26
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 부분도 admin 성격이라서 인증, 인가가 필요합니다. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package gift.doamin.product.dto; | ||
|
||
import gift.doamin.product.entity.Option; | ||
import jakarta.validation.constraints.Max; | ||
import jakarta.validation.constraints.Pattern; | ||
import jakarta.validation.constraints.Positive; | ||
|
||
public class OptionForm { | ||
|
||
@Pattern(regexp = "^[ㄱ-ㅎㅏ-ㅣ가-힣\\w ()\\[\\]+\\-&/_]{1,50}$", message = "이름 형식이 잘못되었습니다.") | ||
private String name; | ||
|
||
@Positive | ||
@Max(99_999_999) | ||
private Integer quantity; | ||
|
||
public OptionForm(String name, Integer quantity) { | ||
this.name = name; | ||
this.quantity = quantity; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public Integer getQuantity() { | ||
return quantity; | ||
} | ||
|
||
public Option toEntity() { | ||
return new Option(name, quantity); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package gift.doamin.product.dto; | ||
|
||
public class OptionParam { | ||
|
||
private Long id; | ||
private String name; | ||
private int quantity; | ||
|
||
public OptionParam(Long id, String name, int quantity) { | ||
this.id = id; | ||
this.name = name; | ||
this.quantity = quantity; | ||
} | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public int getQuantity() { | ||
return quantity; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
엔드포인트마다 인증, 인가 여부를 다르게 한 부분 좋았습니다.