diff --git a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/controller/PostController.java b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/controller/PostController.java new file mode 100644 index 0000000..8d4fd5e --- /dev/null +++ b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/controller/PostController.java @@ -0,0 +1,45 @@ +package sopt.org.ThirdSeminar.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import sopt.org.ThirdSeminar.common.dto.ApiResponseDto; +import sopt.org.ThirdSeminar.controller.dto.request.PostRequestDto; +import sopt.org.ThirdSeminar.controller.dto.response.PostResponseDto; +import sopt.org.ThirdSeminar.exception.ErrorStatus; +import sopt.org.ThirdSeminar.exception.SuccessStatus; +import sopt.org.ThirdSeminar.exception.UserNotFoundException; +import sopt.org.ThirdSeminar.service.PostService; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/post") +public class PostController { + + private final PostService postService; + + //게시물 생성 + @PostMapping("") + @ResponseStatus(HttpStatus.CREATED) + public ApiResponseDto createPost(@RequestBody final PostRequestDto request) { + try { + return ApiResponseDto.success(SuccessStatus.CREATE_POST_SUCCESS, postService.createPost(request)); + } catch (UserNotFoundException e) { + return ApiResponseDto.error(ErrorStatus.USER_NOT_FOUND); + } + } + + //유저아이디로 게시물 조회 + @GetMapping("/{userId}") + public ApiResponseDto> getPostByUserId(@PathVariable final int userId) { + return ApiResponseDto.success(SuccessStatus.READ_ALL_POST, postService.getPostByUserId((long) userId)); + } + + //제목으로 게시물 조회 + @GetMapping("") + public ApiResponseDto> getPostByTitle(@RequestParam final String title) { + return ApiResponseDto.success(SuccessStatus.READ_ALL_POST, postService.getPostByTitle(title)); + } +} diff --git a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/controller/UserController.java b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/controller/UserController.java index cac7283..51bd08a 100644 --- a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/controller/UserController.java +++ b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/controller/UserController.java @@ -20,6 +20,7 @@ public class UserController { private final UserService userService; + //* 유저 생성 @PostMapping("/user/signup") @ResponseStatus(HttpStatus.CREATED) public ApiResponseDto create(@RequestBody @Valid final UserRequestDto request) { diff --git a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/controller/dto/request/PostRequestDto.java b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/controller/dto/request/PostRequestDto.java new file mode 100644 index 0000000..b86ed18 --- /dev/null +++ b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/controller/dto/request/PostRequestDto.java @@ -0,0 +1,15 @@ +package sopt.org.ThirdSeminar.controller.dto.request; + +import lombok.Getter; + +import javax.validation.constraints.NotNull; + +@Getter +public class PostRequestDto { + @NotNull + private Long userId; + @NotNull + private String title; + private String content; + +} diff --git a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/controller/dto/response/PostResponseDto.java b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/controller/dto/response/PostResponseDto.java new file mode 100644 index 0000000..d66f507 --- /dev/null +++ b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/controller/dto/response/PostResponseDto.java @@ -0,0 +1,17 @@ +package sopt.org.ThirdSeminar.controller.dto.response; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class PostResponseDto { + private Long postId; + private String title; + private String content; + + public static PostResponseDto of(Long postId, String title, String content) { + return new PostResponseDto(postId, title, content); + } +} diff --git a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/domain/Post.java b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/domain/Post.java new file mode 100644 index 0000000..13cb636 --- /dev/null +++ b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/domain/Post.java @@ -0,0 +1,35 @@ +package sopt.org.ThirdSeminar.domain; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Post { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(nullable = false) + private String title; + //@Column 생략 가능 + private String content; + private LocalDateTime createdAt; + + @Builder + public Post(String title, String content, User user) { + this.title = title; + this.content = content; + this.user = user; + this.createdAt = LocalDateTime.now(); + } + + @ManyToOne(fetch = FetchType.LAZY) //다대일(N:1) 관계 + @JoinColumn(name = "user_id") //외래키 매핑 + private User user; +} diff --git a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/domain/User.java b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/domain/User.java index a4bb13b..4515300 100644 --- a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/domain/User.java +++ b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/domain/User.java @@ -1,14 +1,21 @@ package sopt.org.ThirdSeminar.domain; -import lombok.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; + @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class User { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "user_id") private Long id; @Column(nullable = false) private String nickname; @@ -16,6 +23,7 @@ public class User { private String email; @Column(nullable = false) private String password; + @Builder public User(String nickname, String email, String password) { this.nickname = nickname; @@ -23,4 +31,7 @@ public User(String nickname, String email, String password) { this.password = password; } + //mappedBy 양방향 연관관계 주인 user x -> post(외래키를 가진 쪽) + @OneToMany(mappedBy = "user") //일대다(1:N) + private final List posts = new ArrayList<>(); } diff --git a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/exception/ErrorStatus.java b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/exception/ErrorStatus.java index e432536..dab170e 100644 --- a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/exception/ErrorStatus.java +++ b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/exception/ErrorStatus.java @@ -26,6 +26,11 @@ public enum ErrorStatus { INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "예상치 못한 서버 에러가 발생했습니다."), BAD_GATEWAY_EXCEPTION(HttpStatus.BAD_GATEWAY, "일시적인 에러가 발생하였습니다.\n잠시 후 다시 시도해주세요!"), SERVICE_UNAVAILABLE_EXCEPTION(HttpStatus.SERVICE_UNAVAILABLE, "현재 점검 중입니다.\n잠시 후 다시 시도해주세요!"), + + /* + User + */ + USER_NOT_FOUND(HttpStatus.NOT_FOUND, "유저가 존재하지 않습니다."), ; private final HttpStatus httpStatus; diff --git a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/exception/SuccessStatus.java b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/exception/SuccessStatus.java index e7fcf27..1fb386f 100644 --- a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/exception/SuccessStatus.java +++ b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/exception/SuccessStatus.java @@ -11,7 +11,13 @@ public enum SuccessStatus { /* user */ - SIGNUP_SUCCESS(HttpStatus.CREATED, "회원가입이 완료되었습니다."), + SIGNUP_SUCCESS(HttpStatus.CREATED, "유저 생성 성공"), + + /* + post + */ + CREATE_POST_SUCCESS(HttpStatus.CREATED, "게시물 작성 성공"), + READ_ALL_POST(HttpStatus.OK, "게시물 조회 성공"), ; private final HttpStatus httpStatus; diff --git a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/exception/UserNotFoundException.java b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/exception/UserNotFoundException.java new file mode 100644 index 0000000..7b0e437 --- /dev/null +++ b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/exception/UserNotFoundException.java @@ -0,0 +1,7 @@ +package sopt.org.ThirdSeminar.exception; + +public class UserNotFoundException extends RuntimeException { + public UserNotFoundException() { + super(); + } +} \ No newline at end of file diff --git a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/infrastructure/PostRepository.java b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/infrastructure/PostRepository.java new file mode 100644 index 0000000..917e375 --- /dev/null +++ b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/infrastructure/PostRepository.java @@ -0,0 +1,14 @@ +package sopt.org.ThirdSeminar.infrastructure; + +import org.springframework.data.repository.Repository; +import sopt.org.ThirdSeminar.domain.Post; + +import java.util.List; + +public interface PostRepository extends Repository { + void save(Post post); + + List findAllByUserId(Long userId); + + List findAllByTitle(String title); +} diff --git a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/infrastructure/UserRepository.java b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/infrastructure/UserRepository.java index db2ed60..5b27a02 100644 --- a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/infrastructure/UserRepository.java +++ b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/infrastructure/UserRepository.java @@ -5,4 +5,6 @@ public interface UserRepository extends Repository { void save(User user); + + User findById(Long id); } diff --git a/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/service/PostService.java b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/service/PostService.java new file mode 100644 index 0000000..8b6df42 --- /dev/null +++ b/ThirdSeminar/src/main/java/sopt/org/ThirdSeminar/service/PostService.java @@ -0,0 +1,56 @@ +package sopt.org.ThirdSeminar.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import sopt.org.ThirdSeminar.controller.dto.request.PostRequestDto; +import sopt.org.ThirdSeminar.controller.dto.response.PostResponseDto; +import sopt.org.ThirdSeminar.domain.Post; +import sopt.org.ThirdSeminar.domain.User; +import sopt.org.ThirdSeminar.exception.UserNotFoundException; +import sopt.org.ThirdSeminar.infrastructure.PostRepository; +import sopt.org.ThirdSeminar.infrastructure.UserRepository; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Service +@RequiredArgsConstructor //final이 붙거나 @NotNull 이 붙은 필드의 생성자를 자동 생성 +public class PostService { + + private final UserRepository userRepository; + private final PostRepository postRepository; + + @Transactional //일련의 작업을 하나로 묶어서 처리 -> 오류가 발생했을 때 모든 작업들을 원상태로 되돌릴 수 있음 + public PostResponseDto createPost(PostRequestDto request) { + final Optional user = Optional.ofNullable(userRepository.findById(request.getUserId())); + user.orElseThrow(UserNotFoundException::new); + + Post post = Post.builder() + .title(request.getTitle()) + .content(request.getContent()) + .user(user.get()) + .build(); + + postRepository.save(post); + + return PostResponseDto.of(post.getId(), post.getTitle(), post.getContent()); + } + + public List getPostByUserId(final Long userId) { + final List postList = new ArrayList<>(); + postRepository.findAllByUserId(userId).forEach((p) -> + postList.add(PostResponseDto.of(p.getId(), p.getTitle(), p.getContent())) + ); + return postList; + } + + public List getPostByTitle(final String title) { + final List postList = new ArrayList<>(); + postRepository.findAllByTitle(title).forEach((p) -> + postList.add(PostResponseDto.of(p.getId(), p.getTitle(), p.getContent())) + ); + return postList; + } +}