국비 90 - 좋아요 처리 기능 (스프링)

냐아암·2023년 8월 23일
0

국비

목록 보기
105/114

좋아요 단순 조회는 전 글에 작성되어 있다.

<%-- 누가(로그인한 회원 번호) 어떤 게시글(현재 게시글 번호) 좋아요를 클릭/취소
         
         로그인한 회원 번호 얻어오기
         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("예외 발생")}); // 예외 발생 시 처리하는 부분
});

Controller

🔑 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);
	}

Service

/** 좋아요 처리 서비스
	 * @param paramMap
	 * @return count
	 */
	int like(Map<String, Integer> paramMap);

🔑 좋아요가 눌러져있을 경우(check==1), delete를 실행하고, 아닌 경우 insert를 실행한다.
이후, 좋아요의 개수를 다시 조회한다 (동시에 좋아요를 누르는 경우 고려)

ServiceImpl

// 좋아요 처리 서비스
	@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;
	}

DAO

/** 좋아요 테이블 삽입
	 * @param paramMap
	 * @return result
	 */
	public int insertBoardLike(Map<String, Integer> paramMap) {
		return sqlSession.insert("boardMapper.insertBoardLike", paramMap);
	}

sql

<!-- 좋아요 삽입 -->
	<insert id="insertBoardLike">
		INSERT INTO BOARD_LIKE VALUES(${boardNo}, ${memberNo})
	</insert>

DAO

/** 좋아요 테이블 삭제
	 * @param paramMap
	 * @return result
	 */
	public int deleteBoardLike(Map<String, Integer> paramMap) {
		return sqlSession.delete("boardMapper.deleteBoardLike", paramMap);
	}

sql

<!-- 좋아요 삭제 -->
	<delete id="deleteBoardLike">
		DELETE FROM BOARD_LIKE WHERE BOARD_NO = ${boardNo} AND MEMBER_NO = ${memberNo}
	</delete>

DAO

/** 좋아요 개수 조회
	 * @param boardNo
	 * @return count
	 */
	public int CountBoardLike(Integer boardNo) {
		return sqlSession.selectOne("boardMapper.CountBoardLike", boardNo);
	}

sql

<!-- 좋아요 개수 조회 -->
	<select id="CountBoardLike" resultType="_int">
		SELECT COUNT(*) FROM BOARD_LIKE
		WHERE BOARD_NO = ${boardNo}
	</select>
profile
개발 일지

0개의 댓글