Spring Boot Board Project_20 게시글 좋아요

송지윤·2024년 4월 24일
0

Spring Framework

목록 보기
53/65

좋아요

1. DB 샘플 데이터 추가

/* 좋아요 테이블(BOARD_LIKE) 샘플 데이터 추가 */
INSERT INTO "BOARD_LIKE"
VALUES(1, 2001); -- 1번 회원이 1998번 글에 좋아요를 클릭함

COMMIT;

SELECT * FROM BOARD_LIKE;

현재 로그인한 회원이 게시글 좋아요를 눌렀는지 안 눌렀는지 COUNT (다시 한번 체크시 DELETE)
좋아요 여부 확인 (1 : O / 0 : X)

SELECT COUNT(*) FROM BOARD_LIKE
WHERE MEMBER_NO = 1
AND BOARD_NO = 2001;

2. 게시글 상세 조회 Service 호출 할 때 좋아요 표시된 것도 조회해서 보여줘야함

매개변수에 Session scope에 올라와있는 loginMember 추가

Spring 스펙 올라가면서 안 써도 됨
클래스 위에 @SessionAttributes({"loginMember"})

BoardController

	@GetMapping("{boardCode:[0-9]+}/{boardNo:[0-9]+}")
	public String boardDetail(@PathVariable("boardCode") int boardCode,
			@PathVariable("boardNo") int boardNo,
			Model model,
			RedirectAttributes ra,
			@SessionAttribute(value="loginMember", required=false) Member loginMember) {

@SessionAttribute(value="loginMember", required=false)

  • @SessionAttribute : Session 에서 속성 값 얻어오기
  • value = "loginMember" : 속성의 key 값 loginMember
  • required = false : 필수 X (없어도 오류 X)
    -> 해당 속성 값이 없으면 null 반환

로그인한 상태에서 게시글 들어갔을 때 내가 누른 좋아요면 표시되게 Controller 에 memberNo 세팅

		// 로그인 상태인 경우에만 memberNo 추가
		if(loginMember != null) {
			map.put("memberNo", loginMember.getMemberNo());
		}

3. Controller 에 내용 추가됨에 따라 Board 클래스, board-mapper.xml 구문 추가

board-mapper.xml selectOne select 문

			 (SELECT COUNT(*)
			 FROM BOARD_LIKE
			 WHERE MEMBER_NO = #{memberNo}
			 AND BOARD_NO = #{boardNo}) LIKE_CHECK
	<select id="selectOne" resultMap="board_rm">
		SELECT BOARD_NO, BOARD_TITLE, BOARD_CONTENT, BOARD_CODE, READ_COUNT,
			MEMBER_NO, MEMBER_NICKNAME, PROFILE_IMG,
			TO_CHAR(BOARD_WRITE_DATE, 'YYYY"년" MM"월" DD"일" HH24:MI:SS') BOARD_WRITE_DATE, 
			TO_CHAR(BOARD_UPDATE_DATE, 'YYYY"년" MM"월" DD"일" HH24:MI:SS') BOARD_UPDATE_DATE,
			(SELECT COUNT(*)
			 FROM "BOARD_LIKE"
			 WHERE BOARD_NO = #{boardNo}) LIKE_COUNT,
			(SELECT IMG_PATH || IMG_RENAME
			 FROM "BOARD_IMG"
			 WHERE BOARD_NO = #{boardNo}
			 AND   IMG_ORDER = 0) THUMBNAIL,
			 (SELECT COUNT(*)
			 FROM BOARD_LIKE
			 WHERE MEMBER_NO = #{memberNo}
			 AND BOARD_NO = #{boardNo}) LIKE_CHECK
		FROM "BOARD"
		JOIN "MEMBER" USING(MEMBER_NO)
		WHERE BOARD_DEL_FL = 'N'
		AND BOARD_CODE = #{boardCode}
		AND BOARD_NO = #{boardNo}
	</select>

Board DTO 에 LIKE_CHECK 라는 필드 없음 만들어줘야함

Board 클래스

	// 좋아요 여부 확인
	private int likeCheck;

4. html에 결과값 보여주기

boardDetail.html

                        <!-- 비동기로 좋아요 누를 때 동작 (4/22 월요일 예정) -->
                        <!-- 좋아요 누른적이 있으면 fa-solid, 없으면 fa-regular 클래스 추가 -->
                        <i class="fa-heart" id="boardLike"
                            th:classappend="*{likeCheck == 1} ? fa-solid : fa-regular"></i>

브라우저에서 로그인한 회원이 좋아요 취소할 수 있게 비동기 요청

좋아요 버튼(하트) 클릭 시 비동기로 좋아요 INSERT/DELETE

Thymeleaf 코드 해석 순서
1. th: 코드(java) + Spring EL
2. html 코드 (+ css, js)

1) 로그인한 회원 번호 준비
--> session 에서 얻어오기 (session은 서버에서 관리하기 때문에 JS에서 바로 얻어올 방법 없음)
2) 현재 게시글 번호 준비
3) 좋아요 여부 준비

1. java 에서 넘겨준 값 html 에서 js 로 넘겨주고 js 연결

boardDetail.html

    <script th:inline="javascript">

        // - loginMember 가 null 인 경우 null 반환
        const loginMemberNo = /*[[${session.loginMember?.memberNo}]]*/ "로그인 회원 번호";

        // 현재 게시글 번호를 전역 변수로 저장
        const boardNo = /*[[${board.boardNo}]]*/ "게시글 번호";

        // 현재 게시글 좋아요 여부를 전역 변수로 저장 (값이 변함)
        let likeCheck = /*[[${board.likeCheck}]]*/ "좋아요 여부";
    </script>

    <script src="/js/board/boardDetail.js"></script>

2. js 에서 좋아요 클릭했을 때 어떻게 되야할지 작성

좋아요 클릭했을 때 로그인 상태가 아닌 경우 호출한 곳으로 돌려보내고 html 에서 js에 setting 해서 보내준 값을 java 에 보내기 위해 js Object로 묶어서 보내주기 fetch로 보내주기
돌려받을 값에 대한 처리

// 1. #boardLike 가 클릭 되었을 때
document.querySelector("#boardLike").addEventListener("click", e => {

    // 2. 로그인 상태가 아닌 경우 동작 X
    if(loginMemberNo == null) {
        alert("로그인 후 이용해주세요");
        return;
    }

    // 3. 준비된 3개의 변수를 객체로 저장 (JSON 변환 예정)
    const obj = {
        "memberNo"  : loginMemberNo,
        "boardNo"   : boardNo,
        "likeCheck" : likeCheck
    };
  
    // 4. 좋아요 INSERT/DELETE 비동기 요청
    fetch("/board/like", {
        method : "POST",
        headers : {"Content-Type" : "application/json"},
        body : JSON.stringify(obj)
    })
    .then(resp => resp.text()) // 반환 결과 text 형태로 변환
    .then(count => {

        // 잘못됐을 때 -1 들어옴
        if(count == -1) {
            console.log("좋아요 처리 실패");
            return;
        }

        // 5. likeCheck 값 0 <-> 1 변환
        // -> 클릭 될 때 마다 INSERT/DELETE 동작을 번갈아 가면서 하게끔
        likeCheck = likeCheck == 0 ? 1 : 0;

        // 6. 하트를 채웠다/비웠다 바꾸기 toggle
        e.target.classList.toggle("fa-regular");
        e.target.classList.toggle("fa-solid");

        // 7. 게시글 좋아요 수 수정 nextSibling 이 좋아요 개수 넣어둔 span 태그
        e.target.nextElementSibling.innerText = count;
    })
});

3. 비동기 요청 받아줄 Controller 에서 바로 Service 호출 후 값 돌려받기

BoardController

	/** 게시글 좋아요 체크/해제
	 * @param map
	 * @return count
	 */
	@ResponseBody
	@PostMapping("like")
	public int boardLike(@RequestBody Map<String, Integer> map) {
		return service.boardLike(map);
	}

4. ServiceImpl 에서 map 에 세팅된 값으로 mapper 호출

BoardServiceImpl

	@Override
	public int boardLike(Map<String, Integer> map) {

		int result = 0;
		
		// 1. 좋아요가 체크된 상태인 경우 (likeCheck == 1)
		// -> BOARD_LIKE 테이블에 DELETE
		if(map.get("likeCheck") == 1) {
			result = mapper.deleteBoardLike(map);
		} else {
			// 2. 좋아요가 해제된 상태인 경우 (likeCheck == 0)
			// -> BOARD_LIKE 테이블에 INSERT
			result = mapper.insertBoardLike(map);
		}

5. mapper.xml 에서 SQL 작성

	<!-- 좋아요 해제 -->
	<delete id="deleteBoardLike">
		DELETE FROM BOARD_LIKE
		WHERE MEMBER_NO = #{memberNo}
		AND BOARD_NO = #{boardNo}
	</delete>
	
	<!-- 좋아요 체크 -->
	<insert id="insertBoardLike">
		INSERT INTO BOARD_LIKE(MEMBER_NO, BOARD_NO)
		VALUES(#{memberNo}, #{boardNo})
	</insert>

6. Service mapper 갔다가 돌아온 반환 값 가지고 다시 mapper 호출

serviceImpl

위에 다 안 걸리면 잘못된 거라서 -1 return

		// 3. 다시 해당 게시글의 좋아요 개수 조회해서 반환
		if(result > 0) {
			return mapper.selectLikeCount(map.get("boardNo"));
		}
        
        return -1;
    }

BoardMapper 인터페이스

	/** 게시글 좋아요 개수 조회
	 * @param integer
	 * @return result
	 */
	int selectLikeCount(int temp);

mapper.xml

	<!-- 게시글 좋아요 수 조회 -->
	<select id="selectLikeCount">
		SELECT COUNT(*)
		FROM BOARD_LIKE
		WHERE BOARD_NO = #{boardNo}
	</select>

7. Controller 에서 js까지 값 전달 됨 html 에서 확인하기

0개의 댓글