Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .idea/data_source_mapping.xml

This file was deleted.

5 changes: 4 additions & 1 deletion src/main/java/org/sopt/common/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ public enum ErrorCode {
INTERNAL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류가 발생했습니다."),

// 아티클 관련 예외
ARTICLE_NOT_FOUND(HttpStatus.NOT_FOUND, "아티클을 찾을 수 없습니다.");
ARTICLE_NOT_FOUND(HttpStatus.NOT_FOUND, "아티클을 찾을 수 없습니다."),

// 댓글 관련 예외
COMMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "댓글을 찾을 수 없습니다."),;

private final HttpStatus status;
private final String message;
Expand Down
49 changes: 49 additions & 0 deletions src/main/java/org/sopt/controller/CommentController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.sopt.controller;

import lombok.RequiredArgsConstructor;
import org.sopt.common.ApiResponse;
import org.sopt.dto.request.CommentCreateRequest;
import org.sopt.dto.request.CommentUpdateRequest;
import org.sopt.dto.response.CommentResponse;
import org.sopt.service.CommentService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/comments")
public class CommentController {

private final CommentService commentService;

// 댓글 생성
@PostMapping
public ResponseEntity<ApiResponse<Long>> createComment(@RequestBody CommentCreateRequest req) {
Long commentId = commentService.create(
req.articleId(), req.memberId(), req.content()
);

return ResponseEntity.ok(ApiResponse.success(commentId));
}

// 댓글 조회
@GetMapping("{id}")
public ResponseEntity<ApiResponse<CommentResponse>> getComment(@PathVariable("id") Long id) {
CommentResponse res = commentService.findById(id);
return ResponseEntity.ok(ApiResponse.success(res));
}

// 댓글 삭제
@DeleteMapping("{id}")
public ResponseEntity<ApiResponse<Void>> deleteComment(@PathVariable("id") Long id) {
commentService.delete(id);
return ResponseEntity.ok(ApiResponse.success(null));
}

// 댓글 수정
@PatchMapping("{id}")
public ResponseEntity<ApiResponse<CommentResponse>> updateComment(@PathVariable("id") Long id, @RequestBody CommentUpdateRequest req) {
CommentResponse res = commentService.update(id, req.content());
return ResponseEntity.ok(ApiResponse.success(res));
}
}
3 changes: 1 addition & 2 deletions src/main/java/org/sopt/controller/MemberController.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import org.sopt.dto.request.MemberUpdateRequest;
import org.sopt.dto.response.MemberResponse;
import org.sopt.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

Expand Down Expand Up @@ -51,7 +50,7 @@ public ResponseEntity<ApiResponse<Void>> deleteMember(@PathVariable Long memberI
}

