ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [무한댓글 게시판] 6. 조회수 / 좋아요
    Spring Boot 2024. 2. 22. 15:37

    조회수

    게시글의 상세페이지로  이동하는 동시에 조회수가 올라가야하는 거니까 게시글 상세 이동 메서드에 로직을 추가해줬다.

    동영상 시연

    좋아요

    좋아요 기능구현을 하기 위해 좋아요의 상태를 담기위해 따로 테이블이 필요할 것 같아서 likes 테이블 설계를 하고 테이브블 생성을 해주었다.

     

    create table likes(
       useremail varchar(25),
        board_id int,
        PRIMARY KEY (useremail, board_id)
    );

     

    likes 테이블은 단일 식별자가 아닌 user 테이블의 PK useremail과 board 테이블의 PK board_id 값을 Likes 테이블을 복합키로 설정해주었다.

     

    Likes.java

    Likes entity

     

    package com.se.social.entity;
    
    import java.io.Serializable;
    
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.IdClass;
    import javax.persistence.JoinColumn;
    import javax.persistence.ManyToOne;
    import javax.persistence.Table;
    import javax.persistence.Transient;
    
    import com.se.social.domain.LikesId;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Entity
    @Table(name = "likes")
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @IdClass(LikesId.class)
    public class Likes implements Serializable {
    
    
        @Id
        private String useremail;
    
        @Id
        @Column(name = "board_id")
        private int board_id;
    }

    LikesId.java

    LikesId domain

    package com.se.social.domain;
    
    import java.io.Serializable;
    
    import javax.persistence.Id;
    
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class LikesId implements Serializable {
    	private static final long serialVersionUID = 1L; // 기본값(초기화)
    	
    	private String useremail;
    
    	private int board_id;
    }

    LikesRepository.java

    LikesRepository도 생성해주었다.

    package com.se.social.repository;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.querydsl.QuerydslPredicateExecutor;
    
    import com.se.social.domain.LikesId;
    import com.se.social.entity.Likes;
    import com.se.social.entity.QLikes;
    import com.querydsl.jpa.impl.JPAQueryFactory;
    
    public interface LikesRepository extends JpaRepository<Likes, LikesId> {
    
    }

     

    LikesService.java

    package com.se.social.service;
    
    import com.se.social.domain.LikesId;
    import com.se.social.entity.Likes;
    
    public interface LikesService {
    	// selectDetail
    	public Likes selectDetail(LikesId likesId);
    
    	// insert, update
    	public int save(Likes entity);
    
    	// delete
    	public LikesId delete(LikesId likesId);
    
    
    }

    LikesService.java

    package com.se.social.service;
    
    import org.springframework.stereotype.Service;
    
    import com.se.social.domain.LikesId;
    import com.se.social.entity.Likes;
    import com.se.social.repository.LikesRepository;
    
    import lombok.RequiredArgsConstructor;
    
    @Service
    @RequiredArgsConstructor
    public class LikesServiceImpl implements LikesService {
    
    	private final LikesRepository repository;
    
    	// selectDetail
    	@Override
    	public Likes selectDetail(LikesId likesId) {
            return repository.findById(likesId).orElse(null);
        }
    	
    	// insert, update
    	@Override
    	public int save(Likes entity) {
    		repository.save(entity);
    		return entity.getBoard_id();
    	}
    
    	// delete
    	@Override
    	public LikesId delete(LikesId likesId) {
    		repository.deleteById(likesId);
    		return likesId;
    
    	}
    }

    LikesService와 LikesServiceImpl을 만들어주었고,

    여기서 주요하게 봐야할 점은 . selectDetail 메서드.

    selectDetail 메서드를 생성할때,Likes 타입으로 만들어주고 타입도 같은 타입으로 반환해준다.

    매개변수는 복합키를 만들어주었던 LikesId를 받아서 복합키를 찾아서 반환해준다. 없다면 null을 반환.

    BoardController.java

    // 좋아요
    	@PostMapping("/toggle")
    	@ResponseBody
    	public ResponseEntity<?> toggleLike(@RequestBody Likes entity) {
    	    try {
    	        LikesId id = new LikesId(entity.getUseremail(), entity.getBoard_id());
    	        Board boardEntity = boardService.selectDetail(entity.getBoard_id());
    
    	        if (boardEntity != null) {
    	            Likes existingLike = likesService.selectDetail(id);
    
    	            if (existingLike == null) {
    	                // 좋아요 추가
    	                boardEntity.setBoard_likes(boardEntity.getBoard_likes() + 1);
    	                likesService.save(entity);
    	                boardService.save(boardEntity); // 트랜잭션 처리
    
    	                System.out.println("좋아요 추가 완료. 현재 좋아요 개수: " + boardEntity.getBoard_likes());
    
    	                return ResponseEntity.ok().build();
    	            } else {
    	                // 좋아요 취소
    	                boardEntity.setBoard_likes(boardEntity.getBoard_likes() - 1);
    	                likesService.delete(id);
    	                boardService.save(boardEntity); // 트랜잭션 처리
    
    	                System.out.println("좋아요 취소 완료. 현재 좋아요 개수: " + boardEntity.getBoard_likes());
    
    	                return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
    	            }
    	        } else {
    	            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("해당 게시글을 찾을 수 없습니다.");
    	        }
    	    } catch (Exception e) {
    	        e.printStackTrace();
    	        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(false);
    	    }
    	}

     

    다음은 controller에 토글 방식으로 만들었던, 좋아요 기능.

    새로운 useremail과 board_id 값으로 좋아요를 누르면 likes 테이블에 데이터 추가,

    또 같은 useremail과 board_id 값으로 좋아요를 누른 상태에서 한번더 누르게 된다면 likes 테이블에서 데이터가 제거 

    ⮕ likes 테이블을 복합키로 구성한 이유

     

    BoardDetail.jsp

    <div class="likes">
    			<span id="likeButton" style="cursor:pointer;" onclick="toggleLikes(${requestScope.boardDetail.board_id},'${sessionScope.loginUser.useremail}')">❤︎</span>
    			<span id="likeCount">${requestScope.boardDetail.board_likes}</span>
    		</div>

    onclick을 추가해서 비동기 방식으로 js를 호출을 해주었다.

    toggleLikes 함수에 매개변수로는 likes 테이블에 필요한 값. 

    아까 복합키로 지정해둔 값들을 파라미터 값으로 전달해주었다. 아래 두 값.

    ${requestScope.boardDetail.board_id},'${sessionScope.loginUser.useremail}'

    useremail은 string 타입이므로 '' 싱글쿼테이션으로 묶어서 전달해주어야한다.

    Board.js

    function toggleLikes(board_id, useremail) {
    	let url = "/board/toggle";
    
    	axios.post(url, {
    		useremail: useremail,
    		board_id: parseInt(board_id)
    	}, { headers: { 'Content-Type': 'application/json' }  }
    
    	).then(response => {
    		let likeCountElement = document.getElementById('likeCount');
    		let currentLikeCount = parseInt(likeCountElement.textContent);
    
    		if (response.status === 200) {
    			likeCountElement.textContent = currentLikeCount + 1; // 좋아요 추가
    		} else if (response.status === 204) {
    			likeCountElement.textContent = currentLikeCount - 1; // 좋아요 삭제
    		}
    
    
    	}).catch(err => {
    		if (err.response && err.response.status === 502) {
    			alert("[삭제 오류]" + err.response.data);
    			alert("[시스템 오류]" + err.message);
    		}
    	});
    
    }

    js파일에서는 axios로 값을 넘겨주는 방식을 이용하였다.

     

    동영상 시연

Designed by Tistory.