Skip to content

Commit

Permalink
add: Member의 필드에 point 추가
Browse files Browse the repository at this point in the history
Member 필드에 point 추가
  • Loading branch information
yunjunghun0116 committed Aug 2, 2024
1 parent 98d546d commit 013cdea
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 8 deletions.
38 changes: 38 additions & 0 deletions src/main/java/gift/controller/PointController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package gift.controller;

import gift.dto.point.PointRequest;
import gift.dto.point.PointResponse;
import gift.service.PointService;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.net.URI;

@RestController
@RequestMapping("/api/points")
public class PointController {

private final PointService pointService;

public PointController(PointService pointService) {
this.pointService = pointService;
}

@PostMapping
public ResponseEntity<PointResponse> addPoint(@RequestAttribute("memberId") Long memberId, @Valid @RequestBody PointRequest pointRequest) {
var point = pointService.addPoint(memberId, pointRequest.point());
return ResponseEntity.created(URI.create("/api/points")).body(point);
}

@GetMapping
public ResponseEntity<PointResponse> getPoint(@RequestAttribute("memberId") Long memberId) {
var point = pointService.getPoint(memberId);
return ResponseEntity.ok(point);
}
}
1 change: 1 addition & 0 deletions src/main/java/gift/controller/api/GiftOrderApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public interface GiftOrderApi {
@Operation(summary = "회원의 새 주문을 생성한다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "주문 생성 성공", content = @Content(schema = @Schema(implementation = GiftOrderResponse.class))),
@ApiResponse(responseCode = "400", description = "주문 생성 실패(사유 : 사용할 수 있는 포인트보다 더 많은 포인트가 입력되었거나 주문 정보가 잘못되었습니다.)", content = @Content(schema = @Schema(hidden = true))),
@ApiResponse(responseCode = "401", description = "주문 생성 실패(사유 : 카카오 토큰이 만료되었거나, 허용되지 않은 요청입니다.)", content = @Content(schema = @Schema(hidden = true))),
@ApiResponse(responseCode = "500", description = "내부 서버의 오류", content = @Content(schema = @Schema(hidden = true)))
})
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/gift/dto/giftorder/GiftOrderRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;

