-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat#21 게시물 생성, 삭제, 수정 API 구현 #26
Changes from 3 commits
eca5fd5
fd762a6
9827dd8
354fc9c
3af9743
9a11fd4
3642345
9b412b4
34779fc
f5dc8cf
83b27e7
c811076
08a5efd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,48 @@ | ||
package com.leets.team2.xclone.domain.post.controller; | ||
|
||
import com.leets.team2.xclone.common.ApiData; | ||
import com.leets.team2.xclone.domain.member.entities.Member; | ||
import com.leets.team2.xclone.domain.member.service.MemberService; | ||
import com.leets.team2.xclone.domain.post.dto.PostDTO; | ||
import com.leets.team2.xclone.domain.post.entity.Post; | ||
import com.leets.team2.xclone.domain.post.service.PostService; | ||
import io.swagger.v3.oas.annotations.parameters.RequestBody; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.validation.annotation.Validated; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api/posts") | ||
public class PostController { | ||
private final PostService postService; | ||
private final MemberService memberService; | ||
|
||
@PostMapping("/create")//게시물 생성 | ||
public ResponseEntity<ApiData<PostDTO>> createPost(@RequestParam String authorTag, @RequestBody @Validated PostDTO postDTO){ | ||
Member author=memberService.findMemberByTag(authorTag); | ||
Post post=postService.createPost(postDTO,author); | ||
return ApiData.created(new PostDTO( | ||
post.getId(), | ||
post.getTitle(), | ||
post.getContent() | ||
)); | ||
} | ||
|
||
@PatchMapping("/{postId}/edit") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HTTP 메서드 자체가 어떤 동작을 수행하는지 보이기때문에 edit 등을 경로에 동작을 명시 안하는게 좋아보입니다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 삭제했습니다!! |
||
public ResponseEntity<ApiData<PostDTO>> updatePost(@PathVariable Long postId,@RequestBody @Validated PostDTO postDTO){ | ||
Post updatedPost=postService.updatePost(postId,postDTO); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 본인이 쓴 게시물인지 확인하는 로직이 필요해 보여요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 구현했습니다. 확인 한번 부탁드립니다. |
||
return ApiData.ok(new PostDTO( | ||
updatedPost.getId(), | ||
updatedPost.getTitle(), | ||
updatedPost.getContent() | ||
)); | ||
} | ||
|
||
@DeleteMapping("/{postId}/delete") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기서도 delete를 경로에 동작을 명시 안하는게 좋아보입니다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아 그렇네요!! 어차피 DeleteMapping해서 없어도 될 것 같아요!! 삭제했습니다. |
||
public ResponseEntity<ApiData<Void>> deletePost(@PathVariable Long postId){ | ||
postService.deletePost(postId); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기서도 본인이 쓴 게시물인지 확인하는 로직도 필요해보여요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 구현했습니다. 확인한번 부탁드립니다. |
||
return ApiData.ok(null); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DTO를 사용하기로 한 이상, 각각의 Request와 Response에 대해서 각각 다른 DTO를 사용하는게 좋습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 수정하였습니다. 확인 한번 부탁드립니다. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,23 @@ | ||
package com.leets.team2.xclone.domain.post.dto; | ||
|
||
import jakarta.validation.constraints.NotBlank; | ||
import jakarta.validation.constraints.NotNull; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Builder; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Data | ||
@Builder | ||
@AllArgsConstructor | ||
@NoArgsConstructor | ||
public class PostDTO { | ||
//DTO 같은 경우 각각의 기능에 따른 DTO를 전부 만들 예정입니다. 다음은 예시 상황입니다. 이런 방식으로 구현하는건 어떻게 생각하시는지 의견 부탁드리겠습니다. | ||
public record CreatePostRequest( | ||
@NotNull(message = "아이디는 필수입니다.") | ||
Long postId, | ||
|
||
@NotBlank(message = "제목은 필수입니다.") | ||
String title, | ||
private Long id;//게시물 id | ||
|
||
@NotBlank | ||
private String title;//제목 | ||
|
||
@NotBlank | ||
private String content;//내용 | ||
|
||
@NotBlank(message = "내용은 필수입니다.") | ||
String content | ||
){} | ||
public record CreatePostResponse( | ||
Long postId, | ||
String title, | ||
String content | ||
){ | ||
public static CreatePostResponse of(Long postId,String title,String content) { | ||
return new CreatePostResponse(postId,title,content); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,43 @@ | ||
package com.leets.team2.xclone.domain.post.service; | ||
|
||
import com.leets.team2.xclone.domain.member.entities.Member; | ||
import com.leets.team2.xclone.domain.member.repository.MemberRepository; | ||
import com.leets.team2.xclone.domain.member.service.MemberService; | ||
import com.leets.team2.xclone.domain.post.dto.PostDTO; | ||
import com.leets.team2.xclone.domain.post.entity.Post; | ||
import com.leets.team2.xclone.domain.post.repository.PostRepository; | ||
import com.leets.team2.xclone.exception.PostNotFoundException; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.util.NoSuchElementException; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class PostService { | ||
private final PostRepository postRepository; | ||
|
||
public Post createPost(PostDTO postDTO, Member author){ | ||
Post post=Post.builder() | ||
.title(postDTO.getTitle()) | ||
.content(postDTO.getContent()) | ||
.author(author) | ||
.build(); | ||
return postRepository.save(post); | ||
} | ||
|
||
public Post updatePost(Long postId,PostDTO postDTO){ | ||
Post post=postRepository.findById(postId) | ||
.orElseThrow(PostNotFoundException::new); | ||
post.setTitle(postDTO.getTitle()); | ||
post.setContent(postDTO.getContent()); | ||
return postRepository.save(post); | ||
} | ||
|
||
public void deletePost(Long postId){ | ||
if(!postRepository.existsById(postId)){//게시물이 없을 경우 예외 발생 | ||
throw new PostNotFoundException(); | ||
} | ||
postRepository.deleteById(postId);//해당 게시물 아이디의 게시물 삭제 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.leets.team2.xclone.exception; | ||
|
||
public class PostNotFoundException extends ApplicationException{//게시물을 찾지 못했을 경우 에러 | ||
public PostNotFoundException(){ | ||
super(ErrorInfo.NO_SUCH_POST); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이런 비즈니스 로직은 Service layer로 분리하는게 좋아보입니다👍