회사에서 게시판 기능을 구현하는 도중에 조회수가 새로고침을 하면 계속해서 오르는 것을 확인했다. 이를 방지하기 위해서 쿠키를 사용한 중복 조회 방지 코드를 짜봤다.
/**
* 이미 조회한 게시물에 대해서 해당 게시물에 대한 중복 조회수 증가를 방지하는 메소드이다.<br>
* @param request
* @param response
* @param nttId - 게시물 id 값
*/
private void addViewedNttIdToCookie(final HttpServletRequest request, final HttpServletResponse response, final String nttId) {
Cookie accumulateNttIdCookie = Arrays
.stream(request.getCookies())
.filter(cookie -> cookie.getName().equals("alreadyViewNttId"))
.findFirst()
.orElseGet(() -> {
Cookie cookie = createAccNttIdCookie(nttId);// 조회수 중복 방지용 쿠키 생성
response.addCookie(cookie); // 생성한 쿠키를 response에 담는다.
bbsService.incrementNttRdCnt(nttId); // 조회수 증가 쿼리 수행
return cookie;
});
// 한번이라도 조회한 게시물에 대해서는 쿠키값에 해당 게시물의 nttId가 저장된다.
// 서로 다른 nttId에 대해서는 "/" 로 구분한다.
// ex) 000000000891/000000000890/000000000889
String cookieValue = accumulateNttIdCookie.getValue();
if(cookieValue.contains(nttId) == false) {
String newCookieValue = cookieValue + "/" + nttId;
response.addCookie(getRemainSecondForTommorow());// 기존에 같은 이름의 쿠키가 있다면 덮어쓴다.
bbsService.incrementNttRdCnt(nttId); // 조회수 증가 쿼리 수행
}
}
/**
* 조회수 중복 증가(= 새로고침에 의한 조회수 증가)를 방지하기 위한 쿠키를 생성하는 메소드 <br>
* 일반 게시판(공지사항, 자료실, 질의응답, FAQ, 사용자요청) 전용
* @param cookieValue
* @return
*/
private Cookie createAccNttIdCookie(String cookieValue) {
Cookie cookie = new Cookie("alreadyViewNttId", cookieValue);
cookie.setComment("조회수 중복 증가 방지 쿠키"); // 쿠키 용도 설명 기재
cookie.setMaxAge(getRemainSecondForTommorow()); // 하루를 준다.
cookie.setHttpOnly(true); // 클라이언트 단에서 javascript로 조작 불가
return cookie;
}
// 다음 날 정각까지 남은 시간(초)
private int getRemainSecondForTommorow() {
LocalDateTime now = LocalDateTime.now();
LocalDateTime tommorow = LocalDateTime.now().plusDays(1L).truncatedTo(ChronoUnit.DAYS);
return (int) now.until(tommorow, ChronoUnit.SECONDS);
}
참고로 위 코드에서 getRemainSecondForTommorow() 메소드에 의해서 쿠키가 상당히 오래 남는다. 쿠키의 유지 시간을 더 짧게 하는 것을 추천한다.
사용자가 개발자 도구를 열어서 해당 쿠키를 지우면 조회수가 중복 증가하게 된다.
이건 쿠키 방식을 사용하면 어쩔 수 없다.
정말 안전하게 하고 싶다면 내 생각에는 Redis 같은 가벼운 DB를 써야지 않을까 싶다.
(혹시 다른 방법이 있다면 댓글 부탁드립니다 😊)
혹시 response.addCookie(getRemainSecondForTommorow());// 기존에 같은 이름의 쿠키가 있다면 덮어쓴다.
이부분 잘 못 된거 아닐까욤.. response.addCookie(createAccCookie(newCookieVaule))여야할거같아서요..