게시물 상세 조회할 때 로그인 유저가 작성한 게시물이 아닌 경우에만 좋아요 버튼이 활성화된다.
로그인 유저가 좋아요 하지 않은 게시물일 때 좋아요 를 누를 수 있도록 한다!
좋아요한 게시물이라면 좋아요를 취소할 수 있도록 한다.
빨간 하트
그림이 보이고 좋아요한 게시물이 아니라면 빈 하트
그림이 보인다.like
변수를 통해 파악한다. boolean like = false; // 비로그인 유저라면 무조건 like = false;
if(user != null){
// 로그인한 사용자라면
/* member_id 반환 */
Long member_id = user.getMember().getId();
...
/* 현재 로그인한 유저가 이 게시물을 좋아요 했는지 안 했는지 여부 확인 */
like = postService.findLike(post_id, member_id);
}
model.addAttribute("like", like);
/** 글 좋아요 확인 **/
@Override
public boolean findLike(Long post_id, Long member_id) {
return memberLikePostRepository.existsByPost_IdAndMember_Id(post_id, member_id);
}
/** 유저가 특정 게시물을 좋아요 했는지 확인 **/
boolean existsByPost_IdAndMember_Id(Long post_id, Long member_id);
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
뷰 화면에서 좋아요를 눌렀을 때 처리는 아래와 같다.
로그인 유저가 좋아요하지 않은 게시물이라면 빈 하트를 보여주고 좋아요를 누를 수 있도록 한다.
비로그인 유저가 좋아요를 클릭하면 로그인하라는 메시지 알림창이 나오도록 한다
id="likeImg"
, id="loginCheck"
속성을 부여한다.th:value
속성을 이용해 서버로부터 like
boolean 변수를 받아와 유저의 좋아요 여부를 판단한다.sec:authorize-expr
을 이용하여 로그인 여부 판단th:unless="${#strings.equals(post.getMember_id(),login_id)}"
이용하여 현재 로그인 유저와 게시글 유저가 동일하지 않은지 판단<div sec:authorize-expr="isAuthenticated()" or th:unless="${#strings.equals(post.getMember_id(),login_id)}" class="d-block">
<!-- 로그인 유저와 작성자가 동일하지 않다면 -->
<!-- 좋아요 -->
<input type="hidden" id="like_check" th:value="${like}">
<img th:id="likeImg" src="/assets/img/like_empty.png" alt="" width="30px"
height="30px">
<span th:text="${post.likeCount}"></span>
</div>
<div sec:authorize-expr="!isAuthenticated()">
<!-- 로그인하지 않은 유저라면 -->
<img id="loginCheck" src="/assets/img/like_empty.png" alt="" width="30px"
height="30px">
<span th:text="${post.likeCount}"></span>
</div>
<script>
const clickLikeUrl = "/assets/img/like_click.png";
const emptyLikeUrl = "/assets/img/like_empty.png";
/** 좋아요 유무에 따라 하트 그림 다르게 보여줌 **/
//브라우저가 웹 문서를 읽기 시작하고 DOM이 생성되면 실행되는 메소드
$(function(){
// 현재 로그인한 유저가 해당 게시물을 좋아요 했다면 likeVal = true,
// 좋아요하지 않았다면 false
let likeVal = $('#like_check').val(); // 데이터가 있으면 true
const likeImg = $('#likeImg');
console.log("likeVal : " + likeVal);
if(likeVal === 'true'){
// 데이터가 존재하면 화면에 채워진 하트 보여줌
$('#likeImg').attr("src", clickLikeUrl);
} else if(likeVal === 'false'){
// 데이터가 없으면 화면에 빈 하트 보여줌
$('#likeImg').attr("src", emptyLikeUrl);
}
});
/** 좋아요 클릭 시 실행 **/
$('#likeImg').click(function() {
const postId = $('#postId').val();
const likeVal = $('#like_check').val();
console.log(likeVal);
if (likeVal === 'true') {
const con_check = confirm("현재 게시물 추천을 취소하시겠습니까?")
if (con_check) {
console.log("추천 취소 진입");
$.ajax({
type: 'POST',
url: '/rest/community/post/like/' + postId,
contentType: 'application/json; charset=utf-8'
}).done(function () {
$('#likeImg').attr("src", emptyLikeUrl);
location.reload();
}).fail(function (error) {
alert(JSON.stringify(error));
})
}
} else if(likeVal === 'false'){
const con_check = confirm("현재 게시물을 추천하시겠습니까?");
if (con_check) {
console.log("추천 진입");
$.ajax({
type: 'POST',
url: '/rest/community/post/like/' + postId,
contentType: 'application/json; charset=utf-8'
}).done(function () {
$('#likeImg').attr("src", clickLikeUrl);
location.reload();
}).fail(function (error) {
alert(JSON.stringify(error));
})
}
}
});
/** 로그인하지 않은 유저가 좋아요 누를 때 **/
$('#loginCheck').click(function(){
alert("로그인 후 이용할 수 있습니다.");
});
</script>
rest/community/like/{post_id}
url에 post
메소드로 통신하여 좋아요 여부에 따라 좋아요 저장/취소 /** 글 좋아요 **/
@PostMapping("/like/{post_id}")
public boolean like(@PathVariable Long post_id, @AuthenticationPrincipal UserAdapter user){
Long member_id = user.getMemberDto().getId();
// 저장 true, 삭제 false
boolean result = postService.saveLike(post_id, member_id);
return result;
}
PostService
의 saveLike
메서드 호출하여 좋아요 저장/취소(삭제) /** 글 좋아요 **/
@Override
public boolean saveLike(Long post_id, Long member_id) {
/** 로그인한 유저가 해당 게시물을 좋아요 했는지 안 했는지 확인 **/
if(!findLike(post_id, member_id)){
/* 좋아요 하지 않은 게시물이면 좋아요 추가, true 반환 */
Member member = memberRepository.findById(member_id).orElseThrow(() ->
new IllegalArgumentException("해당 회원이 존재하지 않습니다."));
Post post = postRepository.findById(post_id).orElseThrow(() ->
new IllegalArgumentException("해당 게시물이 존재하지 않습니다."));
/* 좋아요 엔티티 생성 */
MemberLikePost memberLikePost = new MemberLikePost(member, post);
memberLikePostRepository.save(memberLikePost);
postRepository.plusLike(post_id);
return true;
} else {
/* 좋아요 한 게시물이면 좋아요 삭제, false 반환 */
memberLikePostRepository.deleteByPost_IdAndMember_Id(post_id, member_id);
postRepository.minusLike(post_id);
return false;
}
}
MemberLikePost
객체를 생성하여 리포지토리에 저장plusLike
메서드 호출하여 좋아요 값 + 1MemberLikePostRepository
에서 deleteByPost_IdAndMember_Id
메서드를 호출하여 해당 MemberLikePost
객체 삭제minusLike
메서드 호출하여 좋아요 값 - 1 /** 좋아요 추가 **/
@Modifying
@Query(value = "update Post post set post.likeCount = post.likeCount + 1 where post.id = :post_id")
int plusLike(@Param("post_id") Long post_id);
/** 좋아요 삭제 **/
@Modifying
@Query(value = "update Post post set post.likeCount = post.likeCount - 1 where post.id = :post_id")
int minusLike(@Param("post_id") Long post_id);
@Query
@Modifying
@Modifying
옵션을 사용하면 query가 나가고 난 후 clear 과정을 자동으로 해준다. 따라서 따로 flush clear 하지 않아도 됨