[Spring] 게시글 조회수 중복 방지

Updated:

I. 개요

게시판에 있어서 조회수는 사용자가 읽고 싶은 글을 선택하는데에 중요한 지표가 된다.
하지만 단순히 게시글에 접근했다고 조회수를 모두 올려준다면, 새로고침만으로도 조회수를 끝없이 올릴 수 있다.

이렇듯 조회수를 임의로 조작하는 것은 커뮤니티에서 흔히 발생할 수 있는 일이므로, 방지해야할 필요가 있다고 생각했다.

II. 쿠키를 통한 구현

/**
조회수 중복 방지
**/
private void viewCountUp(Long id, 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("[" + id.toString() + "]")) {
            postService.viewCountUp(id);
            oldCookie.setValue(oldCookie.getValue() + "_[" + id + "]");
            oldCookie.setPath("/");
            oldCookie.setMaxAge(60 * 60 * 24);
            response.addCookie(oldCookie);
        }
    } else {
        postService.viewCountUp(id);
        Cookie newCookie = new Cookie("postView","[" + id + "]");
        newCookie.setPath("/");
        newCookie.setMaxAge(60 * 60 * 24);
        response.addCookie(newCookie);
    }
}

조회수 중복방지는 필요한 기능이지만, 완벽하게 차단해야 할만큼 중대한 사항은 아니라고 생각했고, 따라서 쿠키를 사용하기로 했다.

아래와 같은 로직으로 흘러간다.

  1. HttpServletRequest로부터 클라이언트의 쿠키를 가져온다. 먼저 쿠키가 null인지 검사하고, 그렇지 않다면 foreach를 통해 해당 쿠키들 중 postView라는 이름의 쿠키가 있는지 검사한다.
    만약 존재한다면 oldCookie라는 이름으로 가져온다.
  2. oldCookienull이 아니라면, 즉 postView가 존재한다면 해당 쿠키의 value가 현재 접근한 게시글의 id를 포함하고 있는지 검사한다.
    만약 가지고있다면 아무일도 일어나지 않고(조회수가 증가하지 않고), 가지고있지 않다면 postServiceviewCountUp을 통해 해당 게시글의 조회수를 올려주고, 게시글 id를 괄호로 감싸 oldCookie에 추가하고 HttpServletResponse에게 전달한다.
  3. oldCookienull이라면 마찬가지로 postServiceviewCountUp을 통해 게시글의 조회수를 올려주고, 해당 게시글 id를 괄호로 감싼 새로운 쿠키 postView를 생성하여 HttpServletResponse에게 전달한다.

괄호로 id를 감싼 이유

해당 게시글을 이미 조회한적이 있는지 판단하는데에는 contains를 사용했는데, 단순히 숫자만 사용한다면 문제가 생길 수 있다.
예를 들어, 이미 101번 게시글을 조회하여 postView의 값이 101이라고 하자.
이 때, 10번 게시글을 조회하려 한다면, postView쿠키의 101에 포함되어 있는 값이기 때문에 중복된 조회로 여기고 조회수가 증가하지 않을 것이다.
이를 방지하기 위해 숫자를 온전히 검사하고자 [101], [10]과 같은 식으로 포장하여 검사 및 갱신하도록 하였다.

III. 시연

01

id가 각각 1, 2인 게시글 두개가 있으며, 조회수는 1이고 쿠키는 존재하지 않는 상태이다.

02

먼저, id가 1인 게시글에 접근했다. oldCookienull값이므로 postView쿠키가 생성되고, value[1]을 가지게 된다.

03

기존 조회한 적이 없던 게시글이므로 정상적으로 조회수가 증가한다.

04

다음으로, id가 2인 게시글에 접근했다. postViewoldCookie로 가지고, [2]를 포함하지 않으므로 value[2]를 추가하여 전달한다. 마찬가지로 조회한 적이 없던 게시글이므로 정상적으로 조회수가 증가했을 것이다.

05

다시 id가 1인 게시글에 접근했다. postViewoldCookie로 가지나, [1]을 이미 포함하고 있으므로 쿠키에는 변화가 없다.

06

1번게시글은 두번 접근했음에도 조회수가 1만 올라간 모습을 볼 수 있다.

Leave a comment