[SQL] 즐겨찾기, 좋아요 온오프 (아예 없는 데이터 조회하기 - NVL 사용 불가)
상세보기 페이지를 불러올 때부터 로그인 했는지 세션 체크하고 로그인 했으면 즐겨찾기, 좋아요 여부 체크해서 반영해서 다르게 보여준다.
즐겨찾기는 속이 채워진 아이콘으로, 좋아요는 어두운 바탕색의 버튼으로.
이때 로그인한 사람의 정보를 레시피 컨트롤러의 상세보기 관련 컨트롤러에서 실행하는 쿼리에서는 알지 못해서 쿼리가 안 돌아갔었다.
그래서 리스트에서 상세보기로 넘어갈 때 로그인 정보를 히든인풋으로 담아서 검색, 페이지, 글 번호 히든인풋과 함께 넘어가도록 했는데
지금 생각해보니 그냥 상세보기 컨트롤러에 세션을 추가해줬으면 간단했으려나?
아무튼 그렇게 넘어온 로그인 회원 정보로 즐겨찾기, 좋아요 여부 체크해서 바꿔주는 거까지가 상세보기 페이지 로드 끝이다.
문제는 즐겨찾기, 좋아요 테이블을 따로 분리해두고 온오프 시에만 데이터가 추가되도록 했기 때문에(누르면 DEL = 1, 해제하면 DEL = 0)
한 번도 안 눌러본 사람은 데이터 자체가 없어서 null 조차 뽑을 수가 없는 거다. NVL도 쓸 수가 없었다.
그래서 생각해낸 게 집계 함수..
집계 함수를 쓰면 데이터가 없어도 없다고 체크를 할 수 있기 때문.
대신에 버튼 누른 것과 취소한 것 구하는 쿼리를 따로 해서 실행 쿼리가 매우 늘었다.
로그인한 사람이 글의 좋아요를 누른(DEL = 1) 수를 COUNT 함수로 더해서 그 수가 1이면 && 좋아요 취소한(DEL = 0) 수가 0이면 좋아요 누른 상태이므로 checkLike 변수를 1이라 줬고 그 반대이면 0이라 주고 jsp로 넘겼다.
<!-- 내가 좋아요를 누른 상태인지 -->
<select id="checkLike" resultType="Integer" parameterType="hashmap">
SELECT COUNT(*) AS LIKE_CNT
FROM (SELECT RECIPE_NO, MEM_NO
FROM RECIPE_LIKE
WHERE RECIPE_NO = #{no}
AND MEM_NO = #{sMemNo}
AND DEL = 1)
</select>
<!-- 내가 좋아요를 취소한 상태인지 -->
<select id="checkUnLike" resultType="Integer" parameterType="hashmap">
SELECT COUNT(*) AS UNLIKE_CNT
FROM (SELECT RECIPE_NO, MEM_NO
FROM RECIPE_LIKE
WHERE RECIPE_NO = #{no}
AND MEM_NO = #{sMemNo}
AND DEL = 0)
</select>
//detail.jsp로 가는 컨트롤러 중
int checkLike = 0;
int checkFav = 0;
if(params.get("sMemNo") != null && params.get("sMemNo") != "") {
int cl = dao.getInt("recipe.checkLike", params);
int cul = dao.getInt("recipe.checkUnLike", params);
if(cl == 1 && cul == 0) {
checkLike = 1;
} else {
checkLike = 0;
}
mav.addObject("checkLike", checkLike);
int cf = dao.getInt("recipe.checkFav", params);
int cuf = dao.getInt("recipe.checkUnFav", params);
if(cf == 1 && cuf == 0) {
checkFav = 1;
} else {
checkFav = 0;
}
mav.addObject("checkFav", checkFav);
}
그리고 detail.jsp에서는 JSTL 코어 태그를 써서 세션 정보가 없거나 로그인한 사람이 작성자와 같으면 비활성화 버튼을 만들어주고, 로그인한 사람과 작성자가 다르면 활성화 버튼으로 만들어주었다.
그리고 이미 좋아요를 눌렀던 글이면 그 활성화 버튼의 클래스에 on 클래스를 더해주고 css를 수정해주었다.

(좋아요 버튼은 활성화 버튼과 비활성화 버튼이 같은 이미지인데 비활성화 버튼의 CSS에서 cursor:pointer와 hover를 없애고 배경색을 다르게 주었음. 당연히 스크립트도 다름.)

이건 북마크 버튼
DEL=1인 수 COUNT 했을 때 1이면 좋아요 눌러진 버튼으로 표시해줘야 하고
DEL=0인 수 COUNT 했을 때 1이거나 DEL=1인 수도 0이고 DEL=0인 수도 0이면 좋아요 안 눌러진 버튼으로 표시해줘야 한다.
이건 그냥 상세보기 페이지를 그릴 때 같이 로드되는, 버튼에 현황을 반영해주는 거라서 버튼 누르면서 실시간으로 디비에 집어넣고 수정하는 거랑은 다르다. 좋아요, 북마크 실제 기능은 브라우저가 다 로드된 뒤에 클릭 이벤트로 AJAX로 디비에 접근하고 화면에 변화를 주는 것.
그래서 좋아요, 북마크 누를 때는
DEL=1인 수 COUNT 했을 때 1인 경우(좋아요 누름)와 DEL=0인 수 COUNT 했을 때 1인 경우(좋아요 취소)는 UPDATE 해야 하고,
DEL=1인 수도 0이고 DEL=0인 수도 0이면 INSERT 해서 새로 넣어야 함.
이 부분은 다른 글로 쓰겠다.
정리하자면, 위 쿼리들을 따로 하는 이유는 페이지를 로드했고 아무것도 안 한 상태일 때 현재 화면을 보는 사람에 따라 버튼의 상태를 다르게 주고 싶어서였음!
+ 구글링 해보니
UNION과 NOT EXISTS 또는 ROWNUM을 활용하기도 한다고 함!