// 회원정보 수정
@PutMapping("/{memberId}")
@PatchMapping("/{memberId}")
public ResponseEntity<ApiResponse<MemberResponse>> updateMember(
@PathVariable Long memberId,
@Valid @RequestBody MemberUpdateRequest req) {
Expand Down
34 changes: 9 additions & 25 deletions src/main/java/org/sopt/domain/Article.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package org.sopt.domain;

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

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

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(indexes = {
@Index(name = "idx_article_title", columnList = "title"),
@Index(name = "idx_article_member_id", columnList = "memberId")
Expand All @@ -33,7 +40,8 @@ public class Article {
@Column(updatable = false)
private LocalDateTime createdAt;

protected Article() {}
@OneToMany(mappedBy="article", cascade=CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();

private Article(Member member, String title, String content, Tag tag) {
this.member = member;
Expand All @@ -46,28 +54,4 @@ private Article(Member member, String title, String content, Tag tag) {
public static Article of(Member member, String title, String content, Tag tag) {
return new Article(member, title, content, tag);
}

public Long getId() {
return id;
}

public Member getMember() {
return member;
}

public String getTitle() {
return title;
}

public String getContent() {
return content;
}

public Tag getTag() {
return tag;
}

public LocalDateTime getCreatedAt() {
return createdAt;
}
}
51 changes: 51 additions & 0 deletions src/main/java/org/sopt/domain/Comment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.sopt.domain;

import jakarta.persistence.*;
import lombok.AccessLevel;
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;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EntityListeners(AuditingEntityListener.class)
public class Comment {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "article_id", nullable = false)
private Article article;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id", nullable = false)
private Member member;

@Column(length = 300)
private String content;

@CreatedDate
@Column(updatable = false, nullable = false)
private LocalDateTime createdAt;

@LastModifiedDate
@Column(nullable = false)
private LocalDateTime updatedAt;

public void update(String content) {
this.content = content;
}

public static Comment of(Article article, Member member, String content) {
Comment comment = new Comment();
comment.article = article;
comment.member = member;
comment.content = content;
return comment;
}
}
45 changes: 18 additions & 27 deletions src/main/java/org/sopt/domain/Member.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package org.sopt.domain;

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(indexes = {
@Index(name = "idx_member_name", columnList = "name")
})
Expand All @@ -16,49 +21,35 @@ public class Member {
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;

@Column(nullable = false)
private String name;

@Column(nullable = false)
private LocalDate birthDate;

@Column(nullable = false)
private String email;

@Column(nullable = false)
@Enumerated(EnumType.STRING)
private Sex sex;

@OneToMany(mappedBy="member", cascade=CascadeType.ALL)
private List<Article> articles;
private List<Article> articles = new ArrayList<>();

protected Member() {}

// private 생성자 (외부에서 직접 생성 방지)
private Member(String name, LocalDate birthDate, String email, Sex sex) {
public void update(String name, LocalDate birthDate, String email, Sex sex) {
this.name = name;
this.birthDate = birthDate;
this.email = email;
this.sex = sex;
}

public static Member of(String name, LocalDate birthDate, String email, Sex sex) {
return new Member(name, birthDate, email, sex);
}

public Long getId() {
return id;
}

public String getName() {
return name;
}

public LocalDate getBirthDate() {
return birthDate;
}

public String getEmail() {
return email;
}

public Sex getSex() {
return sex;
Member member = new Member();
member.name = name;
member.birthDate = birthDate;
member.email = email;
member.sex = sex;
return member;
}
}
16 changes: 16 additions & 0 deletions src/main/java/org/sopt/dto/request/CommentCreateRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.sopt.dto.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

public record CommentCreateRequest(
@NotNull(message = "아티클 ID를 입력해주세요")
Long articleId,

@NotNull(message = "작성자 ID를 입력해주세요")
Long memberId,

@NotBlank(message = "내용을 입력해주세요")
String content
) {
}
6 changes: 6 additions & 0 deletions src/main/java/org/sopt/dto/request/CommentUpdateRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.sopt.dto.request;

public record CommentUpdateRequest(
String content
) {
}
15 changes: 13 additions & 2 deletions src/main/java/org/sopt/dto/response/ArticleResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@
import org.sopt.domain.Tag;

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

public record ArticleResponse(
Long id,
Author author,
String title,
String content,
Tag tag,
LocalDateTime createdAt
LocalDateTime createdAt,
List<Comment> comments
) {
public record Author(Long memberId, String name) {}

public record Comment(Long commentId, Long memberId, String comment) {}

public static ArticleResponse from(Article article) {
return new ArticleResponse(
article.getId(),
Expand All @@ -25,7 +29,14 @@ public static ArticleResponse from(Article article) {
article.getTitle(),
article.getContent(),
article.getTag(),
article.getCreatedAt()
article.getCreatedAt(),
article.getComments().stream()
.map(comment -> new Comment(
comment.getId(),
comment.getMember().getId(),
comment.getContent()
))
.toList()
);
}
}
35 changes: 35 additions & 0 deletions src/main/java/org/sopt/dto/response/CommentResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.sopt.dto.response;

import org.sopt.domain.Comment;

import java.time.LocalDateTime;

public record CommentResponse(
Long id,
Article article,
Writer writer,
String content,
LocalDateTime createdAt,
LocalDateTime updatedAt
) {
public record Article(Long id, String title) {}

public record Writer(Long id, String name) {}

public static CommentResponse from(Comment comment) {
return new CommentResponse(
comment.getId(),
new Article(
comment.getArticle().getId(),
comment.getArticle().getTitle()
),
new Writer(
comment.getMember().getId(),
comment.getMember().getName()
),
comment.getContent(),
comment.getCreatedAt(),
comment.getUpdatedAt()
);
}
}
7 changes: 7 additions & 0 deletions src/main/java/org/sopt/repository/CommentRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.sopt.repository;

import org.sopt.domain.Comment;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CommentRepository extends JpaRepository<Comment, Long> {
}
Loading