“핫한 정책 조회” 기능을 구현하기 위해 먼저 정책에 대해 조회수 기능을 추가하기로 했다.
간단하게 구현하면 정책 테이블에 조회수 필드를 추가하면 되지만, 현재 이 프로젝트의 정책 테이블은 주기적으로 삭제되고 “청년 정책 Open API” 호출로 다시 새로운 데이터를 저장한다.
그래서 단순히 정책 테이블에 조회수 필드를 추가한다면, 정책 데이터가 리프레시 될 때 조회수도 초기화 될 것이다.
그래서 정책 조회수는 테이블을 따로 생성해서 관리하도록 결정했다.
1. 프로젝트 구조
src/main/java/com/example/withpeace/
│
├── domain/ # 도메인 모델 (엔티티)
│ ├── YouthPolicy.java # 청년 정책 엔티티
│ └── ViewPolicy.java # 정책 조회 엔티티
│
├── repository/ # 데이터 접근 계층
│ ├── YouthPolicyRepository.java # 청년 정책 레포지토리
│ └── ViewPolicyRepository.java # 정책 조회 레포지토리
│
├── controller/ # 컨트롤러 계층
│ └── PolicyController.java # 정책 관련 API 엔드포인트
│
└── service/ # 비즈니스 로직 계층
└── PolicyService.java # 정책 관련 비즈니스 로직
2. 도메인 엔티티 구현
ViewPolicy
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@DynamicUpdate
@Table(name = "view_policies")
public class ViewPolicy {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false, unique = true)
private Long id;
@Column(name = "policy_id", nullable = false, unique = true)
private String policyId; // 정책 ID
@Column(name = "view_count", nullable = false)
private int viewCount; // 조회수
@Builder
public ViewPolicy(String policyId, int viewCount) {
this.policyId = policyId;
this.viewCount = viewCount;
}
}
3. 레포지토리 구현
ViewPolicyRepository
public interface ViewPolicyRepository extends JpaRepository<ViewPolicy, Long> {
@Modifying
@Query(value = "INSERT INTO view_policies (policy_id, view_count) VALUES (:policyId, 1) " +
"ON DUPLICATE KEY UPDATE view_count = view_count + 1", nativeQuery = true)
void incrementViewCount(String policyId);
}
`incrementViewCount` 메서드는 해당 정책의 조회수를 1 증가시킨다.
정책을 조회하게 되면, 정책 ID를 받아 해당 정책 ID가 “정책 조회수” 테이블에 존재하면 조회수를 1 증가시키고, 존재하지 않으면 새로 데이터를 삽입해야 한다.
이 두 가지를 한 번에 작동시킬 수 있는 쿼리를 사용하면 된다.
INSERT INTO 정책_조회수 (정책_id, 조회수) VALUES (:정책_id, 1)
ON DUPLICATE KEY UPDATE 조회수 = 조회수 + 1;
`ON DUPLICATE KEY UPDATE` 를 사용하면 INSERT 작업 시 UNIQUE 또는 PRIMARY KEY 제약 조건과 충돌이 발생할 경우 UPDATE를 수행한다.
- 해당 정책의 조회 기록이 없는 경우: INSERT 문이 실행되어 조회수 1로 새로운 레코드 생성
- 해당 정책의 조회 기록이 이미 있는 경우: UPDATE 문이 실행되어 기존 조회수에 1을 증가
여러 사용자가 동시에 조회하는 경우에도 조회수가 정확하게 증가한다. (동시성 처리)
4. 서비스 수정
YouthPolicyService
@Transactional
public PolicyDetailResponseDto getPolicyDetail(Long userId, String policyId) {
User user = getUserById(userId);
YouthPolicy policy = getPolicyById(policyId);
boolean isFavorite = isFavoritePolicy(user, policy.getId());
viewPolicyRepository.incrementViewCount(policyId); // 조회수 증가
return PolicyDetailResponseDto.from(policy, isFavorite);
}
`getPolicyDetail` 는 “정책 상세 조회” 서비스 코드이다. “정책 리스트 조회”에서 한 정책을 선택하고 “상세 조회”를 요청할 때 조회수가 증가되도록 구현했다.
5. API 응답 예시
요청 URL
[GET] http://cheongha.site/api/v1/policies/R2024070424687
“정책 상세조회” 시 조회수를 증가시킬 수 있다.
6. 고려할 것
정책 데이터가 리프레시 되었을 때, 더 이상 존재하지 않는 정책에 대해 조회수 데이터를 어떻게 처리할지 생각해야 한다.
그래서 생각해본 방법으로는 주기적으로 정책 데이터를 리프레시 하는 것 처럼, 정책 조회수 데이터도 주기적으로 정책 조회수 테이블의 정책ID가 정책 테이블의 정책ID 중에 존재하는 지 검사하여 삭제하는 방법이다.
(스케줄러 또는 Spring Batch 사용을 해볼 수 있을 것 같다.)
팀원들에게 의견을 물어보고 처리할 것이다.
'Projects > 청하-청년을 위한 커뮤니티 서비스' 카테고리의 다른 글
[청하] 37. 로컬 환경에서 Spring Boot 모니터링 시스템 구축 (with. Prometheus, Grafana) (0) | 2024.10.27 |
---|---|
[청하] 36. 게시글 조회수 기능 구현 (0) | 2024.10.25 |
[청하] 34. 정책 찜하기 기능 - 유니크 제약조건 문제 해결 (0) | 2024.10.23 |
[청하] 33. 정책 조회 API - 찜하기 여부 추가 & 인증 설정 변경 (2) | 2024.10.23 |
[청하] 32. 정책 찜하기 해제 기능 구현 (0) | 2024.10.22 |
댓글