public record GiftOrderRequest(
@NotNull(message = "상품 옵션은 반드시 선택되어야 합니다.")
Expand All @@ -12,6 +13,8 @@ public record GiftOrderRequest(
@Max(value = 100_000_000, message = "수량은 최소 1개 이상, 1억개 미만입니다.")
Integer quantity,
@NotBlank(message = "메시지의 길이는 최소 1자 이상이어야 합니다.")
String message
String message,
@PositiveOrZero(message = "포인트는 0보다 크거나 같아야 합니다.")
Integer point
) {
}
9 changes: 9 additions & 0 deletions src/main/java/gift/dto/point/PointRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package gift.dto.point;

import jakarta.validation.constraints.Positive;

public record PointRequest(
@Positive(message = "포인트는 최소 1원 이상이어야 추가할 수 있습니다.")
Integer point
) {
}
9 changes: 9 additions & 0 deletions src/main/java/gift/dto/point/PointResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package gift.dto.point;

public record PointResponse(
Integer point
) {
public static PointResponse of(Integer point) {
return new PointResponse(point);
}
}
7 changes: 7 additions & 0 deletions src/main/java/gift/exception/GiftOrderException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package gift.exception;

public class GiftOrderException extends RuntimeException {
public GiftOrderException(String message) {
super(message);
}
}
5 changes: 5 additions & 0 deletions src/main/java/gift/exception/GlobalExceptionHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ public ResponseEntity<ExceptionResponse> invalidLoginInfoExceptionHandling() {
return getExceptionResponse(INVALID_LOGIN_INFO_MESSAGE, HttpStatus.UNAUTHORIZED);
}

@ExceptionHandler(value = GiftOrderException.class)
public ResponseEntity<ExceptionResponse> giftOrderExceptionHandling(GiftOrderException exception) {
return getExceptionResponse(exception.getMessage(), HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(value = UnauthorizedAccessException.class)
public ResponseEntity<ExceptionResponse> unauthorizedAccessExceptionHandling(UnauthorizedAccessException exception) {
return getExceptionResponse(exception.getMessage(), HttpStatus.UNAUTHORIZED);
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/gift/model/Member.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package gift.model;

import gift.exception.GiftOrderException;
import gift.exception.InvalidLoginInfoException;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
Expand All @@ -20,6 +21,9 @@ public class Member extends BaseEntity {
@Column(name = "password")
private String password;
@NotNull
@Column(name = "point")
private Integer point = 0;
@NotNull
@Column(name = "deleted")
private Boolean deleted = Boolean.FALSE;

Expand All @@ -40,9 +44,24 @@ public String getPassword() {
return password;
}

public Integer getPoint() {
return point;
}

public void passwordCheck(String inputPassword) {
if (!password.equals(inputPassword)) {
throw new InvalidLoginInfoException("로그인 정보가 유효하지 않습니다.");
}
}

public void addPoint(Integer newPoint) {
this.point = point + newPoint;
}

public void subtractPoint(Integer usedPoint) {
if (point < usedPoint) {
throw new GiftOrderException("사용가능한 포인트보다 더 많은 포인트를 사용할 수 없습니다.");
}
this.point = point - usedPoint;
}
}
5 changes: 4 additions & 1 deletion src/main/java/gift/service/GiftOrderService.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ public class GiftOrderService {
private final GiftOrderRepository giftOrderRepository;
private final MemberRepository memberRepository;
private final WishProductService wishProductService;
private final PointService pointService;

public GiftOrderService(GiftOrderRepository giftOrderRepository, MemberRepository memberRepository, WishProductService wishProductService) {
public GiftOrderService(GiftOrderRepository giftOrderRepository, MemberRepository memberRepository, WishProductService wishProductService, PointService pointService) {
this.giftOrderRepository = giftOrderRepository;
this.memberRepository = memberRepository;
this.wishProductService = wishProductService;
this.pointService = pointService;
}

public GiftOrderResponse addGiftOrder(Long memberId, Option option, GiftOrderRequest giftOrderRequest) {
pointService.subtractPoint(memberId, giftOrderRequest.point());
var order = saveGiftOrderWithGiftOrderRequest(memberId, option, giftOrderRequest);
wishProductService.deleteAllByMemberIdAndProductId(memberId, option.getProduct().getId());
return getGiftOrderResponseFromGiftOrder(order);
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/gift/service/PointService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package gift.service;

import gift.dto.point.PointResponse;
import gift.exception.NotFoundElementException;
import gift.repository.MemberRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class PointService {

private final MemberRepository memberRepository;

public PointService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}

public PointResponse addPoint(Long memberId, Integer point) {
var member = memberRepository.findById(memberId)
.orElseThrow(() -> new NotFoundElementException(memberId + "를 가진 이용자가 존재하지 않습니다."));
member.addPoint(point);
memberRepository.save(member);
return PointResponse.of(member.getPoint());
}

public void subtractPoint(Long memberId, Integer point) {
var member = memberRepository.findById(memberId)
.orElseThrow(() -> new NotFoundElementException(memberId + "를 가진 이용자가 존재하지 않습니다."));
member.subtractPoint(point);
memberRepository.save(member);
}

public PointResponse getPoint(Long memberId) {
var member = memberRepository.findById(memberId)
.orElseThrow(() -> new NotFoundElementException(memberId + "를 가진 이용자가 존재하지 않습니다."));
return PointResponse.of(member.getPoint());
}
}
8 changes: 4 additions & 4 deletions src/main/resources/data.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
insert into member(email, password, deleted)
values ('[email protected]', 'password', 0);
insert into member(email, password, deleted)
values ('[email protected]', 'password', 0);
insert into member(email, password, point, deleted)
values ('[email protected]', 'password', 0, 0);
insert into member(email, password, point, deleted)
values ('[email protected]', 'password', 0, 0);

insert into category(name, description, color, image_url, deleted)
values ('디지털/가전', '가전설명', '#888888', '가전이미지', 0);
Expand Down
4 changes: 2 additions & 2 deletions src/test/java/gift/service/OptionServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ void failAddOptionWithZeroQuantity() {
//given
var optionRequest = new OptionRequest("옵션1", 0);
var savedOption = optionService.addOption(1L, optionRequest);
var orderRequest = new GiftOrderRequest(savedOption.id(), 1, "hello");
var orderRequest = new GiftOrderRequest(savedOption.id(), 1, "hello", 0);
//when, then
Assertions.assertThatThrownBy(() -> optionService.orderOption(savedOption.id(), orderRequest)).isInstanceOf(BadRequestException.class);

Expand All @@ -101,7 +101,7 @@ void failAddOptionWithZeroQuantity() {
@DisplayName("동시성 테스트 - 5개의 쓰레드풀에 500개의 요청을 보냈을 때에도 정상적으로 요청이 처리 된다.")
public void concurrencyTest() throws InterruptedException {
//given
var orderRequest = new GiftOrderRequest(1L, 1, "hello");
var orderRequest = new GiftOrderRequest(1L, 1, "hello", 0);
int requestCount = 500;
var executorService = Executors.newFixedThreadPool(5);
var countDownLatch = new CountDownLatch(requestCount);
Expand Down

0 comments on commit 013cdea

Please sign in to comment.