-
Notifications
You must be signed in to change notification settings - Fork 0
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
제버릇 개 못주고 깔끔하게 구현하지 못한 누누 #9
base: main
Are you sure you want to change the base?
Changes from all commits
1c77a83
19ffe1f
eb76bb9
059164c
af03bf1
c3ad550
75260e2
80e76c0
b61407e
bb5f60b
ae807db
d5b2a08
9195b0e
01e4f25
65094cc
0b93eb1
27cd0a6
4d2dcf3
9e86819
592683f
4cd768e
89bb79e
642a295
b8c97f6
2ec77b5
a01df7f
1f51d38
b967418
b7c9847
1fc25d3
ff5539b
8b954f4
0bcd865
e884086
20d9b71
d840be5
ee68eab
db7492a
34a655b
82d4950
55c7c84
e5dba3b
b5fe4d8
bb1531d
999125a
a870ceb
a71e264
f3451b1
74680f9
fe710f3
18f27f6
0738913
8a4689e
cffa017
faa2692
67e6752
cb45b9f
a0d7783
2e3ddd8
ba3cd1c
905942e
fbb10cc
e343cd8
6114e20
918c63b
cb80b50
9e597e8
48a227f
bbdb7a2
db89307
c684a44
d275899
7790805
b5bfe5f
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,50 @@ | ||
# jwp-shopping-cart | ||
|
||
## 기능 목록 Step2 | ||
|
||
- [x] settings 페이지 연동 | ||
- [x] settings.html 변경 | ||
- [x] 장바구니 페이지 연동 | ||
- [x] cart.html 변경 | ||
|
||
- [x] DB 설계 | ||
|
||
- [x] 필터 작성 | ||
|
||
- [x] User 도메인 추가 | ||
- [x] User 도메인에 Cart 도메인 추가 | ||
- [x] Cart 도메인 추가 | ||
|
||
## 기능목록 | ||
|
||
- [x] 상품 목록 페이지 연동 | ||
- [x] index.html 변경 | ||
- [x] 상품 관리 CRUD API 작성 | ||
- [x] create product | ||
- [x] read product | ||
- [x] update product | ||
- [x] delete product | ||
- [x] 관리자 도구 페이지 연동 | ||
- [x] admin.html 변경 | ||
- [x] admin.js 변경 | ||
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. API 설계한거 URL도 같이 적어주면 (내가) 매우 좋을 듯 |
||
|
||
- [x] DB 설계 | ||
|
||
# 도메인 구조 | ||
|
||
```mermaid | ||
graph TD | ||
|
||
cart --> user | ||
cart --many--> product | ||
``` | ||
|
||
# DB 설계 | ||
|
||
```mermaid | ||
graph TD | ||
|
||
cart --> user | ||
cart --many--> cart_product | ||
product --many--> cart_product | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,8 +6,7 @@ | |
@SpringBootApplication | ||
public class JwpCartApplication { | ||
|
||
public static void main(String[] args) { | ||
public static void main(final String[] args) { | ||
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. 이걸 일케까지?? 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. 어 자동 설정 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. final 붙인거갖고 그러는거야ㅕ? |
||
SpringApplication.run(JwpCartApplication.class, args); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package cart.config; | ||
|
||
import cart.filter.AuthenticationFilter; | ||
import cart.repository.user.UserRepository; | ||
import cart.resolver.AuthenticationResolver; | ||
import java.util.List; | ||
import org.springframework.boot.web.servlet.FilterRegistrationBean; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.web.method.support.HandlerMethodArgumentResolver; | ||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||
|
||
@Configuration | ||
public class SecurityConfig implements WebMvcConfigurer { | ||
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. 옼 이름 좀 간지 GDD |
||
|
||
private final UserRepository userRepository; | ||
|
||
public SecurityConfig(final UserRepository userRepository) { | ||
this.userRepository = userRepository; | ||
} | ||
|
||
@Bean | ||
public FilterRegistrationBean<AuthenticationFilter> filterRegistrationBean() { | ||
final FilterRegistrationBean<AuthenticationFilter> registrationBean = new FilterRegistrationBean<>(); | ||
registrationBean.setFilter(new AuthenticationFilter(userRepository)); | ||
registrationBean.addUrlPatterns("/carts/*, /products/*"); | ||
return registrationBean; | ||
} | ||
|
||
@Override | ||
public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> argumentResolvers) { | ||
argumentResolvers.add(new AuthenticationResolver()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package cart.controller; | ||
|
||
import cart.dto.ErrorResponse; | ||
import cart.exception.AlreadyAddedProductException; | ||
import cart.exception.CartNotFoundException; | ||
import cart.exception.ProductInCartDeleteException; | ||
import cart.exception.ProductNotFoundException; | ||
import cart.exception.UserNotFoundException; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.validation.FieldError; | ||
import org.springframework.web.bind.MethodArgumentNotValidException; | ||
import org.springframework.web.bind.annotation.ExceptionHandler; | ||
import org.springframework.web.bind.annotation.RestControllerAdvice; | ||
import org.springframework.web.context.request.WebRequest; | ||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; | ||
|
||
@RestControllerAdvice | ||
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { | ||
|
||
private final Logger log = LoggerFactory.getLogger(getClass()); | ||
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. 이렇게 로그 찍으면 어디서 어떻게 확인할 수 있어?? |
||
|
||
@ExceptionHandler | ||
private ResponseEntity<ErrorResponse> handleException(final Exception exception) { | ||
log.error("예상치 못한 예외가 발생했습니다.", exception); | ||
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. 로그는 개발자가 보는거라 그대로 exception을 내보내도 되는거야?? |
||
return ResponseEntity.internalServerError().body(new ErrorResponse("예상치 못한 예외가 발생했습니다.")); | ||
} | ||
|
||
@ExceptionHandler | ||
private ResponseEntity<ErrorResponse> handleIllegalArgumentException(final IllegalArgumentException exception) { | ||
log.warn("잘못된 인자가 들어왔습니다", exception); | ||
return ResponseEntity.badRequest().body(new ErrorResponse(exception.getMessage())); | ||
} | ||
|
||
@ExceptionHandler({CartNotFoundException.class, ProductNotFoundException.class, UserNotFoundException.class}) | ||
private ResponseEntity<ErrorResponse> handleNotFoundException(final Exception exception) { | ||
log.warn("존재하지 않는 리소스에 접근했습니다.", exception); | ||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse(exception.getMessage())); | ||
} | ||
|
||
@ExceptionHandler | ||
private ResponseEntity<ErrorResponse> handleAlreadyAddedProduct(final AlreadyAddedProductException e) { | ||
log.warn("이미 장바구니에 담긴 상품입니다.", e); | ||
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage())); | ||
} | ||
|
||
@ExceptionHandler | ||
private ResponseEntity<ErrorResponse> handleProductInCartDelete(final ProductInCartDeleteException e) { | ||
log.warn("장바구니에 담긴 상품을 삭제할 수 없습니다.", e); | ||
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage())); | ||
} | ||
|
||
@Override | ||
protected ResponseEntity<Object> handleMethodArgumentNotValid( | ||
final MethodArgumentNotValidException exception, final HttpHeaders headers, final HttpStatus status, | ||
final WebRequest request) { | ||
log.warn("유효성 검사에 실패했습니다.", exception); | ||
final Map<String, String> body = exception.getFieldErrors() | ||
.stream() | ||
.collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage)); | ||
return handleExceptionInternal(exception, body, headers, status, request); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package cart.controller.cart; | ||
|
||
import cart.domain.cart.Cart; | ||
import cart.domain.product.Product; | ||
import cart.dto.cart.AddCartResponse; | ||
import cart.dto.cart.AddProductRequest; | ||
import cart.dto.cart.FindCartResponse; | ||
import cart.resolver.AuthInfo; | ||
import cart.resolver.Authentication; | ||
import cart.service.cart.CartCommandService; | ||
import cart.service.cart.CartQueryService; | ||
import cart.service.product.ProductQueryService; | ||
import java.util.List; | ||
import org.springframework.http.ResponseEntity; | ||
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.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequestMapping("/carts/cartproduct") | ||
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. cart-product 어떰? ㅋㅋㅋㅎㅎ |
||
public class CartApiController { | ||
|
||
private final CartCommandService cartCommandService; | ||
private final ProductQueryService productQueryService; | ||
private final CartQueryService cartQueryService; | ||
|
||
public CartApiController(final CartCommandService cartCommandService, | ||
final ProductQueryService productQueryService, | ||
final CartQueryService cartQueryService) { | ||
this.cartCommandService = cartCommandService; | ||
this.productQueryService = productQueryService; | ||
this.cartQueryService = cartQueryService; | ||
} | ||
|
||
@PostMapping | ||
public ResponseEntity<AddCartResponse> addProduct(@RequestBody final AddProductRequest addProductRequest, | ||
@Authentication final AuthInfo authInfo) { | ||
final Long productId = addProductRequest.getProductId(); | ||
final String email = authInfo.getEmail(); | ||
final Cart cart = cartCommandService.addProduct(productId, email); | ||
return ResponseEntity.ok(AddCartResponse.from(cart)); | ||
} | ||
|
||
@GetMapping | ||
public ResponseEntity<FindCartResponse> findCart(@Authentication final AuthInfo authInfo) { | ||
final Cart cart = cartQueryService.findByEmail(authInfo.getEmail()); | ||
final List<Product> products = productQueryService.findAllByIds(cart.getCartProducts().getProductIds()); | ||
return ResponseEntity.ok(FindCartResponse.of(cart, products)); | ||
} | ||
|
||
@DeleteMapping("/{cartProductId}") | ||
public ResponseEntity<Void> deleteProduct(@Authentication final AuthInfo authInfo, | ||
@PathVariable final Long cartProductId) { | ||
final String email = authInfo.getEmail(); | ||
cartCommandService.deleteProduct(cartProductId, email); | ||
return ResponseEntity.noContent().build(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package cart.controller.cart; | ||
|
||
import org.springframework.stereotype.Controller; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
|
||
@Controller | ||
public class CartViewController { | ||
|
||
@GetMapping("/cart") | ||
public String getCartPage() { | ||
return "cart"; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package cart.controller.product; | ||
|
||
import cart.domain.product.Product; | ||
import cart.dto.product.ProductRequest; | ||
import cart.dto.product.ProductResponse; | ||
import cart.service.product.ProductCommandService; | ||
import cart.service.product.ProductQueryService; | ||
import java.net.URI; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import javax.validation.Valid; | ||
import org.springframework.http.ResponseEntity; | ||
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.RestController; | ||
|
||
@RestController | ||
public class ProductApiController { | ||
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.
|
||
|
||
private final ProductCommandService productCommandService; | ||
private final ProductQueryService productQueryService; | ||
|
||
public ProductApiController(final ProductCommandService productCommandService, | ||
final ProductQueryService productQueryService) { | ||
this.productCommandService = productCommandService; | ||
this.productQueryService = productQueryService; | ||
} | ||
|
||
@PostMapping("/products") | ||
public ResponseEntity<ProductResponse> createProduct(@RequestBody @Valid final ProductRequest productRequest) { | ||
final Product product = productCommandService.create( | ||
productRequest.getName(), | ||
productRequest.getImage(), | ||
productRequest.getPrice()); | ||
|
||
final ProductResponse productResponse = ProductResponse.from(product); | ||
return ResponseEntity.created(URI.create("/products/" + product.getProductId())) | ||
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. 리소스 위치까지 반환 굳 |
||
.body(productResponse); | ||
} | ||
|
||
@GetMapping("/products") | ||
public ResponseEntity<List<ProductResponse>> getAllProducts() { | ||
final List<ProductResponse> productResponses = productQueryService.findAll() | ||
.stream() | ||
.map(ProductResponse::from) | ||
.collect(Collectors.toList()); | ||
|
||
return ResponseEntity.ok(productResponses); | ||
} | ||
|
||
@PutMapping("/products/{id}") | ||
public ResponseEntity<ProductResponse> updateProduct(@PathVariable final long id, | ||
@RequestBody @Valid final ProductRequest productRequest) { | ||
final Product product = productCommandService.update( | ||
id, | ||
productRequest.getName(), | ||
productRequest.getImage(), | ||
productRequest.getPrice()); | ||
|
||
final ProductResponse productResponse = ProductResponse.from(product); | ||
return ResponseEntity.ok(productResponse); | ||
} | ||
|
||
@DeleteMapping("/products/{id}") | ||
public ResponseEntity<Void> deleteProduct(@PathVariable final long id) { | ||
productCommandService.delete(id); | ||
return ResponseEntity.noContent().build(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package cart.controller.product; | ||
|
||
import cart.dto.product.ProductResponse; | ||
import cart.service.product.ProductQueryService; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import org.springframework.stereotype.Controller; | ||
import org.springframework.ui.Model; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
|
||
@Controller | ||
public class ProductViewController { | ||
|
||
private final ProductQueryService productSearchService; | ||
|
||
public ProductViewController(final ProductQueryService productSearchService) { | ||
this.productSearchService = productSearchService; | ||
} | ||
|
||
@GetMapping("/") | ||
public String getIndexPage(final Model model) { | ||
final List<ProductResponse> productResponses = productSearchService.findAll() | ||
.stream() | ||
.map(ProductResponse::from) | ||
.collect(Collectors.toList()); | ||
|
||
model.addAttribute("products", productResponses); | ||
return "index"; | ||
} | ||
|
||
@GetMapping("/admin") | ||
public String getAdminPage(final Model model) { | ||
final List<ProductResponse> productResponses = productSearchService.findAll() | ||
.stream() | ||
.map(ProductResponse::from) | ||
.collect(Collectors.toList()); | ||
|
||
model.addAttribute("products", productResponses); | ||
return "admin"; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package cart.controller.setting; | ||
|
||
import cart.dto.user.UserResponse; | ||
import cart.service.user.UserQueryService; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import org.springframework.stereotype.Controller; | ||
import org.springframework.ui.Model; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
|
||
@Controller | ||
public class SettingViewController { | ||
|
||
private final UserQueryService userQueryService; | ||
|
||
public SettingViewController(final UserQueryService userQueryService) { | ||
this.userQueryService = userQueryService; | ||
} | ||
|
||
@GetMapping("/settings") | ||
public String getSettingsPage(final Model model) { | ||
final List<UserResponse> userResponses = userQueryService.findAll() | ||
.stream() | ||
.map(UserResponse::from) | ||
.collect(Collectors.toList()); | ||
|
||
model.addAttribute("members", userResponses); | ||
return "settings"; | ||
} | ||
} |
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.
File changed 104 good