[Spring] 조회수 기능 구현 (조회수 중복 방지)

19·2022년 7월 26일
2

Spring

목록 보기
10/29

원인

게시글을 조회했을 때, 조회수가 증가하는데, 문제는 새로고침해도 조회수가 계속 증가한다는 피드백이 있었다.
이를 보완하기 위해 찾아보다가 방법을 찾았고, 적용도 성공해서 적어본다.


변경 전

| Post.java

...
@Column(columnDefinition = "integer default 0", nullable = false)
private int hits;
...
  • 조회 수를 나타내는 필드이다.

| PostService.java

@Transactional
public ResponseEntity<PostReadResponseDto> readPost(Long postId, MemberDetails memberDetails) {
    ...
    // 조회 수 증가
    updateHits(postId);
    ...
}

// 조회수 증가 로직
@Transactional
public int updateHits(Long id) {
    return postRepository.updateHits(id);
}
  • 게시글 조회 시, 조회 수가 증가되도록 구현했다.
    • 하지만 이렇게 구현하면, 게시글에 접근할 때마다 조회 수가 증가한다.

| PostRepository.java

public interface PostRepository extends JpaRepository<Post, Long> {
    ...
    @Modifying
    @Query("update Post p set p.hits = p.hits + 1 where p.id = :id")
    int updateHits(Long id);
}
  • 특정 게시글 ID의 hits(조회 수)를 증가시킨다.
  • @Modifying 어노테이션은 @Query 어노테이션에서 작성된 조회를 제외한 데이터의 변경이 있는
    삽입(Insert), 수정(Update), 삭제(Delete) 쿼리 사용시 필요한 어노테이션이다.


변경 후

서버

게시글 상세 페이지에 접근하면, 조회 수가 증가되기 때문에, readPost()메소드에 조회 수 중복을 방지하는 로직을 추가했다.

| PostService.java

@Transactional
public ResponseEntity<PostReadResponseDto> readPost(Long postId, MemberDetails memberDetails, HttpServletRequest request, HttpServletResponse response) {
    ...
    
    // 조회 수 중복 방지
    Cookie oldCookie = null;
    Cookie[] cookies = request.getCookies();
    if (cookies != null) {
        for (Cookie cookie : cookies) {
           if (cookie.getName().equals("postView")) {
                oldCookie = cookie;
           }
        }
    }
    if (oldCookie != null) {
        if (!oldCookie.getValue().contains("["+ postId.toString() +"]")) {
            updateHits(postId);
            oldCookie.setValue(oldCookie.getValue() + "_[" + postId + "]");
            oldCookie.setPath("/");
            oldCookie.setMaxAge(60 * 60 * 24);
            response.addCookie(oldCookie);
        }
    } else {
        updateHits(postId);
        Cookie newCookie = new Cookie("postView", "[" + postId + "]");
        newCookie.setPath("/");
        newCookie.setMaxAge(60 * 60 * 24);
        response.addCookie(newCookie);
        System.out.println(newCookie);
    }
    ...
}

// 조회수 증가 로직
@Transactional
public int updateHits(Long id) {
    return postRepository.updateHits(id);
}
  • 쿠키를 사용해서 게시글에 접근할 때마다 조회 수가 증가하는 것을 방지한다.
    • 쿠키를 통해 한 번 게시글을 조회했으면 재접근했을 때 조회 수가 증가되지 않도록 함

클라이언트

| post-details.js

// 게시글 상세 읽기
function getPost() {
    ...
    $.ajax({
        type: 'GET',
        url: process.env.BACKEND_HOST + '/post/' + params['id'],
        xhrFields: {
            withCredentials: true
        },
        ...
    });
}

서버는 8080, 클라이언트는 5000번을 쓰기 때문에 서로 출처가 다르다. 이렇게 되면 쿠키를 통해 통신을 할 수 없는데(클라이언트에서 서버로 요청 시, 자동으로 쿠키가 요청 메시지에 담기지 않음), 이를 해결하기 위해 withCredentials = true로 해주어야 한다.

  • 서버에서 쿠키를 보내기 때문에, 사용하기 위해선 클라이언트에서 쿠키로 통신하는 것을 허락해야 한다.
    따라서, xhrFields: { withCredentials: true },를 추가했다.
    • 클라이언트와 서버가 쿠키 값을 공유하겠다는 의미


결과

  • 97, 99, 102번 게시글에 접근했고, 해당 게시글에 재접근해도 조회 수가 중복되어 증가되지 않는다!

게시글에 접근하면, 조회 수가 증가하고, 접근한 게시글 번호가 쿠키에 담긴다.
접근한 게시글에 재접근해도 이전과는 다르게 조회 수가 증가하지 않게 된다.


참고

https://dev-coco.tistory.com/113#--%--%EC%A-%--%EC%-A%A-
https://mighty96.github.io/til/view/
https://kosaf04pyh.tistory.com/152

profile
하나씩 차근차근

0개의 댓글