-
Notifications
You must be signed in to change notification settings - Fork 13
Feat/week-1-2 #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 윤서경
Are you sure you want to change the base?
Feat/week-1-2 #13
Changes from all commits
0953e85
825b9e0
3d0fa47
27419c1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package com.example.devSns.controller; | ||
|
|
||
| import com.example.devSns.entity.Comment; | ||
| import com.example.devSns.service.CommentService; | ||
| import org.springframework.web.bind.annotation.*; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/posts/{postId}/comments") | ||
| public class CommentController { | ||
|
|
||
| private final CommentService commentService; | ||
|
|
||
| public CommentController(CommentService commentService) { | ||
| this.commentService = commentService; | ||
| } | ||
|
|
||
| @PostMapping | ||
| public Comment createComment(@PathVariable Long postId, @RequestBody Comment comment) { | ||
| return commentService.createComment(postId, comment); | ||
| } | ||
|
|
||
| @GetMapping | ||
| public List<Comment> getCommentsByPostId(@PathVariable Long postId) { | ||
| return commentService.getCommentsByPostId(postId); | ||
| } | ||
|
|
||
| @PutMapping("/{id}") | ||
| public Comment updateComment(@PathVariable Long id, @RequestBody Comment comment) { | ||
| return commentService.updateComment(id, comment); | ||
| } | ||
|
|
||
| @DeleteMapping("/{id}") | ||
| public void deleteComment(@PathVariable Long id) { | ||
| commentService.deleteComment(id); | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package com.example.devSns.controller; | ||
|
|
||
| import com.example.devSns.entity.Post; | ||
| import com.example.devSns.service.PostService; | ||
| import org.springframework.http.HttpStatus; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.*; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/posts") | ||
| public class PostController { | ||
| private final PostService postService; | ||
|
|
||
| public PostController(PostService postService) { | ||
| this.postService = postService; | ||
| } | ||
|
|
||
| @PostMapping | ||
| public ResponseEntity<Post> createPost(@RequestBody Post post) { | ||
| Post createdPost = postService.createPost(post); | ||
| return ResponseEntity.status(HttpStatus.CREATED).body(createdPost); | ||
| } | ||
|
|
||
| @GetMapping | ||
| public ResponseEntity<List<Post>> getAllPosts() { | ||
| List<Post> posts = postService.getAllPosts(); | ||
| return ResponseEntity.ok(posts); | ||
| } | ||
|
|
||
| @GetMapping("/{id}") | ||
| public ResponseEntity<Post> getPostById(@PathVariable Long id) { | ||
| Post post = postService.getPostById(id); | ||
| return ResponseEntity.ok(post); | ||
| } | ||
|
|
||
| @PutMapping("/{id}") | ||
| public ResponseEntity<Post> updatePost( | ||
| @PathVariable Long id, | ||
| @RequestBody Post updatedPost) { | ||
| Post post = postService.updatePost(id, updatedPost); | ||
| return ResponseEntity.ok(post); | ||
| } | ||
|
|
||
| @DeleteMapping("/{id}") | ||
| public ResponseEntity<Void> deletePost(@PathVariable Long id) { | ||
| postService.deletePost(id); | ||
| return ResponseEntity.noContent().build(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| package com.example.devSns.entity; | ||
|
|
||
| import jakarta.persistence.*; | ||
| import lombok.*; | ||
| import java.time.LocalDateTime; | ||
|
|
||
| @Entity | ||
| @Table(name = "comments") | ||
| @Getter | ||
| @Setter | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| @Builder | ||
| public class Comment { | ||
| @Id | ||
| @GeneratedValue(strategy = GenerationType.IDENTITY) // auto-incremented | ||
| private Long id; | ||
|
|
||
| @Column(nullable = false) | ||
| private String content; | ||
|
|
||
| @Column(nullable = false) | ||
| private String writer; | ||
|
|
||
| @ManyToOne(fetch = FetchType.LAZY) // 댓글 조회 시 Post는 필요할 때만 불러옴 | ||
| @JoinColumn(name = "post_id", nullable = false) | ||
| private Post post; | ||
|
Comment on lines
+25
to
+27
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @manytoone에도 optional=false 속성을 추가해서 더 안전하게 구성할 수 있습니다! |
||
|
|
||
| @Column(nullable = false, updatable = false) | ||
| private LocalDateTime createdAt; | ||
|
|
||
| private LocalDateTime updatedAt; | ||
|
|
||
| @PrePersist | ||
| public void prePersist() { | ||
| createdAt = LocalDateTime.now(); | ||
| } | ||
|
|
||
| @PreUpdate | ||
| public void preUpdate() { | ||
| updatedAt = LocalDateTime.now(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| package com.example.devSns.entity; | ||
|
|
||
| import jakarta.persistence.*; | ||
| import lombok.*; | ||
| import java.time.LocalDateTime; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| @Entity | ||
| @Table(name = "posts") | ||
| @Getter | ||
| @Setter | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| @Builder | ||
| public class Post { | ||
| @Id | ||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| private Long id; | ||
|
|
||
| @Column(nullable = false) | ||
| private String title; | ||
|
|
||
| @Column(nullable = false, length = 1000) | ||
| private String content; | ||
|
|
||
| @Column(nullable = false) | ||
| private String writer; | ||
|
|
||
| private int likeCount = 0; | ||
|
|
||
| @Column(nullable = false, updatable = false) | ||
| private LocalDateTime createdAt; | ||
|
|
||
| private LocalDateTime updatedAt; | ||
|
|
||
| @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) | ||
| private List<Comment> comments = new ArrayList<>(); | ||
|
Comment on lines
+37
to
+38
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 양방향 연관관계(ManyToOne, OneToMany 모두 적용)의 경우 객체 연관관계 탐색에서 더 유연하다는 장점은 있지만 java 코드상에서 두 연관 객체를 모두 관리해야 한다는 단점이 생깁니다. 그래서 저는 단방향 연관관계만(ManyToOne) 적용하고 추후 필요하다면 양방향 연관관계까지 적용하는 걸 추천드립니다. 어떤 연관관계를 설정하더라도 DB 테이블 구조는 같습니다. |
||
|
|
||
| @PrePersist | ||
| public void prePersist() { | ||
| createdAt = LocalDateTime.now(); | ||
| } | ||
|
|
||
| @PreUpdate | ||
| public void preUpdate() { | ||
| updatedAt = LocalDateTime.now(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package com.example.devSns.repository; | ||
|
|
||
| import com.example.devSns.entity.Comment; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
| import org.springframework.stereotype.Repository; | ||
| import java.util.List; | ||
|
|
||
| @Repository | ||
| public interface CommentRepository extends JpaRepository<Comment, Long> { | ||
| // Comment에서 연관된 Post 객체의 id 기준 | ||
| List<Comment> findByPost_Id(Long postId); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.example.devSns.repository; | ||
|
|
||
| import com.example.devSns.entity.Post; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
| import org.springframework.stereotype.Repository; | ||
|
|
||
| @Repository | ||
| public interface PostRepository extends JpaRepository<Post, Long> { | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| package com.example.devSns.service; | ||
|
|
||
| import com.example.devSns.entity.Comment; | ||
| import com.example.devSns.entity.Post; | ||
| import com.example.devSns.repository.CommentRepository; | ||
| import com.example.devSns.repository.PostRepository; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @Service | ||
| @Transactional | ||
| public class CommentService { | ||
|
|
||
| private final CommentRepository commentRepository; | ||
| private final PostRepository postRepository; | ||
|
|
||
| public CommentService(CommentRepository commentRepository, | ||
| PostRepository postRepository) { | ||
| this.commentRepository = commentRepository; | ||
| this.postRepository = postRepository; | ||
| } | ||
|
|
||
| public Comment createComment(Long postId, Comment comment) { | ||
| Post post = postRepository.findById(postId) | ||
| .orElseThrow(() -> new RuntimeException("Post not found with id: " + postId)); | ||
| comment.setPost(post); | ||
| return commentRepository.save(comment); | ||
| } | ||
|
|
||
| @Transactional(readOnly = true) | ||
| public List<Comment> getCommentsByPostId(Long postId) { | ||
| return commentRepository.findByPost_Id(postId); | ||
| } | ||
|
|
||
| public Comment updateComment(Long id, Comment updatedComment) { | ||
| Comment foundComment = commentRepository.findById(id) | ||
| .orElseThrow(() -> new RuntimeException("Comment not found with id: " + id)); | ||
|
|
||
| foundComment.setContent(updatedComment.getContent()); | ||
| foundComment.setWriter(updatedComment.getWriter()); | ||
|
Comment on lines
+41
to
+42
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 부분들도 setter 없이 엔티티 객체 내부 헬퍼 메소드로 분리할 수 있을 것 같습니다! |
||
|
|
||
| return commentRepository.save(foundComment); | ||
| } | ||
|
|
||
| public void deleteComment(Long id) { | ||
| if (!commentRepository.existsById(id)) { | ||
| throw new RuntimeException("Comment not found with id: " + id); | ||
| } | ||
| commentRepository.deleteById(id); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| package com.example.devSns.service; | ||
|
|
||
| import com.example.devSns.entity.Post; | ||
| import com.example.devSns.repository.PostRepository; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @Service | ||
| @Transactional | ||
| public class PostService { | ||
| private final PostRepository postRepository; | ||
|
|
||
| public PostService(PostRepository postRepository) { | ||
| this.postRepository = postRepository; | ||
| } | ||
|
Comment on lines
+15
to
+17
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @RequiredArgsConstuctor를 사용하는 걸 추천드립니다! |
||
|
|
||
| public Post createPost(Post post) { | ||
| return postRepository.save(post); | ||
| } | ||
|
|
||
| @Transactional(readOnly = true) | ||
| public List<Post> getAllPosts() { | ||
| return postRepository.findAll(); | ||
| } | ||
|
|
||
| @Transactional(readOnly = true) | ||
| public Post getPostById(Long id) { | ||
| return postRepository.findById(id) | ||
| .orElseThrow(() -> new RuntimeException("Post not found with id: " + id)); | ||
| } | ||
|
|
||
| public Post updatePost(Long id, Post updatedPost) { | ||
| Post foundPost = postRepository.findById(id) | ||
| .orElseThrow(() -> new RuntimeException("Post not found with id: " + id)); | ||
|
|
||
| foundPost.setTitle(updatedPost.getTitle()); | ||
| foundPost.setContent(updatedPost.getContent()); | ||
| foundPost.setWriter(updatedPost.getWriter()); | ||
|
|
||
| return postRepository.save(foundPost); | ||
| } | ||
|
Comment on lines
+34
to
+43
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. update로직을 post 엔티티 내부에 구성해서 setter 사용 없이 update 로직의 책임을 post 객체에 위임하면 더 객체지향적으로 코드를 구성할 수 있습니다! 그리고 JPA의 변경 감지 기능 때문에 save를 호출하지 않아도 transaction 커밋 시 업데이트 쿼리가 자동으로 수행됩니다! |
||
|
|
||
| public void deletePost(Long id) { | ||
| if (!postRepository.existsById(id)) { | ||
| throw new RuntimeException("Post not found with id: " + id); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. RuntimeException의 경우 추상적이라 다른 구체적인 예외 타입(e.g. InvalidInputException)을 사용하거나 필요하다면 커스텀 예외 타입을 사용해보시는 걸 추천드립니다! |
||
| } | ||
| postRepository.deleteById(id); | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PostController처럼 responseEntity를 사용해서 응답 코드와 함께 반환하도록 구성해주시면 좋을 것 같아요!