diff --git a/README.md b/README.md new file mode 100644 index 0000000..4841b4f --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +## TODO List +- [x] 게시글 작성 API 구현 + - [x] controller, dto, repository 생성 + - [x] 비즈니스 로직 구현 + - [x] 제목, 내용 not null + - [x] 게시글 일자 자동 기록 + +- [x] 게시글 수정 API 구현 + - [x] controller, dto, repository 생성 + - [x] 비즈니스 로직 구현 (삭제된 게시글 예외처리) + - [x] 제목과 내용만 수정 가능 + - [x] 게시글 수정 일자 자동 기록 + +- [x] 게시글 삭제 API 구현 + - [x] controller, dto, repository 생성 + - [ ] 삭제 시 게시글과 함께 해당 게시글의 모든 댓글도 삭제 처리 + - [x] 삭제 후 복구 불가능 + - [x] 게시글 삭제 시 삭제 상태에 대한 변경만 처리(soft-delete) + +- [x] 게시글 단건 조회 API 구현 + - [x] controller, dto, repository 생성 + - [x] 비즈니스 로직 구현 (삭제된 게시글 예외처리) + - [x] 게시글에 포함된 모든 댓글 목록 조회 + - [ ] 게시글에 댓글 목록 페이징 처리 + - [x] 삭제된 데이터는 조회 불가 + +- [x] 댓글 등록 API 구현 + - [x] controller, dto, repository 생성 + - [x] 비즈니스 로직 구현 + - [x] 댓글 내용 not null + - [x] 댓글 등록 일자 자동 기록 + +- [x] 댓글 수정 API 구현 + - [x] controller, dto, repository 생성 + - [x] 비즈니스 로직 구현 (삭제된 댓글 예외처리) + - [x] 댓글 내용만 수정 가능 + - [x] 댓글 수정 일자 자동 기록 + +- [x] 댓글 삭제 API 구현 + - [x] controller, dto, repository 생성 + - [x] 비즈니스 로직 구현 (삭제된 댓글 예외처리) + - [x] 삭제 후 복구 불가능 + - [x] 댓글 삭제 시 삭제 상태에 대한 변경만 처리(soft-delete) + +## 추후 학습 & 이해가지 않는 부분 +- [ ] 조회된 게시글에 댓글만 페이징 처리 학습 필요 +- [ ] 게시글이 삭제 메서드에 댓글 삭제 로직 추가 필요 +- [ ] QueryDsl 내부 동작 원리 이해 필요 \ No newline at end of file diff --git a/build.gradle b/build.gradle index 8803149..4b568cc 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,7 @@ repositories { } dependencies { + runtimeOnly 'org.postgresql:postgresql' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' diff --git a/src/main/java/io/sparta/board/BoardApplication.java b/src/main/java/io/sparta/board/BoardApplication.java index 2b72c52..66a156a 100644 --- a/src/main/java/io/sparta/board/BoardApplication.java +++ b/src/main/java/io/sparta/board/BoardApplication.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +@EnableJpaAuditing @SpringBootApplication public class BoardApplication { diff --git a/src/main/java/io/sparta/board/application/dto/mapper/CommentMapper.java b/src/main/java/io/sparta/board/application/dto/mapper/CommentMapper.java new file mode 100644 index 0000000..1bc0632 --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/mapper/CommentMapper.java @@ -0,0 +1,28 @@ +package io.sparta.board.application.dto.mapper; + +import io.sparta.board.application.dto.response.comment.CommentCreateResponseDto; +import io.sparta.board.application.dto.response.comment.CommentDeleteResponseDto; +import io.sparta.board.application.dto.response.comment.CommentUpdateResponseDto; +import io.sparta.board.domain.entity.Comment; + +public class CommentMapper { + + public static CommentCreateResponseDto toCommentCreateResponseDto(Comment comment){ + return CommentCreateResponseDto.builder() + .id(comment.getId()) + .content(comment.getContent()) + .build(); + } + + public static CommentUpdateResponseDto toCommentUpdateResponseDto(Comment comment){ + return CommentUpdateResponseDto.builder() + .content(comment.getContent()) + .build(); + } + + public static CommentDeleteResponseDto toCommentDeleteResponseDto(Comment comment){ + return CommentDeleteResponseDto.builder() + .id(comment.getId()) + .build(); + } +} diff --git a/src/main/java/io/sparta/board/application/dto/mapper/PostMapper.java b/src/main/java/io/sparta/board/application/dto/mapper/PostMapper.java new file mode 100644 index 0000000..ddb3571 --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/mapper/PostMapper.java @@ -0,0 +1,60 @@ +package io.sparta.board.application.dto.mapper; + +import io.sparta.board.application.dto.response.comment.CommentResponseDto; +import io.sparta.board.application.dto.response.post.PostCreateResponseDto; +import io.sparta.board.application.dto.response.post.PostGetResponseDto; +import io.sparta.board.application.dto.response.post.PostDeleteResponseDto; +import io.sparta.board.application.dto.response.post.PostUpdateResponseDto; +import io.sparta.board.domain.entity.Comment; +import io.sparta.board.domain.entity.Post; + +import java.util.List; +import java.util.stream.Collectors; + +public class PostMapper { + + public static PostCreateResponseDto toPostCreateResponseDto(Post post) { + return PostCreateResponseDto.builder() + .id(post.getId()) + .title(post.getTitle()) + .content(post.getContent()) + .build(); + } + + public static PostGetResponseDto toPostGetResponseDto(Post post) { + return PostGetResponseDto.builder() + .id(post.getId()) + .title(post.getTitle()) + .content(post.getContent()) + .createdAt(post.getCreatedAt()) + .commentList(toCommentResponseList(post.getCommentList())) + .build(); + } + + private static List toCommentResponseList(List commentList) { + return commentList.stream() + .map(PostMapper::toCommentResponse) + .collect(Collectors.toList()); + } + + private static CommentResponseDto toCommentResponse(Comment comment) { + return CommentResponseDto.builder() + .id(comment.getId()) + .content(comment.getContent()) + .createdAt(comment.getCreatedAt()) + .build(); + } + + public static PostUpdateResponseDto toPostUpdateResponseDto(Post post) { + return PostUpdateResponseDto.builder() + .title(post.getTitle()) + .content(post.getContent()) + .build(); + } + + public static PostDeleteResponseDto toPostDeleteResponseDto(Post post) { + return PostDeleteResponseDto.builder() + .id(post.getId()) + .build(); + } +} diff --git a/src/main/java/io/sparta/board/application/dto/request/comment/CommentCreateRequestDto.java b/src/main/java/io/sparta/board/application/dto/request/comment/CommentCreateRequestDto.java new file mode 100644 index 0000000..5803b30 --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/request/comment/CommentCreateRequestDto.java @@ -0,0 +1,20 @@ +package io.sparta.board.application.dto.request.comment; + +import io.sparta.board.domain.entity.Comment; +import io.sparta.board.domain.entity.Post; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CommentCreateRequestDto { + private String content; + + public Comment toEntity(Post post) { + return Comment.create(content, post); + } +} diff --git a/src/main/java/io/sparta/board/application/dto/request/comment/CommentUpdateRequestDto.java b/src/main/java/io/sparta/board/application/dto/request/comment/CommentUpdateRequestDto.java new file mode 100644 index 0000000..f5468ea --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/request/comment/CommentUpdateRequestDto.java @@ -0,0 +1,14 @@ +package io.sparta.board.application.dto.request.comment; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CommentUpdateRequestDto { + private String content; +} diff --git a/src/main/java/io/sparta/board/application/dto/request/post/PostCreateRequestDto.java b/src/main/java/io/sparta/board/application/dto/request/post/PostCreateRequestDto.java new file mode 100644 index 0000000..4644457 --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/request/post/PostCreateRequestDto.java @@ -0,0 +1,24 @@ +package io.sparta.board.application.dto.request.post; + +import io.sparta.board.domain.entity.Post; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PostCreateRequestDto { + private String title; + private String content; + + public Post toEntity() { + return Post.create( + title, + content + ); + } + +} diff --git a/src/main/java/io/sparta/board/application/dto/request/post/PostUpdateRequestDto.java b/src/main/java/io/sparta/board/application/dto/request/post/PostUpdateRequestDto.java new file mode 100644 index 0000000..3e29ff3 --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/request/post/PostUpdateRequestDto.java @@ -0,0 +1,16 @@ +package io.sparta.board.application.dto.request.post; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PostUpdateRequestDto { + private String title; + private String content; + +} diff --git a/src/main/java/io/sparta/board/application/dto/response/comment/CommentCreateResponseDto.java b/src/main/java/io/sparta/board/application/dto/response/comment/CommentCreateResponseDto.java new file mode 100644 index 0000000..733b999 --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/response/comment/CommentCreateResponseDto.java @@ -0,0 +1,17 @@ +package io.sparta.board.application.dto.response.comment; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CommentCreateResponseDto { + private UUID id; + private String content; +} diff --git a/src/main/java/io/sparta/board/application/dto/response/comment/CommentDeleteResponseDto.java b/src/main/java/io/sparta/board/application/dto/response/comment/CommentDeleteResponseDto.java new file mode 100644 index 0000000..e48d415 --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/response/comment/CommentDeleteResponseDto.java @@ -0,0 +1,16 @@ +package io.sparta.board.application.dto.response.comment; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CommentDeleteResponseDto { + private UUID id; +} diff --git a/src/main/java/io/sparta/board/application/dto/response/comment/CommentResponseDto.java b/src/main/java/io/sparta/board/application/dto/response/comment/CommentResponseDto.java new file mode 100644 index 0000000..b2d698e --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/response/comment/CommentResponseDto.java @@ -0,0 +1,19 @@ +package io.sparta.board.application.dto.response.comment; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.UUID; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CommentResponseDto { + private UUID id; + private String content; + private LocalDateTime createdAt; +} diff --git a/src/main/java/io/sparta/board/application/dto/response/comment/CommentUpdateResponseDto.java b/src/main/java/io/sparta/board/application/dto/response/comment/CommentUpdateResponseDto.java new file mode 100644 index 0000000..28b324f --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/response/comment/CommentUpdateResponseDto.java @@ -0,0 +1,14 @@ +package io.sparta.board.application.dto.response.comment; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CommentUpdateResponseDto { + private String content; +} diff --git a/src/main/java/io/sparta/board/application/dto/response/post/PostCreateResponseDto.java b/src/main/java/io/sparta/board/application/dto/response/post/PostCreateResponseDto.java new file mode 100644 index 0000000..a792c24 --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/response/post/PostCreateResponseDto.java @@ -0,0 +1,18 @@ +package io.sparta.board.application.dto.response.post; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PostCreateResponseDto { + private UUID id; + private String title; + private String content; +} diff --git a/src/main/java/io/sparta/board/application/dto/response/post/PostDeleteResponseDto.java b/src/main/java/io/sparta/board/application/dto/response/post/PostDeleteResponseDto.java new file mode 100644 index 0000000..5fa4a53 --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/response/post/PostDeleteResponseDto.java @@ -0,0 +1,16 @@ +package io.sparta.board.application.dto.response.post; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PostDeleteResponseDto { + private UUID id; +} diff --git a/src/main/java/io/sparta/board/application/dto/response/post/PostGetResponseDto.java b/src/main/java/io/sparta/board/application/dto/response/post/PostGetResponseDto.java new file mode 100644 index 0000000..5c19dee --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/response/post/PostGetResponseDto.java @@ -0,0 +1,23 @@ +package io.sparta.board.application.dto.response.post; + +import io.sparta.board.application.dto.response.comment.CommentResponseDto; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.UUID; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PostGetResponseDto { + private UUID id; + private String title; + private String content; + private LocalDateTime createdAt; + private List commentList; +} diff --git a/src/main/java/io/sparta/board/application/dto/response/post/PostUpdateResponseDto.java b/src/main/java/io/sparta/board/application/dto/response/post/PostUpdateResponseDto.java new file mode 100644 index 0000000..10fa347 --- /dev/null +++ b/src/main/java/io/sparta/board/application/dto/response/post/PostUpdateResponseDto.java @@ -0,0 +1,15 @@ +package io.sparta.board.application.dto.response.post; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PostUpdateResponseDto { + private String title; + private String content; +} diff --git a/src/main/java/io/sparta/board/application/service/CommentService.java b/src/main/java/io/sparta/board/application/service/CommentService.java new file mode 100644 index 0000000..836cfa9 --- /dev/null +++ b/src/main/java/io/sparta/board/application/service/CommentService.java @@ -0,0 +1,62 @@ +package io.sparta.board.application.service; + +import io.sparta.board.application.dto.mapper.CommentMapper; +import io.sparta.board.application.dto.request.comment.CommentCreateRequestDto; +import io.sparta.board.application.dto.request.comment.CommentUpdateRequestDto; +import io.sparta.board.application.dto.response.comment.CommentCreateResponseDto; +import io.sparta.board.application.dto.response.comment.CommentDeleteResponseDto; +import io.sparta.board.application.dto.response.comment.CommentUpdateResponseDto; +import io.sparta.board.domain.entity.Comment; +import io.sparta.board.domain.entity.Post; +import io.sparta.board.domain.repository.CommentRepository; +import io.sparta.board.domain.repository.PostRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class CommentService { + + private final PostRepository postRepository; + private final CommentRepository commentRepository; + + @Transactional + public CommentCreateResponseDto createComment(UUID id, CommentCreateRequestDto request){ + Post post = postRepository.findByPostId(id); + + Comment comment = request.toEntity(post); + Comment savedComment = commentRepository.save(comment); + + CommentCreateResponseDto response = CommentMapper.toCommentCreateResponseDto(savedComment); + + return response; + } + + @Transactional + public CommentUpdateResponseDto updateComment(UUID id, CommentUpdateRequestDto request) { + Comment comment = commentRepository.findById(id); + + if(comment.isDeleted()){ + throw new IllegalArgumentException("삭제된 댓글입니다."); + } + + comment.update(request.getContent()); + + return CommentMapper.toCommentUpdateResponseDto(comment); + } + + @Transactional + public CommentDeleteResponseDto deleteComment(UUID id) { + Comment comment = commentRepository.findById(id); + if(comment.isDeleted()){ + throw new IllegalArgumentException("삭제된 댓글입니다."); + } + + comment.softDelete(); + + return CommentMapper.toCommentDeleteResponseDto(comment); + } +} diff --git a/src/main/java/io/sparta/board/application/service/PostService.java b/src/main/java/io/sparta/board/application/service/PostService.java new file mode 100644 index 0000000..b6dc2da --- /dev/null +++ b/src/main/java/io/sparta/board/application/service/PostService.java @@ -0,0 +1,69 @@ +package io.sparta.board.application.service; + +import io.sparta.board.application.dto.mapper.PostMapper; +import io.sparta.board.application.dto.request.post.PostCreateRequestDto; +import io.sparta.board.application.dto.response.post.PostCreateResponseDto; +import io.sparta.board.application.dto.response.post.PostGetResponseDto; +import io.sparta.board.application.dto.request.post.PostUpdateRequestDto; +import io.sparta.board.application.dto.response.post.PostDeleteResponseDto; +import io.sparta.board.application.dto.response.post.PostUpdateResponseDto; +import io.sparta.board.domain.entity.Post; +import io.sparta.board.domain.repository.PostRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class PostService { + + private final PostRepository postRepository; + + @Transactional + public PostCreateResponseDto createPost(PostCreateRequestDto request){ + Post post = request.toEntity(); + Post savedPost = postRepository.save(post); + PostCreateResponseDto response = PostMapper.toPostCreateResponseDto(savedPost); + + return response; + } + + @Transactional(readOnly = true) + public PostGetResponseDto getDetailPost(UUID id){ + Post post = postRepository.findByPostId(id); + + if(post.isDeleted()){ + throw new IllegalArgumentException("삭제된 게시글입니다."); + } + + return PostMapper.toPostGetResponseDto(post); + } + + @Transactional + public PostUpdateResponseDto updatePost(UUID id, PostUpdateRequestDto request){ + Post post = postRepository.findByPostId(id); + + if(post.isDeleted()){ + throw new IllegalArgumentException("삭제된 게시글 입니다."); + } + + post.update(request.getTitle(), request.getContent()); + + return PostMapper.toPostUpdateResponseDto(post); + } + + @Transactional + public PostDeleteResponseDto deletePost(UUID id){ + Post post = postRepository.findByPostId(id); + + if(post.isDeleted()){ + throw new IllegalArgumentException("삭제된 게시글 입니다."); + } + + post.softDelete(); + + return PostMapper.toPostDeleteResponseDto(post); + } +} diff --git a/src/main/java/io/sparta/board/domain/entity/Comment.java b/src/main/java/io/sparta/board/domain/entity/Comment.java new file mode 100644 index 0000000..0a4bed2 --- /dev/null +++ b/src/main/java/io/sparta/board/domain/entity/Comment.java @@ -0,0 +1,64 @@ +package io.sparta.board.domain.entity; + +import jakarta.persistence.*; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; +import java.util.UUID; + +@Entity +@EntityListeners(AuditingEntityListener.class) +@Table(name = "p_comment") +@Getter +@NoArgsConstructor +public class Comment { + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + @Column(name = "comment_id") + private UUID id; + + @Column(columnDefinition = "TEXT", nullable = false) + private String content; + + @Column(nullable = false) + private boolean deleted = false; + + @CreatedDate + @Column(name = "created_at", updatable = false, nullable = false) + private LocalDateTime createdAt; + + @LastModifiedDate + @Column(name = "updated_at", nullable = false) + private LocalDateTime updatedAt; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "post_id") + private Post post; + + @Builder + public Comment(String content, Post post){ + this.content = content; + this.post = post; + } + + public static Comment create(String content, Post post) { + return Comment.builder() + .content(content) + .post(post) + .build(); + } + + public void update(String content) { + this.content = content; + } + + public void softDelete() { + this.deleted = true; + } +} diff --git a/src/main/java/io/sparta/board/domain/entity/Post.java b/src/main/java/io/sparta/board/domain/entity/Post.java new file mode 100644 index 0000000..1e11763 --- /dev/null +++ b/src/main/java/io/sparta/board/domain/entity/Post.java @@ -0,0 +1,70 @@ +package io.sparta.board.domain.entity; + +import jakarta.persistence.*; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Entity +@EntityListeners(AuditingEntityListener.class) +@Table(name = "p_post") +@Getter +@NoArgsConstructor +public class Post { + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + @Column(name = "post_id") + private UUID id; + + @Column(length = 100, nullable = false) + private String title; + + @Column(columnDefinition = "TEXT", nullable = false) + private String content; + + @Column(nullable = false) + private boolean deleted = false; + + @CreatedDate + @Column(name = "created_at", updatable = false, nullable = false) + private LocalDateTime createdAt; + + @LastModifiedDate + @Column(name = "updated_at", nullable = false) + private LocalDateTime updatedAt; + + @OneToMany(mappedBy = "post", cascade = CascadeType.PERSIST) + private List commentList = new ArrayList<>(); + + @Builder + public Post(String title, String content) { + this.title = title; + this.content = content; + } + + public static Post create(String title, String content) { + Post post = Post.builder() + .title(title) + .content(content) + .build(); + return post; + } + + public void update(String title, String content) { + this.title = title; + this.content = content; + } + + public void softDelete() { + this.deleted = true; + } +} diff --git a/src/main/java/io/sparta/board/domain/repository/CommentRepository.java b/src/main/java/io/sparta/board/domain/repository/CommentRepository.java new file mode 100644 index 0000000..3e964d1 --- /dev/null +++ b/src/main/java/io/sparta/board/domain/repository/CommentRepository.java @@ -0,0 +1,12 @@ +package io.sparta.board.domain.repository; + +import io.sparta.board.domain.entity.Comment; + +import java.util.UUID; + +public interface CommentRepository { + + Comment save(Comment comment); + + Comment findById(UUID id); +} diff --git a/src/main/java/io/sparta/board/domain/repository/PostRepository.java b/src/main/java/io/sparta/board/domain/repository/PostRepository.java new file mode 100644 index 0000000..bf87a13 --- /dev/null +++ b/src/main/java/io/sparta/board/domain/repository/PostRepository.java @@ -0,0 +1,12 @@ +package io.sparta.board.domain.repository; + +import io.sparta.board.domain.entity.Post; + +import java.util.UUID; + +public interface PostRepository { + + Post save(Post post); + + Post findByPostId(UUID id); +} diff --git a/src/main/java/io/sparta/board/infrastructure/repository/CommentRepositoryImpl.java b/src/main/java/io/sparta/board/infrastructure/repository/CommentRepositoryImpl.java new file mode 100644 index 0000000..f566686 --- /dev/null +++ b/src/main/java/io/sparta/board/infrastructure/repository/CommentRepositoryImpl.java @@ -0,0 +1,22 @@ +package io.sparta.board.infrastructure.repository; + +import io.sparta.board.domain.entity.Comment; +import io.sparta.board.domain.repository.CommentRepository; +import io.sparta.board.infrastructure.repository.jpa.CommentJpaRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +@Repository +@RequiredArgsConstructor +public class CommentRepositoryImpl implements CommentRepository { + + private final CommentJpaRepository commentJpaRepository; + + @Override + public Comment save(Comment comment) {return commentJpaRepository.save(comment);} + + @Override + public Comment findById(UUID id){return commentJpaRepository.findById(id).orElse(null);} +} diff --git a/src/main/java/io/sparta/board/infrastructure/repository/PostRepositoryImpl.java b/src/main/java/io/sparta/board/infrastructure/repository/PostRepositoryImpl.java new file mode 100644 index 0000000..7ef422d --- /dev/null +++ b/src/main/java/io/sparta/board/infrastructure/repository/PostRepositoryImpl.java @@ -0,0 +1,24 @@ +package io.sparta.board.infrastructure.repository; + +import io.sparta.board.domain.entity.Post; +import io.sparta.board.domain.repository.PostRepository; +import io.sparta.board.infrastructure.repository.jpa.PostJpaRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +@Repository +@RequiredArgsConstructor +public class PostRepositoryImpl implements PostRepository { + + private final PostJpaRepository postJpaRepository; + + @Override + public Post save(Post post) { + return postJpaRepository.save(post); + } + + @Override + public Post findByPostId(UUID id){return postJpaRepository.findById(id).orElse(null);} +} diff --git a/src/main/java/io/sparta/board/infrastructure/repository/jpa/CommentJpaRepository.java b/src/main/java/io/sparta/board/infrastructure/repository/jpa/CommentJpaRepository.java new file mode 100644 index 0000000..ba74ec1 --- /dev/null +++ b/src/main/java/io/sparta/board/infrastructure/repository/jpa/CommentJpaRepository.java @@ -0,0 +1,9 @@ +package io.sparta.board.infrastructure.repository.jpa; + +import io.sparta.board.domain.entity.Comment; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.UUID; + +public interface CommentJpaRepository extends JpaRepository { +} diff --git a/src/main/java/io/sparta/board/infrastructure/repository/jpa/PostJpaRepository.java b/src/main/java/io/sparta/board/infrastructure/repository/jpa/PostJpaRepository.java new file mode 100644 index 0000000..5d58cd4 --- /dev/null +++ b/src/main/java/io/sparta/board/infrastructure/repository/jpa/PostJpaRepository.java @@ -0,0 +1,10 @@ +package io.sparta.board.infrastructure.repository.jpa; + +import io.sparta.board.domain.entity.Post; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.UUID; + +public interface PostJpaRepository extends JpaRepository { + +} diff --git a/src/main/java/io/sparta/board/presentation/CommentController.java b/src/main/java/io/sparta/board/presentation/CommentController.java new file mode 100644 index 0000000..a4eda26 --- /dev/null +++ b/src/main/java/io/sparta/board/presentation/CommentController.java @@ -0,0 +1,45 @@ +package io.sparta.board.presentation; + +import io.sparta.board.application.dto.request.comment.CommentCreateRequestDto; +import io.sparta.board.application.dto.request.comment.CommentUpdateRequestDto; +import io.sparta.board.application.dto.response.comment.CommentCreateResponseDto; +import io.sparta.board.application.dto.response.comment.CommentDeleteResponseDto; +import io.sparta.board.application.dto.response.comment.CommentUpdateResponseDto; +import io.sparta.board.application.service.CommentService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.UUID; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/comments") +public class CommentController { + + private final CommentService commentService; + + @PostMapping("/boards/{id}/comments") + public ResponseEntity createComment( + @PathVariable UUID id, + @RequestBody CommentCreateRequestDto request){ + + CommentCreateResponseDto response = commentService.createComment(id, request); + return ResponseEntity.ok(response); + } + + @PutMapping("/{id}/updateComment") + public ResponseEntity updateComment( + @PathVariable UUID id, + @RequestBody CommentUpdateRequestDto request){ + CommentUpdateResponseDto response = commentService.updateComment(id, request); + return ResponseEntity.ok(response); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteComment( + @PathVariable UUID id){ + CommentDeleteResponseDto response = commentService.deleteComment(id); + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/io/sparta/board/presentation/PostController.java b/src/main/java/io/sparta/board/presentation/PostController.java new file mode 100644 index 0000000..510af0b --- /dev/null +++ b/src/main/java/io/sparta/board/presentation/PostController.java @@ -0,0 +1,52 @@ +package io.sparta.board.presentation; + +import io.sparta.board.application.dto.request.post.PostCreateRequestDto; +import io.sparta.board.application.dto.response.post.PostCreateResponseDto; +import io.sparta.board.application.dto.response.post.PostGetResponseDto; +import io.sparta.board.application.dto.request.post.PostUpdateRequestDto; +import io.sparta.board.application.dto.response.post.PostDeleteResponseDto; +import io.sparta.board.application.dto.response.post.PostUpdateResponseDto; +import io.sparta.board.application.service.PostService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.UUID; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/boards") +public class PostController { + + private final PostService postService; + + @PostMapping + public ResponseEntity createPost( + @RequestBody PostCreateRequestDto request) { + PostCreateResponseDto response = postService.createPost(request); + return ResponseEntity.ok(response); + } + + @GetMapping("/{id}") + public ResponseEntity GetPost( + @PathVariable UUID id){ + + PostGetResponseDto response = postService.getDetailPost(id); + return ResponseEntity.ok(response); + } + + @PutMapping("/{id}/update") + public ResponseEntity updatePost( + @PathVariable UUID id, + @RequestBody PostUpdateRequestDto request){ + PostUpdateResponseDto response = postService.updatePost(id, request); + return ResponseEntity.ok(response); + } + + @DeleteMapping("/{id}") + public ResponseEntity deletePost( + @PathVariable UUID id){ + PostDeleteResponseDto response = postService.deletePost(id); + return ResponseEntity.ok(response); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 856d19e..7222c38 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -3,12 +3,14 @@ spring: name: board datasource: - hikari.jdbc-url: jdbc:h2:mem:test_db; - username: sa - password: + url: jdbc:postgresql://localhost:5432/board + driver-class-name: org.postgresql.Driver + username: postgres + password: hello12 jpa: - hibernate.ddl-auto: create + hibernate: + ddl-auto: update show-sql: true properties: hibernate: diff --git a/src/test/resources/test/CommentClient.http b/src/test/resources/test/CommentClient.http new file mode 100644 index 0000000..1c71da9 --- /dev/null +++ b/src/test/resources/test/CommentClient.http @@ -0,0 +1,22 @@ +### 1. 댓글 생성 +POST http://localhost:8080/api/comments/boards/e7e659cb-415a-4c9d-82d3-4851d2d46cad/comments +Authorization: Bearer jwt_token_string +Content-Type: application/json + +{ + "content": "댓글입니다2" +} + +### 2. 댓글 수정 +PUT http://localhost:8080/api/comments/1d55b553-62b4-47cf-a9b8-7684f87b57e0/updateComment +Authorization: Bearer jwt_token_string +Content-Type: application/json + +{ + "content": "댓글수정완" +} + +### 3. 댓글 삭제 +DELETE http://localhost:8080/api/comments/c4ed3a63-9481-42af-9ba5-bdbd89aa581b +Authorization: Bearer jwt_token_string +Content-Type: application/json \ No newline at end of file diff --git a/src/test/resources/test/PostClient.http b/src/test/resources/test/PostClient.http new file mode 100644 index 0000000..ad795da --- /dev/null +++ b/src/test/resources/test/PostClient.http @@ -0,0 +1,29 @@ +### 1. 게시물 생성 +POST http://localhost:8080/api/boards +Authorization: Bearer jwt_token_string +Content-Type: application/json + +{ + "title": "게시물 제목입니다2.", + "content": "게시물 내용입니다2." +} + +### 2. 게시물 단건 조회 +GET http://localhost:8080/api/boards/4b1da82c-f2e5-4778-8be7-4533d5c6390a +Authorization: Bearer jwt_token_string +Content-Type: application/json + +### 3. 게시물 수정 +PUT http://localhost:8080/api/boards/4b1da82c-f2e5-4778-8be7-4533d5c6390a/update +Authorization: Bearer jwt_token_string +Content-Type: application/json + +{ + "title": "게시물 제목 수정완2", + "content": "게시물 내용 수정완2" +} + +### 4. 게시물 삭제 +DELETE http://localhost:8080/api/boards/4b1da82c-f2e5-4778-8be7-4533d5c6390a +Authorization: Bearer jwt_token_string +Content-Type: application/json