From e313192b802dddb2d8ebf04662d3d99c3fbd20fb Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Wed, 5 Jul 2023 13:22:52 +0900 Subject: [PATCH 01/36] Add: article create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 게시글 생성 기능 추가 --- .idea/.gitignore | 8 +++ .idea/.name | 1 + .idea/compiler.xml | 15 +++++ .idea/jarRepositories.xml | 20 +++++++ .idea/misc.xml | 5 ++ .idea/vcs.xml | 6 ++ .../java/com/gdsc/blog/BlogApplication.java | 8 +-- .../article/controller/ArticleController.java | 15 +++++ .../com/gdsc/blog/article/entity/Article.java | 40 +++++++++++++ .../article/repository/ArticleRepository.java | 10 ++++ .../blog/user/controller/UserController.java | 56 +++++++++---------- .../java/com/gdsc/blog/user/entity/User.java | 25 ++++++--- .../com/gdsc/blog/BlogApplicationTests.java | 22 +++++++- 13 files changed, 187 insertions(+), 44 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/.name create mode 100644 .idea/compiler.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml create mode 100644 src/main/java/com/gdsc/blog/article/controller/ArticleController.java create mode 100644 src/main/java/com/gdsc/blog/article/entity/Article.java create mode 100644 src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..0d50744 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +blog \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..a410458 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..fdc392f --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..668048d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/main/java/com/gdsc/blog/BlogApplication.java b/src/main/java/com/gdsc/blog/BlogApplication.java index 56b0143..42bc01c 100644 --- a/src/main/java/com/gdsc/blog/BlogApplication.java +++ b/src/main/java/com/gdsc/blog/BlogApplication.java @@ -5,9 +5,7 @@ @SpringBootApplication public class BlogApplication { - - public static void main(String[] args) { - SpringApplication.run(BlogApplication.class, args); - } - + public static void main(String[] args) { + SpringApplication.run(BlogApplication.class, args); + } } diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java new file mode 100644 index 0000000..870295f --- /dev/null +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -0,0 +1,15 @@ +package com.gdsc.blog.article.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@Tag(name = "Article", description = "Article API") +@RestController +@RequestMapping("/api/article") +public class ArticleController { + + +} diff --git a/src/main/java/com/gdsc/blog/article/entity/Article.java b/src/main/java/com/gdsc/blog/article/entity/Article.java new file mode 100644 index 0000000..927a1d5 --- /dev/null +++ b/src/main/java/com/gdsc/blog/article/entity/Article.java @@ -0,0 +1,40 @@ +package com.gdsc.blog.article.entity; + +import com.gdsc.blog.user.entity.User; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Table(name = "articles") +public class Article { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long idx; //id + + @Column(length = 200) + private String title; + + @Column(columnDefinition = "TEXT") //no limit length of text + private String content; + + private LocalDateTime createDate; + + //set relationship between article and user + @ManyToOne + private User user; +} \ No newline at end of file diff --git a/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java b/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java new file mode 100644 index 0000000..6c54653 --- /dev/null +++ b/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java @@ -0,0 +1,10 @@ +package com.gdsc.blog.article.repository; + +import com.gdsc.blog.article.entity.Article; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ArticleRepository extends JpaRepository { + +} diff --git a/src/main/java/com/gdsc/blog/user/controller/UserController.java b/src/main/java/com/gdsc/blog/user/controller/UserController.java index 463a5d9..a81e789 100644 --- a/src/main/java/com/gdsc/blog/user/controller/UserController.java +++ b/src/main/java/com/gdsc/blog/user/controller/UserController.java @@ -26,42 +26,42 @@ @RequestMapping("/api/user") public class UserController { - UserService userService; + UserService userService; - public UserController(UserService userService) { - this.userService = userService; - } + public UserController(UserService userService) { + this.userService = userService; + } - @PostMapping("/signup") - @Operation(summary = "회원가입") - public User signup(@RequestBody SignUpDto user) { + @PostMapping("/signup") + @Operation(summary = "회원가입") + public User signup(@RequestBody SignUpDto user) { - User user1 = User.builder().email(user.getEmail()).password(user.getPassword()) - .username(user.getUsername()).build(); + User user1 = User.builder().email(user.getEmail()).password(user.getPassword()) + .username(user.getUsername()).build(); - return userService.signup(user1); - } + return userService.signup(user1); + } - @PostMapping("/signin") - @Operation(summary = "로그인") - public Token signin(@RequestBody SignInDto signInDto) { - Token token = Token.builder() - .token(userService.singin(signInDto.getEmail(), signInDto.getPassword())).build(); - return token; + @PostMapping("/signin") + @Operation(summary = "로그인") + public Token signin(@RequestBody SignInDto signInDto) { + Token token = Token.builder() + .token(userService.singin(signInDto.getEmail(), signInDto.getPassword())).build(); + return token; - } + } - @GetMapping("/getUser/{email}") - @PreAuthorize("hasRole('ROLE_ADMIN')") - public User getUser(@PathVariable("email") String email) { - return userService.getUser(email); - } + @GetMapping("/getUser/{email}") + @PreAuthorize("hasRole('ROLE_ADMIN')") + public User getUser(@PathVariable("email") String email) { + return userService.getUser(email); + } - @GetMapping("/whoisme") - @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") - public User whoisme(HttpServletRequest req) { - return userService.whoami(req); - } + @GetMapping("/whoisme") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") + public User whoisme(HttpServletRequest req) { + return userService.whoami(req); + } } diff --git a/src/main/java/com/gdsc/blog/user/entity/User.java b/src/main/java/com/gdsc/blog/user/entity/User.java index 28cddab..c261b45 100644 --- a/src/main/java/com/gdsc/blog/user/entity/User.java +++ b/src/main/java/com/gdsc/blog/user/entity/User.java @@ -1,5 +1,8 @@ package com.gdsc.blog.user.entity; +import com.gdsc.blog.article.entity.Article; +import jakarta.persistence.CascadeType; +import jakarta.persistence.OneToMany; import java.util.Collection; import java.util.List; import java.util.Set; @@ -29,18 +32,22 @@ @NoArgsConstructor @Table(name = "users") public class User { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long idx; - @Column(unique = true) - private String email; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long idx; - private String password; + @Column(unique = true) + private String email; - private String username; + private String password; - @ElementCollection(fetch = FetchType.EAGER) - List roles; + private String username; + @ElementCollection(fetch = FetchType.EAGER) + List roles; + + //set relationship between article and user + @OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE) + private List
articles; } diff --git a/src/test/java/com/gdsc/blog/BlogApplicationTests.java b/src/test/java/com/gdsc/blog/BlogApplicationTests.java index 533a031..0110b45 100644 --- a/src/test/java/com/gdsc/blog/BlogApplicationTests.java +++ b/src/test/java/com/gdsc/blog/BlogApplicationTests.java @@ -1,14 +1,32 @@ package com.gdsc.blog; +import com.gdsc.blog.article.entity.Article; +import com.gdsc.blog.article.repository.ArticleRepository; +import java.time.LocalDateTime; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Profile; @SpringBootTest @Profile("test") class BlogApplicationTests { + @Autowired + private ArticleRepository articleRepository; - @Test - void contextLoads() {} + @Test + void contextLoads() {} + + @Test + void testRepository(){ + //create new post + Article post1 = new Article(); + //set title and content + post1.setTitle("Post test 1 title"); + post1.setContent("Post test 2 content"); + post1.setCreateDate(LocalDateTime.now()); + //save post + this.articleRepository.save(post1); + } } From fe9b97ecf24df18fa0ae4df0a64df6f5d8a83c2d Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Wed, 5 Jul 2023 13:42:04 +0900 Subject: [PATCH 02/36] Add: find by title in article MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Article Repository - findByTitle 메서드 추가 Test code - 모든 article 받아오기 (findAll) - article id 체크 (findById) - 제목으로 검색 (findByTitle) --- .../com/gdsc/blog/article/entity/Article.java | 1 - .../article/repository/ArticleRepository.java | 2 +- .../com/gdsc/blog/BlogApplicationTests.java | 46 +++++++++++++++++-- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/entity/Article.java b/src/main/java/com/gdsc/blog/article/entity/Article.java index 927a1d5..f560511 100644 --- a/src/main/java/com/gdsc/blog/article/entity/Article.java +++ b/src/main/java/com/gdsc/blog/article/entity/Article.java @@ -7,7 +7,6 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import java.time.LocalDateTime; import lombok.AllArgsConstructor; diff --git a/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java b/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java index 6c54653..92d28cb 100644 --- a/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java +++ b/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java @@ -6,5 +6,5 @@ @Repository public interface ArticleRepository extends JpaRepository { - + Article findByTitle(String title); } diff --git a/src/test/java/com/gdsc/blog/BlogApplicationTests.java b/src/test/java/com/gdsc/blog/BlogApplicationTests.java index 0110b45..f7a42ba 100644 --- a/src/test/java/com/gdsc/blog/BlogApplicationTests.java +++ b/src/test/java/com/gdsc/blog/BlogApplicationTests.java @@ -1,8 +1,12 @@ package com.gdsc.blog; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.repository.ArticleRepository; import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -19,14 +23,50 @@ void contextLoads() {} @Test void testRepository(){ - //create new post + ////create new post Article post1 = new Article(); //set title and content - post1.setTitle("Post test 1 title"); - post1.setContent("Post test 2 content"); + post1.setTitle("Post1 title"); + post1.setContent("Post1 content"); post1.setCreateDate(LocalDateTime.now()); //save post this.articleRepository.save(post1); + + Article post2 = new Article(); + post2.setTitle("Post2 title"); + post2.setContent("Post2 content"); + post2.setCreateDate(LocalDateTime.now()); + this.articleRepository.save(post2); + + ////find all post + List
posts = this.articleRepository.findAll(); + assertEquals(2, posts.size()); //check post count + + ////check post title and content + Article p1 = posts.get(0); + assertEquals("Post1 title", p1.getTitle()); + assertEquals("Post1 content", p1.getContent()); + Article p2 = posts.get(1); + assertEquals("Post2 title", p2.getTitle()); + assertEquals("Post2 content", p2.getContent()); + + ////get id + Optional
oa1 = this.articleRepository.findById(p1.getIdx()); + Optional
oa2 = this.articleRepository.findById(p2.getIdx()); + if(oa1.isPresent() && oa2.isPresent()){ + Article a1 = oa1.get(); + Article a2 = oa2.get(); + assertEquals("Post1 title", a1.getTitle()); + assertEquals("Post1 content", a1.getContent()); + assertEquals("Post2 title", a2.getTitle()); + assertEquals("Post2 content", a2.getContent()); + } + + //search by title + Article a1 = this.articleRepository.findByTitle("Post1 title"); + assertEquals(1, a1.getIdx()); + Article a2 = this.articleRepository.findByTitle("Post2 title"); + assertEquals(2, a2.getIdx()); } } From d85b433a380bacbf0a8efbfd7c6fe30731e3073d Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Wed, 5 Jul 2023 15:06:34 +0900 Subject: [PATCH 03/36] Add: like search by title or content in article MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit findByTitleLikeOrContentLike() Title과 Content를 like로 검색 --- .../com/gdsc/blog/article/repository/ArticleRepository.java | 2 ++ src/test/java/com/gdsc/blog/BlogApplicationTests.java | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java b/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java index 92d28cb..879283d 100644 --- a/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java +++ b/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java @@ -1,10 +1,12 @@ package com.gdsc.blog.article.repository; import com.gdsc.blog.article.entity.Article; +import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface ArticleRepository extends JpaRepository { Article findByTitle(String title); + List
findByTitleLikeOrContentLike(String title, String content); } diff --git a/src/test/java/com/gdsc/blog/BlogApplicationTests.java b/src/test/java/com/gdsc/blog/BlogApplicationTests.java index f7a42ba..f1e8985 100644 --- a/src/test/java/com/gdsc/blog/BlogApplicationTests.java +++ b/src/test/java/com/gdsc/blog/BlogApplicationTests.java @@ -67,6 +67,12 @@ void testRepository(){ assertEquals(1, a1.getIdx()); Article a2 = this.articleRepository.findByTitle("Post2 title"); assertEquals(2, a2.getIdx()); + + //search by title or content + List
findPost = this.articleRepository.findByTitleLikeOrContentLike("%Post1%", "%Post1%"); + post1 = findPost.get(0); + assertEquals("Post1 title", post1.getTitle()); + assertEquals("Post1 content", post1.getContent()); } } From 5a563f87b8332d5551dca4b34538fee71dba57be Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Wed, 5 Jul 2023 15:11:56 +0900 Subject: [PATCH 04/36] Add: Update article feature in test code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test code를 통해 article 데이터 수정 구현 --- src/test/java/com/gdsc/blog/BlogApplicationTests.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/test/java/com/gdsc/blog/BlogApplicationTests.java b/src/test/java/com/gdsc/blog/BlogApplicationTests.java index f1e8985..2ea5d9d 100644 --- a/src/test/java/com/gdsc/blog/BlogApplicationTests.java +++ b/src/test/java/com/gdsc/blog/BlogApplicationTests.java @@ -73,6 +73,13 @@ void testRepository(){ post1 = findPost.get(0); assertEquals("Post1 title", post1.getTitle()); assertEquals("Post1 content", post1.getContent()); + + //update post + post1.setTitle("Post1 title updated"); + post1.setContent("Post1 content updated"); + this.articleRepository.save(post1); + assertEquals("Post1 title updated", post1.getTitle()); + assertEquals("Post1 content update", post1.getContent()); } } From 71c21fbbd4c2e12d42772738fafb62d3ed5f2a70 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Wed, 5 Jul 2023 15:14:09 +0900 Subject: [PATCH 05/36] Add: Delete article feature in test code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test code를 통해 article 삭제 구현 --- src/test/java/com/gdsc/blog/BlogApplicationTests.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/gdsc/blog/BlogApplicationTests.java b/src/test/java/com/gdsc/blog/BlogApplicationTests.java index 2ea5d9d..009da75 100644 --- a/src/test/java/com/gdsc/blog/BlogApplicationTests.java +++ b/src/test/java/com/gdsc/blog/BlogApplicationTests.java @@ -77,9 +77,15 @@ void testRepository(){ //update post post1.setTitle("Post1 title updated"); post1.setContent("Post1 content updated"); - this.articleRepository.save(post1); + this.articleRepository.save(post1); //save post assertEquals("Post1 title updated", post1.getTitle()); - assertEquals("Post1 content update", post1.getContent()); + assertEquals("Post1 content updated", post1.getContent()); + + //delete post + assertEquals(2, this.articleRepository.count()); //before delete post + this.articleRepository.delete(post1); //delete one post + assertEquals(1, this.articleRepository.count()); //after delete post + } } From 10e249c527d43780dff73b44af03f22650952b63 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Sat, 8 Jul 2023 09:11:27 +0900 Subject: [PATCH 06/36] Add: Create comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commentService.create를 통해 댓글 저장 기능 추가 --- .../article/controller/ArticleController.java | 13 +++- .../com/gdsc/blog/article/entity/Article.java | 7 ++ .../article/repository/ArticleRepository.java | 2 +- .../blog/article/service/ArticleService.java | 29 +++++++ .../comment/controller/CommentController.java | 35 +++++++++ .../com/gdsc/blog/comment/entity/Comment.java | 35 +++++++++ .../comment/repository/CommentRepository.java | 9 +++ .../blog/comment/service/CommentService.java | 22 ++++++ .../gdsc/blog/user/service/UserService.java | 78 +++++++++---------- .../com/gdsc/blog/BlogApplicationTests.java | 34 +++++++- 10 files changed, 221 insertions(+), 43 deletions(-) create mode 100644 src/main/java/com/gdsc/blog/article/service/ArticleService.java create mode 100644 src/main/java/com/gdsc/blog/comment/controller/CommentController.java create mode 100644 src/main/java/com/gdsc/blog/comment/entity/Comment.java create mode 100644 src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java create mode 100644 src/main/java/com/gdsc/blog/comment/service/CommentService.java diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index 870295f..4b06dd2 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -1,7 +1,12 @@ package com.gdsc.blog.article.controller; +import com.gdsc.blog.article.entity.Article; +import com.gdsc.blog.article.service.ArticleService; import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; import lombok.extern.slf4j.Slf4j; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -10,6 +15,12 @@ @RestController @RequestMapping("/api/article") public class ArticleController { + ArticleService articleService; - + @GetMapping("/article/list") + public String list(Model model) { + List
articleList = this.articleService.getArticleList(); + model.addAttribute("articleList", articleList); + return "article/list"; + } } diff --git a/src/main/java/com/gdsc/blog/article/entity/Article.java b/src/main/java/com/gdsc/blog/article/entity/Article.java index f560511..a8c7a83 100644 --- a/src/main/java/com/gdsc/blog/article/entity/Article.java +++ b/src/main/java/com/gdsc/blog/article/entity/Article.java @@ -1,14 +1,18 @@ package com.gdsc.blog.article.entity; +import com.gdsc.blog.comment.entity.Comment; import com.gdsc.blog.user.entity.User; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import java.time.LocalDateTime; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -36,4 +40,7 @@ public class Article { //set relationship between article and user @ManyToOne private User user; + + @OneToMany(mappedBy = "article", cascade = CascadeType.REMOVE) + private List comments; } \ No newline at end of file diff --git a/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java b/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java index 879283d..2ab0283 100644 --- a/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java +++ b/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java @@ -9,4 +9,4 @@ public interface ArticleRepository extends JpaRepository { Article findByTitle(String title); List
findByTitleLikeOrContentLike(String title, String content); -} +} \ No newline at end of file diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java new file mode 100644 index 0000000..8065fcd --- /dev/null +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -0,0 +1,29 @@ +package com.gdsc.blog.article.service; + +import com.gdsc.blog.article.entity.Article; +import com.gdsc.blog.article.repository.ArticleRepository; +import java.util.List; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Service; + +@RequiredArgsConstructor +@Service +public class ArticleService { + private final ArticleRepository articleRepository; + + public List
getArticleList(){ //get all articles + return this.articleRepository.findAll(); + } + + public Article getArticle(Long idx){ //get article by id + Optional
article = this.articleRepository.findById(idx); + if(article.isPresent()){ + return article.get(); + } + else{ //not found article by id + throw new NullPointerException("Article not found"); + } + } +} diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java new file mode 100644 index 0000000..a2a6423 --- /dev/null +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -0,0 +1,35 @@ +package com.gdsc.blog.comment.controller; + +import com.gdsc.blog.article.entity.Article; +import com.gdsc.blog.article.service.ArticleService; +import com.gdsc.blog.comment.entity.Comment; +import com.gdsc.blog.comment.repository.CommentRepository; +import com.gdsc.blog.comment.service.CommentService; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.time.LocalDateTime; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@Controller +@RequestMapping("/comment") +@RequiredArgsConstructor +@Slf4j +@Tag(name = "Comment", description = "Comment API") +public class CommentController { + private final ArticleService articleService; + private final CommentService commentService; + + @PostMapping("/create/{postId}") + public void createComment(@PathVariable("id") Long idx, @RequestParam String content){ + Article article = this.articleService.getArticle(idx); + this.commentService.create(article, content); + } +} diff --git a/src/main/java/com/gdsc/blog/comment/entity/Comment.java b/src/main/java/com/gdsc/blog/comment/entity/Comment.java new file mode 100644 index 0000000..00b0969 --- /dev/null +++ b/src/main/java/com/gdsc/blog/comment/entity/Comment.java @@ -0,0 +1,35 @@ +package com.gdsc.blog.comment.entity; + +import com.gdsc.blog.article.entity.Article; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Table(name = "comments") +public class Comment { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long idx; //id + + @Column(length = 200) + private String content; //내용 + + private LocalDateTime creeateData; + + @ManyToOne + private Article article; +} diff --git a/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java b/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java new file mode 100644 index 0000000..4b257eb --- /dev/null +++ b/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java @@ -0,0 +1,9 @@ +package com.gdsc.blog.comment.repository; + +import com.gdsc.blog.comment.entity.Comment; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CommentRepository extends JpaRepository{ + List findByArticleIdx(Long articleIdx); +} diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java new file mode 100644 index 0000000..67eef3a --- /dev/null +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -0,0 +1,22 @@ +package com.gdsc.blog.comment.service; + +import com.gdsc.blog.article.entity.Article; +import com.gdsc.blog.comment.entity.Comment; +import com.gdsc.blog.comment.repository.CommentRepository; +import java.time.LocalDateTime; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@RequiredArgsConstructor +@Service +public class CommentService { + private final CommentRepository commentRepository; + + public void create(Article article, String content){ + Comment comment = new Comment(); + comment.setArticle(article); + comment.setContent(content); + comment.setCreeateData(LocalDateTime.now()); + this.commentRepository.save(comment); + } +} diff --git a/src/main/java/com/gdsc/blog/user/service/UserService.java b/src/main/java/com/gdsc/blog/user/service/UserService.java index 3160448..a8969cf 100644 --- a/src/main/java/com/gdsc/blog/user/service/UserService.java +++ b/src/main/java/com/gdsc/blog/user/service/UserService.java @@ -22,50 +22,50 @@ @RequiredArgsConstructor public class UserService { - private final UserRepository userRepository; - private final PasswordEncoder passwordEncoder; - private final JwtTokenProvider jwtTokenProvider; + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + private final JwtTokenProvider jwtTokenProvider; - public String singin(String email, String password) { - try { - User user = userRepository.findByEmail(email).get(); - log.info("user: {}", user); - log.info("email: {}", email); - log.info("password: {}", password); - if (!passwordEncoder.matches(password, user.getPassword())) { - log.error("Invalid password"); - throw new RuntimeException("Invalid password"); - } - return jwtTokenProvider.createToken(user.getUsername(), user.getRoles()); + public String singin(String email, String password) { + try { + User user = userRepository.findByEmail(email).get(); + log.info("user: {}", user); + log.info("email: {}", email); + log.info("password: {}", password); + if (!passwordEncoder.matches(password, user.getPassword())) { + log.error("Invalid password"); + throw new RuntimeException("Invalid password"); + } + return jwtTokenProvider.createToken(user.getUsername(), user.getRoles()); - } catch (Exception e) { - log.info(e.getMessage()); - log.error("Invalid username/password supplied"); - throw new RuntimeException("Invalid username/password supplied"); - } - } + } catch (Exception e) { + log.info(e.getMessage()); + log.error("Invalid username/password supplied"); + throw new RuntimeException("Invalid username/password supplied"); + } + } - public User signup(User user) { - user.setPassword(passwordEncoder.encode(user.getPassword())); - // Client 역할 부여 - if (user.getRoles() == null) { - List set = new ArrayList(); - set.add(UserRole.ROLE_CLIENT); - user.setRoles(set); - } - return userRepository.save(user); - } + public User signup(User user) { + user.setPassword(passwordEncoder.encode(user.getPassword())); + // Client 역할 부여 + if (user.getRoles() == null) { + List set = new ArrayList(); + set.add(UserRole.ROLE_CLIENT); + user.setRoles(set); + } + return userRepository.save(user); + } - public User getUser(String username) { - return userRepository.findByEmail(username).get(); - } + public User getUser(String username) { + return userRepository.findByEmail(username).get(); + } - public User whoami(HttpServletRequest req) { - log.info(jwtTokenProvider.resolveToken(req)); - return userRepository - .findByUsername(jwtTokenProvider.getUsername(jwtTokenProvider.resolveToken(req))) - .get(); - } + public User whoami(HttpServletRequest req) { + log.info(jwtTokenProvider.resolveToken(req)); + return userRepository + .findByUsername(jwtTokenProvider.getUsername(jwtTokenProvider.resolveToken(req))) + .get(); + } } diff --git a/src/test/java/com/gdsc/blog/BlogApplicationTests.java b/src/test/java/com/gdsc/blog/BlogApplicationTests.java index 009da75..36b9b52 100644 --- a/src/test/java/com/gdsc/blog/BlogApplicationTests.java +++ b/src/test/java/com/gdsc/blog/BlogApplicationTests.java @@ -4,6 +4,9 @@ import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.repository.ArticleRepository; +import com.gdsc.blog.comment.entity.Comment; +import com.gdsc.blog.comment.repository.CommentRepository; +import com.gdsc.blog.comment.service.CommentService; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -22,7 +25,7 @@ class BlogApplicationTests { void contextLoads() {} @Test - void testRepository(){ + void testArticle(){ ////create new post Article post1 = new Article(); //set title and content @@ -85,7 +88,34 @@ void testRepository(){ assertEquals(2, this.articleRepository.count()); //before delete post this.articleRepository.delete(post1); //delete one post assertEquals(1, this.articleRepository.count()); //after delete post - } + + @Autowired + private CommentRepository commentRepository; + @Autowired + private CommentService commentService; + + @Test + void testComment(){ + //create new post + Article post1 = new Article(); + //set title and content + post1.setTitle("Post1 title"); + post1.setContent("Post1 content"); + post1.setCreateDate(LocalDateTime.now()); + //save post + this.articleRepository.save(post1); + + //create new comment + String content = "post1 comment"; + this.commentService.create(post1, content); + this.commentService.create(post1, content); + this.commentService.create(post1, content); + + //get comment by article + Long articleIdx = post1.getIdx(); + List comments = this.commentRepository.findByArticleIdx(articleIdx); + assertEquals(3, comments.size()); //check comment count + } } From 67e0277e8a3c69d212ff96446946777666f5ac91 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Sat, 8 Jul 2023 09:51:58 +0900 Subject: [PATCH 07/36] Add: Read comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CommentService.getComment를 통해 댓글 내용 확인 기능 추가 --- .../comment/controller/CommentController.java | 16 ++++++++++++++++ .../comment/repository/CommentRepository.java | 2 +- .../blog/comment/service/CommentService.java | 14 ++++++++++++++ .../java/com/gdsc/blog/BlogApplicationTests.java | 12 ++++++++---- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index a2a6423..55768bf 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -27,9 +27,25 @@ public class CommentController { private final ArticleService articleService; private final CommentService commentService; + /** + * Create comment + * @param idx article id + * @param content comment content + */ @PostMapping("/create/{postId}") public void createComment(@PathVariable("id") Long idx, @RequestParam String content){ Article article = this.articleService.getArticle(idx); this.commentService.create(article, content); } + + /** + * Read comment + * @param idx comment id + * @return comment content + */ + @PostMapping("/read/{commentId}") + public String readComment(@PathVariable("commentId") Long idx){ + Comment comment = this.commentService.getComment(idx); + return comment.getContent(); + } } diff --git a/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java b/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java index 4b257eb..03d2b38 100644 --- a/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java +++ b/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java @@ -6,4 +6,4 @@ public interface CommentRepository extends JpaRepository{ List findByArticleIdx(Long articleIdx); -} +} \ No newline at end of file diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index 67eef3a..91d244b 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -12,6 +12,11 @@ public class CommentService { private final CommentRepository commentRepository; + /** + * Create comment + * @param article article object + * @param content comment content + */ public void create(Article article, String content){ Comment comment = new Comment(); comment.setArticle(article); @@ -19,4 +24,13 @@ public void create(Article article, String content){ comment.setCreeateData(LocalDateTime.now()); this.commentRepository.save(comment); } + + /** + * Get comment object + * @param idx comment id + * @return comment object + */ + public Comment getComment(Long idx){ + return this.commentRepository.findById(idx).orElseThrow(); + } } diff --git a/src/test/java/com/gdsc/blog/BlogApplicationTests.java b/src/test/java/com/gdsc/blog/BlogApplicationTests.java index 36b9b52..c725a9d 100644 --- a/src/test/java/com/gdsc/blog/BlogApplicationTests.java +++ b/src/test/java/com/gdsc/blog/BlogApplicationTests.java @@ -108,14 +108,18 @@ void testComment(){ this.articleRepository.save(post1); //create new comment - String content = "post1 comment"; - this.commentService.create(post1, content); - this.commentService.create(post1, content); - this.commentService.create(post1, content); + for(int i = 0; i < 3; i++){ + this.commentService.create(post1, "post1 comment" + String.valueOf(i+1)); + } //get comment by article Long articleIdx = post1.getIdx(); List comments = this.commentRepository.findByArticleIdx(articleIdx); assertEquals(3, comments.size()); //check comment count + + //get comment by id + Comment c = comments.get(2); + String content = this.commentService.getComment(c.getIdx()).getContent(); + assertEquals("post1 comment3", content); } } From 247011c4ead7ad9c99a1b1713034fd600c34660f Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Sat, 8 Jul 2023 10:07:59 +0900 Subject: [PATCH 08/36] Fix: test get comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit id를 통해 comment를 받아서 바로 결과를 테스트합니다 --- .../gdsc/blog/comment/controller/CommentController.java | 8 ++++---- .../com/gdsc/blog/comment/service/CommentService.java | 1 + src/test/java/com/gdsc/blog/BlogApplicationTests.java | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index 55768bf..94edc4d 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -34,8 +34,8 @@ public class CommentController { */ @PostMapping("/create/{postId}") public void createComment(@PathVariable("id") Long idx, @RequestParam String content){ - Article article = this.articleService.getArticle(idx); - this.commentService.create(article, content); + Article article = this.articleService.getArticle(idx); //get article object + this.commentService.create(article, content); //create comment } /** @@ -45,7 +45,7 @@ public void createComment(@PathVariable("id") Long idx, @RequestParam String con */ @PostMapping("/read/{commentId}") public String readComment(@PathVariable("commentId") Long idx){ - Comment comment = this.commentService.getComment(idx); - return comment.getContent(); + Comment comment = this.commentService.getComment(idx); //get comment object + return comment.getContent(); //return comment content } } diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index 91d244b..3a2a89e 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -31,6 +31,7 @@ public void create(Article article, String content){ * @return comment object */ public Comment getComment(Long idx){ + //return comment object if exists, or thorw exception return this.commentRepository.findById(idx).orElseThrow(); } } diff --git a/src/test/java/com/gdsc/blog/BlogApplicationTests.java b/src/test/java/com/gdsc/blog/BlogApplicationTests.java index c725a9d..69031a1 100644 --- a/src/test/java/com/gdsc/blog/BlogApplicationTests.java +++ b/src/test/java/com/gdsc/blog/BlogApplicationTests.java @@ -118,8 +118,8 @@ void testComment(){ assertEquals(3, comments.size()); //check comment count //get comment by id - Comment c = comments.get(2); - String content = this.commentService.getComment(c.getIdx()).getContent(); - assertEquals("post1 comment3", content); + Comment c = this.commentService.getComment(Long.valueOf(3)); //get comment by id + String content = c.getContent(); //get comment content + assertEquals("post1 comment3", content); //check comment content } } From c305540e1727ff23e03ecf3daa1471b9bbba3147 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Sat, 8 Jul 2023 10:34:43 +0900 Subject: [PATCH 09/36] Add: update comment --- .../blog/comment/controller/CommentController.java | 13 +++++++++++++ .../java/com/gdsc/blog/comment/entity/Comment.java | 3 ++- .../gdsc/blog/comment/service/CommentService.java | 11 ++++++++++- .../java/com/gdsc/blog/BlogApplicationTests.java | 8 +++++++- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index 94edc4d..6304223 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -48,4 +48,17 @@ public String readComment(@PathVariable("commentId") Long idx){ Comment comment = this.commentService.getComment(idx); //get comment object return comment.getContent(); //return comment content } + + /** + * Update comment + * @param idx comment id + * @param content comment content + */ + @PostMapping("/update/{commentId}") + public void updateComment(@PathVariable("commentId") Long idx, @RequestParam String content){ + Comment comment = this.commentService.getComment(idx); //get comment object + comment.setContent(content); //update comment content + comment.setModifyData(LocalDateTime.now()); //update modify date + this.commentService.update(comment); //save comment + } } diff --git a/src/main/java/com/gdsc/blog/comment/entity/Comment.java b/src/main/java/com/gdsc/blog/comment/entity/Comment.java index 00b0969..eff0749 100644 --- a/src/main/java/com/gdsc/blog/comment/entity/Comment.java +++ b/src/main/java/com/gdsc/blog/comment/entity/Comment.java @@ -28,7 +28,8 @@ public class Comment { @Column(length = 200) private String content; //내용 - private LocalDateTime creeateData; + private LocalDateTime createData; //create date + private LocalDateTime modifyData; //update date @ManyToOne private Article article; diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index 3a2a89e..c0ce020 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -21,7 +21,8 @@ public void create(Article article, String content){ Comment comment = new Comment(); comment.setArticle(article); comment.setContent(content); - comment.setCreeateData(LocalDateTime.now()); + comment.setCreateData(LocalDateTime.now()); + comment.setModifyData(LocalDateTime.now()); this.commentRepository.save(comment); } @@ -34,4 +35,12 @@ public Comment getComment(Long idx){ //return comment object if exists, or thorw exception return this.commentRepository.findById(idx).orElseThrow(); } + + /** + * Update comment + * @param comment comment object + */ + public void update(Comment comment){ + this.commentRepository.save(comment); + } } diff --git a/src/test/java/com/gdsc/blog/BlogApplicationTests.java b/src/test/java/com/gdsc/blog/BlogApplicationTests.java index 69031a1..035336c 100644 --- a/src/test/java/com/gdsc/blog/BlogApplicationTests.java +++ b/src/test/java/com/gdsc/blog/BlogApplicationTests.java @@ -117,9 +117,15 @@ void testComment(){ List comments = this.commentRepository.findByArticleIdx(articleIdx); assertEquals(3, comments.size()); //check comment count - //get comment by id + //get comment content Comment c = this.commentService.getComment(Long.valueOf(3)); //get comment by id String content = c.getContent(); //get comment content assertEquals("post1 comment3", content); //check comment content + + //update comment + c.setContent("post1 comment3 updated"); + c.setModifyData(LocalDateTime.now()); + this.commentService.update(c); + assertEquals("post1 comment3 updated", c.getContent()); //check updated content } } From bdc530dd2862774dfdbd1a9b8c6042b463d39167 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Sat, 8 Jul 2023 10:44:30 +0900 Subject: [PATCH 10/36] Add: delete comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 나중에 로그인 인증 후 CRUD을 수행할 수 있게 추가하겠습니다 --- .../com/gdsc/blog/comment/controller/CommentController.java | 6 ++++++ .../java/com/gdsc/blog/comment/service/CommentService.java | 6 +++++- src/test/java/com/gdsc/blog/BlogApplicationTests.java | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index 6304223..faec039 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -61,4 +61,10 @@ public void updateComment(@PathVariable("commentId") Long idx, @RequestParam Str comment.setModifyData(LocalDateTime.now()); //update modify date this.commentService.update(comment); //save comment } + + @PostMapping("/delete/{commentId}") + public void deleteComment(@PathVariable("commentId") Long idx){ + Comment comment = this.commentService.getComment(idx); //get comment object + this.commentService.delete(comment); //delete comment + } } diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index c0ce020..13ce5d1 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -32,7 +32,7 @@ public void create(Article article, String content){ * @return comment object */ public Comment getComment(Long idx){ - //return comment object if exists, or thorw exception + //return comment object if exists, or throw exception return this.commentRepository.findById(idx).orElseThrow(); } @@ -43,4 +43,8 @@ public Comment getComment(Long idx){ public void update(Comment comment){ this.commentRepository.save(comment); } + + public void delete(Comment comment){ + this.commentRepository.delete(comment); + } } diff --git a/src/test/java/com/gdsc/blog/BlogApplicationTests.java b/src/test/java/com/gdsc/blog/BlogApplicationTests.java index 035336c..c523993 100644 --- a/src/test/java/com/gdsc/blog/BlogApplicationTests.java +++ b/src/test/java/com/gdsc/blog/BlogApplicationTests.java @@ -127,5 +127,9 @@ void testComment(){ c.setModifyData(LocalDateTime.now()); this.commentService.update(c); assertEquals("post1 comment3 updated", c.getContent()); //check updated content + + //delete comment + this.commentService.delete(c); + assertEquals(2, this.commentRepository.count()); //check comment count } } From e76bd33f111e7d244f5cfc371495858b9b5e09b5 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Sun, 9 Jul 2023 11:26:34 +0900 Subject: [PATCH 11/36] Add save login user in comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit comment 저장 시 로그인된 유저를 저장 --- .../gdsc/blog/article/service/ArticleService.java | 2 ++ .../comment/controller/CommentController.java | 15 +++++++++------ .../com/gdsc/blog/comment/entity/Comment.java | 4 ++++ .../gdsc/blog/comment/service/CommentService.java | 5 ++++- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index 8065fcd..16198d3 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -13,6 +13,8 @@ public class ArticleService { private final ArticleRepository articleRepository; + + public List
getArticleList(){ //get all articles return this.articleRepository.findAll(); } diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index faec039..b6edcda 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -3,16 +3,15 @@ import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.service.ArticleService; import com.gdsc.blog.comment.entity.Comment; -import com.gdsc.blog.comment.repository.CommentRepository; import com.gdsc.blog.comment.service.CommentService; +import com.gdsc.blog.user.entity.User; +import com.gdsc.blog.user.service.UserService; import io.swagger.v3.oas.annotations.tags.Tag; +import java.security.Principal; import java.time.LocalDateTime; -import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -26,16 +25,20 @@ public class CommentController { private final ArticleService articleService; private final CommentService commentService; + private final UserService userService; /** * Create comment * @param idx article id * @param content comment content + * @param principal login user */ @PostMapping("/create/{postId}") - public void createComment(@PathVariable("id") Long idx, @RequestParam String content){ + public void createComment(@PathVariable("id") Long idx, @RequestParam String content, Principal principal){ Article article = this.articleService.getArticle(idx); //get article object - this.commentService.create(article, content); //create comment + User user = this.userService.getUser(principal.getName()); //login 유저 정보 가져오기 + + this.commentService.create(article, content, user); //create comment } /** diff --git a/src/main/java/com/gdsc/blog/comment/entity/Comment.java b/src/main/java/com/gdsc/blog/comment/entity/Comment.java index eff0749..26627fa 100644 --- a/src/main/java/com/gdsc/blog/comment/entity/Comment.java +++ b/src/main/java/com/gdsc/blog/comment/entity/Comment.java @@ -1,6 +1,7 @@ package com.gdsc.blog.comment.entity; import com.gdsc.blog.article.entity.Article; +import com.gdsc.blog.user.entity.User; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -33,4 +34,7 @@ public class Comment { @ManyToOne private Article article; + + @ManyToOne + private User user; } diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index 13ce5d1..2810956 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -3,6 +3,7 @@ import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.comment.entity.Comment; import com.gdsc.blog.comment.repository.CommentRepository; +import com.gdsc.blog.user.entity.User; import java.time.LocalDateTime; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -16,13 +17,15 @@ public class CommentService { * Create comment * @param article article object * @param content comment content + * @param user login user */ - public void create(Article article, String content){ + public void create(Article article, String content, User user){ Comment comment = new Comment(); comment.setArticle(article); comment.setContent(content); comment.setCreateData(LocalDateTime.now()); comment.setModifyData(LocalDateTime.now()); + comment.setUser(user); this.commentRepository.save(comment); } From e33831ba365274ffebca6758f321b36defe95186 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Sun, 9 Jul 2023 11:41:56 +0900 Subject: [PATCH 12/36] Add save login user in Article MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Article에 user 정보가 함께 저장됩니다 --- .../article/controller/ArticleController.java | 14 +++++++++++++- .../blog/article/service/ArticleService.java | 17 ++++++++++++++++- .../comment/controller/CommentController.java | 2 +- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index 4b06dd2..87c3807 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -2,11 +2,15 @@ import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.service.ArticleService; +import com.gdsc.blog.user.entity.User; +import com.gdsc.blog.user.service.UserService; import io.swagger.v3.oas.annotations.tags.Tag; +import java.security.Principal; import java.util.List; import lombok.extern.slf4j.Slf4j; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -16,8 +20,16 @@ @RequestMapping("/api/article") public class ArticleController { ArticleService articleService; + UserService userService; - @GetMapping("/article/list") + @PostMapping("/create") + public void createArticle(String title, String content, Principal principal){ + User user = this.userService.getUser(principal.getName()); //login 유저 정보 가져오기 + + this.articleService.createArticle(title, content, user); //게시글 생성 + } + + @GetMapping("/list") public String list(Model model) { List
articleList = this.articleService.getArticleList(); model.addAttribute("articleList", articleList); diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index 16198d3..df7fadd 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -2,6 +2,8 @@ import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.repository.ArticleRepository; +import com.gdsc.blog.user.entity.User; +import java.time.LocalDateTime; import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; @@ -13,7 +15,20 @@ public class ArticleService { private final ArticleRepository articleRepository; - + /** + * 게시글 생성 + * @param title 제목 + * @param content 내용 + * @param user 작성자 + */ + public void createArticle(String title, String content, User user){ //create new article + Article article = new Article(); + article.setTitle(title); + article.setContent(content); + article.setCreateDate(LocalDateTime.now()); + article.setUser(user); + this.articleRepository.save(article); + } public List
getArticleList(){ //get all articles return this.articleRepository.findAll(); diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index b6edcda..e707a8f 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -18,7 +18,7 @@ import org.springframework.web.bind.annotation.RequestParam; @Controller -@RequestMapping("/comment") +@RequestMapping("api/comment") @RequiredArgsConstructor @Slf4j @Tag(name = "Comment", description = "Comment API") From 55fa8a2e58e6dbe7c82ede5ca4c3ca8c9311389e Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Sun, 9 Jul 2023 11:55:28 +0900 Subject: [PATCH 13/36] Add method article controller and service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit article의 controller와 service에서 실행되어야 할 기능 메서드 추가 --- .../article/controller/ArticleController.java | 29 ++++++++++++++++++- .../com/gdsc/blog/article/entity/Article.java | 3 +- .../blog/article/service/ArticleService.java | 26 +++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index 87c3807..c56d694 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -6,13 +6,17 @@ import com.gdsc.blog.user.service.UserService; import io.swagger.v3.oas.annotations.tags.Tag; import java.security.Principal; +import java.time.LocalDateTime; import java.util.List; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; @Slf4j @Tag(name = "Article", description = "Article API") @@ -25,14 +29,37 @@ public class ArticleController { @PostMapping("/create") public void createArticle(String title, String content, Principal principal){ User user = this.userService.getUser(principal.getName()); //login 유저 정보 가져오기 - this.articleService.createArticle(title, content, user); //게시글 생성 } + @GetMapping("/list") public String list(Model model) { List
articleList = this.articleService.getArticleList(); model.addAttribute("articleList", articleList); return "article/list"; } + + @PreAuthorize("isAuthenticated()") + @GetMapping("/update/{articleId}") + public void updateArticle(String title, String content, Long id, Principal principal){ + Article article = this.articleService.getArticle(id); //게시글 정보 가져오기 + if(!article.getUser().getUsername().equals(principal.getName())){ //게시글 작성자와 로그인 유저가 다를 경우 + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "게시글을 수정할 권한이 없습니다."); + } + article.setTitle(title); + article.setContent(content); + article.setModifyDate(LocalDateTime.now()); + this.articleService.update(article); + } + + @PreAuthorize("isAuthenticated()") + @GetMapping("/delete/{articleId}") + public void deleteArticle(Long id, Principal principal){ + Article article = this.articleService.getArticle(id); //게시글 정보 가져오기 + if(!article.getUser().getUsername().equals(principal.getName())){ //게시글 작성자와 로그인 유저가 다를 경우 + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "게시글을 삭제할 권한이 없습니다."); + } + this.articleService.delete(article); + } } diff --git a/src/main/java/com/gdsc/blog/article/entity/Article.java b/src/main/java/com/gdsc/blog/article/entity/Article.java index a8c7a83..b2464e7 100644 --- a/src/main/java/com/gdsc/blog/article/entity/Article.java +++ b/src/main/java/com/gdsc/blog/article/entity/Article.java @@ -35,7 +35,8 @@ public class Article { @Column(columnDefinition = "TEXT") //no limit length of text private String content; - private LocalDateTime createDate; + private LocalDateTime createDate; //생성 날짜 + private LocalDateTime modifyDate; //수정된 날짜 //set relationship between article and user @ManyToOne diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index df7fadd..29201e0 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -26,14 +26,24 @@ public void createArticle(String title, String content, User user){ //create new article.setTitle(title); article.setContent(content); article.setCreateDate(LocalDateTime.now()); + article.setModifyDate(LocalDateTime.now()); article.setUser(user); this.articleRepository.save(article); } + /** + * 게시글 목록 조회 + * @return 게시글 목록 + */ public List
getArticleList(){ //get all articles return this.articleRepository.findAll(); } + /** + * id로 게시글 조회 + * @param idx 게시글 id + * @return Article 객체 + */ public Article getArticle(Long idx){ //get article by id Optional
article = this.articleRepository.findById(idx); if(article.isPresent()){ @@ -43,4 +53,20 @@ public Article getArticle(Long idx){ //get article by id throw new NullPointerException("Article not found"); } } + + /** + * 게시글 수정 + * @param article Article 객체 + */ + public void update(Article article){ + this.articleRepository.save(article); + } + + /** + * 게시글 삭제 + * @param article Article 객체 + */ + public void delete(Article article){ + this.articleRepository.delete(article); + } } From 3d1490352e3ed7cabc252f0e7c2f0e7a9762ae3d Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Mon, 10 Jul 2023 09:50:43 +0900 Subject: [PATCH 14/36] Add Principal in article and comment controller method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 로그인 권한을 확인하기 위해 Principal 객체 추가 Principal로 로그인 권한 확인 후 수정, 삭제 기능 수행 --- .idea/misc.xml | 2 +- .idea/modules.xml | 8 ++++++++ .idea/modules/blog.main.iml | 8 ++++++++ .../article/controller/ArticleController.java | 6 +++--- .../comment/controller/CommentController.java | 15 +++++++++++++-- 5 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 .idea/modules.xml create mode 100644 .idea/modules/blog.main.iml diff --git a/.idea/misc.xml b/.idea/misc.xml index 668048d..49504ef 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..0f4e222 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/blog.main.iml b/.idea/modules/blog.main.iml new file mode 100644 index 0000000..afc1871 --- /dev/null +++ b/.idea/modules/blog.main.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index c56d694..9723ace 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -40,8 +40,8 @@ public String list(Model model) { return "article/list"; } - @PreAuthorize("isAuthenticated()") @GetMapping("/update/{articleId}") + @PreAuthorize("isAuthenticated()") public void updateArticle(String title, String content, Long id, Principal principal){ Article article = this.articleService.getArticle(id); //게시글 정보 가져오기 if(!article.getUser().getUsername().equals(principal.getName())){ //게시글 작성자와 로그인 유저가 다를 경우 @@ -53,11 +53,11 @@ public void updateArticle(String title, String content, Long id, Principal princ this.articleService.update(article); } - @PreAuthorize("isAuthenticated()") @GetMapping("/delete/{articleId}") + @PreAuthorize("isAuthenticated()") public void deleteArticle(Long id, Principal principal){ Article article = this.articleService.getArticle(id); //게시글 정보 가져오기 - if(!article.getUser().getUsername().equals(principal.getName())){ //게시글 작성자와 로그인 유저가 다를 경우 + if(!article.getUser().getUsername().equals(principal.getName())){ //게시글 삭제 권한 확인 throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "게시글을 삭제할 권한이 없습니다."); } this.articleService.delete(article); diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index e707a8f..d6de697 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -11,11 +11,14 @@ import java.time.LocalDateTime; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.server.ResponseStatusException; @Controller @RequestMapping("api/comment") @@ -58,16 +61,24 @@ public String readComment(@PathVariable("commentId") Long idx){ * @param content comment content */ @PostMapping("/update/{commentId}") - public void updateComment(@PathVariable("commentId") Long idx, @RequestParam String content){ + @PreAuthorize("isAuthenticated()") + public void updateComment(@PathVariable("commentId") Long idx, @RequestParam String content, Principal principal){ Comment comment = this.commentService.getComment(idx); //get comment object + if(!comment.getUser().getUsername().equals(principal.getName())){ //수정 권한 확인 + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "댓글을 수정할 권한이 없습니다."); + } comment.setContent(content); //update comment content comment.setModifyData(LocalDateTime.now()); //update modify date this.commentService.update(comment); //save comment } @PostMapping("/delete/{commentId}") - public void deleteComment(@PathVariable("commentId") Long idx){ + @PreAuthorize("isAuthenticated()") + public void deleteComment(@PathVariable("commentId") Long idx, Principal principal){ Comment comment = this.commentService.getComment(idx); //get comment object + if(comment.getUser().getUsername().equals(principal.getName())){ //삭제 권한 확인 + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "댓글을 삭제할 권한이 없습니다."); + } this.commentService.delete(comment); //delete comment } } From ea9c94588ea9d9b0b69429700eca430a28895523 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Tue, 11 Jul 2023 21:02:51 +0900 Subject: [PATCH 15/36] Add Swagger annotation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Article과 Comment에 Swagger 어노테이션 추가 --- .idea/misc.xml | 3 ++ .../article/controller/ArticleController.java | 31 ++++++++++--------- .../blog/article/service/ArticleService.java | 24 +++++++++++--- .../comment/controller/CommentController.java | 25 ++++++++++++--- .../blog/comment/service/CommentService.java | 22 ++++++++++--- .../com/gdsc/blog/BlogApplicationTests.java | 16 ++++++++-- 6 files changed, 91 insertions(+), 30 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 49504ef..de0c428 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,5 +1,8 @@ + + + \ No newline at end of file diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index 9723ace..25b67b1 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -4,14 +4,14 @@ import com.gdsc.blog.article.service.ArticleService; import com.gdsc.blog.user.entity.User; import com.gdsc.blog.user.service.UserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import java.security.Principal; import java.time.LocalDateTime; -import java.util.List; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -19,7 +19,7 @@ import org.springframework.web.server.ResponseStatusException; @Slf4j -@Tag(name = "Article", description = "Article API") +@Tag(name = "게시글 Controller", description = "Article controller API") @RestController @RequestMapping("/api/article") public class ArticleController { @@ -27,22 +27,23 @@ public class ArticleController { UserService userService; @PostMapping("/create") - public void createArticle(String title, String content, Principal principal){ + @Operation(summary = "게시글 생성") + public void createArticle( + @Parameter(name = "제목") String title, + @Parameter(name = "내용") String content, + @Parameter(name = "Principal", description = "로그인 유저 정보를 가지는 principal 객체") Principal principal + ){ User user = this.userService.getUser(principal.getName()); //login 유저 정보 가져오기 this.articleService.createArticle(title, content, user); //게시글 생성 } - - @GetMapping("/list") - public String list(Model model) { - List
articleList = this.articleService.getArticleList(); - model.addAttribute("articleList", articleList); - return "article/list"; - } - @GetMapping("/update/{articleId}") @PreAuthorize("isAuthenticated()") - public void updateArticle(String title, String content, Long id, Principal principal){ + public void updateArticle( + @Parameter(name = "제목") String title, + @Parameter(name = "수정할 내용") String content, + @Parameter(name = "게시글 id") Long id, + @Parameter(name = "Principal", description = "로그인 유저 정보를 가지는 principal 객체") Principal principal){ Article article = this.articleService.getArticle(id); //게시글 정보 가져오기 if(!article.getUser().getUsername().equals(principal.getName())){ //게시글 작성자와 로그인 유저가 다를 경우 throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "게시글을 수정할 권한이 없습니다."); @@ -55,7 +56,9 @@ public void updateArticle(String title, String content, Long id, Principal princ @GetMapping("/delete/{articleId}") @PreAuthorize("isAuthenticated()") - public void deleteArticle(Long id, Principal principal){ + public void deleteArticle( + @Parameter(name = "제목") Long id, + @Parameter(name = "Principal", description = "로그인 유저 정보를 가지는 principal 객체") Principal principal){ Article article = this.articleService.getArticle(id); //게시글 정보 가져오기 if(!article.getUser().getUsername().equals(principal.getName())){ //게시글 삭제 권한 확인 throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "게시글을 삭제할 권한이 없습니다."); diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index 29201e0..44e7a57 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -3,15 +3,18 @@ import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.repository.ArticleRepository; import com.gdsc.blog.user.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; @RequiredArgsConstructor @Service +@Tag(name = "게시글 Service", description = "Article service API") public class ArticleService { private final ArticleRepository articleRepository; @@ -21,7 +24,11 @@ public class ArticleService { * @param content 내용 * @param user 작성자 */ - public void createArticle(String title, String content, User user){ //create new article + @Operation(summary = "게시글 생성") + public void createArticle( + @Parameter(name = "제목") String title, + @Parameter(name = "내용") String content, + @Parameter(name = "유저 객체") User user){ //create new article Article article = new Article(); article.setTitle(title); article.setContent(content); @@ -35,6 +42,7 @@ public void createArticle(String title, String content, User user){ //create new * 게시글 목록 조회 * @return 게시글 목록 */ + @Operation(summary = "게시글 목록 가져오기") public List
getArticleList(){ //get all articles return this.articleRepository.findAll(); } @@ -44,7 +52,9 @@ public List
getArticleList(){ //get all articles * @param idx 게시글 id * @return Article 객체 */ - public Article getArticle(Long idx){ //get article by id + @Operation(summary = "게시글 조회") + public Article getArticle( + @Parameter(name = "게시글 id") Long idx){ //get article by id Optional
article = this.articleRepository.findById(idx); if(article.isPresent()){ return article.get(); @@ -58,7 +68,9 @@ public Article getArticle(Long idx){ //get article by id * 게시글 수정 * @param article Article 객체 */ - public void update(Article article){ + @Operation(summary = "게시글 수정") + public void update( + @Parameter(name = "개시글 객체") Article article){ this.articleRepository.save(article); } @@ -66,7 +78,9 @@ public void update(Article article){ * 게시글 삭제 * @param article Article 객체 */ - public void delete(Article article){ + @Operation(summary = "게시글 삭제") + public void delete( + @Parameter(name = "개시글 객체") Article article){ this.articleRepository.delete(article); } } diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index d6de697..35a47b4 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -6,6 +6,8 @@ import com.gdsc.blog.comment.service.CommentService; import com.gdsc.blog.user.entity.User; import com.gdsc.blog.user.service.UserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import java.security.Principal; import java.time.LocalDateTime; @@ -24,7 +26,7 @@ @RequestMapping("api/comment") @RequiredArgsConstructor @Slf4j -@Tag(name = "Comment", description = "Comment API") +@Tag(name = "댓글", description = "Comment Controller API") public class CommentController { private final ArticleService articleService; private final CommentService commentService; @@ -37,7 +39,11 @@ public class CommentController { * @param principal login user */ @PostMapping("/create/{postId}") - public void createComment(@PathVariable("id") Long idx, @RequestParam String content, Principal principal){ + @Operation(summary = "댓글 생성") + public void createComment( + @Parameter(name = "게시글 id") @PathVariable("postId") Long idx, + @Parameter(name = "내용") String content, + @Parameter(name = "principal", description = "로그인 유저 정보를 가지는 principal 객체") Principal principal) { Article article = this.articleService.getArticle(idx); //get article object User user = this.userService.getUser(principal.getName()); //login 유저 정보 가져오기 @@ -50,7 +56,9 @@ public void createComment(@PathVariable("id") Long idx, @RequestParam String con * @return comment content */ @PostMapping("/read/{commentId}") - public String readComment(@PathVariable("commentId") Long idx){ + @Operation(summary = "댓글 읽기") + public String readComment( + @Parameter(name = "댓글 id") @PathVariable("commentId") Long idx){ Comment comment = this.commentService.getComment(idx); //get comment object return comment.getContent(); //return comment content } @@ -62,7 +70,11 @@ public String readComment(@PathVariable("commentId") Long idx){ */ @PostMapping("/update/{commentId}") @PreAuthorize("isAuthenticated()") - public void updateComment(@PathVariable("commentId") Long idx, @RequestParam String content, Principal principal){ + @Operation(summary = "댓글 수정") + public void updateComment( + @Parameter(name = "댓글 id") @PathVariable("commentId") Long idx, + @Parameter(name = "수정 내용") @RequestParam String content, + @Parameter(name = "principal", description = "로그인 유저 정보를 가지는 principal 객체") Principal principal){ Comment comment = this.commentService.getComment(idx); //get comment object if(!comment.getUser().getUsername().equals(principal.getName())){ //수정 권한 확인 throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "댓글을 수정할 권한이 없습니다."); @@ -74,7 +86,10 @@ public void updateComment(@PathVariable("commentId") Long idx, @RequestParam Str @PostMapping("/delete/{commentId}") @PreAuthorize("isAuthenticated()") - public void deleteComment(@PathVariable("commentId") Long idx, Principal principal){ + @Operation(summary = "댓글 삭제") + public void deleteComment( + @Parameter(name = "댓글 id") @PathVariable("commentId") Long idx, + @Parameter(name = "principal", description = "로그인 유저 정보를 가지는 principal 객체") Principal principal){ Comment comment = this.commentService.getComment(idx); //get comment object if(comment.getUser().getUsername().equals(principal.getName())){ //삭제 권한 확인 throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "댓글을 삭제할 권한이 없습니다."); diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index 2810956..5dbafe0 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -4,12 +4,16 @@ import com.gdsc.blog.comment.entity.Comment; import com.gdsc.blog.comment.repository.CommentRepository; import com.gdsc.blog.user.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; import java.time.LocalDateTime; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @RequiredArgsConstructor @Service +@Tag(name = "댓글 service", description = "Comment service API") public class CommentService { private final CommentRepository commentRepository; @@ -19,7 +23,11 @@ public class CommentService { * @param content comment content * @param user login user */ - public void create(Article article, String content, User user){ + @Operation(summary = "댓글 생성") + public void create( + @Parameter(name = "article", description = "댓글을 생성할 게시글") Article article, + @Parameter(name = "댓글 내용") String content, + @Parameter(name = "로그인 유저", description = "user 객체") User user){ Comment comment = new Comment(); comment.setArticle(article); comment.setContent(content); @@ -34,7 +42,9 @@ public void create(Article article, String content, User user){ * @param idx comment id * @return comment object */ - public Comment getComment(Long idx){ + @Operation(summary = "id로 댓글 가져오기") + public Comment getComment( + @Parameter(name = "댓글 id") Long idx) { //return comment object if exists, or throw exception return this.commentRepository.findById(idx).orElseThrow(); } @@ -43,11 +53,15 @@ public Comment getComment(Long idx){ * Update comment * @param comment comment object */ - public void update(Comment comment){ + @Operation(summary = "댓글 수정") + public void update( + @Parameter(name = "댓글", description = "수정할 댓글 객체") Comment comment){ this.commentRepository.save(comment); } - public void delete(Comment comment){ + @Operation(summary = "댓글 삭제") + public void delete( + @Parameter(name = "댓글", description = "삭제할 댓글 객체") Comment comment){ this.commentRepository.delete(comment); } } diff --git a/src/test/java/com/gdsc/blog/BlogApplicationTests.java b/src/test/java/com/gdsc/blog/BlogApplicationTests.java index c523993..683a77c 100644 --- a/src/test/java/com/gdsc/blog/BlogApplicationTests.java +++ b/src/test/java/com/gdsc/blog/BlogApplicationTests.java @@ -4,9 +4,12 @@ import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.repository.ArticleRepository; +import com.gdsc.blog.article.service.ArticleService; import com.gdsc.blog.comment.entity.Comment; import com.gdsc.blog.comment.repository.CommentRepository; import com.gdsc.blog.comment.service.CommentService; +import com.gdsc.blog.user.controller.UserController; +import com.gdsc.blog.user.entity.User; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -18,12 +21,21 @@ @SpringBootTest @Profile("test") class BlogApplicationTests { - @Autowired - private ArticleRepository articleRepository; @Test void contextLoads() {} + @Autowired + private UserController userController; + + + @Autowired + private ArticleRepository articleRepository; + + @Autowired + private ArticleService articleService; + + @Test void testArticle(){ ////create new post From 6630e49732da9799837dd5ba4777a2de2c395ce5 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Wed, 12 Jul 2023 12:11:36 +0900 Subject: [PATCH 16/36] Fix DI to Article controller of UserService MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Article controller에 UserService가 제대로 DI되지 않아 발생한 오류 해결 --- .../article/controller/ArticleController.java | 75 +++++++++++++------ .../comment/controller/CommentController.java | 40 +++++----- .../blog/configuration/SecurityConfig.java | 11 +-- .../gdsc/blog/user/service/UserService.java | 24 +++++- 4 files changed, 99 insertions(+), 51 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index 25b67b1..274a1ec 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -7,62 +7,89 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; -import java.security.Principal; +import jakarta.servlet.http.HttpServletRequest; import java.time.LocalDateTime; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.server.ResponseStatusException; @Slf4j @Tag(name = "게시글 Controller", description = "Article controller API") @RestController @RequestMapping("/api/article") public class ArticleController { - ArticleService articleService; - UserService userService; - @PostMapping("/create") - @Operation(summary = "게시글 생성") + private final ArticleService articleService; + private final UserService userService; + + @Autowired + public ArticleController(ArticleService articleService, UserService userService) { + this.articleService = articleService; + this.userService = userService; + } + + /** + * 게시글 생성 + * @param title 제목 + * @param content 내용 + */ + @PostMapping("/create") //컨트롤러 메핑 + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") //권한 설정 + @Operation(summary = "게시글 생성") //swagger 설명 public void createArticle( - @Parameter(name = "제목") String title, - @Parameter(name = "내용") String content, - @Parameter(name = "Principal", description = "로그인 유저 정보를 가지는 principal 객체") Principal principal - ){ - User user = this.userService.getUser(principal.getName()); //login 유저 정보 가져오기 + @Parameter(name = "제목") String title, //swagger 파라미터 설명 + @Parameter(name = "내용") String content) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + String userName = authentication.getName(); + + User user = userService.getUserByName(userName); //로그인 유저 정보 가져오기 this.articleService.createArticle(title, content, user); //게시글 생성 } + /** + * 게시글 수정 + * @param title 제목 + * @param content 내용 + * @param id 게시글 id + * @param req HTTP 파싱 객체 + */ @GetMapping("/update/{articleId}") - @PreAuthorize("isAuthenticated()") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") + @Operation(summary = "게시글 수정") public void updateArticle( @Parameter(name = "제목") String title, @Parameter(name = "수정할 내용") String content, @Parameter(name = "게시글 id") Long id, - @Parameter(name = "Principal", description = "로그인 유저 정보를 가지는 principal 객체") Principal principal){ + @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { + User user = userService.whoami(req); //로그인 유저 정보 가져오기 + Article article = this.articleService.getArticle(id); //게시글 정보 가져오기 - if(!article.getUser().getUsername().equals(principal.getName())){ //게시글 작성자와 로그인 유저가 다를 경우 - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "게시글을 수정할 권한이 없습니다."); - } article.setTitle(title); article.setContent(content); article.setModifyDate(LocalDateTime.now()); this.articleService.update(article); } + /** + * 게시글 삭제 + * @param id 게시글 id + * @param req HTTP 파싱 객체 + */ @GetMapping("/delete/{articleId}") - @PreAuthorize("isAuthenticated()") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") + @Operation(summary = "게시글 삭제") public void deleteArticle( - @Parameter(name = "제목") Long id, - @Parameter(name = "Principal", description = "로그인 유저 정보를 가지는 principal 객체") Principal principal){ - Article article = this.articleService.getArticle(id); //게시글 정보 가져오기 - if(!article.getUser().getUsername().equals(principal.getName())){ //게시글 삭제 권한 확인 - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "게시글을 삭제할 권한이 없습니다."); - } + @Parameter(name = "게시글 id") Long id, + @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { + User user = userService.whoami(req); + Article article = this.articleService.getArticle(id); + this.articleService.delete(article); } } diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index 35a47b4..d1c3196 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -9,18 +9,16 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; -import java.security.Principal; +import jakarta.servlet.http.HttpServletRequest; import java.time.LocalDateTime; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.server.ResponseStatusException; @Controller @RequestMapping("api/comment") @@ -36,17 +34,18 @@ public class CommentController { * Create comment * @param idx article id * @param content comment content - * @param principal login user + * @param req HTTP parsing object */ - @PostMapping("/create/{postId}") + @PostMapping("/create/{postId}") //컨트롤러 메핑 + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") //권한 설정 @Operation(summary = "댓글 생성") public void createComment( @Parameter(name = "게시글 id") @PathVariable("postId") Long idx, @Parameter(name = "내용") String content, - @Parameter(name = "principal", description = "로그인 유저 정보를 가지는 principal 객체") Principal principal) { - Article article = this.articleService.getArticle(idx); //get article object - User user = this.userService.getUser(principal.getName()); //login 유저 정보 가져오기 + @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { + User user = userService.whoami(req); //로그인 유저 정보 가져오기 + Article article = this.articleService.getArticle(idx); //get article object this.commentService.create(article, content, user); //create comment } @@ -56,6 +55,7 @@ public void createComment( * @return comment content */ @PostMapping("/read/{commentId}") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") @Operation(summary = "댓글 읽기") public String readComment( @Parameter(name = "댓글 id") @PathVariable("commentId") Long idx){ @@ -67,33 +67,37 @@ public String readComment( * Update comment * @param idx comment id * @param content comment content + * @param req HTTP parsing object */ @PostMapping("/update/{commentId}") - @PreAuthorize("isAuthenticated()") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") @Operation(summary = "댓글 수정") public void updateComment( @Parameter(name = "댓글 id") @PathVariable("commentId") Long idx, @Parameter(name = "수정 내용") @RequestParam String content, - @Parameter(name = "principal", description = "로그인 유저 정보를 가지는 principal 객체") Principal principal){ + @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req){ + User user = userService.whoami(req); + Comment comment = this.commentService.getComment(idx); //get comment object - if(!comment.getUser().getUsername().equals(principal.getName())){ //수정 권한 확인 - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "댓글을 수정할 권한이 없습니다."); - } comment.setContent(content); //update comment content comment.setModifyData(LocalDateTime.now()); //update modify date this.commentService.update(comment); //save comment } + /** + * 댓글 삭제 + * @param idx 댓글 id + * @param req HTTP 파싱 객체 + */ @PostMapping("/delete/{commentId}") - @PreAuthorize("isAuthenticated()") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") @Operation(summary = "댓글 삭제") public void deleteComment( @Parameter(name = "댓글 id") @PathVariable("commentId") Long idx, - @Parameter(name = "principal", description = "로그인 유저 정보를 가지는 principal 객체") Principal principal){ + @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req){ + User user = userService.whoami(req); + Comment comment = this.commentService.getComment(idx); //get comment object - if(comment.getUser().getUsername().equals(principal.getName())){ //삭제 권한 확인 - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "댓글을 삭제할 권한이 없습니다."); - } this.commentService.delete(comment); //delete comment } } diff --git a/src/main/java/com/gdsc/blog/configuration/SecurityConfig.java b/src/main/java/com/gdsc/blog/configuration/SecurityConfig.java index d194f30..608bd50 100644 --- a/src/main/java/com/gdsc/blog/configuration/SecurityConfig.java +++ b/src/main/java/com/gdsc/blog/configuration/SecurityConfig.java @@ -2,6 +2,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -26,12 +27,12 @@ public PasswordEncoder passwordEncoder() { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { // Disable CSRF (cross site request forgery) - http.authorizeRequests() - .requestMatchers("/h2-console/**", "/swagger-ui/**", "/swagger-resources/**", - "/v3/api-docs/**", "/api/user/signin", "/api/user/signup") - .permitAll().anyRequest().authenticated(); +// http.authorizeRequests() +// .requestMatchers("/h2-console/**", "/swagger-ui/**", "/swagger-resources/**", +// "/v3/api-docs/**", "/api/user/signin", "/api/user/signup") +// .permitAll().anyRequest().authenticated(); - http.csrf().disable(); + http.csrf(csrf->csrf.disable()); http.apply(new JwtTokenFilterConfigurer(jwtTokenProvider)); diff --git a/src/main/java/com/gdsc/blog/user/service/UserService.java b/src/main/java/com/gdsc/blog/user/service/UserService.java index a8969cf..7f91f6f 100644 --- a/src/main/java/com/gdsc/blog/user/service/UserService.java +++ b/src/main/java/com/gdsc/blog/user/service/UserService.java @@ -27,6 +27,8 @@ public class UserService { private final JwtTokenProvider jwtTokenProvider; + + public String singin(String email, String password) { try { User user = userRepository.findByEmail(email).get(); @@ -61,11 +63,25 @@ public User getUser(String username) { return userRepository.findByEmail(username).get(); } + public User getUserByName(String username) { + try { + return userRepository.findByUsername(username).get(); + } catch (Exception e) { //예외 처리 + log.error("User not found"); + throw new RuntimeException("User not found"); + } + } + public User whoami(HttpServletRequest req) { - log.info(jwtTokenProvider.resolveToken(req)); - return userRepository - .findByUsername(jwtTokenProvider.getUsername(jwtTokenProvider.resolveToken(req))) - .get(); + try{ + log.info(jwtTokenProvider.resolveToken(req)); + return userRepository + .findByUsername(jwtTokenProvider.getUsername(jwtTokenProvider.resolveToken(req))) + .get(); + } catch (Exception e) { //예외 처리 + log.error("User not found"); + throw new RuntimeException("User not found"); + } } } From 8a8d54af52846fe6674f1745e9cb98fd34627937 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Wed, 12 Jul 2023 13:16:23 +0900 Subject: [PATCH 17/36] Fix sendError() when create Article MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Article을 생성할 때 발생하는 sendError() 해결 - Entity에 @JsonBackReference 추가 --- .../article/controller/ArticleController.java | 40 +++++++++++++------ .../com/gdsc/blog/article/entity/Article.java | 5 +++ .../blog/article/service/ArticleService.java | 21 +++++----- .../com/gdsc/blog/comment/entity/Comment.java | 2 + 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index 274a1ec..d8faec5 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -9,6 +9,8 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import java.time.LocalDateTime; +import java.util.List; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; @@ -23,33 +25,45 @@ @Tag(name = "게시글 Controller", description = "Article controller API") @RestController @RequestMapping("/api/article") +@RequiredArgsConstructor public class ArticleController { private final ArticleService articleService; private final UserService userService; - @Autowired - public ArticleController(ArticleService articleService, UserService userService) { - this.articleService = articleService; - this.userService = userService; - } - /** * 게시글 생성 * @param title 제목 * @param content 내용 + * @return 생성된 게시글 */ @PostMapping("/create") //컨트롤러 메핑 @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") //권한 설정 @Operation(summary = "게시글 생성") //swagger 설명 - public void createArticle( + public Article createArticle( @Parameter(name = "제목") String title, //swagger 파라미터 설명 @Parameter(name = "내용") String content) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String userName = authentication.getName(); User user = userService.getUserByName(userName); //로그인 유저 정보 가져오기 - this.articleService.createArticle(title, content, user); //게시글 생성 + return articleService.createArticle(title, content, user); //게시글 생성 + } + + /** + * 모든 게시글 조회 + * @param req HTTP 파싱 객체 + * @return 게시글 목록 + */ + @GetMapping("/allArticle") + @Operation(summary = "모든 게시글 조회") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") + public List
getUserArticle( + @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req + ) { + User user = userService.whoami(req); //로그인 유저 정보 가져오기 + + return articleService.getUserArticle(user); } /** @@ -67,13 +81,13 @@ public void updateArticle( @Parameter(name = "수정할 내용") String content, @Parameter(name = "게시글 id") Long id, @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { - User user = userService.whoami(req); //로그인 유저 정보 가져오기 + User user = userService.whoami(req); - Article article = this.articleService.getArticle(id); //게시글 정보 가져오기 + Article article = articleService.getArticle(id); //게시글 정보 가져오기 article.setTitle(title); article.setContent(content); article.setModifyDate(LocalDateTime.now()); - this.articleService.update(article); + articleService.update(article); } /** @@ -88,8 +102,8 @@ public void deleteArticle( @Parameter(name = "게시글 id") Long id, @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { User user = userService.whoami(req); - Article article = this.articleService.getArticle(id); + Article article = articleService.getArticle(id); - this.articleService.delete(article); + articleService.delete(article); } } diff --git a/src/main/java/com/gdsc/blog/article/entity/Article.java b/src/main/java/com/gdsc/blog/article/entity/Article.java index b2464e7..0fb1927 100644 --- a/src/main/java/com/gdsc/blog/article/entity/Article.java +++ b/src/main/java/com/gdsc/blog/article/entity/Article.java @@ -1,5 +1,6 @@ package com.gdsc.blog.article.entity; +import com.fasterxml.jackson.annotation.JsonBackReference; import com.gdsc.blog.comment.entity.Comment; import com.gdsc.blog.user.entity.User; import jakarta.persistence.CascadeType; @@ -14,6 +15,8 @@ import java.time.LocalDateTime; import java.util.List; import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -23,6 +26,7 @@ @NoArgsConstructor @Getter @Setter +@Builder @Table(name = "articles") public class Article { @Id @@ -40,6 +44,7 @@ public class Article { //set relationship between article and user @ManyToOne + @JsonBackReference private User user; @OneToMany(mappedBy = "article", cascade = CascadeType.REMOVE) diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index 44e7a57..88d6ff5 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -10,10 +10,11 @@ import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -@RequiredArgsConstructor @Service +@RequiredArgsConstructor @Tag(name = "게시글 Service", description = "Article service API") public class ArticleService { private final ArticleRepository articleRepository; @@ -25,7 +26,7 @@ public class ArticleService { * @param user 작성자 */ @Operation(summary = "게시글 생성") - public void createArticle( + public Article createArticle( @Parameter(name = "제목") String title, @Parameter(name = "내용") String content, @Parameter(name = "유저 객체") User user){ //create new article @@ -35,16 +36,16 @@ public void createArticle( article.setCreateDate(LocalDateTime.now()); article.setModifyDate(LocalDateTime.now()); article.setUser(user); - this.articleRepository.save(article); + return articleRepository.save(article); } /** - * 게시글 목록 조회 + * 유저 게시글 목록 조회 * @return 게시글 목록 */ - @Operation(summary = "게시글 목록 가져오기") - public List
getArticleList(){ //get all articles - return this.articleRepository.findAll(); + @Operation(summary = "유저 게시글 목록 가져오기") + public List
getUserArticle(User user){ //get all articles + return user.getArticles(); } /** @@ -55,7 +56,7 @@ public List
getArticleList(){ //get all articles @Operation(summary = "게시글 조회") public Article getArticle( @Parameter(name = "게시글 id") Long idx){ //get article by id - Optional
article = this.articleRepository.findById(idx); + Optional
article = articleRepository.findById(idx); if(article.isPresent()){ return article.get(); } @@ -71,7 +72,7 @@ public Article getArticle( @Operation(summary = "게시글 수정") public void update( @Parameter(name = "개시글 객체") Article article){ - this.articleRepository.save(article); + articleRepository.save(article); } /** @@ -81,6 +82,6 @@ public void update( @Operation(summary = "게시글 삭제") public void delete( @Parameter(name = "개시글 객체") Article article){ - this.articleRepository.delete(article); + articleRepository.delete(article); } } diff --git a/src/main/java/com/gdsc/blog/comment/entity/Comment.java b/src/main/java/com/gdsc/blog/comment/entity/Comment.java index 26627fa..0539702 100644 --- a/src/main/java/com/gdsc/blog/comment/entity/Comment.java +++ b/src/main/java/com/gdsc/blog/comment/entity/Comment.java @@ -1,5 +1,6 @@ package com.gdsc.blog.comment.entity; +import com.fasterxml.jackson.annotation.JsonBackReference; import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.user.entity.User; import jakarta.persistence.Column; @@ -36,5 +37,6 @@ public class Comment { private Article article; @ManyToOne + @JsonBackReference private User user; } From 3d08cfe5ca1d501a66f64a32f5690981c5fcb7bb Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Wed, 12 Jul 2023 13:28:33 +0900 Subject: [PATCH 18/36] Add dto in article MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit article에 dto를 적용하여 DB에 저장 --- .../article/controller/ArticleController.java | 19 +++++++++++------ .../com/gdsc/blog/article/dto/CreateDto.java | 21 +++++++++++++++++++ .../blog/article/service/ArticleService.java | 10 ++------- 3 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/gdsc/blog/article/dto/CreateDto.java diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index d8faec5..f6fccb3 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -1,5 +1,6 @@ package com.gdsc.blog.article.controller; +import com.gdsc.blog.article.dto.CreateDto; import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.service.ArticleService; import com.gdsc.blog.user.entity.User; @@ -18,6 +19,7 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -33,21 +35,26 @@ public class ArticleController { /** * 게시글 생성 - * @param title 제목 - * @param content 내용 + * @param dto 게시글 생성 정보 * @return 생성된 게시글 */ @PostMapping("/create") //컨트롤러 메핑 @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") //권한 설정 @Operation(summary = "게시글 생성") //swagger 설명 public Article createArticle( - @Parameter(name = "제목") String title, //swagger 파라미터 설명 - @Parameter(name = "내용") String content) { + @RequestBody CreateDto dto){ + //게시글 생성 + Article article = Article.builder() + .title(dto.getTitle()) + .content(dto.getContent()) + .build(); + + //로그인 유저 정보 가져오기 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String userName = authentication.getName(); - User user = userService.getUserByName(userName); //로그인 유저 정보 가져오기 - return articleService.createArticle(title, content, user); //게시글 생성 + User user = userService.getUserByName(userName); //유저 이름 가져오기 + return articleService.createArticle(article, user); } /** diff --git a/src/main/java/com/gdsc/blog/article/dto/CreateDto.java b/src/main/java/com/gdsc/blog/article/dto/CreateDto.java new file mode 100644 index 0000000..ca67574 --- /dev/null +++ b/src/main/java/com/gdsc/blog/article/dto/CreateDto.java @@ -0,0 +1,21 @@ +package com.gdsc.blog.article.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Getter +@Setter +public class CreateDto { + @Schema(description = "제목") + public String title; + + @Schema(description = "내용") + public String content; +} diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index 88d6ff5..a1c52ef 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service @@ -21,18 +20,13 @@ public class ArticleService { /** * 게시글 생성 - * @param title 제목 - * @param content 내용 + * @param article Article 객체 * @param user 작성자 */ @Operation(summary = "게시글 생성") public Article createArticle( - @Parameter(name = "제목") String title, - @Parameter(name = "내용") String content, + Article article, @Parameter(name = "유저 객체") User user){ //create new article - Article article = new Article(); - article.setTitle(title); - article.setContent(content); article.setCreateDate(LocalDateTime.now()); article.setModifyDate(LocalDateTime.now()); article.setUser(user); From 877e468dc4df37577ca1d95abe95cfec7ce1bbc4 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Thu, 13 Jul 2023 00:05:39 +0900 Subject: [PATCH 19/36] Fix http 400, 500 error of Article CRUD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DTO 생성 - @PathVariable에서 @Parameter 제거 - 권한 ROLE_CLIENT 변경 --- .../article/controller/ArticleController.java | 53 +++++++++++-------- .../com/gdsc/blog/article/dto/UpdateDto.java | 21 ++++++++ .../com/gdsc/blog/article/entity/Article.java | 2 +- .../blog/article/service/ArticleService.java | 28 +++++++--- .../comment/controller/CommentController.java | 2 +- .../java/com/gdsc/blog/user/entity/User.java | 4 ++ .../gdsc/blog/user/service/UserService.java | 23 ++++---- 7 files changed, 87 insertions(+), 46 deletions(-) create mode 100644 src/main/java/com/gdsc/blog/article/dto/UpdateDto.java diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index f6fccb3..55a7c9e 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -1,6 +1,7 @@ package com.gdsc.blog.article.controller; import com.gdsc.blog.article.dto.CreateDto; +import com.gdsc.blog.article.dto.UpdateDto; import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.service.ArticleService; import com.gdsc.blog.user.entity.User; @@ -13,11 +14,13 @@ import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.crossstore.ChangeSetPersister; +import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -39,10 +42,10 @@ public class ArticleController { * @return 생성된 게시글 */ @PostMapping("/create") //컨트롤러 메핑 - @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") //권한 설정 + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") //권한 설정 @Operation(summary = "게시글 생성") //swagger 설명 public Article createArticle( - @RequestBody CreateDto dto){ + @Parameter(name="게시글 생성 DTO") @RequestBody CreateDto dto){ //게시글 생성 Article article = Article.builder() .title(dto.getTitle()) @@ -64,7 +67,7 @@ public Article createArticle( */ @GetMapping("/allArticle") @Operation(summary = "모든 게시글 조회") - @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") public List
getUserArticle( @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req ) { @@ -73,28 +76,31 @@ public List
getUserArticle( return articleService.getUserArticle(user); } + @GetMapping("/update/{id}") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") + @Operation(summary = "id로 게시글 조회") + public Article getArticleById( + @PathVariable("id") Long id, //PathVariable에는 @Parameter를 사용할 수 없음! + @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req){ + return articleService.getArticleById(id); + } + /** * 게시글 수정 - * @param title 제목 - * @param content 내용 * @param id 게시글 id + * @param dto 게시글 수정 정보 * @param req HTTP 파싱 객체 */ - @GetMapping("/update/{articleId}") - @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") + @PostMapping("/update/{id}") //생성 & 수정은 PostMapping + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "게시글 수정") - public void updateArticle( - @Parameter(name = "제목") String title, - @Parameter(name = "수정할 내용") String content, - @Parameter(name = "게시글 id") Long id, - @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { + public Article updateArticle( + @PathVariable(value = "id") Long id, + @Parameter(name="게시글 생성 DTO") @RequestBody UpdateDto dto, + @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) throws ChangeSetPersister.NotFoundException, AccessDeniedException { User user = userService.whoami(req); - Article article = articleService.getArticle(id); //게시글 정보 가져오기 - article.setTitle(title); - article.setContent(content); - article.setModifyDate(LocalDateTime.now()); - articleService.update(article); + return articleService.updateArticle(id, dto, user); } /** @@ -102,15 +108,16 @@ public void updateArticle( * @param id 게시글 id * @param req HTTP 파싱 객체 */ - @GetMapping("/delete/{articleId}") - @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") + @GetMapping("/delete/{id}") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "게시글 삭제") public void deleteArticle( - @Parameter(name = "게시글 id") Long id, + @PathVariable(value = "id") Long id, @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { User user = userService.whoami(req); - Article article = articleService.getArticle(id); - articleService.delete(article); + Article article = articleService.getArticleById(id); + + articleService.deleteArticle(article); } } diff --git a/src/main/java/com/gdsc/blog/article/dto/UpdateDto.java b/src/main/java/com/gdsc/blog/article/dto/UpdateDto.java new file mode 100644 index 0000000..5dd92d3 --- /dev/null +++ b/src/main/java/com/gdsc/blog/article/dto/UpdateDto.java @@ -0,0 +1,21 @@ +package com.gdsc.blog.article.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Getter +@Setter +public class UpdateDto { + @Schema(description = "수정할 제목") + public String title; + + @Schema(description = "수정할 내용") + public String content; +} diff --git a/src/main/java/com/gdsc/blog/article/entity/Article.java b/src/main/java/com/gdsc/blog/article/entity/Article.java index 0fb1927..2623491 100644 --- a/src/main/java/com/gdsc/blog/article/entity/Article.java +++ b/src/main/java/com/gdsc/blog/article/entity/Article.java @@ -22,8 +22,8 @@ import lombok.Setter; @Entity -@AllArgsConstructor @NoArgsConstructor +@AllArgsConstructor //생성자 자동 생성 @Getter @Setter @Builder diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index a1c52ef..c4f7c9c 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -1,5 +1,6 @@ package com.gdsc.blog.article.service; +import com.gdsc.blog.article.dto.UpdateDto; import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.repository.ArticleRepository; import com.gdsc.blog.user.entity.User; @@ -25,7 +26,7 @@ public class ArticleService { */ @Operation(summary = "게시글 생성") public Article createArticle( - Article article, + @Parameter(name = "게시글 객체") Article article, @Parameter(name = "유저 객체") User user){ //create new article article.setCreateDate(LocalDateTime.now()); article.setModifyDate(LocalDateTime.now()); @@ -48,25 +49,36 @@ public List
getUserArticle(User user){ //get all articles * @return Article 객체 */ @Operation(summary = "게시글 조회") - public Article getArticle( + public Article getArticleById( @Parameter(name = "게시글 id") Long idx){ //get article by id Optional
article = articleRepository.findById(idx); + if(article.isPresent()){ return article.get(); } else{ //not found article by id - throw new NullPointerException("Article not found"); + throw new NullPointerException("Not found Article by id"); } } /** * 게시글 수정 - * @param article Article 객체 + * @param id 게시글 id + * @param dto 게시글 수정 DTO + * @param user 작성자 + * @return Article 객체 */ @Operation(summary = "게시글 수정") - public void update( - @Parameter(name = "개시글 객체") Article article){ - articleRepository.save(article); + public Article updateArticle( + @Parameter(name = "게시글 id") Long id, + @Parameter(name = "게시글 수정 DTO") UpdateDto dto, + @Parameter(name = "작성자") User user){ + + Article article = getArticleById(id); //게시글 id로 게시글 가져오기 + article.setTitle(dto.getTitle()); + article.setContent(dto.getContent()); + article.setModifyDate(LocalDateTime.now()); + return articleRepository.save(article); } /** @@ -74,7 +86,7 @@ public void update( * @param article Article 객체 */ @Operation(summary = "게시글 삭제") - public void delete( + public void deleteArticle( @Parameter(name = "개시글 객체") Article article){ articleRepository.delete(article); } diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index d1c3196..a2c4e26 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -45,7 +45,7 @@ public void createComment( @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { User user = userService.whoami(req); //로그인 유저 정보 가져오기 - Article article = this.articleService.getArticle(idx); //get article object + Article article = this.articleService.getArticleById(idx); //get article object this.commentService.create(article, content, user); //create comment } diff --git a/src/main/java/com/gdsc/blog/user/entity/User.java b/src/main/java/com/gdsc/blog/user/entity/User.java index c261b45..aefb45b 100644 --- a/src/main/java/com/gdsc/blog/user/entity/User.java +++ b/src/main/java/com/gdsc/blog/user/entity/User.java @@ -7,6 +7,8 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import lombok.Getter; +import lombok.Setter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; @@ -30,6 +32,8 @@ @Builder @AllArgsConstructor @NoArgsConstructor +@Getter +@Setter @Table(name = "users") public class User { diff --git a/src/main/java/com/gdsc/blog/user/service/UserService.java b/src/main/java/com/gdsc/blog/user/service/UserService.java index 7f91f6f..efb0db6 100644 --- a/src/main/java/com/gdsc/blog/user/service/UserService.java +++ b/src/main/java/com/gdsc/blog/user/service/UserService.java @@ -26,8 +26,16 @@ public class UserService { private final PasswordEncoder passwordEncoder; private final JwtTokenProvider jwtTokenProvider; - - + public User signup(User user) { + user.setPassword(passwordEncoder.encode(user.getPassword())); + // Client 역할 부여 + if (user.getRoles() == null) { + List set = new ArrayList(); + set.add(UserRole.ROLE_CLIENT); + user.setRoles(set); + } + return userRepository.save(user); + } public String singin(String email, String password) { try { @@ -48,17 +56,6 @@ public String singin(String email, String password) { } } - public User signup(User user) { - user.setPassword(passwordEncoder.encode(user.getPassword())); - // Client 역할 부여 - if (user.getRoles() == null) { - List set = new ArrayList(); - set.add(UserRole.ROLE_CLIENT); - user.setRoles(set); - } - return userRepository.save(user); - } - public User getUser(String username) { return userRepository.findByEmail(username).get(); } From a72394cbff452fa7286044728e452968edb42344 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Thu, 13 Jul 2023 00:19:55 +0900 Subject: [PATCH 20/36] Fix add @controller in ArticleController --- .../gdsc/blog/article/controller/ArticleController.java | 9 +++++---- src/main/java/com/gdsc/blog/comment/dto/CreateDto.java | 2 ++ src/main/java/com/gdsc/blog/comment/dto/UpdateDto.java | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/gdsc/blog/comment/dto/CreateDto.java create mode 100644 src/main/java/com/gdsc/blog/comment/dto/UpdateDto.java diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index 55a7c9e..c606a8f 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -10,7 +10,6 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; -import java.time.LocalDateTime; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -19,6 +18,7 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -26,11 +26,12 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -@Slf4j -@Tag(name = "게시글 Controller", description = "Article controller API") -@RestController +@Controller @RequestMapping("/api/article") +@RestController @RequiredArgsConstructor +@Tag(name = "게시글 Controller", description = "Article controller API") +@Slf4j public class ArticleController { private final ArticleService articleService; diff --git a/src/main/java/com/gdsc/blog/comment/dto/CreateDto.java b/src/main/java/com/gdsc/blog/comment/dto/CreateDto.java new file mode 100644 index 0000000..7ef7167 --- /dev/null +++ b/src/main/java/com/gdsc/blog/comment/dto/CreateDto.java @@ -0,0 +1,2 @@ +package com.gdsc.blog.comment.dto;public class CreateDto { +} diff --git a/src/main/java/com/gdsc/blog/comment/dto/UpdateDto.java b/src/main/java/com/gdsc/blog/comment/dto/UpdateDto.java new file mode 100644 index 0000000..8f28c26 --- /dev/null +++ b/src/main/java/com/gdsc/blog/comment/dto/UpdateDto.java @@ -0,0 +1,2 @@ +package com.gdsc.blog.comment.dto;public class UpdateDto { +} From 5d5be0ac51eac6c2f15442fd62d2202d6195c137 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Thu, 13 Jul 2023 00:21:40 +0900 Subject: [PATCH 21/36] Add comment DTO --- .../com/gdsc/blog/article/dto/CreateDto.java | 4 ++-- .../com/gdsc/blog/article/dto/UpdateDto.java | 4 ++-- .../com/gdsc/blog/comment/dto/CreateDto.java | 18 +++++++++++++++++- .../com/gdsc/blog/comment/dto/UpdateDto.java | 18 +++++++++++++++++- .../com/gdsc/blog/comment/entity/Comment.java | 3 +++ 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/dto/CreateDto.java b/src/main/java/com/gdsc/blog/article/dto/CreateDto.java index ca67574..02f517c 100644 --- a/src/main/java/com/gdsc/blog/article/dto/CreateDto.java +++ b/src/main/java/com/gdsc/blog/article/dto/CreateDto.java @@ -13,9 +13,9 @@ @Getter @Setter public class CreateDto { - @Schema(description = "제목") + @Schema(description = "제목", example = "게시글 제목") public String title; - @Schema(description = "내용") + @Schema(description = "내용", example = "게시글 내용") public String content; } diff --git a/src/main/java/com/gdsc/blog/article/dto/UpdateDto.java b/src/main/java/com/gdsc/blog/article/dto/UpdateDto.java index 5dd92d3..3109b68 100644 --- a/src/main/java/com/gdsc/blog/article/dto/UpdateDto.java +++ b/src/main/java/com/gdsc/blog/article/dto/UpdateDto.java @@ -13,9 +13,9 @@ @Getter @Setter public class UpdateDto { - @Schema(description = "수정할 제목") + @Schema(description = "수정할 제목", example = "수정된 게시글 제목") public String title; - @Schema(description = "수정할 내용") + @Schema(description = "수정할 내용", example = "수정된 게시글 내용") public String content; } diff --git a/src/main/java/com/gdsc/blog/comment/dto/CreateDto.java b/src/main/java/com/gdsc/blog/comment/dto/CreateDto.java index 7ef7167..510cb95 100644 --- a/src/main/java/com/gdsc/blog/comment/dto/CreateDto.java +++ b/src/main/java/com/gdsc/blog/comment/dto/CreateDto.java @@ -1,2 +1,18 @@ -package com.gdsc.blog.comment.dto;public class CreateDto { +package com.gdsc.blog.comment.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Getter +@Setter +public class CreateDto { + @Schema(description = "내용", example = "댓글 내용") + public String content; } diff --git a/src/main/java/com/gdsc/blog/comment/dto/UpdateDto.java b/src/main/java/com/gdsc/blog/comment/dto/UpdateDto.java index 8f28c26..ad0b8ae 100644 --- a/src/main/java/com/gdsc/blog/comment/dto/UpdateDto.java +++ b/src/main/java/com/gdsc/blog/comment/dto/UpdateDto.java @@ -1,2 +1,18 @@ -package com.gdsc.blog.comment.dto;public class UpdateDto { +package com.gdsc.blog.comment.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Getter +@Setter +public class UpdateDto { + @Schema(description = "수정할 내용", example = "수정된 댓글 내용") + public String content; } diff --git a/src/main/java/com/gdsc/blog/comment/entity/Comment.java b/src/main/java/com/gdsc/blog/comment/entity/Comment.java index 0539702..8ca11ae 100644 --- a/src/main/java/com/gdsc/blog/comment/entity/Comment.java +++ b/src/main/java/com/gdsc/blog/comment/entity/Comment.java @@ -12,6 +12,7 @@ import jakarta.persistence.Table; import java.time.LocalDateTime; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -21,6 +22,7 @@ @NoArgsConstructor @Getter @Setter +@Builder @Table(name = "comments") public class Comment { @Id @@ -34,6 +36,7 @@ public class Comment { private LocalDateTime modifyData; //update date @ManyToOne + @JsonBackReference private Article article; @ManyToOne From 9c66e7c792cf95f20d34ced0c6ec69d157b4888d Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Thu, 13 Jul 2023 01:40:38 +0900 Subject: [PATCH 22/36] Add feature of Comment Create and Read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 댓글 생성과 읽기에 대한 기능 추가 --- .../article/controller/ArticleController.java | 10 +-- .../{CreateDto.java => ArticleCreateDto.java} | 2 +- .../{UpdateDto.java => ArticleUpdateDto.java} | 2 +- .../blog/article/service/ArticleService.java | 4 +- .../comment/controller/CommentController.java | 85 +++++++++++++------ .../{CreateDto.java => CommentCreateDto.java} | 2 +- .../{UpdateDto.java => CommentUpdateDto.java} | 2 +- .../comment/repository/CommentRepository.java | 3 + .../blog/comment/service/CommentService.java | 55 +++++++----- 9 files changed, 107 insertions(+), 58 deletions(-) rename src/main/java/com/gdsc/blog/article/dto/{CreateDto.java => ArticleCreateDto.java} (93%) rename src/main/java/com/gdsc/blog/article/dto/{UpdateDto.java => ArticleUpdateDto.java} (94%) rename src/main/java/com/gdsc/blog/comment/dto/{CreateDto.java => CommentCreateDto.java} (92%) rename src/main/java/com/gdsc/blog/comment/dto/{UpdateDto.java => CommentUpdateDto.java} (92%) diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index c606a8f..454c684 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -1,7 +1,7 @@ package com.gdsc.blog.article.controller; -import com.gdsc.blog.article.dto.CreateDto; -import com.gdsc.blog.article.dto.UpdateDto; +import com.gdsc.blog.article.dto.ArticleCreateDto; +import com.gdsc.blog.article.dto.ArticleUpdateDto; import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.service.ArticleService; import com.gdsc.blog.user.entity.User; @@ -46,7 +46,7 @@ public class ArticleController { @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") //권한 설정 @Operation(summary = "게시글 생성") //swagger 설명 public Article createArticle( - @Parameter(name="게시글 생성 DTO") @RequestBody CreateDto dto){ + @Parameter(name="게시글 생성 DTO") @RequestBody ArticleCreateDto dto){ //게시글 생성 Article article = Article.builder() .title(dto.getTitle()) @@ -77,7 +77,7 @@ public List
getUserArticle( return articleService.getUserArticle(user); } - @GetMapping("/update/{id}") + @GetMapping("/{id}") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "id로 게시글 조회") public Article getArticleById( @@ -97,7 +97,7 @@ public Article getArticleById( @Operation(summary = "게시글 수정") public Article updateArticle( @PathVariable(value = "id") Long id, - @Parameter(name="게시글 생성 DTO") @RequestBody UpdateDto dto, + @Parameter(name="게시글 생성 DTO") @RequestBody ArticleUpdateDto dto, @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) throws ChangeSetPersister.NotFoundException, AccessDeniedException { User user = userService.whoami(req); diff --git a/src/main/java/com/gdsc/blog/article/dto/CreateDto.java b/src/main/java/com/gdsc/blog/article/dto/ArticleCreateDto.java similarity index 93% rename from src/main/java/com/gdsc/blog/article/dto/CreateDto.java rename to src/main/java/com/gdsc/blog/article/dto/ArticleCreateDto.java index 02f517c..96634a7 100644 --- a/src/main/java/com/gdsc/blog/article/dto/CreateDto.java +++ b/src/main/java/com/gdsc/blog/article/dto/ArticleCreateDto.java @@ -12,7 +12,7 @@ @Builder @Getter @Setter -public class CreateDto { +public class ArticleCreateDto { @Schema(description = "제목", example = "게시글 제목") public String title; diff --git a/src/main/java/com/gdsc/blog/article/dto/UpdateDto.java b/src/main/java/com/gdsc/blog/article/dto/ArticleUpdateDto.java similarity index 94% rename from src/main/java/com/gdsc/blog/article/dto/UpdateDto.java rename to src/main/java/com/gdsc/blog/article/dto/ArticleUpdateDto.java index 3109b68..bd8aaf6 100644 --- a/src/main/java/com/gdsc/blog/article/dto/UpdateDto.java +++ b/src/main/java/com/gdsc/blog/article/dto/ArticleUpdateDto.java @@ -12,7 +12,7 @@ @Builder @Getter @Setter -public class UpdateDto { +public class ArticleUpdateDto { @Schema(description = "수정할 제목", example = "수정된 게시글 제목") public String title; diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index c4f7c9c..1c58ee3 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -1,6 +1,6 @@ package com.gdsc.blog.article.service; -import com.gdsc.blog.article.dto.UpdateDto; +import com.gdsc.blog.article.dto.ArticleUpdateDto; import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.repository.ArticleRepository; import com.gdsc.blog.user.entity.User; @@ -71,7 +71,7 @@ public Article getArticleById( @Operation(summary = "게시글 수정") public Article updateArticle( @Parameter(name = "게시글 id") Long id, - @Parameter(name = "게시글 수정 DTO") UpdateDto dto, + @Parameter(name = "게시글 수정 DTO") ArticleUpdateDto dto, @Parameter(name = "작성자") User user){ Article article = getArticleById(id); //게시글 id로 게시글 가져오기 diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index a2c4e26..5a25718 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -1,7 +1,9 @@ package com.gdsc.blog.comment.controller; +import com.gdsc.blog.article.dto.ArticleCreateDto; import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.service.ArticleService; +import com.gdsc.blog.comment.dto.CommentCreateDto; import com.gdsc.blog.comment.entity.Comment; import com.gdsc.blog.comment.service.CommentService; import com.gdsc.blog.user.entity.User; @@ -11,17 +13,23 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import java.time.LocalDateTime; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.h2.command.Command; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; @Controller @RequestMapping("api/comment") +@RestController @RequiredArgsConstructor @Slf4j @Tag(name = "댓글", description = "Comment Controller API") @@ -31,36 +39,63 @@ public class CommentController { private final UserService userService; /** - * Create comment - * @param idx article id - * @param content comment content - * @param req HTTP parsing object + * 댓글 생성 + * @param id 게시글 id + * @param dto 댓글 생성 정보 + * @param req HTTP 파싱 객체 */ @PostMapping("/create/{postId}") //컨트롤러 메핑 - @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") //권한 설정 + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") //권한 설정 @Operation(summary = "댓글 생성") - public void createComment( - @Parameter(name = "게시글 id") @PathVariable("postId") Long idx, - @Parameter(name = "내용") String content, + public Comment createComment( + @PathVariable("postId") Long id, + @Parameter(name="댓글 생성 DTO") @RequestBody CommentCreateDto dto, @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { + + Comment comment = Comment.builder() + .content(dto.getContent()) + .build(); + User user = userService.whoami(req); //로그인 유저 정보 가져오기 - Article article = this.articleService.getArticleById(idx); //get article object - this.commentService.create(article, content, user); //create comment + Article article = this.articleService.getArticleById(id); //get article object + return this.commentService.create(comment, article, user); //create comment } /** - * Read comment - * @param idx comment id - * @return comment content + * 게시글에 대한 모든 댓글 조회 + * @param id 게시글 id + * @param req HTTP 파싱 객체 + * @return 댓글 객체 List */ - @PostMapping("/read/{commentId}") - @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") - @Operation(summary = "댓글 읽기") - public String readComment( - @Parameter(name = "댓글 id") @PathVariable("commentId") Long idx){ - Comment comment = this.commentService.getComment(idx); //get comment object - return comment.getContent(); //return comment content + @GetMapping("/allCommands/{postId}") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") + @Operation(summary = "게시글에 대한 모든 댓글 조회") + public List getAllCommand( + @PathVariable("postId") Long id, + @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { + User user = userService.whoami(req); + + Article article = this.articleService.getArticleById(id); //get article object + + return commentService.getAllCommandByArticle(article); //return comment content + } + + /** + * id로 댓글 조회 + * @param id 댓글 id + * @param req HTTP 파싱 객체 + * @return 댓글 객체 + */ + @GetMapping("/{postId}") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") + @Operation(summary = "id로 댓글 조회") + public Comment getCommentById( + @PathVariable("postId") Long id, + @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { + User user = userService.whoami(req); + + return commentService.getCommentById(id); } /** @@ -70,7 +105,7 @@ public String readComment( * @param req HTTP parsing object */ @PostMapping("/update/{commentId}") - @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "댓글 수정") public void updateComment( @Parameter(name = "댓글 id") @PathVariable("commentId") Long idx, @@ -78,7 +113,7 @@ public void updateComment( @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req){ User user = userService.whoami(req); - Comment comment = this.commentService.getComment(idx); //get comment object + Comment comment = this.commentService.getCommentById(idx); //get comment object comment.setContent(content); //update comment content comment.setModifyData(LocalDateTime.now()); //update modify date this.commentService.update(comment); //save comment @@ -89,15 +124,15 @@ public void updateComment( * @param idx 댓글 id * @param req HTTP 파싱 객체 */ - @PostMapping("/delete/{commentId}") - @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") + @GetMapping("/delete/{commentId}") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "댓글 삭제") public void deleteComment( @Parameter(name = "댓글 id") @PathVariable("commentId") Long idx, @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req){ User user = userService.whoami(req); - Comment comment = this.commentService.getComment(idx); //get comment object + Comment comment = this.commentService.getCommentById(idx); //get comment object this.commentService.delete(comment); //delete comment } } diff --git a/src/main/java/com/gdsc/blog/comment/dto/CreateDto.java b/src/main/java/com/gdsc/blog/comment/dto/CommentCreateDto.java similarity index 92% rename from src/main/java/com/gdsc/blog/comment/dto/CreateDto.java rename to src/main/java/com/gdsc/blog/comment/dto/CommentCreateDto.java index 510cb95..3dec1a6 100644 --- a/src/main/java/com/gdsc/blog/comment/dto/CreateDto.java +++ b/src/main/java/com/gdsc/blog/comment/dto/CommentCreateDto.java @@ -12,7 +12,7 @@ @Builder @Getter @Setter -public class CreateDto { +public class CommentCreateDto { @Schema(description = "내용", example = "댓글 내용") public String content; } diff --git a/src/main/java/com/gdsc/blog/comment/dto/UpdateDto.java b/src/main/java/com/gdsc/blog/comment/dto/CommentUpdateDto.java similarity index 92% rename from src/main/java/com/gdsc/blog/comment/dto/UpdateDto.java rename to src/main/java/com/gdsc/blog/comment/dto/CommentUpdateDto.java index ad0b8ae..0409303 100644 --- a/src/main/java/com/gdsc/blog/comment/dto/UpdateDto.java +++ b/src/main/java/com/gdsc/blog/comment/dto/CommentUpdateDto.java @@ -12,7 +12,7 @@ @Builder @Getter @Setter -public class UpdateDto { +public class CommentUpdateDto { @Schema(description = "수정할 내용", example = "수정된 댓글 내용") public String content; } diff --git a/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java b/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java index 03d2b38..4ed530a 100644 --- a/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java +++ b/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java @@ -1,9 +1,12 @@ package com.gdsc.blog.comment.repository; +import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.comment.entity.Comment; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; public interface CommentRepository extends JpaRepository{ List findByArticleIdx(Long articleIdx); + + List findByArticle(Article article); } \ No newline at end of file diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index 5dbafe0..0b5f69e 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -8,45 +8,56 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -@RequiredArgsConstructor @Service +@RequiredArgsConstructor @Tag(name = "댓글 service", description = "Comment service API") public class CommentService { private final CommentRepository commentRepository; /** - * Create comment - * @param article article object - * @param content comment content - * @param user login user + * 댓글 생성 + * @param comment 댓글 객체 + * @param article 개시글 객체 + * @param user 로그인 유저 객체 */ @Operation(summary = "댓글 생성") - public void create( - @Parameter(name = "article", description = "댓글을 생성할 게시글") Article article, - @Parameter(name = "댓글 내용") String content, - @Parameter(name = "로그인 유저", description = "user 객체") User user){ - Comment comment = new Comment(); + public Comment create( + @Parameter(name = "댓글 객체") Comment comment, + @Parameter(name = "게시글 내용") Article article, + @Parameter(name = "로그인 유저") User user){ comment.setArticle(article); - comment.setContent(content); + comment.setUser(user); comment.setCreateData(LocalDateTime.now()); comment.setModifyData(LocalDateTime.now()); - comment.setUser(user); - this.commentRepository.save(comment); + + return commentRepository.save(comment); + } + + public List getAllCommandByArticle(Article article){ + return commentRepository.findByArticle(article); } /** - * Get comment object - * @param idx comment id - * @return comment object + * id로 댓글 조회 + * @param idx 댓글 id + * @return 댓글 객체 */ - @Operation(summary = "id로 댓글 가져오기") - public Comment getComment( + @Operation(summary = "id로 댓글 조회") + public Comment getCommentById( @Parameter(name = "댓글 id") Long idx) { - //return comment object if exists, or throw exception - return this.commentRepository.findById(idx).orElseThrow(); + Optional comment = commentRepository.findById(idx); + + if(comment.isPresent()){ + return comment.get(); + } + else{ + throw new NullPointerException("Not found Comment by id"); + } } /** @@ -56,12 +67,12 @@ public Comment getComment( @Operation(summary = "댓글 수정") public void update( @Parameter(name = "댓글", description = "수정할 댓글 객체") Comment comment){ - this.commentRepository.save(comment); + commentRepository.save(comment); } @Operation(summary = "댓글 삭제") public void delete( @Parameter(name = "댓글", description = "삭제할 댓글 객체") Comment comment){ - this.commentRepository.delete(comment); + commentRepository.delete(comment); } } From dd1ba9bc916e6ecc694567875aa9e293992137c0 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Thu, 13 Jul 2023 01:42:26 +0900 Subject: [PATCH 23/36] Fix typo postID -> commentID --- .../com/gdsc/blog/comment/controller/CommentController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index 5a25718..beb91e7 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -87,11 +87,11 @@ public List getAllCommand( * @param req HTTP 파싱 객체 * @return 댓글 객체 */ - @GetMapping("/{postId}") + @GetMapping("/{commentId}") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "id로 댓글 조회") public Comment getCommentById( - @PathVariable("postId") Long id, + @PathVariable("commentId") Long id, @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { User user = userService.whoami(req); From 48c9199379571aa6cbca1c9087436f4c814259c2 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Thu, 13 Jul 2023 01:52:51 +0900 Subject: [PATCH 24/36] Add feature of comment update and delete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 댓글 수정, 삭제 기능 구현 --- .../article/controller/ArticleController.java | 2 +- .../blog/article/service/ArticleService.java | 2 +- .../comment/controller/CommentController.java | 36 +++++++++---------- .../blog/comment/service/CommentService.java | 25 +++++++++---- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index 454c684..8086675 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -97,7 +97,7 @@ public Article getArticleById( @Operation(summary = "게시글 수정") public Article updateArticle( @PathVariable(value = "id") Long id, - @Parameter(name="게시글 생성 DTO") @RequestBody ArticleUpdateDto dto, + @Parameter(name="게시글 수정 DTO") @RequestBody ArticleUpdateDto dto, @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) throws ChangeSetPersister.NotFoundException, AccessDeniedException { User user = userService.whoami(req); diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index 1c58ee3..db01c22 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -83,7 +83,7 @@ public Article updateArticle( /** * 게시글 삭제 - * @param article Article 객체 + * @param article 게시글 객체 */ @Operation(summary = "게시글 삭제") public void deleteArticle( diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index beb91e7..e7efa4c 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -1,9 +1,11 @@ package com.gdsc.blog.comment.controller; import com.gdsc.blog.article.dto.ArticleCreateDto; +import com.gdsc.blog.article.dto.ArticleUpdateDto; import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.service.ArticleService; import com.gdsc.blog.comment.dto.CommentCreateDto; +import com.gdsc.blog.comment.dto.CommentUpdateDto; import com.gdsc.blog.comment.entity.Comment; import com.gdsc.blog.comment.service.CommentService; import com.gdsc.blog.user.entity.User; @@ -58,8 +60,8 @@ public Comment createComment( User user = userService.whoami(req); //로그인 유저 정보 가져오기 - Article article = this.articleService.getArticleById(id); //get article object - return this.commentService.create(comment, article, user); //create comment + Article article = articleService.getArticleById(id); //get article object + return commentService.create(comment, article, user); //create comment } /** @@ -76,7 +78,7 @@ public List getAllCommand( @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { User user = userService.whoami(req); - Article article = this.articleService.getArticleById(id); //get article object + Article article = articleService.getArticleById(id); //get article object return commentService.getAllCommandByArticle(article); //return comment content } @@ -99,40 +101,38 @@ public Comment getCommentById( } /** - * Update comment - * @param idx comment id - * @param content comment content - * @param req HTTP parsing object + * 댓글 수정 + * @param id 댓글 id + * @param dto 댓글 수정 정보 + * @param req HTTP 파싱 객체 */ @PostMapping("/update/{commentId}") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "댓글 수정") - public void updateComment( - @Parameter(name = "댓글 id") @PathVariable("commentId") Long idx, - @Parameter(name = "수정 내용") @RequestParam String content, + public Comment updateComment( + @PathVariable("commentId") Long id, + @Parameter(name="댓글 수정 DTO") @RequestBody CommentUpdateDto dto, @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req){ User user = userService.whoami(req); - Comment comment = this.commentService.getCommentById(idx); //get comment object - comment.setContent(content); //update comment content - comment.setModifyData(LocalDateTime.now()); //update modify date - this.commentService.update(comment); //save comment + return commentService.updateComment(id, dto); } /** * 댓글 삭제 - * @param idx 댓글 id + * @param id 댓글 id * @param req HTTP 파싱 객체 */ @GetMapping("/delete/{commentId}") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "댓글 삭제") public void deleteComment( - @Parameter(name = "댓글 id") @PathVariable("commentId") Long idx, + @PathVariable("commentId") Long id, @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req){ User user = userService.whoami(req); - Comment comment = this.commentService.getCommentById(idx); //get comment object - this.commentService.delete(comment); //delete comment + Comment comment = commentService.getCommentById(id); //get comment object + + commentService.delete(comment); //delete comment } } diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index 0b5f69e..1fa50c5 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -1,6 +1,7 @@ package com.gdsc.blog.comment.service; import com.gdsc.blog.article.entity.Article; +import com.gdsc.blog.comment.dto.CommentUpdateDto; import com.gdsc.blog.comment.entity.Comment; import com.gdsc.blog.comment.repository.CommentRepository; import com.gdsc.blog.user.entity.User; @@ -61,18 +62,30 @@ public Comment getCommentById( } /** - * Update comment - * @param comment comment object + * 댓글 수정 + * @param id 댓글 id + * @param commentUpdateDto 댓글 수정 DTO */ @Operation(summary = "댓글 수정") - public void update( - @Parameter(name = "댓글", description = "수정할 댓글 객체") Comment comment){ - commentRepository.save(comment); + public Comment updateComment( + @Parameter(name = "댓글 id") Long id, + @Parameter(name = "댓글 수정 DTO") CommentUpdateDto commentUpdateDto){ + + Comment comment = getCommentById(id); + comment.setContent(commentUpdateDto.getContent()); + comment.setModifyData(LocalDateTime.now()); + + return commentRepository.save(comment); } + + /** + * 댓글 삭제 + * @param comment 댓글 객체 + */ @Operation(summary = "댓글 삭제") public void delete( - @Parameter(name = "댓글", description = "삭제할 댓글 객체") Comment comment){ + @Parameter(name = "댓글", description = "댓글 객체") Comment comment){ commentRepository.delete(comment); } } From d2f41450471c74f0173fe8c68fc7ef7af89f7659 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Fri, 14 Jul 2023 11:30:15 +0900 Subject: [PATCH 25/36] Update: apply mapping path as HTTP Method of REST API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Article과 Comment의 Controller에 있는 mapping 경로를 HTTP Method에 맞게 수정 --- .../gdsc/blog/article/controller/ArticleController.java | 6 +++--- .../gdsc/blog/comment/controller/CommentController.java | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index 8086675..24b0b77 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -42,7 +42,7 @@ public class ArticleController { * @param dto 게시글 생성 정보 * @return 생성된 게시글 */ - @PostMapping("/create") //컨트롤러 메핑 + @PostMapping //컨트롤러 메핑 @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") //권한 설정 @Operation(summary = "게시글 생성") //swagger 설명 public Article createArticle( @@ -66,7 +66,7 @@ public Article createArticle( * @param req HTTP 파싱 객체 * @return 게시글 목록 */ - @GetMapping("/allArticle") + @GetMapping("/get") @Operation(summary = "모든 게시글 조회") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") public List
getUserArticle( @@ -92,7 +92,7 @@ public Article getArticleById( * @param dto 게시글 수정 정보 * @param req HTTP 파싱 객체 */ - @PostMapping("/update/{id}") //생성 & 수정은 PostMapping + @PostMapping("/patch/{id}") //생성 & 수정은 PostMapping @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "게시글 수정") public Article updateArticle( diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index e7efa4c..36c01a6 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -46,7 +46,7 @@ public class CommentController { * @param dto 댓글 생성 정보 * @param req HTTP 파싱 객체 */ - @PostMapping("/create/{postId}") //컨트롤러 메핑 + @PostMapping("/{postId}") //컨트롤러 메핑 @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") //권한 설정 @Operation(summary = "댓글 생성") public Comment createComment( @@ -70,7 +70,7 @@ public Comment createComment( * @param req HTTP 파싱 객체 * @return 댓글 객체 List */ - @GetMapping("/allCommands/{postId}") + @GetMapping("/{postId}") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "게시글에 대한 모든 댓글 조회") public List getAllCommand( @@ -89,7 +89,7 @@ public List getAllCommand( * @param req HTTP 파싱 객체 * @return 댓글 객체 */ - @GetMapping("/{commentId}") + @GetMapping("/get/{commentId}") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "id로 댓글 조회") public Comment getCommentById( @@ -106,7 +106,7 @@ public Comment getCommentById( * @param dto 댓글 수정 정보 * @param req HTTP 파싱 객체 */ - @PostMapping("/update/{commentId}") + @PostMapping("/patch/{commentId}") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "댓글 수정") public Comment updateComment( From 7c153c10345eb4254d33d3cc2fdedac1cb078849 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Fri, 14 Jul 2023 11:43:49 +0900 Subject: [PATCH 26/36] Update: HttpServletRequest Swagger parameter to hidden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HttpServletRequest 파라미터를 Swagger에 노출되지 않게 hidden 옵션으로 수정 --- .../blog/article/controller/ArticleController.java | 8 ++++---- .../blog/comment/controller/CommentController.java | 14 +++++--------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index 24b0b77..4174c2e 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -70,7 +70,7 @@ public Article createArticle( @Operation(summary = "모든 게시글 조회") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") public List
getUserArticle( - @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req + @Parameter(hidden = true) HttpServletRequest req ) { User user = userService.whoami(req); //로그인 유저 정보 가져오기 @@ -82,7 +82,7 @@ public List
getUserArticle( @Operation(summary = "id로 게시글 조회") public Article getArticleById( @PathVariable("id") Long id, //PathVariable에는 @Parameter를 사용할 수 없음! - @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req){ + @Parameter(hidden = true) HttpServletRequest req){ return articleService.getArticleById(id); } @@ -98,7 +98,7 @@ public Article getArticleById( public Article updateArticle( @PathVariable(value = "id") Long id, @Parameter(name="게시글 수정 DTO") @RequestBody ArticleUpdateDto dto, - @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) throws ChangeSetPersister.NotFoundException, AccessDeniedException { + @Parameter(hidden = true) HttpServletRequest req) throws ChangeSetPersister.NotFoundException, AccessDeniedException { User user = userService.whoami(req); return articleService.updateArticle(id, dto, user); @@ -114,7 +114,7 @@ public Article updateArticle( @Operation(summary = "게시글 삭제") public void deleteArticle( @PathVariable(value = "id") Long id, - @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { + @Parameter(hidden = true) HttpServletRequest req) { User user = userService.whoami(req); Article article = articleService.getArticleById(id); diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index 36c01a6..446a994 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -1,7 +1,5 @@ package com.gdsc.blog.comment.controller; -import com.gdsc.blog.article.dto.ArticleCreateDto; -import com.gdsc.blog.article.dto.ArticleUpdateDto; import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.service.ArticleService; import com.gdsc.blog.comment.dto.CommentCreateDto; @@ -14,11 +12,9 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; -import java.time.LocalDateTime; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.h2.command.Command; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -52,7 +48,7 @@ public class CommentController { public Comment createComment( @PathVariable("postId") Long id, @Parameter(name="댓글 생성 DTO") @RequestBody CommentCreateDto dto, - @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { + @Parameter(hidden = true) HttpServletRequest req) { Comment comment = Comment.builder() .content(dto.getContent()) @@ -75,7 +71,7 @@ public Comment createComment( @Operation(summary = "게시글에 대한 모든 댓글 조회") public List getAllCommand( @PathVariable("postId") Long id, - @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { + @Parameter(hidden = true) HttpServletRequest req) { User user = userService.whoami(req); Article article = articleService.getArticleById(id); //get article object @@ -94,7 +90,7 @@ public List getAllCommand( @Operation(summary = "id로 댓글 조회") public Comment getCommentById( @PathVariable("commentId") Long id, - @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req) { + @Parameter(hidden = true) HttpServletRequest req) { User user = userService.whoami(req); return commentService.getCommentById(id); @@ -112,7 +108,7 @@ public Comment getCommentById( public Comment updateComment( @PathVariable("commentId") Long id, @Parameter(name="댓글 수정 DTO") @RequestBody CommentUpdateDto dto, - @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req){ + @Parameter(hidden = true) HttpServletRequest req){ User user = userService.whoami(req); return commentService.updateComment(id, dto); @@ -128,7 +124,7 @@ public Comment updateComment( @Operation(summary = "댓글 삭제") public void deleteComment( @PathVariable("commentId") Long id, - @Parameter(name = "HTTP 파싱 객체") HttpServletRequest req){ + @Parameter(hidden = true) HttpServletRequest req){ User user = userService.whoami(req); Comment comment = commentService.getCommentById(id); //get comment object From 207341413bd5045c23d281660c1a870834a3472c Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Fri, 14 Jul 2023 12:10:01 +0900 Subject: [PATCH 27/36] Update: add @Parameter to @PathVariable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @PathVariable에 Swagger 파라미터 API인 @Parameter(description) 추가 --- .../blog/article/controller/ArticleController.java | 6 +++--- .../blog/comment/controller/CommentController.java | 11 +++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index 4174c2e..36d6e33 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -81,7 +81,7 @@ public List
getUserArticle( @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "id로 게시글 조회") public Article getArticleById( - @PathVariable("id") Long id, //PathVariable에는 @Parameter를 사용할 수 없음! + @Parameter(description = "게시글 id") @PathVariable("id") Long id, @Parameter(hidden = true) HttpServletRequest req){ return articleService.getArticleById(id); } @@ -96,7 +96,7 @@ public Article getArticleById( @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "게시글 수정") public Article updateArticle( - @PathVariable(value = "id") Long id, + @Parameter(description = "게시글 id") @PathVariable(value = "id") Long id, @Parameter(name="게시글 수정 DTO") @RequestBody ArticleUpdateDto dto, @Parameter(hidden = true) HttpServletRequest req) throws ChangeSetPersister.NotFoundException, AccessDeniedException { User user = userService.whoami(req); @@ -113,7 +113,7 @@ public Article updateArticle( @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "게시글 삭제") public void deleteArticle( - @PathVariable(value = "id") Long id, + @Parameter(description = "게시글 id") @PathVariable(value = "id") Long id, @Parameter(hidden = true) HttpServletRequest req) { User user = userService.whoami(req); diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index 446a994..431b2fe 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -22,7 +22,6 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @Controller @@ -46,7 +45,7 @@ public class CommentController { @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") //권한 설정 @Operation(summary = "댓글 생성") public Comment createComment( - @PathVariable("postId") Long id, + @Parameter(description = "댓글 id") @PathVariable("postId") Long id, @Parameter(name="댓글 생성 DTO") @RequestBody CommentCreateDto dto, @Parameter(hidden = true) HttpServletRequest req) { @@ -70,7 +69,7 @@ public Comment createComment( @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "게시글에 대한 모든 댓글 조회") public List getAllCommand( - @PathVariable("postId") Long id, + @Parameter(description = "댓글 id") @PathVariable("postId") Long id, @Parameter(hidden = true) HttpServletRequest req) { User user = userService.whoami(req); @@ -89,7 +88,7 @@ public List getAllCommand( @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "id로 댓글 조회") public Comment getCommentById( - @PathVariable("commentId") Long id, + @Parameter(description = "댓글 id") @PathVariable("commentId") Long id, @Parameter(hidden = true) HttpServletRequest req) { User user = userService.whoami(req); @@ -106,7 +105,7 @@ public Comment getCommentById( @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "댓글 수정") public Comment updateComment( - @PathVariable("commentId") Long id, + @Parameter(description = "댓글 id") @PathVariable("commentId") Long id, @Parameter(name="댓글 수정 DTO") @RequestBody CommentUpdateDto dto, @Parameter(hidden = true) HttpServletRequest req){ User user = userService.whoami(req); @@ -123,7 +122,7 @@ public Comment updateComment( @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "댓글 삭제") public void deleteComment( - @PathVariable("commentId") Long id, + @Parameter(description = "댓글 id") @PathVariable("commentId") Long id, @Parameter(hidden = true) HttpServletRequest req){ User user = userService.whoami(req); From ac9ac26c1a6c429c82517cee3c1ea87b5f99b725 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Fri, 14 Jul 2023 12:15:13 +0900 Subject: [PATCH 28/36] Remove Swagger documentation in service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 사용자에게 노출되지 않는 Service에 Swagger documention 제거 --- .../blog/article/service/ArticleService.java | 45 ++++++++----------- .../blog/comment/service/CommentService.java | 41 +++++++---------- 2 files changed, 33 insertions(+), 53 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index db01c22..08738cc 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -4,9 +4,6 @@ import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.repository.ArticleRepository; import com.gdsc.blog.user.entity.User; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -15,19 +12,19 @@ @Service @RequiredArgsConstructor -@Tag(name = "게시글 Service", description = "Article service API") public class ArticleService { + private final ArticleRepository articleRepository; /** * 게시글 생성 + * * @param article Article 객체 - * @param user 작성자 + * @param user 작성자 */ - @Operation(summary = "게시글 생성") public Article createArticle( - @Parameter(name = "게시글 객체") Article article, - @Parameter(name = "유저 객체") User user){ //create new article + Article article, + User user) { //create new article article.setCreateDate(LocalDateTime.now()); article.setModifyDate(LocalDateTime.now()); article.setUser(user); @@ -36,43 +33,38 @@ public Article createArticle( /** * 유저 게시글 목록 조회 + * * @return 게시글 목록 */ - @Operation(summary = "유저 게시글 목록 가져오기") - public List
getUserArticle(User user){ //get all articles + public List
getUserArticle(User user) { //get all articles return user.getArticles(); } /** * id로 게시글 조회 + * * @param idx 게시글 id * @return Article 객체 */ - @Operation(summary = "게시글 조회") - public Article getArticleById( - @Parameter(name = "게시글 id") Long idx){ //get article by id - Optional
article = articleRepository.findById(idx); + public Article getArticleById(Long idx) { //get article by id + Optional
article = articleRepository.findById(idx); - if(article.isPresent()){ + if (article.isPresent()) { return article.get(); - } - else{ //not found article by id + } else { //not found article by id throw new NullPointerException("Not found Article by id"); } } /** * 게시글 수정 - * @param id 게시글 id - * @param dto 게시글 수정 DTO + * + * @param id 게시글 id + * @param dto 게시글 수정 DTO * @param user 작성자 * @return Article 객체 */ - @Operation(summary = "게시글 수정") - public Article updateArticle( - @Parameter(name = "게시글 id") Long id, - @Parameter(name = "게시글 수정 DTO") ArticleUpdateDto dto, - @Parameter(name = "작성자") User user){ + public Article updateArticle(Long id, ArticleUpdateDto dto, User user) { Article article = getArticleById(id); //게시글 id로 게시글 가져오기 article.setTitle(dto.getTitle()); @@ -83,11 +75,10 @@ public Article updateArticle( /** * 게시글 삭제 + * * @param article 게시글 객체 */ - @Operation(summary = "게시글 삭제") - public void deleteArticle( - @Parameter(name = "개시글 객체") Article article){ + public void deleteArticle(Article article) { articleRepository.delete(article); } } diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index 1fa50c5..86a0c37 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -5,9 +5,6 @@ import com.gdsc.blog.comment.entity.Comment; import com.gdsc.blog.comment.repository.CommentRepository; import com.gdsc.blog.user.entity.User; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -16,60 +13,53 @@ @Service @RequiredArgsConstructor -@Tag(name = "댓글 service", description = "Comment service API") public class CommentService { + private final CommentRepository commentRepository; /** * 댓글 생성 + * * @param comment 댓글 객체 * @param article 개시글 객체 - * @param user 로그인 유저 객체 + * @param user 로그인 유저 객체 */ - @Operation(summary = "댓글 생성") - public Comment create( - @Parameter(name = "댓글 객체") Comment comment, - @Parameter(name = "게시글 내용") Article article, - @Parameter(name = "로그인 유저") User user){ + public Comment create(Comment comment, Article article, User user) { comment.setArticle(article); comment.setUser(user); comment.setCreateData(LocalDateTime.now()); comment.setModifyData(LocalDateTime.now()); - + return commentRepository.save(comment); } - public List getAllCommandByArticle(Article article){ + public List getAllCommandByArticle(Article article) { return commentRepository.findByArticle(article); } /** * id로 댓글 조회 + * * @param idx 댓글 id * @return 댓글 객체 */ - @Operation(summary = "id로 댓글 조회") - public Comment getCommentById( - @Parameter(name = "댓글 id") Long idx) { - Optional comment = commentRepository.findById(idx); + public Comment getCommentById(Long idx) { + Optional comment = commentRepository.findById(idx); - if(comment.isPresent()){ + if (comment.isPresent()) { return comment.get(); - } - else{ + } else { throw new NullPointerException("Not found Comment by id"); } } /** * 댓글 수정 + * * @param id 댓글 id * @param commentUpdateDto 댓글 수정 DTO */ - @Operation(summary = "댓글 수정") - public Comment updateComment( - @Parameter(name = "댓글 id") Long id, - @Parameter(name = "댓글 수정 DTO") CommentUpdateDto commentUpdateDto){ + public Comment updateComment(Long id, CommentUpdateDto commentUpdateDto) { Comment comment = getCommentById(id); comment.setContent(commentUpdateDto.getContent()); @@ -81,11 +71,10 @@ public Comment updateComment( /** * 댓글 삭제 + * * @param comment 댓글 객체 */ - @Operation(summary = "댓글 삭제") - public void delete( - @Parameter(name = "댓글", description = "댓글 객체") Comment comment){ + public void delete(Comment comment) { commentRepository.delete(comment); } } From 3b99ccfed39436f80225a85331cdb1fb610a311c Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Fri, 14 Jul 2023 13:00:38 +0900 Subject: [PATCH 29/36] Add: get article by title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 제목으로 게시글 검색 기능 추가 - url mapping 혼란을 막기 위해 /id/{id}, /title/{title}로 변경 - 검색 결과가 없을 경우를 대비하여 repository 메서드 리턴 타입을 Optional으로 수정 --- .../article/controller/ArticleController.java | 24 ++++++++++++++++++- .../article/repository/ArticleRepository.java | 3 ++- .../blog/article/service/ArticleService.java | 4 ++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index 36d6e33..b0719a4 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -11,6 +11,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.crossstore.ChangeSetPersister; @@ -77,7 +78,13 @@ public List
getUserArticle( return articleService.getUserArticle(user); } - @GetMapping("/{id}") + /** + * id로 게시글 조회 + * @param id 게시글 id + * @param req HTTP 파싱 객체 + * @return 게시글 + */ + @GetMapping("/get/id/{id}") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "id로 게시글 조회") public Article getArticleById( @@ -86,6 +93,21 @@ public Article getArticleById( return articleService.getArticleById(id); } + /** + * 제목으로 게시글 조회 + * @param title 게시글 제목 + * @param req HTTP 파싱 객체 + * @return 게시글 + */ + @GetMapping("/get/title/{title}") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") + @Operation(summary = "제목으로 게시글 조회") + public Optional
getArticleByTitle( + @Parameter(description = "게시글 제목") @PathVariable(value = "title") String title, + @Parameter(hidden = true) HttpServletRequest req){ + return articleService.getArticleByTitle(title); + } + /** * 게시글 수정 * @param id 게시글 id diff --git a/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java b/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java index 2ab0283..b10ed8e 100644 --- a/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java +++ b/src/main/java/com/gdsc/blog/article/repository/ArticleRepository.java @@ -2,11 +2,12 @@ import com.gdsc.blog.article.entity.Article; import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface ArticleRepository extends JpaRepository { - Article findByTitle(String title); + Optional
findByTitle(String title); List
findByTitleLikeOrContentLike(String title, String content); } \ No newline at end of file diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index 08738cc..b655b25 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -56,6 +56,10 @@ public Article getArticleById(Long idx) { //get article by id } } + public Optional
getArticleByTitle(String title){ + return articleRepository.findByTitle(title); + } + /** * 게시글 수정 * From 6fd13b0a8af37d334614797afb98938d6e3cd132 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Fri, 14 Jul 2023 13:07:55 +0900 Subject: [PATCH 30/36] Update: use orElseThrow() instead of if-else MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Optional 타입의 객체에서 if-else 대신 orElseThrow()로 사용 --- .../blog/article/controller/ArticleController.java | 2 +- .../gdsc/blog/article/service/ArticleService.java | 13 ++++++------- .../blog/comment/controller/CommentController.java | 4 ++-- .../gdsc/blog/comment/service/CommentService.java | 6 +----- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index b0719a4..16c85e4 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -102,7 +102,7 @@ public Article getArticleById( @GetMapping("/get/title/{title}") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "제목으로 게시글 조회") - public Optional
getArticleByTitle( + public Article getArticleByTitle( @Parameter(description = "게시글 제목") @PathVariable(value = "title") String title, @Parameter(hidden = true) HttpServletRequest req){ return articleService.getArticleByTitle(title); diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index b655b25..90206eb 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -49,15 +49,13 @@ public List
getUserArticle(User user) { //get all articles public Article getArticleById(Long idx) { //get article by id Optional
article = articleRepository.findById(idx); - if (article.isPresent()) { - return article.get(); - } else { //not found article by id - throw new NullPointerException("Not found Article by id"); - } + return article.orElseThrow(() -> new NullPointerException("Not found Article by id")); } - public Optional
getArticleByTitle(String title){ - return articleRepository.findByTitle(title); + public Article getArticleByTitle(String title){ + Optional
article = articleRepository.findByTitle(title); + + return article.orElseThrow(() -> new NullPointerException("Not found Article by title")); } /** @@ -74,6 +72,7 @@ public Article updateArticle(Long id, ArticleUpdateDto dto, User user) { article.setTitle(dto.getTitle()); article.setContent(dto.getContent()); article.setModifyDate(LocalDateTime.now()); + return articleRepository.save(article); } diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index 431b2fe..7b8b483 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -65,7 +65,7 @@ public Comment createComment( * @param req HTTP 파싱 객체 * @return 댓글 객체 List */ - @GetMapping("/{postId}") + @GetMapping("/get/{postId}") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "게시글에 대한 모든 댓글 조회") public List getAllCommand( @@ -84,7 +84,7 @@ public List getAllCommand( * @param req HTTP 파싱 객체 * @return 댓글 객체 */ - @GetMapping("/get/{commentId}") + @GetMapping("/get/all/{commentId}") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "id로 댓글 조회") public Comment getCommentById( diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index 86a0c37..7a0810e 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -46,11 +46,7 @@ public List getAllCommandByArticle(Article article) { public Comment getCommentById(Long idx) { Optional comment = commentRepository.findById(idx); - if (comment.isPresent()) { - return comment.get(); - } else { - throw new NullPointerException("Not found Comment by id"); - } + return comment.orElseThrow(() -> new NullPointerException("Not found Comment by id")); } /** From a8d6e2fbe868b6b0968b2462be77a04f3eb88aae Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Fri, 14 Jul 2023 13:13:33 +0900 Subject: [PATCH 31/36] =?UTF-8?q?Fix=20typo:=20=EA=B2=8C=EC=8B=9C=EA=B8=80?= =?UTF-8?q?=20id=20instead=20of=20=EB=8C=93=EA=B8=80=20id=20in=20swagger?= =?UTF-8?q?=20parameter=20annotation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gdsc/blog/comment/controller/CommentController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index 7b8b483..1c8972b 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -45,7 +45,7 @@ public class CommentController { @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") //권한 설정 @Operation(summary = "댓글 생성") public Comment createComment( - @Parameter(description = "댓글 id") @PathVariable("postId") Long id, + @Parameter(description = "게시글 id") @PathVariable("postId") Long id, @Parameter(name="댓글 생성 DTO") @RequestBody CommentCreateDto dto, @Parameter(hidden = true) HttpServletRequest req) { @@ -69,7 +69,7 @@ public Comment createComment( @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "게시글에 대한 모든 댓글 조회") public List getAllCommand( - @Parameter(description = "댓글 id") @PathVariable("postId") Long id, + @Parameter(description = "게시글 id") @PathVariable("postId") Long id, @Parameter(hidden = true) HttpServletRequest req) { User user = userService.whoami(req); From 66e9e2c1a57adf30e6d4cb04f448f2e18352e630 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Fri, 14 Jul 2023 13:14:52 +0900 Subject: [PATCH 32/36] Remove findByArticleIdx method --- .../com/gdsc/blog/comment/repository/CommentRepository.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java b/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java index 4ed530a..e88a578 100644 --- a/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java +++ b/src/main/java/com/gdsc/blog/comment/repository/CommentRepository.java @@ -6,7 +6,5 @@ import org.springframework.data.jpa.repository.JpaRepository; public interface CommentRepository extends JpaRepository{ - List findByArticleIdx(Long articleIdx); - List findByArticle(Article article); } \ No newline at end of file From 122bb7b5144356c7922cc772e2dadafc947efa06 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Fri, 14 Jul 2023 14:17:31 +0900 Subject: [PATCH 33/36] Refactor: improve responsibility distribution by create Article, Comment object in Service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 객체를 생성하는 로직을 전부 Service에서 처리합니다. Controller에서 수행하는 역할을 단순화 시켰습니다 --- .../article/controller/ArticleController.java | 17 ++++---------- .../blog/article/service/ArticleService.java | 22 ++++++++++--------- .../comment/controller/CommentController.java | 11 +++------- .../blog/comment/service/CommentService.java | 13 ++++++----- 4 files changed, 26 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index 16c85e4..edf0b3d 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -11,11 +11,8 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import java.util.List; -import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.crossstore.ChangeSetPersister; -import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -48,18 +45,12 @@ public class ArticleController { @Operation(summary = "게시글 생성") //swagger 설명 public Article createArticle( @Parameter(name="게시글 생성 DTO") @RequestBody ArticleCreateDto dto){ - //게시글 생성 - Article article = Article.builder() - .title(dto.getTitle()) - .content(dto.getContent()) - .build(); - //로그인 유저 정보 가져오기 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String userName = authentication.getName(); - User user = userService.getUserByName(userName); //유저 이름 가져오기 - return articleService.createArticle(article, user); + + return articleService.createArticle(dto, user); } /** @@ -120,10 +111,10 @@ public Article getArticleByTitle( public Article updateArticle( @Parameter(description = "게시글 id") @PathVariable(value = "id") Long id, @Parameter(name="게시글 수정 DTO") @RequestBody ArticleUpdateDto dto, - @Parameter(hidden = true) HttpServletRequest req) throws ChangeSetPersister.NotFoundException, AccessDeniedException { + @Parameter(hidden = true) HttpServletRequest req) { User user = userService.whoami(req); - return articleService.updateArticle(id, dto, user); + return articleService.updateArticle(id, dto); } /** diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index 90206eb..c342a30 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -1,5 +1,6 @@ package com.gdsc.blog.article.service; +import com.gdsc.blog.article.dto.ArticleCreateDto; import com.gdsc.blog.article.dto.ArticleUpdateDto; import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.repository.ArticleRepository; @@ -19,15 +20,18 @@ public class ArticleService { /** * 게시글 생성 * - * @param article Article 객체 + * @param dto 게시글 생성 정보 * @param user 작성자 */ - public Article createArticle( - Article article, - User user) { //create new article - article.setCreateDate(LocalDateTime.now()); - article.setModifyDate(LocalDateTime.now()); - article.setUser(user); + public Article createArticle(ArticleCreateDto dto, User user) { //create new article + Article article = Article.builder() + .title(dto.getTitle()) + .content(dto.getContent()) + .createDate(LocalDateTime.now()) + .modifyDate(LocalDateTime.now()) + .user(user) + .build(); + return articleRepository.save(article); } @@ -63,11 +67,9 @@ public Article getArticleByTitle(String title){ * * @param id 게시글 id * @param dto 게시글 수정 DTO - * @param user 작성자 * @return Article 객체 */ - public Article updateArticle(Long id, ArticleUpdateDto dto, User user) { - + public Article updateArticle(Long id, ArticleUpdateDto dto) { Article article = getArticleById(id); //게시글 id로 게시글 가져오기 article.setTitle(dto.getTitle()); article.setContent(dto.getContent()); diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index 1c8972b..d635650 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -46,17 +46,12 @@ public class CommentController { @Operation(summary = "댓글 생성") public Comment createComment( @Parameter(description = "게시글 id") @PathVariable("postId") Long id, - @Parameter(name="댓글 생성 DTO") @RequestBody CommentCreateDto dto, + @Parameter(name = "댓글 생성 DTO") @RequestBody CommentCreateDto dto, @Parameter(hidden = true) HttpServletRequest req) { - - Comment comment = Comment.builder() - .content(dto.getContent()) - .build(); - User user = userService.whoami(req); //로그인 유저 정보 가져오기 - Article article = articleService.getArticleById(id); //get article object - return commentService.create(comment, article, user); //create comment + + return commentService.create(article, user); //create comment } /** diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index 7a0810e..76b0627 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -20,15 +20,16 @@ public class CommentService { /** * 댓글 생성 * - * @param comment 댓글 객체 * @param article 개시글 객체 * @param user 로그인 유저 객체 */ - public Comment create(Comment comment, Article article, User user) { - comment.setArticle(article); - comment.setUser(user); - comment.setCreateData(LocalDateTime.now()); - comment.setModifyData(LocalDateTime.now()); + public Comment create(Article article, User user) { + Comment comment = Comment.builder() + .article(article) + .user(user) + .createData(LocalDateTime.now()) + .modifyData(LocalDateTime.now()) + .build(); return commentRepository.save(comment); } From d39ccfd467007ee865053ff2c14830b8d3f1d0b9 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Fri, 14 Jul 2023 15:53:47 +0900 Subject: [PATCH 34/36] Add: Base Entity to remove Duplicate code in entity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Base를 생성하고 Article과 Comment가 Base를 상속 - 중복으로 사용되는 속성을 제거 - @CreatedDate, @LastModifiedDate 추가 - Entity를 생성하거나 변경할 때 자동으로 시간 데이터를 추가 --- .../java/com/gdsc/blog/BlogApplication.java | 2 + .../com/gdsc/blog/article/entity/Article.java | 29 +++++--------- .../blog/article/service/ArticleService.java | 5 --- .../java/com/gdsc/blog/base/entity/Base.java | 40 +++++++++++++++++++ .../com/gdsc/blog/comment/entity/Comment.java | 27 +++++-------- .../blog/comment/service/CommentService.java | 5 +-- 6 files changed, 62 insertions(+), 46 deletions(-) create mode 100644 src/main/java/com/gdsc/blog/base/entity/Base.java diff --git a/src/main/java/com/gdsc/blog/BlogApplication.java b/src/main/java/com/gdsc/blog/BlogApplication.java index 42bc01c..9d91992 100644 --- a/src/main/java/com/gdsc/blog/BlogApplication.java +++ b/src/main/java/com/gdsc/blog/BlogApplication.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @SpringBootApplication +@EnableJpaAuditing //자동으로 시간을 매핑 public class BlogApplication { public static void main(String[] args) { SpringApplication.run(BlogApplication.class, args); diff --git a/src/main/java/com/gdsc/blog/article/entity/Article.java b/src/main/java/com/gdsc/blog/article/entity/Article.java index 2623491..723fa0c 100644 --- a/src/main/java/com/gdsc/blog/article/entity/Article.java +++ b/src/main/java/com/gdsc/blog/article/entity/Article.java @@ -1,51 +1,40 @@ package com.gdsc.blog.article.entity; -import com.fasterxml.jackson.annotation.JsonBackReference; +import com.gdsc.blog.base.entity.Base; import com.gdsc.blog.comment.entity.Comment; -import com.gdsc.blog.user.entity.User; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; +import jakarta.persistence.DiscriminatorValue; import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; -import java.time.LocalDateTime; import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; -import lombok.Data; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; @Entity @NoArgsConstructor @AllArgsConstructor //생성자 자동 생성 @Getter @Setter -@Builder +@SuperBuilder @Table(name = "articles") -public class Article { +public class Article extends Base { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long idx; //id + private Long id; //id @Column(length = 200) - private String title; - - @Column(columnDefinition = "TEXT") //no limit length of text - private String content; - - private LocalDateTime createDate; //생성 날짜 - private LocalDateTime modifyDate; //수정된 날짜 - - //set relationship between article and user - @ManyToOne - @JsonBackReference - private User user; + private String title; //제목 @OneToMany(mappedBy = "article", cascade = CascadeType.REMOVE) private List comments; diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index c342a30..2fe135b 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -5,7 +5,6 @@ import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.repository.ArticleRepository; import com.gdsc.blog.user.entity.User; -import java.time.LocalDateTime; import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; @@ -14,7 +13,6 @@ @Service @RequiredArgsConstructor public class ArticleService { - private final ArticleRepository articleRepository; /** @@ -27,8 +25,6 @@ public Article createArticle(ArticleCreateDto dto, User user) { //create new art Article article = Article.builder() .title(dto.getTitle()) .content(dto.getContent()) - .createDate(LocalDateTime.now()) - .modifyDate(LocalDateTime.now()) .user(user) .build(); @@ -73,7 +69,6 @@ public Article updateArticle(Long id, ArticleUpdateDto dto) { Article article = getArticleById(id); //게시글 id로 게시글 가져오기 article.setTitle(dto.getTitle()); article.setContent(dto.getContent()); - article.setModifyDate(LocalDateTime.now()); return articleRepository.save(article); } diff --git a/src/main/java/com/gdsc/blog/base/entity/Base.java b/src/main/java/com/gdsc/blog/base/entity/Base.java new file mode 100644 index 0000000..b86bf98 --- /dev/null +++ b/src/main/java/com/gdsc/blog/base/entity/Base.java @@ -0,0 +1,40 @@ +package com.gdsc.blog.base.entity; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.gdsc.blog.user.entity.User; +import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MappedSuperclass; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@MappedSuperclass //엔티티 부모 클래스 +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@SuperBuilder +@EntityListeners(AuditingEntityListener.class) +public abstract class Base { + @Column(columnDefinition = "TEXT") //no limit length of text + private String content; + + @ManyToOne + @JsonBackReference + private User user; + + @CreatedDate + @Column(updatable = false) //수정 방지 + private LocalDateTime createDate; //생성 날짜 + + @LastModifiedDate + private LocalDateTime modifyDate; //수정된 날짜 +} diff --git a/src/main/java/com/gdsc/blog/comment/entity/Comment.java b/src/main/java/com/gdsc/blog/comment/entity/Comment.java index 8ca11ae..cd8e5d1 100644 --- a/src/main/java/com/gdsc/blog/comment/entity/Comment.java +++ b/src/main/java/com/gdsc/blog/comment/entity/Comment.java @@ -2,44 +2,37 @@ import com.fasterxml.jackson.annotation.JsonBackReference; import com.gdsc.blog.article.entity.Article; -import com.gdsc.blog.user.entity.User; -import jakarta.persistence.Column; +import com.gdsc.blog.base.entity.Base; import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import jakarta.persistence.MappedSuperclass; import jakarta.persistence.Table; -import java.time.LocalDateTime; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; @Entity -@AllArgsConstructor @NoArgsConstructor +@AllArgsConstructor @Getter @Setter -@Builder +@SuperBuilder +@EntityListeners(AuditingEntityListener.class) @Table(name = "comments") -public class Comment { +public class Comment extends Base { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long idx; //id - - @Column(length = 200) - private String content; //내용 - - private LocalDateTime createData; //create date - private LocalDateTime modifyData; //update date + private Long id; //id @ManyToOne @JsonBackReference private Article article; - @ManyToOne - @JsonBackReference - private User user; } diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index 76b0627..33c9fc6 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -5,7 +5,6 @@ import com.gdsc.blog.comment.entity.Comment; import com.gdsc.blog.comment.repository.CommentRepository; import com.gdsc.blog.user.entity.User; -import java.time.LocalDateTime; import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; @@ -26,9 +25,8 @@ public class CommentService { public Comment create(Article article, User user) { Comment comment = Comment.builder() .article(article) + .content(article.getContent()) .user(user) - .createData(LocalDateTime.now()) - .modifyData(LocalDateTime.now()) .build(); return commentRepository.save(comment); @@ -60,7 +58,6 @@ public Comment updateComment(Long id, CommentUpdateDto commentUpdateDto) { Comment comment = getCommentById(id); comment.setContent(commentUpdateDto.getContent()); - comment.setModifyData(LocalDateTime.now()); return commentRepository.save(comment); } From c5109641973707dae4d23a3928afa64114d8a04f Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Fri, 14 Jul 2023 16:22:16 +0900 Subject: [PATCH 35/36] Add: Transactional annotation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 생성 및 수정 상황에서 에러가 발생하는 경우 여러 문제를 방지하기 위해 Transactional 어노테이션 추가 --- src/main/java/com/gdsc/blog/article/entity/Article.java | 4 ---- .../java/com/gdsc/blog/article/service/ArticleService.java | 4 ++++ src/main/java/com/gdsc/blog/base/entity/Base.java | 1 - src/main/java/com/gdsc/blog/comment/entity/Comment.java | 1 - .../java/com/gdsc/blog/comment/service/CommentService.java | 4 ++++ 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/entity/Article.java b/src/main/java/com/gdsc/blog/article/entity/Article.java index 723fa0c..6d3b2dd 100644 --- a/src/main/java/com/gdsc/blog/article/entity/Article.java +++ b/src/main/java/com/gdsc/blog/article/entity/Article.java @@ -4,9 +4,7 @@ import com.gdsc.blog.comment.entity.Comment; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; -import jakarta.persistence.DiscriminatorValue; import jakarta.persistence.Entity; -import jakarta.persistence.EntityListeners; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @@ -14,12 +12,10 @@ import jakarta.persistence.Table; import java.util.List; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.experimental.SuperBuilder; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; @Entity @NoArgsConstructor diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index 2fe135b..8a33f4d 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -5,6 +5,7 @@ import com.gdsc.blog.article.entity.Article; import com.gdsc.blog.article.repository.ArticleRepository; import com.gdsc.blog.user.entity.User; +import jakarta.transaction.Transactional; import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; @@ -21,6 +22,7 @@ public class ArticleService { * @param dto 게시글 생성 정보 * @param user 작성자 */ + @Transactional public Article createArticle(ArticleCreateDto dto, User user) { //create new article Article article = Article.builder() .title(dto.getTitle()) @@ -65,6 +67,7 @@ public Article getArticleByTitle(String title){ * @param dto 게시글 수정 DTO * @return Article 객체 */ + @Transactional public Article updateArticle(Long id, ArticleUpdateDto dto) { Article article = getArticleById(id); //게시글 id로 게시글 가져오기 article.setTitle(dto.getTitle()); @@ -78,6 +81,7 @@ public Article updateArticle(Long id, ArticleUpdateDto dto) { * * @param article 게시글 객체 */ + @Transactional public void deleteArticle(Article article) { articleRepository.delete(article); } diff --git a/src/main/java/com/gdsc/blog/base/entity/Base.java b/src/main/java/com/gdsc/blog/base/entity/Base.java index b86bf98..1c0516b 100644 --- a/src/main/java/com/gdsc/blog/base/entity/Base.java +++ b/src/main/java/com/gdsc/blog/base/entity/Base.java @@ -18,7 +18,6 @@ @MappedSuperclass //엔티티 부모 클래스 @NoArgsConstructor -@AllArgsConstructor @Getter @Setter @SuperBuilder diff --git a/src/main/java/com/gdsc/blog/comment/entity/Comment.java b/src/main/java/com/gdsc/blog/comment/entity/Comment.java index cd8e5d1..96c96d1 100644 --- a/src/main/java/com/gdsc/blog/comment/entity/Comment.java +++ b/src/main/java/com/gdsc/blog/comment/entity/Comment.java @@ -9,7 +9,6 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; -import jakarta.persistence.MappedSuperclass; import jakarta.persistence.Table; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index 33c9fc6..eff3f5f 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -5,6 +5,7 @@ import com.gdsc.blog.comment.entity.Comment; import com.gdsc.blog.comment.repository.CommentRepository; import com.gdsc.blog.user.entity.User; +import jakarta.transaction.Transactional; import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; @@ -22,6 +23,7 @@ public class CommentService { * @param article 개시글 객체 * @param user 로그인 유저 객체 */ + @Transactional public Comment create(Article article, User user) { Comment comment = Comment.builder() .article(article) @@ -54,6 +56,7 @@ public Comment getCommentById(Long idx) { * @param id 댓글 id * @param commentUpdateDto 댓글 수정 DTO */ + @Transactional public Comment updateComment(Long id, CommentUpdateDto commentUpdateDto) { Comment comment = getCommentById(id); @@ -68,6 +71,7 @@ public Comment updateComment(Long id, CommentUpdateDto commentUpdateDto) { * * @param comment 댓글 객체 */ + @Transactional public void delete(Comment comment) { commentRepository.delete(comment); } From 79683bdc3695ef1d0ae055a425a49b94334ad299 Mon Sep 17 00:00:00 2001 From: thelight0804 Date: Fri, 14 Jul 2023 16:31:35 +0900 Subject: [PATCH 36/36] Remove: save() method in update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Transactional 어노테이션을 사용하기 때문에 변경사항을 자동으로 적용해줍니다 --- .../com/gdsc/blog/article/controller/ArticleController.java | 4 ++-- .../java/com/gdsc/blog/article/service/ArticleService.java | 6 +++--- .../com/gdsc/blog/comment/controller/CommentController.java | 4 ++-- .../java/com/gdsc/blog/comment/service/CommentService.java | 4 +--- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java index edf0b3d..70e7c59 100644 --- a/src/main/java/com/gdsc/blog/article/controller/ArticleController.java +++ b/src/main/java/com/gdsc/blog/article/controller/ArticleController.java @@ -108,13 +108,13 @@ public Article getArticleByTitle( @PostMapping("/patch/{id}") //생성 & 수정은 PostMapping @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "게시글 수정") - public Article updateArticle( + public void updateArticle( @Parameter(description = "게시글 id") @PathVariable(value = "id") Long id, @Parameter(name="게시글 수정 DTO") @RequestBody ArticleUpdateDto dto, @Parameter(hidden = true) HttpServletRequest req) { User user = userService.whoami(req); - return articleService.updateArticle(id, dto); + articleService.updateArticle(id, dto); } /** diff --git a/src/main/java/com/gdsc/blog/article/service/ArticleService.java b/src/main/java/com/gdsc/blog/article/service/ArticleService.java index 8a33f4d..d8193d6 100644 --- a/src/main/java/com/gdsc/blog/article/service/ArticleService.java +++ b/src/main/java/com/gdsc/blog/article/service/ArticleService.java @@ -65,15 +65,15 @@ public Article getArticleByTitle(String title){ * * @param id 게시글 id * @param dto 게시글 수정 DTO - * @return Article 객체 */ @Transactional - public Article updateArticle(Long id, ArticleUpdateDto dto) { + public void updateArticle(Long id, ArticleUpdateDto dto) { Article article = getArticleById(id); //게시글 id로 게시글 가져오기 article.setTitle(dto.getTitle()); article.setContent(dto.getContent()); - return articleRepository.save(article); + //articleRepository.save(article); + //Transactional 어노테이션으로 save() 메소드를 사용하지 않아도 된다. } /** diff --git a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java index d635650..ae42a1a 100644 --- a/src/main/java/com/gdsc/blog/comment/controller/CommentController.java +++ b/src/main/java/com/gdsc/blog/comment/controller/CommentController.java @@ -99,13 +99,13 @@ public Comment getCommentById( @PostMapping("/patch/{commentId}") @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')") @Operation(summary = "댓글 수정") - public Comment updateComment( + public void updateComment( @Parameter(description = "댓글 id") @PathVariable("commentId") Long id, @Parameter(name="댓글 수정 DTO") @RequestBody CommentUpdateDto dto, @Parameter(hidden = true) HttpServletRequest req){ User user = userService.whoami(req); - return commentService.updateComment(id, dto); + commentService.updateComment(id, dto); } /** diff --git a/src/main/java/com/gdsc/blog/comment/service/CommentService.java b/src/main/java/com/gdsc/blog/comment/service/CommentService.java index eff3f5f..c6b4fc8 100644 --- a/src/main/java/com/gdsc/blog/comment/service/CommentService.java +++ b/src/main/java/com/gdsc/blog/comment/service/CommentService.java @@ -57,12 +57,10 @@ public Comment getCommentById(Long idx) { * @param commentUpdateDto 댓글 수정 DTO */ @Transactional - public Comment updateComment(Long id, CommentUpdateDto commentUpdateDto) { + public void updateComment(Long id, CommentUpdateDto commentUpdateDto) { Comment comment = getCommentById(id); comment.setContent(commentUpdateDto.getContent()); - - return commentRepository.save(comment); }