[게시판] 게시글 좋아요 / 좋아요 취소

2023. 1. 25. 16:19프로젝트/라이프 챌린지

728x90
SMALL

추가적인 기능 요소인 게시글 좋아요 기능을 만들어줄 것이다.

 


PostController

// 게시글 좋아요
@PostMapping("/post/like/{post_id}")
public ResponseEntity<ResponseBody> postLike(HttpServletRequest request, @PathVariable Long post_id){
    log.info("게시글 좋아요 - 좋아요를 누른 유저 : {}, 좋아요한 게시글 : {}", jwtTokenProvider.getMemberFromAuthentication().getNickname(), post_id);

    return postService.postLike(request, post_id);
}

좋아요 api를 만들어준다.

  • 좋아요한 정보가 저장될 것이므로 PostMapping 으로 method 타입을 지정해준다.
  • Service 단에 넘길 인자값은 HttpServletRequest, 좋아요할 게시글의 post_id.

 

 

 

MemberLikePost

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;


@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class MemberLikePost {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private Long memberlikepost_id;

    @JsonIgnore
    @JoinColumn(name = "member_pk_id")
    @ManyToOne(fetch = FetchType.LAZY)
    private Member member;

    @JsonIgnore
    @JoinColumn(name = "post_pk_id")
    @ManyToOne(fetch = FetchType.LAZY)
    private Post post;
}

좋아요와 좋아요 취소를 구분하기위해 좋아요 이력을 저장한 엔티티를 만들어준다.

  • Member 객체를 ManyToOne 으로 지정하여 속성으로 만들어준다. 유저 한 명당 여러 게시글을 좋아요할 수 있기 때문에 ManyToOne으로 지정해주었다. 
    • @JoinColumn을 통해 member_pk_id(member 고유 id)로 지정하여 넣겠다고 명시해준다.
    • FetchType.LAZY 로 지정하여 Post까지 한번에 조회될 수 있는 문제를 예방한다. (N+1 문제)
  • Post 객체를 ManyToOne 으로 지정하여 속성으로 만들어준다. 한 게시글 당 여러명이 좋아요를 할 수 있기 때문이다.
    • @JoinColumn을 통해 posT_pk_id(post 고유 id)로 지정하여 넣겠다고 명시해준다.
    • FetchType.LAZY 로 지정하여 Post까지 한번에 조회될 수 있는 문제를 예방한다. (N+1 문제)

 

 

 

Member

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.*;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
@Entity
public class Member extends Timestamped {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private Long member_pk_id;

    @Column(nullable = false)
    private String member_id;

    @Column(nullable = false)
    private String password;

    @Column(nullable = false)
    private String nickname;

    @Column(nullable = false)
    private String address;

    @ElementCollection(fetch = FetchType.EAGER)
    @Builder.Default
    private List<String> roles = new ArrayList<>();

