-
Notifications
You must be signed in to change notification settings - Fork 122
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_정재빈_step3 #206
Open
JaeBin2019
wants to merge
56
commits into
kakao-tech-campus-2nd-step2:jaebin2019
Choose a base branch
from
JaeBin2019:step1
base: jaebin2019
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
부산대 BE_정재빈_step3 #206
Changes from all commits
Commits
Show all changes
56 commits
Select commit
Hold shift + click to select a range
98f3a17
feat(global): create global controller
JaeBin2019 e114c0e
docs(global): summerize list of features
JaeBin2019 5b37775
feat(product): create product controller
JaeBin2019 2b52d04
feat(product): create product entity
JaeBin2019 f54b33a
fix(product): add column id into product entity
JaeBin2019 f376876
feat(product): add method get product by id in controller
JaeBin2019 0ded7d3
feat(product): create product request record
JaeBin2019 dc565f4
feat(product): add constructor to initialize Product from ProductRequest
JaeBin2019 5507db1
fix(product): change RequestMapping url error
JaeBin2019 fa94538
feat(product): add create product method
JaeBin2019 3028213
fix(product): change endpoint product to products
JaeBin2019 eedb420
feat(product): add update product method
JaeBin2019 c3c5908
feat(product): add delete product method
JaeBin2019 317a4ba
feat(product): create http request file
JaeBin2019 5d21ad1
refactor(global): combine common parts of API URLs
JaeBin2019 c42e117
feat(product): add get all product method
JaeBin2019 225aaf7
chore(product): rename global controller to view controller
JaeBin2019 ebc23b2
fix(global): change get products list api url
JaeBin2019 bf7afcd
chore(view): delete unnecssary parameter
JaeBin2019 ecc4ff9
feat(view): create product management UI
JaeBin2019 199c894
feat(product): create ServiceDto
JaeBin2019 a38cc6f
feat(product): add toServiceDto method to convert ProductRequest
JaeBin2019 4c57bf1
feat(product): change all method to use productService
JaeBin2019 20d14b7
feat(product): create Product Not Found Exception
JaeBin2019 dd3d0e5
feat(product): create Service Dto
JaeBin2019 fc49319
feat(product): create Product Service and methods
JaeBin2019 a944475
feat(product): add isNew method in product entity
JaeBin2019 56f5f57
chore(global): add data jdbc dependency
JaeBin2019 29cf8c4
feat(product): create product repository and methods
JaeBin2019 714baf2
feat(global): setting global exception handler
JaeBin2019 902f597
feat(global): setting db properties
JaeBin2019 71fb6ed
feat(product): create input initial data sql
JaeBin2019 b00ee6f
feat(product): create schema sql to make table products
JaeBin2019 1d4f2bb
fix(product): add default constructor and change directory entity to …
JaeBin2019 199a7ff
feat(global): create result code enum
JaeBin2019 b388095
feat(product): set result code of product api
JaeBin2019 8a22e26
feat(global): create result response
JaeBin2019 9410cc5
fix(global): change result code status type String to int
JaeBin2019 c3736c5
fix(global): change result response private to public
JaeBin2019 7bac451
chore(global): change ResultResponse name to ResultResponseDto
JaeBin2019 0759818
fix(http): update url for get all products
JaeBin2019 7e61e41
feat(global): create simple result response dto
JaeBin2019 3ef0273
chore(global): move global exception handler package response to handler
JaeBin2019 1d83a57
feat(product): change all method response to use ResponseEntity
JaeBin2019 c300531
fix(product): remove return value from create and update methods
JaeBin2019 77076be
feat(global): create response helper util
JaeBin2019 fd89619
refactor(product): apply ResponseHelper for response creation in Prod…
JaeBin2019 8fdd8ea
fix(product): change method name from isNew to checkNew to fix JSON s…
JaeBin2019 ebee7f4
fix(view): update index.html to use response.data for request parameter
JaeBin2019 d512a90
refactor(global): change resultCode variable to code in ResultCode enum
JaeBin2019 bedd0c2
feat(global): create ErrorCode enum
JaeBin2019 9d897c4
feat(global): create ErrorResponseDto record
JaeBin2019 39cddd4
fix(global): add private constructor to ResponseHelper class
JaeBin2019 18efb9c
refactor(global): update error handling to return ErrorResponseDto in…
JaeBin2019 025b774
refactor(product): rename ProductRequest to ProductRequestDto
JaeBin2019 52a232e
feat(view): add search product by productId
JaeBin2019 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,46 @@ | ||
# spring-gift-product | ||
# spring-gift-product | ||
|
||
--- | ||
|
||
## Step1 | ||
|
||
**요구 사항**<br> | ||
아래와 같이 http 메세지를 받도록 구현한다 | ||
|
||
```http request | ||
GET /api/products HTTP/1.1 | ||
``` | ||
|
||
```http request | ||
HTTP/1.1 200 | ||
Content-Type: application/json | ||
|
||
[ | ||
{ | ||
"id": 8146027, | ||
"name": "아이스 카페 아메리카노 T", | ||
"price": 4500, | ||
"imageUrl": "https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg" | ||
} | ||
] | ||
``` | ||
|
||
|
||
**필요 조건**<br> | ||
상품 데이터 관리 | ||
현재는 별도의 데이터베이스가 없으므로 적절한 컬렉션을 이용하여 메모리에 저장한다. | ||
```java | ||
public class ProductController { | ||
private final Map<Long, Product> productMap = new HashMap<>(); | ||
} | ||
``` | ||
---- | ||
## 구현 기능 | ||
- product 조회 | ||
- product 추가 | ||
- product 수정 | ||
- product 삭제 | ||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
### get product list | ||
GET http://localhost:8080/api/products | ||
Content-Type: application/json | ||
|
||
### get product | ||
GET http://localhost:8080/api/products/1 | ||
Content-Type: application/json | ||
|
||
### create product | ||
POST http://localhost:8080/api/products | ||
Content-Type: application/json | ||
|
||
{ | ||
"name": "아메리카노", | ||
"price": "4500", | ||
"imageUrl": "http://hello" | ||
} | ||
|
||
### update product | ||
PUT http://localhost:8080/api/products/1 | ||
Content-Type: application/json | ||
|
||
{ | ||
"name": "아메리카노2", | ||
"price": "5000", | ||
"imageUrl": "http://hello" | ||
} | ||
|
||
### delete product | ||
DELETE http://localhost:8080/api/products/1 | ||
Content-Type: application/json |
21 changes: 21 additions & 0 deletions
21
src/main/java/gift/global/exception/BusinessException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package gift.global.exception; | ||
|
||
import gift.global.response.ErrorCode; | ||
|
||
public class BusinessException extends RuntimeException { | ||
private final ErrorCode errorCode; | ||
|
||
public BusinessException(ErrorCode errorCode) { | ||
super(errorCode.getMessage()); | ||
this.errorCode = errorCode; | ||
} | ||
|
||
public ErrorCode getErrorCode() { | ||
return errorCode; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return errorCode.toString() + " : " + super.toString(); | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/java/gift/global/handler/GlobalExceptionHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package gift.global.handler; | ||
|
||
import gift.global.exception.BusinessException; | ||
import gift.global.response.ErrorResponseDto; | ||
import gift.global.utils.ResponseHelper; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.ExceptionHandler; | ||
import org.springframework.web.bind.annotation.RestControllerAdvice; | ||
|
||
@RestControllerAdvice | ||
public class GlobalExceptionHandler { | ||
@ExceptionHandler(BusinessException.class) | ||
public ResponseEntity<ErrorResponseDto> handleBusinessException(BusinessException e) { | ||
return ResponseHelper.createErrorResponse(e.getErrorCode()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package gift.global.response; | ||
|
||
public enum ErrorCode { | ||
// Product | ||
PRODUCT_NOT_FOUND_ERROR(400, "EP001", "Product Not Found Error"), | ||
; | ||
private final int status; | ||
private final String code; | ||
private final String message; | ||
|
||
ErrorCode(int status, String code, String message) { | ||
this.status = status; | ||
this.code = code; | ||
this.message = message; | ||
} | ||
|
||
public int getStatus() { | ||
return status; | ||
} | ||
|
||
public String getCode() { | ||
return code; | ||
} | ||
|
||
public String getMessage() { | ||
return message; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package gift.global.response; | ||
|
||
public record ErrorResponseDto(String code, String message) { | ||
public ErrorResponseDto(ErrorCode errorCode) { | ||
this(errorCode.getCode(), errorCode.getMessage()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package gift.global.response; | ||
|
||
public enum ResultCode { | ||
// Product | ||
GET_ALL_PRODUCTS_SUCCESS(200, "P001", "모든 제품 조회 성공"), | ||
GET_PRODUCT_BY_ID_SUCCESS(200, "P002", "단일 제품 조회 성공"), | ||
CREATE_PRODUCT_SUCCESS(200, "P003", "제품 추가 성공"), | ||
UPDATE_PRODUCT_SUCCESS(200, "P002", "제품 수정 성공"), | ||
DELETE_PRODUCT_SUCCESS(200, "P002", "제품 삭제 성공"), | ||
|
||
; | ||
|
||
// status 를 HttpStatus 로 관리하는 것이 좋을까, 아니면 int로 관리하는 것이 좋을까? | ||
private final int status; | ||
private final String code; | ||
private final String message; | ||
|
||
ResultCode(int status, String code, String message) { | ||
this.status = status; | ||
this.code = code; | ||
this.message = message; | ||
} | ||
|
||
public int getStatus() { | ||
return status; | ||
} | ||
|
||
public String getCode() { | ||
return code; | ||
} | ||
|
||
public String getMessage() { | ||
return message; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package gift.global.response; | ||
|
||
public record ResultResponseDto<T>(String code, String message, T data) { | ||
// 자바 record 에서 생성자를 만들 경우, 반드시 canonical(표준) 생성자를 사용해야 한다!! | ||
public ResultResponseDto(ResultCode resultCode, T data) { | ||
this(resultCode.getCode(), resultCode.getMessage(), data); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/gift/global/response/SimpleResultResponseDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package gift.global.response; | ||
|
||
public record SimpleResultResponseDto(String code, String message) { | ||
public SimpleResultResponseDto(ResultCode resultCode) { | ||
this(resultCode.getCode(), resultCode.getMessage()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package gift.global.utils; | ||
|
||
import gift.global.response.*; | ||
import org.springframework.http.ResponseEntity; | ||
|
||
public class ResponseHelper { | ||
private ResponseHelper() {} | ||
|
||
public static <T> ResponseEntity<ResultResponseDto<T>> createResponse(ResultCode resultCode, T data) { | ||
ResultResponseDto<T> resultResponseDto = new ResultResponseDto<>(resultCode, data); | ||
return org.springframework.http.ResponseEntity.status(resultCode.getStatus()) | ||
.body(resultResponseDto); | ||
} | ||
|
||
public static ResponseEntity<SimpleResultResponseDto> createSimpleResponse(ResultCode resultCode) { | ||
var resultResponseDto = new SimpleResultResponseDto(resultCode); | ||
return ResponseEntity.status(resultCode.getStatus()) | ||
.body(resultResponseDto); | ||
} | ||
|
||
public static ResponseEntity<ErrorResponseDto> createErrorResponse(ErrorCode errorCode) { | ||
ErrorResponseDto errorResponseDto = new ErrorResponseDto(errorCode); | ||
return ResponseEntity.status(errorCode.getStatus()) | ||
.body(errorResponseDto); | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
src/main/java/gift/product/controller/ProductController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package gift.product.controller; | ||
|
||
import gift.global.response.ResultCode; | ||
import gift.global.response.ResultResponseDto; | ||
import gift.global.response.SimpleResultResponseDto; | ||
import gift.global.utils.ResponseHelper; | ||
import gift.product.dto.ProductRequestDto; | ||
import gift.product.domain.Product; | ||
import gift.product.service.ProductService; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import java.util.List; | ||
|
||
@RestController | ||
@RequestMapping("/api/products") | ||
public class ProductController { | ||
private final ProductService productService; | ||
|
||
public ProductController(ProductService productService) { | ||
this.productService = productService; | ||
} | ||
|
||
@GetMapping("") | ||
public ResponseEntity<ResultResponseDto<List<Product>>> getAllProducts() { | ||
List<Product> products = productService.getAllProducts(); | ||
return ResponseHelper.createResponse(ResultCode.GET_ALL_PRODUCTS_SUCCESS, products); | ||
} | ||
|
||
@GetMapping("/{id}") | ||
public ResponseEntity<ResultResponseDto<Product>> getProductById(@PathVariable(name = "id") Long id) { | ||
Product product = productService.getProductById(id); | ||
return ResponseHelper.createResponse(ResultCode.GET_PRODUCT_BY_ID_SUCCESS, product); | ||
} | ||
|
||
@PostMapping("") | ||
public ResponseEntity<SimpleResultResponseDto> createProduct(@RequestBody ProductRequestDto productRequestDto) { | ||
productService.createProduct(productRequestDto.toServiceDto()); | ||
return ResponseHelper.createSimpleResponse(ResultCode.CREATE_PRODUCT_SUCCESS); | ||
} | ||
|
||
@PutMapping("/{id}") | ||
public ResponseEntity<SimpleResultResponseDto> updateProduct(@PathVariable(name = "id") Long id, @RequestBody ProductRequestDto productRequestDto) { | ||
productService.updateProduct(productRequestDto.toServiceDto(id)); | ||
return ResponseHelper.createSimpleResponse(ResultCode.UPDATE_PRODUCT_SUCCESS); | ||
} | ||
|
||
@DeleteMapping("/{id}") | ||
public ResponseEntity<SimpleResultResponseDto> deleteProduct(@PathVariable(name = "id") Long id) { | ||
productService.deleteProduct(id); | ||
return ResponseHelper.createSimpleResponse(ResultCode.DELETE_PRODUCT_SUCCESS); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package gift.product.domain; | ||
|
||
import gift.product.dto.ProductRequestDto; | ||
import org.springframework.data.annotation.Id; | ||
import org.springframework.data.relational.core.mapping.Table; | ||
|
||
@Table("products") | ||
public class Product { | ||
@Id | ||
private Long id; | ||
private String name; | ||
private int price; | ||
private String imageUrl; | ||
|
||
// JDBC 에서 엔티티 클래스를 인스턴스화할 때 반드시 기본 생성자와 파라미터 생성자가 필요하다 | ||
public Product() {} | ||
|
||
public Product(Long id, String name, int price, String imageUrl) { | ||
this.id = id; | ||
this.name = name; | ||
this.price = price; | ||
this.imageUrl = imageUrl; | ||
} | ||
|
||
public Product(Long id, ProductRequestDto productRequestDto) { | ||
this.id = id; | ||
this.name = productRequestDto.name(); | ||
this.price = productRequestDto.price(); | ||
this.imageUrl = productRequestDto.imageUrl(); | ||
} | ||
|
||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public int getPrice() { | ||
return price; | ||
} | ||
|
||
public String getImageUrl() { | ||
return imageUrl; | ||
} | ||
|
||
public boolean checkNew() { | ||
return id == null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package gift.product.dto; | ||
|
||
import java.util.Objects; | ||
|
||
public record ProductRequestDto(String name, int price, String imageUrl) { | ||
public ProductRequestDto { | ||
Objects.requireNonNull(name); | ||
Objects.requireNonNull(imageUrl); | ||
} | ||
|
||
public ServiceDto toServiceDto() { | ||
return new ServiceDto(null, this.name, this.price, this.imageUrl); | ||
} | ||
|
||
public ServiceDto toServiceDto(Long id) { | ||
return new ServiceDto(id, this.name, this.price, this.imageUrl); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package gift.product.dto; | ||
|
||
import gift.product.domain.Product; | ||
|
||
public record ServiceDto(Long id, String name, int price, String imageUrl) { | ||
public Product toProduct() { | ||
return new Product(id, name, price, imageUrl); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/java/gift/product/exception/ProductNotFoundException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package gift.product.exception; | ||
|
||
import gift.global.exception.BusinessException; | ||
import gift.global.response.ErrorCode; | ||
|
||
public class ProductNotFoundException extends BusinessException { | ||
public ProductNotFoundException() { | ||
super(ErrorCode.PRODUCT_NOT_FOUND_ERROR); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Advice랑 Handler 까지 구현하셨군요... 빠르시네요
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.
혹시 ResultCode 에서 현재는 status 값을 int 로 관리하고 있는데,
이 값을 HttpStatus 로 관리하는 편이 더 좋을까요?
현재 status 값이 사용되는 곳은 ResponseEntity.status(resultCode.getStatus()) 이고
과정을 거쳐서 ResponseEntity 가 생성되고 있습니다
=> 따라서, HttpStatus 로 수정하는 것이 좋다. 고 생각합니다
혹시, 이에 대해서는 어떻게 생각하시나요?
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.
이 서비스 기준으로 정답은 사실 다양합니다. 왜냐하면 서비스가 크지 않은 상태에서 포맷팅은 쓸데 없이 코드가 복잡해지는 건 사실이거든요.
다만 현업 기준으로 가면 HttpStatus가 맞습니다. 메소드가 천 개가 넘어가는 서비스 안에서 HTTP Code를 int로 관리하면 문제가 많을 겁니다. 예를 들어 외부 통신 에러 ExternalException을 400으로 설정했다고 합니다. 만약 이 때 팀 차원에서 이것을 500으로 격상시킨다면 어떻게 될까요? 아 물론 예시가 적절치 않았을 수도 있지만, 기본적인 원칙은 그 메소드만 보고도 판단을 할 수 있게 한다. 를 기준으로 삼으면 좋을 거 같습니다.
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.
넵 감사합니다