좋아요 단순 조회는 전 글에 작성되어 있다.
<%-- 누가(로그인한 회원 번호) 어떤 게시글(현재 게시글 번호) 좋아요를 클릭/취소
로그인한 회원 번호 얻어오기
1) ajax로 session에 있는 loginMember와 memberNo를 반환
2) HTML 요소에 로그인한 회원의 번호를 숨겨놓고 JS로 얻어오기
3) jsp파일 제일 위에 있는 script 태그에 JS + EL 이용해서 전역변수로 선언해두기
--%>
<script>
// JSP에서 작성 가능한 언어/라이브러리
// -> html, css, js, java, EL, JSTL
// JSP 해석 우선 순위 : Java/EL/JSTL > HTML,CSS,JS
// 게시글 번호 전역변수로 선언
const boardNo = "${board.boardNo}";
// 로그인한 회원 번호 전역변수로 선언
// 작성한 EL 구문이 null일 경우 빈칸으로 출력되어 변수에 값이 대입되지 않는 문제가 발생할 수 있음
// -> 양 끝에 쌍따옴표를 넣어서 빈값이라도 빈 문자열이 들어갈 수 있게 한다.
// --> EL 구문의 해석순서 우선 순위 ! ! ! (+ EL은 값이 null이어도 ""(빈문자열)로 출력)
const loginMemberNo = "${loginMember.memberNo}";
// console.log(boardNo);
// console.log(memberNo);
</script>
📍 contains("클래스명") : 클래스가 있으면 true, 없으면 false
📍 toggle() : class가 있으면 없애고, 없으면 추가
🔑 좋아요 체크 여부는 check라는 변수에 담아 controller로 보낸다.
🔑 ajax 서버로 데이터를 제출할 때 데이터가 여러 개인 경우 JS 객체를 생성해 보낸다.
// 좋아요 버튼이 클릭되었을 때
const boardLike = document.getElementById("boardLike");
boardLike.addEventListener("click" , e => {
// 로그인 여부 검사
if(loginMemberNo == ""){
alert("로그인 후 이용해주세요");
return;
}
let check; // 기존에 좋아요 X(빈 하트) : 0
// 기존에 좋아요 O(꽉 찬 하트) : 1
// contains("클래스명") : 클래스가 있으면 true, 없으면 false
if(e.target.classList.contains("fa-regular")){ // 빈 하트 (좋아요 X)
check = 0;
} else { // 꽉 찬 하트 (좋아요 O)
check = 1;
}
// ajax로 서버로 제출할 파라미터를 모아둔 JS 객체
const data = { "boardNo" : boardNo,
"memberNo" : loginMemberNo,
"check" : check}; // JS 객체
// ajax 코드 작성
fetch("/board/like", {
method : "POST",
headers : {"Content-Type" : "application/json"},
body : JSON.stringify(data)
})
.then(resp => resp.text()) // 응답 객체를 필요한 형태로 파싱하여 리턴
.then(count => { // 파싱된 데이터를 받아서 처리하는 코드 작성
console.log("count : " + count);
if(count == -1){ // insert 혹은 delete 실패
console.log("좋아요 처리 실패");
return;
}
// toggle() : class가 있으면 없애고, 없으면 추가하고
e.target.classList.toggle("fa-regular");
e.target.classList.toggle("fa-solid");
// 현재 게시글의 좋아요 수를 화면에 출력
e.target.nextElementSibling.innerText = count;
})
.catch( err =>{console.log(err); console.log("예외 발생")}); // 예외 발생 시 처리하는 부분
});
🔑 BoardController 안에 이미
@GetMapping("/{boardCode}")
가 매핑되어 있다 -> /like 요청을 제대로 처리하기 위한 정규표현식을 작성해야 함
📍 @PathVariable 사용 시 문제점과 해결 방법
- 문제점 : 요청 주소와 @PathVariable로 가져다 쓸 주소의 레벨이 같다면 구분하지 않고 모두 매핑되는 문제가 발생 -> 요청을 했는데 원하는 메소드 실행 안 됨
- 해결 방법 : @PathVariable 지정 시 정규 표현식 사용
{키 : 정규표현식}
@PostMapping("/like")
@ResponseBody // 반환되는 값이 비동기 요청한 곳으로 돌아가게 함
public int like(@RequestBody Map<String, Integer> paramMap) {
// System.out.println(paramMap);
return service.like(paramMap);
}
/** 좋아요 처리 서비스
* @param paramMap
* @return count
*/
int like(Map<String, Integer> paramMap);
🔑 좋아요가 눌러져있을 경우(check==1), delete를 실행하고, 아닌 경우 insert를 실행한다.
이후, 좋아요의 개수를 다시 조회한다 (동시에 좋아요를 누르는 경우 고려)
// 좋아요 처리 서비스
@Transactional(rollbackFor = {Exception.class})
@Override
public int like(Map<String, Integer> paramMap) {
int result = 0;
if(paramMap.get("check") == 0) { // 좋아요 상태가 X
// BOARD_LIKE 테이블 INSERT
result = dao.insertBoardLike(paramMap);
} else { // 좋아요 상태
// BOARD_LIKE 테이블 DELETE
result = dao.deleteBoardLike(paramMap);
}
// SQL 수행 결과가 0 == DB 또는 파라미터에 문제가 있다.
// 1) 에러를 나타내는 임의의 값 반환(-1)
if(result == 0) return -1;
// 현재 게시글의 좋아요 개수 조회
int count = dao.CountBoardLike(paramMap.get("boardNo"));
return count;
}
/** 좋아요 테이블 삽입
* @param paramMap
* @return result
*/
public int insertBoardLike(Map<String, Integer> paramMap) {
return sqlSession.insert("boardMapper.insertBoardLike", paramMap);
}
<!-- 좋아요 삽입 -->
<insert id="insertBoardLike">
INSERT INTO BOARD_LIKE VALUES(${boardNo}, ${memberNo})
</insert>
/** 좋아요 테이블 삭제
* @param paramMap
* @return result
*/
public int deleteBoardLike(Map<String, Integer> paramMap) {
return sqlSession.delete("boardMapper.deleteBoardLike", paramMap);
}
<!-- 좋아요 삭제 -->
<delete id="deleteBoardLike">
DELETE FROM BOARD_LIKE WHERE BOARD_NO = ${boardNo} AND MEMBER_NO = ${memberNo}
</delete>
/** 좋아요 개수 조회
* @param boardNo
* @return count
*/
public int CountBoardLike(Integer boardNo) {
return sqlSession.selectOne("boardMapper.CountBoardLike", boardNo);
}
<!-- 좋아요 개수 조회 -->
<select id="CountBoardLike" resultType="_int">
SELECT COUNT(*) FROM BOARD_LIKE
WHERE BOARD_NO = ${boardNo}
</select>