Skip to content

Conversation

@PicturePark1101
Copy link
Contributor

@PicturePark1101 PicturePark1101 commented May 11, 2025

작업내용

조회수 리워드를 구현했습니다.

상세설명_ & 캡쳐

ViewCountPolicy

  • domain - note - shared - model 패키지 내부에 ViewCountPolicy 객체 생성

  • milestoneRewardMap은 마일스톤(달성 조건) - 보상을 매핑한 Map 형 변수

public class ViewCountPolicy {

	private final Map<Long, Long> milestoneRewardMap = Map.of(
		10L, 1L,
		25L, 2L,
		50L, 3L
	);

	private final Map<Long, String> milestoneMessageMap = Map.of(
		10L, "조회수 10회 달성!",
		25L, "조회수 25회 달성!",
		50L, "조회수 50회 달성!"
	);

	public Long getRewardForExactMilestone(long viewCount) {
		return milestoneRewardMap.get(viewCount);
	}

	public String getMessageForMilestone(long milestone) {
		String message = milestoneMessageMap.get(milestone);
		if (message == null) {
			log.info("정의되지 않은 milestone입니다: milestoen={}", milestone);
		}
		return message;
	}
}

조회수 카운트 관련 service 분리

  • ViewCountService를 생성해서 조회수를 다루는 객체를 분리했습니다.
    1. 중복 보상인지 확인
  • 2, 연필 계좌를 찾고, 계좌 잔액 증가
    1. 얻은 연필 내역에 데이터 추가
    1. 보상 내역에 추가
	@Transactional
	public void giveViewCountReward(Member member, Long sharedNoteId, Long milestone, Long rewardPencil) {

		if (alreadyViewCountRewardEarned(RewardType.VIEWCOUNT, sharedNoteId, milestone)) {
			return;
		}

		PencilAccount account = pencilAccountFinder.findByMemberWithLock(member);
		account.increaseAcquiredBalance(rewardPencil);

		acquiredPencilUpdater.save(
			createAcquiredPencil(member, sharedNoteId, milestone, rewardPencil));
		rewardUpdater.save(createReward(member, sharedNoteId, milestone, rewardPencil));
	}

이벤트 리스너 구현

  • 서비스 간 의존성을 줄이고 최적화를 위해 SharedNoteQueryService에서 이벤트를 발행하여 ViewCountService가 실행되도록 구현하였습니다.
  • event.subscriber 패키지 내부
  • 리워드 조건이 충족되는지(조회수 조건) 확인하고, 충족시 ViewCountService 호출
	@Async
	@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
	public void handleRewardViewCountEvent(RewardViewCountEvent rewardViewCountEvent) {

		Long reward = viewCountPolicy.getRewardForExactMilestone(
			rewardViewCountEvent.viewCount());

		if (reward == null) {
			return;
		}

		try {
			rewardService.giveViewCountReward(rewardViewCountEvent.member(), rewardViewCountEvent.sharedNoteId(),
				rewardViewCountEvent.viewCount(), reward);
		} catch (Exception e) {
			log.error("조회수 리워드 지급 실패", e);
		}
	}

Reward Entity 생성 및 중복 보상 방지

  • Reward 엔티티를 추가해서 중복 보상을 방지하는 로직을 생성했습니다.
	private boolean alreadyViewCountRewardEarned(RewardType type, Long sharedNoteId, Long milestone) {
		return rewardFinder.existsByTypeAndMilestoneAndSharedNoteId(type, milestone, sharedNoteId);
	}

@PicturePark1101 PicturePark1101 self-assigned this May 11, 2025
@PicturePark1101 PicturePark1101 added ✨ feature 기능 추가 진이 작업했습니다. 👊🏻 PULL REQUEST pr날릴때 labels May 11, 2025
Copy link
Contributor

@essaysir essaysir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이벤트 발행 구조로 설계해두신 코드에 대해 잘봤습니다.!! 고생하셨습니다.

@PicturePark1101 PicturePark1101 merged commit bb702f6 into dev May 12, 2025
1 check passed
PicturePark1101 added a commit that referenced this pull request Jun 1, 2025
[feat/#366] 조회수 리워드 구현
@essaysir essaysir deleted the feat/#366 branch September 10, 2025 13:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ feature 기능 추가 진이 작업했습니다. 👊🏻 PULL REQUEST pr날릴때

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants