Skip to content

Commit

Permalink
Merge pull request #18 from Leets-Official/feat/#15/CRUD-기능-구현
Browse files Browse the repository at this point in the history
[Feat] #18 피드 CRUD  기능 구현
  • Loading branch information
seokjun01 authored Nov 5, 2024
2 parents b8c4668 + d5d696d commit 9ae6678
Show file tree
Hide file tree
Showing 21 changed files with 601 additions and 34 deletions.
4 changes: 1 addition & 3 deletions src/main/java/com/leets/X/domain/comment/domain/Comment.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
@Getter
public class Comment extends BaseTimeEntity {

@Id
Expand All @@ -24,9 +25,6 @@ public class Comment extends BaseTimeEntity {
@JoinColumn(name = "user_id") // user_id 컬럼을 통해 join을 하겠다
private User user;

@ManyToOne
@JoinColumn(name="post_id")
private Post post;

}

11 changes: 7 additions & 4 deletions src/main/java/com/leets/X/domain/image/domain/Image.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package com.leets.X.domain.image.domain;

import com.leets.X.domain.post.domain.Post;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.*;

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
@Getter
public class Image {

@Id
Expand All @@ -21,4 +20,8 @@ public class Image {

private String url;

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

}
51 changes: 33 additions & 18 deletions src/main/java/com/leets/X/domain/like/domain/Like.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,36 @@
package com.leets.X.domain.like.domain;
package com.leets.X.domain.like.domain;

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import com.leets.X.domain.post.domain.Post;
import com.leets.X.domain.user.domain.User;
import jakarta.persistence.*;
import lombok.*;

@Entity
// mysql 예약어이기 때문에 별도 지정
@Table(name = "likes")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class Like {
@Entity
// mysql 예약어이기 때문에 별도 지정
@Table(name = "likes")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
@Getter
public class Like {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "like_id")
private Long id;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "like_id")
private Long id;

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

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

// 게시물과 사용자 정보를 받는 생성자 추가
public Like(Post post, User user) {
this.post = post;
this.user = user;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.leets.X.domain.like.repository;

import com.leets.X.domain.like.domain.Like;
import com.leets.X.domain.post.domain.Post;
import com.leets.X.domain.user.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface LikeRepository extends JpaRepository<Like, Long> {
boolean existsByPostAndUser(Post post, User user); // 좋아요 여부 확인
void deleteByPostAndUser(Post post, User user); // 좋아요 삭제
long countByPost(Post post); // 특정 게시물의 좋아요 수 계산
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.leets.X.domain.post.controller;

import com.leets.X.domain.post.domain.Post;
import com.leets.X.domain.post.dto.request.PostRequestDTO;
import com.leets.X.domain.post.dto.response.PostResponseDto;
import com.leets.X.domain.post.service.PostService;
import com.leets.X.global.common.response.ResponseDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
//컨트롤러에서 ResponseDto만들게끔
@Tag(name = "POST")
@RestController
@RequestMapping("/api/v1/posts")
@RequiredArgsConstructor
public class PostController {

private final PostService postService;


@GetMapping("/{id}")
@Operation(summary = "게시물 ID로 조회")
public ResponseDto<PostResponseDto> getPost(@PathVariable Long id) {
PostResponseDto postResponseDto = postService.getPostResponse(id);
return ResponseDto.response(ResponseMessage.GET_POST_SUCCESS.getCode(), ResponseMessage.GET_POST_SUCCESS.getMessage(), postResponseDto);
}


@GetMapping("/likes")
@Operation(summary = "좋아요 수로 정렬한 게시물 조회")
public ResponseDto<List<PostResponseDto>> getPostsSortedByLikes() {
List<PostResponseDto> posts = postService.getPostsSortedByLikes();
return ResponseDto.response(ResponseMessage.GET_SORTED_BY_LIKES_SUCCESS.getCode(), ResponseMessage.GET_SORTED_BY_LIKES_SUCCESS.getMessage(), posts);
}


@GetMapping("/latest")
@Operation(summary = "최신 게시물 조회")
public ResponseDto<List<PostResponseDto>> getLatestPosts() {
List<PostResponseDto> posts = postService.getLatestPosts();
return ResponseDto.response(ResponseMessage.GET_LATEST_POST_SUCCESS.getCode(), ResponseMessage.GET_LATEST_POST_SUCCESS.getMessage(), posts);
}


@PostMapping("/post")
@Operation(summary = "글 생성")
public ResponseDto<PostResponseDto> createPost(@RequestBody PostRequestDTO postRequestDTO, @AuthenticationPrincipal String email) {
// 인증된 사용자의 이메일을 `@AuthenticationPrincipal`을 통해 주입받음
PostResponseDto postResponseDto = postService.createPost(postRequestDTO, email);
return ResponseDto.response(ResponseMessage.POST_SUCCESS.getCode(), ResponseMessage.POST_SUCCESS.getMessage(), postResponseDto);
}

@PostMapping("/{postId}/like")
@Operation(summary = "게시물에 좋아요 추가")
public ResponseDto<String> addLike(@PathVariable Long postId, @AuthenticationPrincipal String email) {
String responseMessage = postService.addLike(postId, email);
return ResponseDto.response(ResponseMessage.ADD_LIKE_SUCCESS.getCode(), responseMessage);
}


@DeleteMapping("/{postId}")
@Operation(summary = "게시물 삭제")
public ResponseDto<String> deletePost(@PathVariable Long postId, @AuthenticationPrincipal String email) {
String responseMessage = postService.deletePost(postId, email);
return ResponseDto.response(ResponseMessage.POST_DELETED_SUCCESS.getCode(), responseMessage);
}


@DeleteMapping("/{postId}/like")
@Operation(summary = "좋아요 취소")
public ResponseDto<String> cancelLike(@PathVariable Long postId, @AuthenticationPrincipal String email) {
String responseMessage = postService.cancelLike(postId, email);
return ResponseDto.response(ResponseMessage.LIKE_CANCEL_SUCCESS.getCode(), responseMessage);
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.leets.X.domain.post.controller;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum ResponseMessage {

POST_SUCCESS(201, "게시물이 성공적으로 생성되었습니다."),
GET_POST_SUCCESS(200, "게시물 조회에 성공했습니다."),
GET_SORTED_BY_LIKES_SUCCESS(200, "좋아요 순으로 게시물 조회에 성공했습니다."),
GET_LATEST_POST_SUCCESS(200, "최신 게시물 조회에 성공했습니다."),
ADD_LIKE_SUCCESS(201, "좋아요가 추가되었습니다."),
POST_DELETED_SUCCESS(200, "게시물이 성공적으로 삭제되었습니다."),
LIKE_CANCEL_SUCCESS(200, "좋아요가 성공적으로 취소되었습니다.");

private final int code;
private final String message;
}
72 changes: 64 additions & 8 deletions src/main/java/com/leets/X/domain/post/domain/Post.java
Original file line number Diff line number Diff line change
@@ -1,38 +1,94 @@
package com.leets.X.domain.post.domain;

import com.leets.X.domain.comment.domain.Comment;
import com.leets.X.domain.image.domain.Image;
import com.leets.X.domain.like.domain.Like;
import com.leets.X.domain.post.domain.enums.IsDeleted;
import com.leets.X.domain.user.domain.User;
import com.leets.X.global.common.domain.BaseTimeEntity;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
@Getter
public class Post extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "post_id")
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

@OneToMany(mappedBy = "post", cascade = CascadeType.REMOVE, orphanRemoval = true)
private List<Like> likes = new ArrayList<>();

@OneToMany(mappedBy = "post", cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, fetch = FetchType.LAZY)
private List<Image> images = new ArrayList<>();


@Column(columnDefinition = "TEXT")
private String content;

private Integer views;

private Boolean isDeleted;
private IsDeleted isDeleted;

private LocalDateTime deletedAt;

@OneToMany(mappedBy = "post")
private List<Comment> commentList;
// 좋아요 수를 관리하기 위한 필드

@Column(name = "like_count")
private Long likeCount = 0L; // 기본값을 0L로 초기화하여 null을 방지

public void incrementLikeCount() {
if (this.likeCount == null) {
this.likeCount = 1L; // null인 경우 1로 초기화
} else {
this.likeCount++;
}
}

// private List<Image> imageList;
public void decrementLikeCount() {
if (this.likeCount == null || this.likeCount == 0) {
this.likeCount = 0L; // null이거나 0일 경우 0으로 유지
} else {
this.likeCount--;
}
}

public long getLikesCount() {
return likeCount != null ? likeCount : 0; // null일 경우 0 반환
}



// 서비스에서 글의 상태를 삭제 상태로 바꾸기 위한 메서드
public void delete() {
if (this.isDeleted == IsDeleted.ACTIVE) { // 이미 삭제 상태가 아닐 때만 변경
this.isDeleted = IsDeleted.DELETED;
}
}

// 정적 메서드로 글 생성
public static Post create(User user, String content) {
return Post.builder()
.user(user)
.content(content)
.views(0) // 기본 조회 수
.likeCount(0L) // 좋아요 갯수 추가
.isDeleted(IsDeleted.ACTIVE) // 기본값 ACTIVE로 설정
.images(new ArrayList<>()) // 빈 리스트로 초기화
.build();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.leets.X.domain.post.domain.enums;

public enum IsDeleted {
ACTIVE, //게시물이 활성화된 상태
DELETED // 게시물이 삭제된 상태
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.leets.X.domain.post.dto.request;

import jakarta.validation.constraints.NotBlank;

public record PostRequestDTO(@NotBlank(message = "Content cannot be empty") String content) {

public static PostRequestDTO from(String content) {
return new PostRequestDTO(content);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.leets.X.domain.post.dto.response;

import com.leets.X.domain.comment.domain.Comment;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class CommentResponseDto {
private Long commentId;
private String content;

public static CommentResponseDto from(Comment comment) {
return new CommentResponseDto(comment.getId(), comment.getContent());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.leets.X.domain.post.dto.response;

import com.leets.X.domain.image.domain.Image;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ImageResponseDto {

private Long imageId;
private String url;

public static ImageResponseDto from(Image image) {
return new ImageResponseDto(image.getId(), image.getUrl());
}
}
Loading

0 comments on commit 9ae6678

Please sign in to comment.