diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/PracticeApplication.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/PracticeApplication.java" index 34319b9..e9de726 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/PracticeApplication.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/PracticeApplication.java" @@ -6,8 +6,8 @@ @SpringBootApplication public class PracticeApplication { - public static void main(String[] args) { - SpringApplication.run(PracticeApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(PracticeApplication.class, args); + } } diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/GlobalExceptionHandler.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/GlobalExceptionHandler.java" index c4e394c..b166899 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/GlobalExceptionHandler.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/GlobalExceptionHandler.java" @@ -1,9 +1,9 @@ package org.sopt.practice.common; -import jakarta.persistence.EntityNotFoundException; import org.sopt.practice.common.dto.ErrorMessage; import org.sopt.practice.common.dto.ErrorResponse; import org.sopt.practice.exception.NotFoundException; +import org.sopt.practice.exception.CustomizedException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; @@ -22,8 +22,13 @@ protected ResponseEntity handleMethodArgumentNotValidException(Me } @ExceptionHandler(NotFoundException.class) - protected ResponseEntity handleEntityNotFoundException (NotFoundException e){ + protected ResponseEntity handleEntityNotFoundException(NotFoundException e) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ErrorResponse.of(ErrorMessage.MEMBER_NOT_FOUND_BY_ID_EXCEPTION)); } + @ExceptionHandler(CustomizedException.class) + public ResponseEntity handleUnauthorizedAccessException(CustomizedException e) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ErrorResponse.of(ErrorMessage.UNAUTHORIZED_ACCESS)); + } + } diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/ErrorMessage.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/ErrorMessage.java" index 55b89e5..26a196b 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/ErrorMessage.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/ErrorMessage.java" @@ -9,6 +9,9 @@ public enum ErrorMessage { MEMBER_NOT_FOUND_BY_ID_EXCEPTION(HttpStatus.NOT_FOUND.value(), "ID에 해당하는 사용자가 존재하지 않습니다."), BLOG_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "ID에 해당하는 블로그가 존재하지 않습니다."), + UNAUTHORIZED_ACCESS(HttpStatus.UNAUTHORIZED.value(), "접근 권한이 없습니다."), + POST_NOT_FOUND_BY_POST_ID_EXCEPTION(HttpStatus.NOT_FOUND.value(), "글이 존재하지 않습니다."), + POST_NOT_FOUND_BY_BLOG_ID_EXCEPTION(HttpStatus.NOT_FOUND.value(), "해당 블로그에 작성한 글이 존재하지 않습니다."), ; private final int status; private final String message; diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/ErrorResponse.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/ErrorResponse.java" index f70caac..8938738 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/ErrorResponse.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/ErrorResponse.java" @@ -4,7 +4,7 @@ public record ErrorResponse( int status, String message ) { - public static ErrorResponse of(int status, String message){ + public static ErrorResponse of(int status, String message) { return new ErrorResponse(status, message); } diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/SuccessMessage.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/SuccessMessage.java" index 37843df..43f96f1 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/SuccessMessage.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/SuccessMessage.java" @@ -7,7 +7,11 @@ @Getter @AllArgsConstructor public enum SuccessMessage { - BLOG_CREATE_SUCCESS(HttpStatus.CREATED.value(),"블로그 생성이 완료되었습니다."), + BLOG_CREATE_SUCCESS(HttpStatus.CREATED.value(), "블로그 생성이 완료되었습니다."), + POST_CREATE_SUCCESS(HttpStatus.CREATED.value(), "글 작성이 완료되었습니다."), + POST_ALL_FIND_SUCCESS(HttpStatus.OK.value(), "작성된 글을 모두 불러왔습니다."), + POST_FIND_SUCCESS(HttpStatus.OK.value(), "요청한 글을 불러왔습니다."), + ; private final int status; private final String message; diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/SuccessStatusResponse.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/SuccessStatusResponse.java" index 493641b..31c36cf 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/SuccessStatusResponse.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/common/dto/SuccessStatusResponse.java" @@ -1,9 +1,13 @@ package org.sopt.practice.common.dto; public record SuccessStatusResponse( - int status, String message + int status, String message, Object data ) { public static SuccessStatusResponse of(SuccessMessage successMessage){ - return new SuccessStatusResponse(successMessage.getStatus(), successMessage.getMessage()); + return new SuccessStatusResponse(successMessage.getStatus(), successMessage.getMessage(), null); } + public static SuccessStatusResponse of(int status, String message, Object data) { + return new SuccessStatusResponse(status, message, data); + } + } diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/controller/BlogController.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/controller/BlogController.java" index caf4ab6..1d0cb85 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/controller/BlogController.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/controller/BlogController.java" @@ -5,8 +5,8 @@ import lombok.RequiredArgsConstructor; import org.sopt.practice.common.dto.SuccessMessage; import org.sopt.practice.common.dto.SuccessStatusResponse; -import org.sopt.practice.dto.BlogCreateRequest; -import org.sopt.practice.dto.BlogTitleUpdateRequest; +import org.sopt.practice.dto.blog.BlogCreateRequest; +import org.sopt.practice.dto.blog.BlogTitleUpdateRequest; import org.sopt.practice.service.BlogService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -21,8 +21,8 @@ public class BlogController { //성공했을 때 값을 반환하기 위한 SuccessStatusResponse @PostMapping("/blog") public ResponseEntity creatBlog(@RequestHeader Long memberId, - @RequestBody BlogCreateRequest blogCreateRequest){ - return ResponseEntity.status(HttpStatus.CREATED).header("Location",blogService.create(memberId, blogCreateRequest)) + @RequestBody BlogCreateRequest blogCreateRequest) { + return ResponseEntity.status(HttpStatus.CREATED).header("Location", blogService.create(memberId, blogCreateRequest)) .body(SuccessStatusResponse.of(SuccessMessage.BLOG_CREATE_SUCCESS)); } @@ -30,7 +30,7 @@ public ResponseEntity creatBlog(@RequestHeader Long membe public ResponseEntity updateBlogTitle( @PathVariable Long blogId, @Valid @RequestBody BlogTitleUpdateRequest blogTitleUpdateRequest - ){ + ) { blogService.updateTitle(blogId, blogTitleUpdateRequest); return ResponseEntity.noContent().build(); } diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/controller/MemberController.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/controller/MemberController.java" index 8382adb..85aa901 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/controller/MemberController.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/controller/MemberController.java" @@ -1,8 +1,8 @@ package org.sopt.practice.controller; import lombok.RequiredArgsConstructor; -import org.sopt.practice.dto.MemberCreateDto; -import org.sopt.practice.dto.MemberFindDto; +import org.sopt.practice.dto.member.MemberCreateDto; +import org.sopt.practice.dto.member.MemberFindDto; import org.sopt.practice.service.MemberService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -17,20 +17,19 @@ public class MemberController { private final MemberService memberService; @PostMapping - public ResponseEntity postMember(@RequestBody MemberCreateDto memberCreateDto) - { + public ResponseEntity postMember(@RequestBody MemberCreateDto memberCreateDto) { return ResponseEntity.created(URI.create(memberService.createMember(memberCreateDto))).build(); } //ResponseEntity는 generic타입을 넣을 수 있음 @GetMapping("/{memberId}") - public ResponseEntity findMemberById(@PathVariable Long memberId){ - return ResponseEntity.ok(memberService.findMemberById(memberId)); + public ResponseEntity findMemberById(@PathVariable Long memberId) { + return ResponseEntity.ok(memberService.findMemberById(memberId)); } @DeleteMapping("/{memberId}") - public ResponseEntity deleteMemberById(@PathVariable Long memberId){ + public ResponseEntity deleteMemberById(@PathVariable Long memberId) { memberService.deleteMemberById(memberId); return ResponseEntity.noContent().build(); } diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/controller/PostController.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/controller/PostController.java" new file mode 100644 index 0000000..6da89df --- /dev/null +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/controller/PostController.java" @@ -0,0 +1,56 @@ +package org.sopt.practice.controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.sopt.practice.common.dto.SuccessMessage; +import org.sopt.practice.common.dto.SuccessStatusResponse; +import org.sopt.practice.domain.Post; +import org.sopt.practice.dto.post.PostCreateRequest; +import org.sopt.practice.dto.post.PostResponse; +import org.sopt.practice.service.PostService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api/v1") +@RequiredArgsConstructor +public class PostController { + + private final PostService postService; + + @PostMapping("/post") + public ResponseEntity writePost(@RequestHeader Long blogId, @RequestHeader Long memberId, + @Valid @RequestBody PostCreateRequest postCreateRequest) { + return ResponseEntity.status(HttpStatus.CREATED).header("Location", postService.writePost(blogId, memberId, postCreateRequest)) + .body(SuccessStatusResponse.of(SuccessMessage.POST_CREATE_SUCCESS)); + } + + @GetMapping("/post") + public ResponseEntity findAllPostsByBlogId(@RequestHeader Long blogId, @RequestHeader Long memberId) { + List posts = postService.findAllPostsByBlogId(blogId, memberId); + List responses = posts.stream() + .map(post -> new PostResponse(post.getId(), post.getTitle(), post.getContent())) + .collect(Collectors.toList()); + return ResponseEntity.ok(SuccessStatusResponse.of( + SuccessMessage.POST_ALL_FIND_SUCCESS.getStatus(), + SuccessMessage.POST_ALL_FIND_SUCCESS.getMessage(), + responses + )); + } + + @GetMapping("/post/{postId}") + public ResponseEntity getPostById(@RequestHeader Long blogId, @RequestHeader Long memberId, + @PathVariable Long postId) { + Post post = postService.findPostById(blogId, memberId, postId); + PostResponse postResponse = new PostResponse(post.getId(), post.getTitle(), post.getContent()); + return ResponseEntity.ok(new SuccessStatusResponse( + SuccessMessage.POST_FIND_SUCCESS.getStatus(), + SuccessMessage.POST_FIND_SUCCESS.getMessage(), + postResponse + )); + } +} diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/domain/Blog.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/domain/Blog.java" index aa23bf0..60114f3 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/domain/Blog.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/domain/Blog.java" @@ -4,11 +4,14 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import java.util.ArrayList; +import java.util.List; + //엔티티 클래스 @Entity @Getter @NoArgsConstructor -public class Blog extends BaseTimeEntity{ +public class Blog extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -21,20 +24,24 @@ public class Blog extends BaseTimeEntity{ private String description; - private Blog(Member member, String title, String description){ + private Blog(Member member, String title, String description) { this.member = member; this.title = title; - this.description= description; + this.description = description; } - public static Blog create(Member member, String title, String description){ + public static Blog create(Member member, String title, String description) { return new Blog(member, title, description); } + public void updateTitle( String title ) { this.title = title; } + @OneToMany(mappedBy = "blog", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + private List posts = new ArrayList<>(); + } diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/domain/Member.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/domain/Member.java" index 6f222db..db08c64 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/domain/Member.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/domain/Member.java" @@ -13,7 +13,7 @@ public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - private String name; + private String name; @Enumerated(EnumType.STRING) //enum class의 string 값을 가져옴 private Part part; @@ -22,13 +22,13 @@ public class Member { //접근 제어자 private인 이유 : 객체의 무분별한 생성을 막기 위해서 @Builder - public Member(String name, Part part, int age){ + public Member(String name, Part part, int age) { this.name = name; this.part = part; this.age = age; } - public static Member create(String name, Part part, int age){ + public static Member create(String name, Part part, int age) { return Member.builder() .name(name) .part(part) diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/domain/Post.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/domain/Post.java" index 11f09be..159e92e 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/domain/Post.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/domain/Post.java" @@ -4,18 +4,33 @@ import lombok.Getter; import lombok.NoArgsConstructor; + @Entity @Getter -@NoArgsConstructor -public class Post extends BaseTimeEntity{ +@NoArgsConstructor +public class Post extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Blog blog; + + private String title; + private String content; - @ManyToOne(fetch =FetchType.LAZY) - private Blog blog; + public static Post create(Blog blog, String title, String content) { + return new Post(blog, title, content); + } + public Post(Blog blog, String title, String content) { + this.blog = blog; + + this.title = title; + this.content = content; + } } + diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/BlogTitleUpdateRequest.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/BlogTitleUpdateRequest.java" deleted file mode 100644 index 5861ca1..0000000 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/BlogTitleUpdateRequest.java" +++ /dev/null @@ -1,9 +0,0 @@ -package org.sopt.practice.dto; - -import jakarta.validation.constraints.Size; - -public record BlogTitleUpdateRequest( - @Size(max = 5 , message = "블로그 제목이 최대 글자 수(5자)를 초과했습니다.") - String title -) { -} diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/MemberCreateDto.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/MemberCreateDto.java" deleted file mode 100644 index cb19f2b..0000000 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/MemberCreateDto.java" +++ /dev/null @@ -1,7 +0,0 @@ -package org.sopt.practice.dto; - -import org.sopt.practice.domain.Part; - -public record MemberCreateDto(String name, Part part, int age){ - -} diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/BlogCreateRequest.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/blog/BlogCreateRequest.java" similarity index 66% rename from "\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/BlogCreateRequest.java" rename to "\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/blog/BlogCreateRequest.java" index f6102ae..9aaaeee 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/BlogCreateRequest.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/blog/BlogCreateRequest.java" @@ -1,4 +1,4 @@ -package org.sopt.practice.dto; +package org.sopt.practice.dto.blog; public record BlogCreateRequest(String title, String description) { } diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/blog/BlogTitleUpdateRequest.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/blog/BlogTitleUpdateRequest.java" new file mode 100644 index 0000000..7dc60f6 --- /dev/null +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/blog/BlogTitleUpdateRequest.java" @@ -0,0 +1,9 @@ +package org.sopt.practice.dto.blog; + +import jakarta.validation.constraints.Size; + +public record BlogTitleUpdateRequest( + @Size(max = 5, message = "블로그 제목이 최대 글자 수(5자)를 초과했습니다.") + String title +) { +} diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/member/MemberCreateDto.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/member/MemberCreateDto.java" new file mode 100644 index 0000000..cd23be5 --- /dev/null +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/member/MemberCreateDto.java" @@ -0,0 +1,7 @@ +package org.sopt.practice.dto.member; + +import org.sopt.practice.domain.Part; + +public record MemberCreateDto(String name, Part part, int age) { + +} diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/MemberFindDto.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/member/MemberFindDto.java" similarity index 78% rename from "\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/MemberFindDto.java" rename to "\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/member/MemberFindDto.java" index ef720a1..ce0f1e1 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/MemberFindDto.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/member/MemberFindDto.java" @@ -1,14 +1,14 @@ -package org.sopt.practice.dto; +package org.sopt.practice.dto.member; import org.sopt.practice.domain.Member; import org.sopt.practice.domain.Part; //정보만을 가져오는 !! public record MemberFindDto( - String name, - Part part, - int age -){ + String name, + Part part, + int age +) { public static MemberFindDto of(Member member) //한 멤버 객체에서 멤버를 찾는다 라는 의미의 of 함수 { return new MemberFindDto(member.getName(), member.getPart(), member.getAge()); diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/post/PostCreateRequest.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/post/PostCreateRequest.java" new file mode 100644 index 0000000..877ecd2 --- /dev/null +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/post/PostCreateRequest.java" @@ -0,0 +1,14 @@ +package org.sopt.practice.dto.post; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public record PostCreateRequest( + @NotBlank(message = "제목을 입력해주세요.") + @Size(max = 100, message = "제목은 100자 이하로 작성해주세요.") + String title, + @NotBlank(message = "내용을 입력해주세요.") + @Size(max = 1000, message = "내용은 1000자 이하로 작성해주세요.") + String content) { + +} diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/post/PostResponse.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/post/PostResponse.java" new file mode 100644 index 0000000..afd0143 --- /dev/null +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/dto/post/PostResponse.java" @@ -0,0 +1,4 @@ +package org.sopt.practice.dto.post; + +public record PostResponse(Long id, String title, String content) { +} diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/exception/BusinessException.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/exception/BusinessException.java" index daa1a33..9da254c 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/exception/BusinessException.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/exception/BusinessException.java" @@ -2,9 +2,10 @@ import org.sopt.practice.common.dto.ErrorMessage; -public class BusinessException extends RuntimeException{ +public class BusinessException extends RuntimeException { private ErrorMessage errorMessage; - public BusinessException(ErrorMessage errorMessage){ + + public BusinessException(ErrorMessage errorMessage) { super(errorMessage.getMessage()); this.errorMessage = errorMessage; } diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/exception/CustomizedException.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/exception/CustomizedException.java" new file mode 100644 index 0000000..885de58 --- /dev/null +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/exception/CustomizedException.java" @@ -0,0 +1,9 @@ +package org.sopt.practice.exception; + +import org.sopt.practice.common.dto.ErrorMessage; + +public class CustomizedException extends BusinessException { + public CustomizedException(ErrorMessage errorMessage) { + super(errorMessage); + } +} \ No newline at end of file diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/exception/NotFoundException.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/exception/NotFoundException.java" index 3e2837f..0ef3964 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/exception/NotFoundException.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/exception/NotFoundException.java" @@ -3,7 +3,7 @@ import org.sopt.practice.common.dto.ErrorMessage; public class NotFoundException extends BusinessException { - public NotFoundException(ErrorMessage errorMessage){ + public NotFoundException(ErrorMessage errorMessage) { super(errorMessage); } } diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/repository/BlogRepository.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/repository/BlogRepository.java" index 6a10f32..13bb161 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/repository/BlogRepository.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/repository/BlogRepository.java" @@ -3,5 +3,5 @@ import org.sopt.practice.domain.Blog; import org.springframework.data.jpa.repository.JpaRepository; -public interface BlogRepository extends JpaRepository { +public interface BlogRepository extends JpaRepository { } diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/repository/PostRepository.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/repository/PostRepository.java" new file mode 100644 index 0000000..cc261ff --- /dev/null +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/repository/PostRepository.java" @@ -0,0 +1,10 @@ +package org.sopt.practice.repository; + +import org.sopt.practice.domain.Post; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface PostRepository extends JpaRepository { + List findByBlogId(Long blogId); +} diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/service/BlogService.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/service/BlogService.java" index 84393c5..0d4ce2a 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/service/BlogService.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/service/BlogService.java" @@ -1,13 +1,13 @@ package org.sopt.practice.service; -import jakarta.persistence.EntityNotFoundException; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.sopt.practice.common.dto.ErrorMessage; import org.sopt.practice.domain.Blog; import org.sopt.practice.domain.Member; -import org.sopt.practice.dto.BlogCreateRequest; -import org.sopt.practice.dto.BlogTitleUpdateRequest; +import org.sopt.practice.dto.blog.BlogCreateRequest; +import org.sopt.practice.dto.blog.BlogTitleUpdateRequest; +import org.sopt.practice.exception.CustomizedException; import org.sopt.practice.exception.NotFoundException; import org.sopt.practice.repository.BlogRepository; import org.springframework.stereotype.Service; @@ -32,9 +32,17 @@ public void updateTitle(Long blogId, BlogTitleUpdateRequest blogTitleUpdateReque blog.updateTitle(blogTitleUpdateRequest.title()); } + public Blog findBlogById(Long blogId){ return blogRepository.findById(blogId).orElseThrow( () -> new NotFoundException(ErrorMessage.BLOG_NOT_FOUND) ); } + // 멤버의 블로그 소유권을 검증하는 메서드 + public void validateBlogMember(Long blogId, Long memberId) { + Blog blog = this.findBlogById(blogId); + if (!blog.getMember().getId().equals(memberId)) { + throw new CustomizedException(ErrorMessage.UNAUTHORIZED_ACCESS); + } + } } \ No newline at end of file diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/service/MemberService.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/service/MemberService.java" index dc023d6..f4d58bf 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/service/MemberService.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/service/MemberService.java" @@ -1,13 +1,11 @@ package org.sopt.practice.service; -import jakarta.persistence.EntityNotFoundException; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.sopt.practice.common.dto.ErrorMessage; -import org.sopt.practice.common.dto.ErrorResponse; import org.sopt.practice.domain.Member; -import org.sopt.practice.dto.MemberCreateDto; -import org.sopt.practice.dto.MemberFindDto; +import org.sopt.practice.dto.member.MemberCreateDto; +import org.sopt.practice.dto.member.MemberFindDto; import org.sopt.practice.exception.NotFoundException; import org.sopt.practice.repository.MemberRepository; import org.springframework.stereotype.Service; @@ -18,27 +16,28 @@ public class MemberService { private final MemberRepository memberRepository; @Transactional //DB변경사항을 반영할 때 사용 - public String createMember(MemberCreateDto memberCreateDto) - { + public String createMember(MemberCreateDto memberCreateDto) { Member member = memberRepository.save(Member.create(memberCreateDto.name(), memberCreateDto.part(), memberCreateDto.age())); return member.getId().toString(); } + public Member findById(Long memberId) { return memberRepository.findById(memberId).orElseThrow( () -> new NotFoundException(ErrorMessage.MEMBER_NOT_FOUND_BY_ID_EXCEPTION) ); } - public MemberFindDto findMemberById(Long memberId){ + public MemberFindDto findMemberById(Long memberId) { return MemberFindDto.of(memberRepository.findById(memberId).orElseThrow( () -> new NotFoundException(ErrorMessage.MEMBER_NOT_FOUND_BY_ID_EXCEPTION) )); } + @Transactional //삭제도 DB변경사항 적용이라 //아무것도 return 하지 않아서 void - public void deleteMemberById(Long memberId){ + public void deleteMemberById(Long memberId) { Member member = memberRepository.findById(memberId) - .orElseThrow(()-> new NotFoundException(ErrorMessage.MEMBER_NOT_FOUND_BY_ID_EXCEPTION)); + .orElseThrow(() -> new NotFoundException(ErrorMessage.MEMBER_NOT_FOUND_BY_ID_EXCEPTION)); memberRepository.delete(member); } diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/service/PostService.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/service/PostService.java" new file mode 100644 index 0000000..040d740 --- /dev/null +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/main/java/org/sopt/practice/service/PostService.java" @@ -0,0 +1,53 @@ +package org.sopt.practice.service; + +import lombok.RequiredArgsConstructor; +import org.sopt.practice.common.dto.ErrorMessage; +import org.sopt.practice.domain.Blog; +import org.sopt.practice.domain.Member; +import org.sopt.practice.domain.Post; +import org.sopt.practice.dto.post.PostCreateRequest; +import org.sopt.practice.exception.CustomizedException; +import org.sopt.practice.repository.PostRepository; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class PostService { + + private final PostRepository postRepository; + private final BlogService blogService; + private final MemberService memberService; + + public String writePost(Long blogId, Long memberId, PostCreateRequest postCreateRequest) { + // 블로그 소유권 검증 + blogService.validateBlogMember(blogId, memberId); + // 글 생성 및 저장 로직 + Post post = postRepository.save(Post.create( + blogService.findBlogById(blogId), // Blog 객체 검색 + postCreateRequest.title(), + postCreateRequest.content() + )); + return post.toString(); + } + + public List findAllPostsByBlogId(Long blogId, Long memberId) { + // 블로그 소유권 검증 + blogService.validateBlogMember(blogId, memberId); + List posts = postRepository.findByBlogId(blogId); + if (posts.isEmpty()) { + throw new CustomizedException(ErrorMessage.POST_NOT_FOUND_BY_BLOG_ID_EXCEPTION); + } + return posts; + } + + public Post findPostById(Long blogId, Long memberId, Long postId) { + // 블로그 소유권 검증 + blogService.validateBlogMember(blogId, memberId); + // 특정 포스트 ID로 게시물 검색 + return postRepository.findById(postId) + .orElseThrow(() -> new CustomizedException(ErrorMessage.POST_NOT_FOUND_BY_POST_ID_EXCEPTION)); + } + +} diff --git "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/test/java/org/sopt/practice/controller/BlogControllerTest.java" "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/test/java/org/sopt/practice/controller/BlogControllerTest.java" index 7435c65..340d715 100644 --- "a/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/test/java/org/sopt/practice/controller/BlogControllerTest.java" +++ "b/\354\204\270\353\257\270\353\202\230/3\354\260\250 \354\204\270\353\257\270\353\202\230/practice/src/test/java/org/sopt/practice/controller/BlogControllerTest.java" @@ -6,7 +6,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.sopt.practice.dto.BlogCreateRequest; +import org.sopt.practice.dto.blog.BlogCreateRequest; import org.sopt.practice.repository.BlogRepository; import org.sopt.practice.repository.MemberRepository; import org.sopt.practice.service.BlogService;