    @JsonIgnore
    @OneToMany(mappedBy = "member", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Post> posts;

    @JsonIgnore
    @OneToMany(mappedBy = "member", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<MemberLikePost> likePosts;

}

MemberLikePost 엔티티와 연관관계를 맺었으니 MemberLikePost에 대한 필드값을 추가 생성해준다.

  • 일대다(OneToMany) 연관관계를 맺었으므로 MemberLikePost는 List로 만들어야한다.
  • @JsonIgnore를 지정함으로서, Member 객체를 조회할 때 MemberLikePost는 조회될 수 없게끔 무시할 수 있도록 만든다.
  • 일대다 관계(@OneToMany)를 지정한다.
  • mappedBy를 통해 member 객체에 매핑한다고 명시.
  • FetchType.LAZY를 통해 한번에 조회되는 이슈를 방지.
  • cascade를 통해 member 가 삭제될 경우 해당되는 MemberLikePost 데이터들도 함께 삭제됨을 명시.
  • orphanRemoval을 통해 고아 객체가 발생될경우 삭제처리됨을 명시.

 

 

Post

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.util.List;

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Post extends Timestamped{

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private Long post_id;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String content;

    @Column(nullable = false)
    private Integer viewcnt;

    @Column(nullable = false)
    private Integer likecnt;

    @JsonIgnore
    @JoinColumn(name = "member_pk_id")
    @ManyToOne(fetch = FetchType.LAZY)
    private Member member;

    @JsonIgnore
    @OneToMany(mappedBy = "post", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<MemberLikePost> likePosts;

}

Post 엔티티에도 MemberLikePost 엔티티와 연관관계를 맺었으니 MemberLikePost에 대한 필드값을 추가 생성해준다.

  • 일대다(OneToMany) 연관관계를 맺었으므로 MemberLikePost는 List로 만들어야한다.
  • @JsonIgnore를 지정함으로서, Post 객체를 조회할 때 MemberLikePost는 조회될 수 없게끔 무시할 수 있도록 만든다.
  • 일대다 관계(@OneToMany)를 지정한다.
  • mappedBy를 통해 post 객체에 매핑한다고 명시.
  • FetchType.LAZY를 통해 한번에 조회되는 이슈를 방지.
  • cascade를 통해 post 가 삭제될 경우 해당되는 MemberLikePost 데이터들도 함께 삭제됨을 명시.
  • orphanRemoval을 통해 고아 객체가 발생될경우 삭제처리됨을 명시.

 

 

 

PostService

// 게시글 좋아요
@Transactional
public ResponseEntity<ResponseBody> postLike(HttpServletRequest request, Long post_id){

    // 유저 검증
    Member auth_member = checkAuthentication(request);

    // 좋아요할 게시글 조회
    Post like_post = queryFactory
            .selectFrom(post)
            .where(post.post_id.eq(post_id))
            .fetchOne();

    // 좋아요가 되었는지 좋아요가 취소되었는지 알기위한 알림 문구
    String notice = "";

    // 좋아요할 게시글에 이미 좋아요 처리가 되어있는지 확인
    if(queryFactory
            .selectFrom(memberLikePost)
            .where(memberLikePost.member.eq(auth_member).and(memberLikePost.post.eq(like_post)))
            .fetchOne() != null){
        // 좋아요가 이미 되어있을 경우 MemberLikePost 에서 좋아요 삭제처리
        queryFactory
                .delete(memberLikePost)
                .where(memberLikePost.member.eq(auth_member).and(memberLikePost.post.eq(like_post)))
                .execute();

        // 좋아요 취소 시 notice에 문구 반영
        notice = "좋아요 취소";
    }else{
        // 유저가 게시글에 좋아요한 이력 저장
        MemberLikePost likepost = MemberLikePost.builder()
                .post(like_post)
                .member(auth_member)
                .build();

        memberLIkePostRepository.save(likepost);

        // 좋아요 시 notica에 문구 반영
        notice = "좋아요";
     }

    // 해당 게시글좋아요 수
    Long likeCnt = queryFactory
            .select(memberLikePost.count())
            .from(memberLikePost)
            .where(memberLikePost.post.eq(like_post))
            .fetchOne();

    // 게시글 likecnt 정보 업데이트
    queryFactory
            .update(post)
            .set(post.likecnt, Integer.parseInt(likeCnt.toString()))
            .where(post.post_id.eq(like_post.getPost_id()))
            .execute();

    return new ResponseEntity<>(new ResponseBody<>(StatusCode.OK.getStatusCode(), StatusCode.OK.getStatus(), notice), HttpStatus.OK);
}

좋아요 처리를 할 Service 로직을 만들어준다.

  • checkAuthentication 으로 유효한 유저 검증 처리.
  • 좋아요할 게시글 post 객체 불러오기.
  • 좋아요가 되었는지 좋아요 취소 처리가 되었는지 확인하기 위한 notice 변수 생성.
  • MemberLikPost 에 좋아요한 유저와 좋아요한 게시글 정보 이력이 저장되어있다면 delete 문으로 해당 이력 삭제 + notice에 "좋아요 취소" 문구 저장.
  • MemberLikPost 에 좋아요한 유저와 좋아요한 게시글 정보 이력이 저장되어있지않다면 MemberLikePost 에 이력 저장 + notice에 "좋아요" 문구 저장.
  • MemberLikePost 에서 해당 게시글에 대한 좋아요 수가 몇개인지 조회. 
  • 해당 post 객체에 likecnt 수정 업데이트. (좋아요면 +1, 좋아요 취소면 -1)
  • 좋아요 / 좋아요 취소 처리 확인은 반환되는 notice 변수로 확인

 

 

포스트맨으로 확인.

# 토큰을 넣어 좋아요 api 호출

 

# 좋아요 취소 처리

 

좋아요 api 를 한번 호출했을 때 정상적으로 좋아요 처리가 된 것을 확인할 수 있고, 두 번 호출하면 좋아요 취소 처리가 된 것을 확인할 수 있다.

 

728x90
반응형
LIST

'프로젝트 > 라이프 챌린지' 카테고리의 다른 글

[댓글] 댓글 수정  (0) 2023.01.28
[댓글] 댓글 작성  (0) 2023.01.28
[게시판] 게시글 전체 목록 조회  (0) 2023.01.25
[게시판] 게시글 조회  (0) 2023.01.25
[게시판] 게시글 삭제  (0) 2023.01.25