스프링래거시 좋아요기능 구현하기
우선
좋아요가 되어있는지 안되어있는지 상태체크하는 기능 구현하기
보드넘버와 로그인한 유저의 넘버가 필요함.
1.
좋아요를 담는 테이블 만들기
CREATE TABLE BOARD_LIKE (
LIKE_NO NUMBER NOT NULL, --좋아요에 번호부여
BOARD_NO NUMBER NOT NULL, --좋아요 게시글 식별자
USER_NO NUMBER NOT NULL, -- 좋아요 유저 식별자
LIKE_DATE DATE DEFAULT SYSDATE NOT NULL, -- 좋아요 날짜 식별자...인데 굳이 안해도됐었을까...?
CONSTRAINT PK_BOARD_LIKE PRIMARY KEY (LIKE_NO),
CONSTRAINT FK_BOARD_LIKE_BOARD FOREIGN KEY (BOARD_NO) REFERENCES BOARD(BOARD_NO),
CONSTRAINT FK_BOARD_LIKE_USER FOREIGN KEY (USER_NO) REFERENCES "USER" (USER_NO)
);
CREATE SEQUENCE BOARD_LIKE_SEQ; -- 시퀀스
2. vo만들기
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class BoardLikeVO {
private int boardLike;
private int boardNo;
private int userNo;
private int likeCheck;
private int loginUserNo; // 로그인유저 값 받아야하기때문에
}
boardMapper애 추가.===================
<!-- 좋아요 한지 안한지 체크 -->
<select id="checkLike" resultType="_int">
SELECT COUNT(*) FROM BOARD_LIKE WHERE BOARD_NO = #{boardNo} AND USER_NO = #{loginUserNo}
</select>
BoardService애 추가.===================
int checkLike(BoardLikeVO likeVo);
BoardServiceImpl에 추가.===================
@Override
public int checkLike(BoardLikeVO likeVo) {
return dao.checkLike(likeVo);
}
BoardDAO애 추가.===================
public int checkLike(BoardLikeVO likeVo) {
return sqlSession.selectOne("boardMapper.checkLike", likeVo);
}
BoardController애 추가.===================(엄청 길어서 좋아요부분만 가져옴)
@GetMapping("/boardDetail")
public String boardDetail(@RequestParam("boardNo")int boardNo,
Model model, Criteria cri,
@RequestParam(value = "searchType",required = false, defaultValue = "title") String searchType,
@RequestParam(value = "keyword",required = false, defaultValue = "") String keywor
,HttpSession session,
@RequestParam(value = "loginUserNo", required = false, defaultValue = "0") int loginUserNo,
HttpServletRequest req, HttpServletResponse resp
) {
// likeVo 객체선언하고
BoardLikeVO likeVo = new BoardLikeVO();
likeVo.setBoardNo(boardNo); // boardNo 값 세팅
likeVo.setLoginUserNo(loginUserNo);// loginUserNo 값 세팅
int result = service.checkLike(likeVo); //디비에서 값 가져오기 1 or 0
if(result > 0) { // 디비에 좋아요한 기록이 있는지 유무 판단하기
model.addAttribute("likeck", "T"); // 디비에 기록이 있으면 뷰(jsp)에 T 보내기
}else {
model.addAttribute("likeck", "F"); // 디비에 기록이 없으면 뷰에 F 보내기
}
boardDetail.jsp애 추가.===================(엄청 길어서 좋아요부분만 가져옴)
<div class="BoardDetailTitle">${BoardDetail.boardTitle}</div>
<input id="boardNo" type="hidden" value="${BoardDetail.boardNo}" name="boardNo">
<input id="userNo" type="hidden" value="${BoardDetail.userNo}" name="userNo">
<input id="loginUserNo" type="hidden" value="${sessionScope.loginUser.userNo}" name="loginUserNo">
<input id="likeck" type="hidden" value="${likeck}" name="likeck">
<div class="commentBox2" onclick="commentBox2()">
<c:choose>
<c:when test="${sessionScope.loginUser != null}">
<c:if test="${likeck eq 'T'}">
<div id="addLike" >
<svg id="heart" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="w-6 h-6 like">
<path d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" />
</svg>
</div>
</c:if>
<c:if test="${likeck eq 'F'}">
<div id="addLike" >
<svg id="heart" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="w-6 h-6">
<path d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" />
</svg>
</div>
</c:if>
</c:when>
<c:otherwise>
<a href='${contextPath}/login'>
<svg id="heart" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="w-6 h-6">
<path d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" />
</svg>
</a>
</c:otherwise>
</c:choose>
</div>
input hidden으로 value 설정해주기는 기본.
이렇게 설정하면 뷰(jsp)에서 boardNo와 loginUserNo를 받아온다음
likeVo에 실어서 디비에서 검증하고
값이 있으면
model.addAttribute로 T를
값이 없으면 F를 뷰로 전달함.
그럼 서버에서 받아온 값이 T라면
뷰에서는 눌러진하트를
F라면 안눌러진 하트를 보여줌.
(쓰던거 날라가서 흑흑흑 아이고 귀찮아 )
하트를 눌렀을때(좋아요버튼 = 하트) 디비에 값이 들어가게 만들어야함
boardMapper애 추가.===================
<!-- 좋아요 테이블 좋아요 등록 -->
<insert id="addLike" >
INSERT INTO BOARD_LIKE VALUES(BOARD_LIKE_SEQ.NEXTVAL, #{boardNo}, #{loginUserNo}, DEFAULT)
</insert>
BoardService애 추가.===================
public void addLike(BoardLikeVO likeVo);
BoardServiceImpl에 추가.===================
@Override
public void addLike(BoardLikeVO likeVo) {
dao.addLike(likeVo);
}
BoardDAO애 추가.===================
public void addLike(BoardLikeVO likeVo) {
sqlSession.insert("boardMapper.addLike", likeVo);
}
BoardController애 추가.===================
@PostMapping("/addLike")
public String addLike(BoardLikeVO likeVo,
@RequestParam("boardNo") int boardNo,
@RequestParam("userNo") int userNo,
@RequestParam("loginUserNo") int loginUserNo,
@ModelAttribute("loginUser") User loginUser
) {
likeVo.setBoardNo(boardNo);
likeVo.setLoginUserNo(loginUserNo);
logger.info("boardNo" + boardNo);
logger.info("loginUserNo" + loginUserNo);
logger.info("userNo" + userNo);
service.addLike(likeVo);
return "redirect:/boardDetail";
}
boardDetail.jsp는 따로 추가할거없음
boardDetail.js애 추가.===================
const addLikeDiv = document.getElementById("addLike");
function addLike() {
let boardNo = document.getElementById("boardNo").value;
let userNo = document.getElementById("userNo").value;
let loginUserNo = document.getElementById("loginUserNo").value;
let likeck = document.getElementById("likeck");
if (likeck.value == "T") {
console.log("TTTTTTT");
} // if 끝
else {
console.log("FFFFFF NOTHING");
$.ajax({
url: "addLike",
method: "POST",
data: { boardNo: boardNo, userNo: userNo, loginUserNo: loginUserNo },
success: function () {
console.log("요청이 성공적으로 처리되었습니다.");
},
error: function (request, status, error) {
console.log("addLike AJAX 에러 발생");
console.log("상태코드 : " + request.status);
},
});
} // else끝
}
addLikeDiv.addEventListener("click", addLike);
즉 안눌러진 하트를 눌렀을때는
js에서 likeck.value 가 "T"인지 "F"인지 구분하고
F가 안눌러진 하트니까 F에 해당하는 ajax이 실행됨.
addLike라는 주소로
boardNo, userNo, loginUserNo값들이 서버로 넘어가게 되어지고
그 값들을 likeVo객체에 심어서 디비에 추가함.
그럼 다시 하트를 눌렀을때 좋아요가 취소되게 만들어야 한다면?
boardMapper애 추가.===================
<!-- 좋아요 테이블 좋아요 삭제 -->
<delete id="removeLike" >
DELETE FROM BOARD_LIKE WHERE BOARD_NO = #{boardNo} AND USER_NO = #{loginUserNo}
</delete>
BoardService애 추가.===================
public void removeLike(BoardLikeVO likeVo);
BoardServiceImpl에 추가.===================
@Override
public void removeLike(BoardLikeVO likeVo) {
dao.removeLike(likeVo);
}
BoardDAO애 추가.===================
public void removeLike(BoardLikeVO likeVo) {
sqlSession.delete("boardMapper.removeLike", likeVo);
}
BoardController애 추가.===================
@PostMapping("/removeLike")
public String removeLike(BoardLikeVO likeVo,
@RequestParam("boardNo") int boardNo,
@RequestParam("userNo") int userNo,
@RequestParam("loginUserNo") int loginUserNo,
@ModelAttribute("loginUser") User loginUser
) {
likeVo.setBoardNo(boardNo);
likeVo.setLoginUserNo(loginUserNo);
logger.info("boardNo" + boardNo);
logger.info("loginUserNo" + loginUserNo);
logger.info("userNo" + userNo);
service.removeLike(likeVo);
return "redirect:/boardDetail";
}
boardDetail.jsp는 따로 추가할거없음
boardDetail.js애 추가.===================
const addLikeDiv = document.getElementById("addLike");
function addLike() {
let boardNo = document.getElementById("boardNo").value;
let userNo = document.getElementById("userNo").value;
let loginUserNo = document.getElementById("loginUserNo").value;
let likeck = document.getElementById("likeck");
if (likeck.value == "T") {
console.log("TTTTTTT");
$.ajax({
url: "removeLike",
method: "POST",
data: { boardNo: boardNo, userNo: userNo, loginUserNo: loginUserNo },
success: function () {
console.log("삭제요청이 성공적으로 처리되었습니다.");
likeck.value = "F";
},
error: function (request, status, error) {
console.log("removeLike AJAX 에러 발생");
console.log("상태코드 : " + request.status);
},
});
} // if 끝
else {
console.log("FFFFFF NOTHING");
$.ajax({
url: "addLike",
method: "POST",
data: { boardNo: boardNo, userNo: userNo, loginUserNo: loginUserNo },
success: function () {
console.log("요청이 성공적으로 처리되었습니다.");
},
error: function (request, status, error) {
console.log("addLike AJAX 에러 발생");
console.log("상태코드 : " + request.status);
},
});
} // else끝
}
addLikeDiv.addEventListener("click", addLike);
(아니....아니 왜 자꾸 쓴거 날라가지..? 저장하고 껐는데 ㅠ 열심히 설명해놓은거 어디갔어 ㅠ )
아무튼 음.....좋아요추가랑 별 다른거없다.
다만 좋아요취소를 했으니 하트도 원상태로 돌아가게 해놓음.
일단 여기까지는 기본적인 기능들이고
그럼 좋아요갯수를 어떻게 표시해야할까?
좋아요갯수를 보여주는 기능구현
boardMapper애 추가.===================
<!--좋아요 갯수-->
<select id="countLike" resultType="_int">
SELECT COUNT(*) FROM BOARD_LIKE WHERE BOARD_NO = ${boardNo}
</select>
BoardService애 추가.===================
public int countLike(int boardNo);
BoardServiceImpl에 추가.===================
@Override
public int countLike(int boardNo) {
return dao.countLike(boardNo);
}
BoardDAO애 추가.===================
public int countLike(int boardNo) {
return sqlSession.selectOne("boardMapper.countLike", boardNo);
}
BoardController애 추가.===================(엄청 길어서 좋아요부분만 가져옴)
@GetMapping("/boardDetail")
public String boardDetail(@RequestParam("boardNo")int boardNo,
Model model, Criteria cri,
@RequestParam(value = "searchType",required = false, defaultValue = "title") String searchType,
@RequestParam(value = "keyword",required = false, defaultValue = "") String keywor
,HttpSession session,
@RequestParam(value = "loginUserNo", required = false, defaultValue = "0") int loginUserNo,
HttpServletRequest req, HttpServletResponse resp
) {
// likeVo 객체선언하고
BoardLikeVO likeVo = new BoardLikeVO();
likeVo.setBoardNo(boardNo); // boardNo 값 세팅
likeVo.setLoginUserNo(loginUserNo);// loginUserNo 값 세팅
// 이부분을 추가 함
int countLike = service.countLike(boardNo);
model.addAttribute("countLike",countLike);
int result = service.checkLike(likeVo);
model.addAttribute("LikeVo",likeVo);
if(result > 0) { // 디비에 좋아요한 기록이 있는지 유무 판단하기
model.addAttribute("likeck", "T"); // 디비에 기록이 있으면 뷰(jsp)에 T 보내기
}else {
model.addAttribute("likeck", "F"); // 디비에 기록이 없으면 뷰에 F 보내기
}
addAttribute에 countLike를 담아서 뷰로 보내고
boardDetail.jsp애 추가.===================
<input id="countLike" type="hidden" value="${countLike}" name="countLike">
히든으로 값 선언해서
<span id='like_Check' style='margin-left: 3px;'>${countLike}</span>
<span style='margin-left: 3px;'>like</span>
갯수표시할 부분에 적어주면 끝!
인줄 알았으나!!
갯수는 새로고침 할때만 업데이트가 된다는걸 깨닫게되면서
js에
location.reload()
함수 추가함
스프링레거시 좋아요기능 카운트를 실시간으로 어떻게 바꿀까
좋아요기능에 필요한 좋아요갯수를 카운트하는 것까지는 구현하였으나 새로고침을 눌러야지만 카운트가 반영이 되었다 이것을 어떻게하면 실시간으로 반영할수있을까 잠깐 고민해보았다 실
k-kk.tistory.com
boardDetail.js애 추가.===================
const addLikeDiv = document.getElementById("addLike");
function addLike() {
let boardNo = document.getElementById("boardNo").value;
let userNo = document.getElementById("userNo").value;
let loginUserNo = document.getElementById("loginUserNo").value;
let likeck = document.getElementById("likeck");
if (likeck.value == "T") {
console.log("TTTTTTT");
$.ajax({
url: "removeLike",
method: "POST",
data: { boardNo: boardNo, userNo: userNo, loginUserNo: loginUserNo },
success: function () {
console.log("삭제요청이 성공적으로 처리되었습니다.");
likeck.value = "F";
location.reload()
},
error: function (request, status, error) {
console.log("removeLike AJAX 에러 발생");
console.log("상태코드 : " + request.status);
},
});
} // if 끝
else {
console.log("FFFFFF NOTHING");
$.ajax({
url: "addLike",
method: "POST",
data: { boardNo: boardNo, userNo: userNo, loginUserNo: loginUserNo },
success: function () {
console.log("요청이 성공적으로 처리되었습니다.");
location.reload()
},
error: function (request, status, error) {
console.log("addLike AJAX 에러 발생");
console.log("상태코드 : " + request.status);
},
});
} // else끝
}
addLikeDiv.addEventListener("click", addLike);
이제 거의 다 완성이 됐다
그럼 최종적으로
글목록에서 좋아요 갯수 보여주기
최고의 난관을 맞이하게 되는데......
는 밑에를 참고해주세요!
스프링레거시 글목록에 좋아요갯수 표시하기
처음엔 깊게 생각하지않고 글디테일에서 뿌려줬던것처럼 똑같은 방법으로 좋아요갯수를뿌려주면 되겠거니 했다 저렇게 냅다 카운트뿌려벌임 ㅎ 근데 안나오는것이다.. ${board.readCount} ${countLike}
k-kk.tistory.com
결론적으로
서브쿼리로 좋아요갯수를 가져오는게 아닌
board테이블에 있는 boardLike칼럼을 이용하여 매퍼를 두개 정의하고
좋아요추가삭제 dao부분을 조금 수정하는것을 택하였다.
<!--보드테이블에 좋아요 갯수 추가-->
<update id="boardLikePlus" parameterType="board">
UPDATE BOARD SET BOARD_LIKE = BOARD_LIKE + 1 WHERE BOARD_NO = #{boardNo}
</update>
<!--보드테이블에 좋아요 갯수 빼기-->
<update id="boardLikeMinus" parameterType="board">
UPDATE BOARD SET BOARD_LIKE = BOARD_LIKE - 1 WHERE BOARD_NO = #{boardNo}
</update>
매퍼에 추가해주고
public int addLike(BoardLikeVO likeVo) {
int addLike = sqlSession.insert("boardMapper.addLike", likeVo);
if(addLike > 0) {
sqlSession.update("boardMapper.boardLikePlus",likeVo.getBoardNo());
return addLike;
} else {
return -1;
}
}
public int removeLike(BoardLikeVO likeVo) {
int removeLike = sqlSession.delete("boardMapper.removeLike", likeVo);
if(removeLike > 0) {
sqlSession.update("boardMapper.boardLikeMinus",likeVo.getBoardNo());
return removeLike;
} else {
return -1;
}
}
dao부분을 수정만 해주면 끝난다.
<td class="heart">${board.boardLike}</td>
jsp부분에 추가해주면
최종적으로 잘 마무리 된것을 확인할수 있다.
좋아요기능이 많이 어려울거라고 생각했는데
생각보다 쉬워서 놀랬다.
로직도 생각보다 많이 단순하고.
조금 더 시간이 된다면
내가 쓴 글에는 좋아요를 할수없게도 추가하고싶다.