Skip to content

Commit 94c3a3b

Browse files
authored
[Refactor]: 알림 코드 리팩토링
1. 메소드 기능별 구분 2. RsData 정적 메소드 활용 3. 코드 간결화 및 불필요한 로직 제거 4. ServiceException 정적 메소드 활용 -> 입찰/알림 모두 적용
2 parents 910a8f4 + b7dabdb commit 94c3a3b

File tree

4 files changed

+92
-73
lines changed

4 files changed

+92
-73
lines changed

src/main/java/com/backend/domain/bid/service/BidPaymentService.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,28 +46,28 @@ public RsData<BidPayResponseDto> payForBid(Long memberId, Long bidId) {
4646
// ======================================= find/get methods ======================================= //
4747
private Bid getBidById(Long bidId) {
4848
return bidRepository.findById(bidId)
49-
.orElseThrow(() -> new ServiceException("404", "입찰을 찾을 수 없습니다."));
49+
.orElseThrow(() -> ServiceException.notFound("입찰을 찾을 수 없습니다."));
5050
}
5151

5252
// ======================================= validation methods ======================================= //
5353
private void validatePayment(Long memberId, Bid bid, Product product) {
5454
// 내가 한 입찰인지 확인
5555
Member bidder = bid.getMember();
5656
if (bidder == null || !bidder.getId().equals(memberId)) {
57-
throw new ServiceException("403", "내 입찰만 결제할 수 있습니다.");
57+
throw ServiceException.forbidden("내 입찰만 결제할 수 있습니다.");
5858
}
5959

6060
// 상품이 '낙찰' 상태인지 확인
6161
String successfulStatus = AuctionStatus.SUCCESSFUL.getDisplayName();
6262
if (product == null || product.getStatus() == null || !successfulStatus.equals(product.getStatus())) {
63-
throw new ServiceException("400", "아직 낙찰이 확정되지 않았습니다.");
63+
throw ServiceException.badRequest("아직 낙찰이 확정되지 않았습니다.");
6464
}
6565
}
6666

6767
private void validateHighestBid(Bid bid, Product product) {
6868
Long highest = bidRepository.findHighestBidPrice(product.getId()).orElse(0L);
6969
if (!bid.getBidPrice().equals(highest)) {
70-
throw new ServiceException("400", "현재 낙찰가와 일치하지 않습니다. 다시 확인해주세요.");
70+
throw ServiceException.badRequest("현재 낙찰가와 일치하지 않습니다. 다시 확인해주세요.");
7171
}
7272
}
7373

src/main/java/com/backend/domain/bid/service/BidService.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ public RsData<BidResponseDto> createBid(Long productId, Long bidderId, BidReques
5656
private RsData<BidResponseDto> createBidInternal(Long productId, Long bidderId, BidRequestDto request) {
5757
// Product/Member 조회
5858
Product product = productRepository.findById(productId)
59-
.orElseThrow(() -> new ServiceException("404", "존재하지 않는 상품입니다."));
59+
.orElseThrow(() -> ServiceException.notFound("존재하지 않는 상품입니다."));
6060
Member member = memberRepository.findById(bidderId)
61-
.orElseThrow(() -> new ServiceException("404", "존재하지 않는 사용자입니다."));
61+
.orElseThrow(() -> ServiceException.notFound("존재하지 않는 사용자입니다."));
6262

6363
// 유효성 검증
6464
validateBid(product, member, request.price());
@@ -157,7 +157,7 @@ public RsData<MyBidResponseDto> getMyBids(Long memberId, int page, int size) {
157157

158158
private Product getProductById(Long productId) {
159159
return productRepository.findById(productId)
160-
.orElseThrow(() -> new ServiceException("404", "존재하지 않는 상품입니다."));
160+
.orElseThrow(() -> ServiceException.notFound("존재하지 않는 상품입니다."));
161161
}
162162

163163
private List<BidCurrentResponseDto.RecentBid> createAnonymizedRecentBids(List<Bid> recentBids) {
@@ -240,47 +240,47 @@ private void validateBid(Product product, Member member, Long bidPrice) {
240240

241241
private void validateAuctionStatus(Product product) {
242242
if (!AuctionStatus.BIDDING.getDisplayName().equals(product.getStatus())) {
243-
throw new ServiceException("400", "현재 입찰할 수 없는 상품입니다.");
243+
throw ServiceException.badRequest("현재 입찰할 수 없는 상품입니다.");
244244
}
245245
}
246246

247247
private void validateAuctionTime(Product product) {
248248
LocalDateTime now = LocalDateTime.now();
249249
if (product.getStartTime() != null && now.isBefore(product.getStartTime())) {
250-
throw new ServiceException("400", "경매가 아직 시작되지 않았습니다.");
250+
throw ServiceException.badRequest("경매가 아직 시작되지 않았습니다.");
251251
}
252252
if (product.getEndTime() != null && now.isAfter(product.getEndTime())) {
253-
throw new ServiceException("400", "경매가 이미 종료되었습니다.");
253+
throw ServiceException.badRequest("경매가 이미 종료되었습니다.");
254254
}
255255
}
256256

257257
private void validateNotSelfBid(Product product, Member member) {
258258
Member seller = product.getSeller();
259259
if (seller != null && seller.getId().equals(member.getId())) {
260-
throw new ServiceException("400", "본인이 등록한 상품에는 입찰할 수 없습니다.");
260+
throw ServiceException.badRequest("본인이 등록한 상품에는 입찰할 수 없습니다.");
261261
}
262262
}
263263

264264
private void validateBidPrice(Long bidPrice, Product product) {
265265
// 입찰 금액 기본 검증
266266
if (bidPrice == null || bidPrice <= 0) {
267-
throw new ServiceException("400", "입찰 금액은 0보다 커야 합니다.");
267+
throw ServiceException.badRequest("입찰 금액은 0보다 커야 합니다.");
268268
}
269269

270270
// 현재 최고가보다 높은지 확인
271271
Long currentHighestPrice = bidRepository.findHighestBidPrice(product.getId()).orElse(0L);
272272
if (bidPrice <= currentHighestPrice) {
273-
throw new ServiceException("400", "입찰 금액이 현재 최고가인 " + currentHighestPrice + "원 보다 높아야 합니다.");
273+
throw ServiceException.badRequest("입찰 금액이 현재 최고가인 " + currentHighestPrice + "원 보다 높아야 합니다.");
274274
}
275275

276276
// 최소 입찰단위 100원
277277
if (bidPrice % 100 != 0) {
278-
throw new ServiceException("400", "입찰 금액은 100원 단위로 입력해주세요.");
278+
throw ServiceException.badRequest("입찰 금액은 100원 단위로 입력해주세요.");
279279
}
280280

281281
// 최소 입찰단위 지켰는지 확인
282282
if (bidPrice < currentHighestPrice + 100) {
283-
throw new ServiceException("400", "최소 100원이상 높게 입찰해주세요.");
283+
throw ServiceException.badRequest("최소 100원이상 높게 입찰해주세요.");
284284
}
285285
}
286286

src/main/java/com/backend/domain/notification/controller/ApiV1NotificationController.java

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,30 +27,29 @@ public class ApiV1NotificationController {
2727

2828
@Operation(summary = "알림 목록 조회", description = "사용자의 알림 목록을 페이지네이션으로 조회, 읽음 상태로 필터링 가능.")
2929
@ApiResponses(value = {
30-
@ApiResponse(responseCode = "200", description = "알림 목록 조회 성공",
31-
content = @Content(schema = @Schema(implementation = RsData.class))),
32-
@ApiResponse(responseCode = "401", description = "인증 실패",
33-
content = @Content(schema = @Schema(implementation = RsData.class)))
30+
@ApiResponse(responseCode = "200", description = "알림 목록 조회 성공",
31+
content = @Content(schema = @Schema(implementation = RsData.class))),
32+
@ApiResponse(responseCode = "401", description = "인증 실패",
33+
content = @Content(schema = @Schema(implementation = RsData.class)))
3434
})
3535
@GetMapping
3636
public RsData<NotificationListResponseDto> getNotifications(
3737
@Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0") int page,
3838
@Parameter(description = "페이지 크기", example = "10") @RequestParam(defaultValue = "10") int size,
3939
@Parameter(description = "읽음 상태 필터 (true: 읽음, false: 안읽음, null: 전체)", example = "false") @RequestParam(required = false) Boolean isRead,
40-
@Parameter(hidden = true) @AuthenticationPrincipal User user
41-
) {
40+
@Parameter(hidden = true) @AuthenticationPrincipal User user) {
4241
Long memberId = getCurrentMemberId(user);
4342
return notificationService.getNotifications(memberId, page, size, isRead);
4443
}
4544

4645
@Operation(summary = "알림 읽음 처리", description = "특정 알림을 읽음 상태로 변경.")
4746
@ApiResponses(value = {
48-
@ApiResponse(responseCode = "200", description = "알림 읽음 처리 성공",
49-
content = @Content(schema = @Schema(implementation = RsData.class))),
50-
@ApiResponse(responseCode = "401", description = "인증 실패",
51-
content = @Content(schema = @Schema(implementation = RsData.class))),
52-
@ApiResponse(responseCode = "404", description = "알림을 찾을 수 없음",
53-
content = @Content(schema = @Schema(implementation = RsData.class)))
47+
@ApiResponse(responseCode = "200", description = "알림 읽음 처리 성공",
48+
content = @Content(schema = @Schema(implementation = RsData.class))),
49+
@ApiResponse(responseCode = "401", description = "인증 실패",
50+
content = @Content(schema = @Schema(implementation = RsData.class))),
51+
@ApiResponse(responseCode = "404", description = "알림을 찾을 수 없음",
52+
content = @Content(schema = @Schema(implementation = RsData.class)))
5453
})
5554
@PutMapping("/{id}/read")
5655
public RsData<Void> markAsRead(
@@ -62,30 +61,33 @@ public RsData<Void> markAsRead(
6261

6362
@Operation(summary = "모든 알림 읽음 처리", description = "사용자의 모든 알림을 읽음 상태로 변경.")
6463
@ApiResponses(value = {
65-
@ApiResponse(responseCode = "200", description = "모든 알림 읽음 처리 성공",
66-
content = @Content(schema = @Schema(implementation = RsData.class))),
67-
@ApiResponse(responseCode = "401", description = "인증 실패",
68-
content = @Content(schema = @Schema(implementation = RsData.class)))
64+
@ApiResponse(responseCode = "200", description = "모든 알림 읽음 처리 성공",
65+
content = @Content(schema = @Schema(implementation = RsData.class))),
66+
@ApiResponse(responseCode = "401", description = "인증 실패",
67+
content = @Content(schema = @Schema(implementation = RsData.class)))
6968
})
7069
@PutMapping("/read-all")
71-
public RsData<Integer> markAllAsRead(@Parameter(hidden = true) @AuthenticationPrincipal User user) {
70+
public RsData<Integer> markAllAsRead(
71+
@Parameter(hidden = true) @AuthenticationPrincipal User user) {
7272
Long memberId = getCurrentMemberId(user);
7373
return notificationService.markAllAsRead(memberId);
7474
}
7575

7676
@Operation(summary = "읽지 않은 알림 개수 조회", description = "사용자의 읽지 않은 알림 개수 조회.")
7777
@ApiResponses(value = {
78-
@ApiResponse(responseCode = "200", description = "읽지 않은 알림 개수 조회 성공",
79-
content = @Content(schema = @Schema(implementation = RsData.class))),
80-
@ApiResponse(responseCode = "401", description = "인증 실패",
81-
content = @Content(schema = @Schema(implementation = RsData.class)))
78+
@ApiResponse(responseCode = "200", description = "읽지 않은 알림 개수 조회 성공",
79+
content = @Content(schema = @Schema(implementation = RsData.class))),
80+
@ApiResponse(responseCode = "401", description = "인증 실패",
81+
content = @Content(schema = @Schema(implementation = RsData.class)))
8282
})
8383
@GetMapping("/unread-count")
84-
public RsData<Integer> getUnreadCount(@Parameter(hidden = true) @AuthenticationPrincipal User user) {
84+
public RsData<Integer> getUnreadCount(
85+
@Parameter(hidden = true) @AuthenticationPrincipal User user) {
8586
Long memberId = getCurrentMemberId(user);
8687
return notificationService.getUnreadCount(memberId);
8788
}
8889

90+
// ======================================= helper methods ======================================= //
8991
private Long getCurrentMemberId(User user) {
9092
if (user != null) {
9193
return Long.parseLong(user.getUsername());

src/main/java/com/backend/domain/notification/service/NotificationService.java

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,29 @@
1313
import org.springframework.transaction.annotation.Transactional;
1414

1515
import java.util.List;
16-
import java.util.Optional;
1716

1817
@Service
19-
@Transactional(readOnly = true)
2018
@RequiredArgsConstructor
2119
public class NotificationService {
2220
private final NotificationRepository notificationRepository;
2321

22+
// ======================================= find/get methods ======================================= //
23+
@Transactional(readOnly = true)
2424
public RsData<NotificationListResponseDto> getNotifications(Long memberId, int page, int size, Boolean isRead) {
25-
Pageable pageable = PageRequest.of(page,size);
26-
// 1. 조건에 따른 알림조회
27-
Page<Notification> notificationPage;
28-
if (isRead != null && !isRead) {
29-
// 읽지 않은 알림만 조회
30-
notificationPage = notificationRepository.findUnreadNotifications(memberId, pageable);
31-
} else if (isRead != null && isRead) {
32-
// 읽은 알림만 조회
33-
notificationPage = notificationRepository.findReadNotifications(memberId, pageable);
34-
} else {
35-
// 전체 알림 조회 (isRead가 null인 경우)
36-
notificationPage = notificationRepository.findByMemberId(memberId, pageable);
37-
}
38-
// 2. 읽지않은 알림 개수 조회
25+
// 페이지 설정
26+
Pageable pageable = PageRequest.of(page, size);
27+
28+
// 조건에 따른 알림 조회
29+
Page<Notification> notificationPage = getNotificationsByReadStatus(memberId, isRead, pageable);
30+
31+
// 읽지 않은 알림 개수 조회
3932
Integer unreadCount = notificationRepository.countUnreadNotifications(memberId);
40-
// 3. DTO 변환 및 response 반환
33+
34+
// 응답 데이터 생성
4135
List<NotificationListResponseDto.NotificationItem> notificationItems = notificationPage.getContent().stream()
42-
.map(this::convertToNotifiactionItem).toList();
36+
.map(this::convertToNotificationItem)
37+
.toList();
38+
4339
NotificationListResponseDto response = new NotificationListResponseDto(
4440
notificationItems,
4541
(int) notificationPage.getTotalElements(),
@@ -49,39 +45,60 @@ public RsData<NotificationListResponseDto> getNotifications(Long memberId, int p
4945
notificationPage.hasNext(),
5046
unreadCount
5147
);
52-
return new RsData<>("200","알림 목록 조회가 완료되었습니다.",response);
48+
49+
return RsData.ok("알림 목록 조회가 완료되었습니다.", response);
5350
}
5451

55-
public RsData<Void> markAsRead(Long notificationId, Long memberId) {
56-
// 1. 알림 존재 및 사용자 확인
57-
Optional<Notification> notification = notificationRepository.findByIdAndMemberId(notificationId,memberId);
58-
if (notification.isEmpty()) return new RsData<>("404","알림을 찾을 수 없습니다.",null);
59-
// 2. 읽음 처리
60-
Notification n = notification.get();
61-
n.setIsRead(true);
62-
notificationRepository.save(n);
63-
return new RsData<>("200","알림이 읽음 처리되었습니다.",null);
52+
@Transactional(readOnly = true)
53+
public RsData<Integer> getUnreadCount(Long memberId) {
54+
Integer unreadCount = notificationRepository.countUnreadNotifications(memberId);
55+
return RsData.ok("읽지 않은 알림 개수가 조회되었습니다.", unreadCount);
56+
}
57+
58+
private Page<Notification> getNotificationsByReadStatus(Long memberId, Boolean isRead, Pageable pageable) {
59+
if (isRead != null && !isRead) {
60+
// 읽지 않은 알림만 조회
61+
return notificationRepository.findUnreadNotifications(memberId, pageable);
62+
} else if (isRead != null && isRead) {
63+
// 읽은 알림만 조회
64+
return notificationRepository.findReadNotifications(memberId, pageable);
65+
} else {
66+
// 전체 알림 조회
67+
return notificationRepository.findByMemberId(memberId, pageable);
68+
}
6469
}
6570

71+
// ======================================= update methods ======================================= //
6672
@Transactional
67-
public RsData<Integer> markAllAsRead(Long memberId) {
68-
int updatedCount = notificationRepository.markAllAsRead(memberId);
69-
return new RsData<>("200","모든 알림이 읽음 처리되었습니다.",updatedCount);
73+
public RsData<Void> markAsRead(Long notificationId, Long memberId) {
74+
// 알림 존재 및 사용자 확인
75+
Notification notification = notificationRepository.findByIdAndMemberId(notificationId, memberId)
76+
.orElseThrow(() -> com.backend.global.exception.ServiceException.notFound("알림을 찾을 수 없습니다."));
77+
78+
// 읽음 처리
79+
notification.setIsRead(true);
80+
notificationRepository.save(notification);
81+
82+
return RsData.ok("알림이 읽음 처리되었습니다.", null);
7083
}
7184

72-
public RsData<Integer> getUnreadCount(Long memberId) {
73-
Integer unreadCount = notificationRepository.countUnreadNotifications(memberId);
74-
return new RsData<>("200","읽지 않은 알림 개수가 조회되었습니다.",unreadCount);
85+
@Transactional
86+
public RsData<Integer> markAllAsRead(Long memberId) {
87+
int updatedCount = notificationRepository.markAllAsRead(memberId);
88+
return RsData.ok("모든 알림이 읽음 처리되었습니다.", updatedCount);
7589
}
7690

77-
private NotificationListResponseDto.NotificationItem convertToNotifiactionItem(Notification notification) {
91+
// ======================================= helper methods ======================================= //
92+
private NotificationListResponseDto.NotificationItem convertToNotificationItem(Notification notification) {
7893
String productName = null;
7994
Long productId = null;
80-
if(notification.getProduct()!=null){
95+
96+
if (notification.getProduct() != null) {
8197
Product product = notification.getProduct();
8298
productName = product.getProductName();
8399
productId = product.getId();
84100
}
101+
85102
return new NotificationListResponseDto.NotificationItem(
86103
notification.getId(),
87104
notification.getMessage(),

0 commit comments

Comments
 (0)