diff --git a/build.gradle b/build.gradle index 728ec9c..f07f4ff 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,12 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-jdbc' + implementation 'org.projectlombok:lombok:1.18.30' + implementation 'org.hibernate.validator:hibernate-validator' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly 'com.mysql:mysql-connector-j' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' } diff --git a/src/main/java/com/example/demo/controller/ArticleController.java b/src/main/java/com/example/demo/controller/ArticleController.java index b28e4dd..f74f3f2 100644 --- a/src/main/java/com/example/demo/controller/ArticleController.java +++ b/src/main/java/com/example/demo/controller/ArticleController.java @@ -3,6 +3,7 @@ import java.net.URI; import java.util.List; +import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -45,7 +46,7 @@ public ResponseEntity getArticle( @PostMapping("/articles") public ResponseEntity crateArticle( - @RequestBody ArticleCreateRequest request + @Valid @RequestBody ArticleCreateRequest request ) { ArticleResponse response = articleService.create(request); return ResponseEntity.created(URI.create("/articles/" + response.id())).body(response); diff --git a/src/main/java/com/example/demo/controller/BoardController.java b/src/main/java/com/example/demo/controller/BoardController.java index ada81dc..6194662 100644 --- a/src/main/java/com/example/demo/controller/BoardController.java +++ b/src/main/java/com/example/demo/controller/BoardController.java @@ -2,6 +2,7 @@ import java.util.List; +import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -39,7 +40,7 @@ public BoardResponse getBoard( @PostMapping("/boards") public BoardResponse createBoard( - @RequestBody BoardCreateRequest request + @Valid @RequestBody BoardCreateRequest request ) { return boardService.createBoard(request); } diff --git a/src/main/java/com/example/demo/controller/MemberController.java b/src/main/java/com/example/demo/controller/MemberController.java index ddb18ec..c1fae43 100644 --- a/src/main/java/com/example/demo/controller/MemberController.java +++ b/src/main/java/com/example/demo/controller/MemberController.java @@ -2,6 +2,7 @@ import java.util.List; +import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -41,7 +42,7 @@ public ResponseEntity getMember( @PostMapping("/members") public ResponseEntity create( - @RequestBody MemberCreateRequest request + @Valid @RequestBody MemberCreateRequest request ) { MemberResponse response = memberService.create(request); return ResponseEntity.ok(response); diff --git a/src/main/java/com/example/demo/controller/dto/request/ArticleCreateRequest.java b/src/main/java/com/example/demo/controller/dto/request/ArticleCreateRequest.java index d1f82a5..6cb74de 100644 --- a/src/main/java/com/example/demo/controller/dto/request/ArticleCreateRequest.java +++ b/src/main/java/com/example/demo/controller/dto/request/ArticleCreateRequest.java @@ -1,10 +1,13 @@ package com.example.demo.controller.dto.request; +import jakarta.annotation.Nonnull; +import jakarta.validation.constraints.NotNull; + public record ArticleCreateRequest( - Long authorId, - Long boardId, - String title, - String description + @NotNull(message = "멤버ID를 입력해주세요.") Long authorId, + @NotNull(message = "게시판ID를 입력해주세요.") Long boardId, + @NotNull(message = "제목을 입력해주세요.") String title, + @NotNull(message = "내용을 입력해주세요.") String content ) { } diff --git a/src/main/java/com/example/demo/controller/dto/request/BoardCreateRequest.java b/src/main/java/com/example/demo/controller/dto/request/BoardCreateRequest.java index d1db14b..9347100 100644 --- a/src/main/java/com/example/demo/controller/dto/request/BoardCreateRequest.java +++ b/src/main/java/com/example/demo/controller/dto/request/BoardCreateRequest.java @@ -1,7 +1,9 @@ package com.example.demo.controller.dto.request; +import jakarta.validation.constraints.NotNull; + public record BoardCreateRequest( - String name + @NotNull(message = "이름을 입력해주세요.") String name ) { } diff --git a/src/main/java/com/example/demo/controller/dto/request/MemberCreateRequest.java b/src/main/java/com/example/demo/controller/dto/request/MemberCreateRequest.java index 44f74a5..bb58739 100644 --- a/src/main/java/com/example/demo/controller/dto/request/MemberCreateRequest.java +++ b/src/main/java/com/example/demo/controller/dto/request/MemberCreateRequest.java @@ -1,9 +1,11 @@ package com.example.demo.controller.dto.request; +import jakarta.validation.constraints.NotNull; + public record MemberCreateRequest( - String name, - String email, - String password + @NotNull(message = "이름을 입력해주세요.") String name, + @NotNull(message = "이메일을 입력해주세요.") String email, + @NotNull(message = "비밀번호를 입력해주세요") String password ) { } diff --git a/src/main/java/com/example/demo/controller/dto/request/MemberUpdateRequest.java b/src/main/java/com/example/demo/controller/dto/request/MemberUpdateRequest.java index 15f4345..79f701d 100644 --- a/src/main/java/com/example/demo/controller/dto/request/MemberUpdateRequest.java +++ b/src/main/java/com/example/demo/controller/dto/request/MemberUpdateRequest.java @@ -1,8 +1,10 @@ package com.example.demo.controller.dto.request; +import jakarta.validation.constraints.NotNull; + public record MemberUpdateRequest( - String name, - String email + @NotNull(message = "멤버의 이름을 적어주세요.") String name, + @NotNull(message = "멤버의 이메일을 적어주세요") String email ) { } diff --git a/src/main/java/com/example/demo/domain/Article.java b/src/main/java/com/example/demo/domain/Article.java index e0183db..ea24ec6 100644 --- a/src/main/java/com/example/demo/domain/Article.java +++ b/src/main/java/com/example/demo/domain/Article.java @@ -1,18 +1,35 @@ package com.example.demo.domain; +import jakarta.persistence.*; + import java.time.LocalDateTime; +@Entity public class Article { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "article_id") private Long id; - private Long authorId; - private Long boardId; +// private Long authorId; +// private Long boardId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "author_id") + private Member member; + + @ManyToOne + @JoinColumn(name = "board_id") + private Board board; + private String title; private String content; + @Column(name = "created_date") private LocalDateTime createdAt; + @Column(name = "modified_date") private LocalDateTime modifiedAt; - public Article( +/* public Article( Long id, Long authorId, Long boardId, @@ -37,16 +54,33 @@ public Article(Long authorId, Long boardId, String title, String content) { this.title = title; this.content = content; this.createdAt = LocalDateTime.now(); - this.modifiedAt = LocalDateTime.now(); + }*/ + + public Article() { + } - public void update(Long boardId, String title, String description) { - this.boardId = boardId; + public void update(Board board, String title, String description) { + this.board = board; this.title = title; this.content = description; this.modifiedAt = LocalDateTime.now(); } + public void setMember(Member member) { + this.member = member; + member.getArticles().add(this); + } + + public void setBoard(Board board) { + this.board = board; + board.getArticles().add(this); + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + public void setId(Long id) { this.id = id; } @@ -59,13 +93,13 @@ public Long getId() { return id; } - public Long getAuthorId() { - return authorId; - } - - public Long getBoardId() { - return boardId; - } +// public Long getAuthorId() { +// return authorId; +// } +// +// public Long getBoardId() { +// return boardId; +// } public String getTitle() { return title; @@ -82,4 +116,30 @@ public LocalDateTime getCreatedAt() { public LocalDateTime getModifiedAt() { return modifiedAt; } + + public Member getMember() { + return member; + } + + public Board getBoard() { + return board; + } + + private void setTitle(String title) { + this.title = title; + } + + private void setContent(String content) { + this.content = content; + } + + public static Article createArticle(String title, String content, Member member, Board board) { + Article article = new Article(); + article.setTitle(title); + article.setContent(content); + article.setMember(member); + article.setBoard(board); + article.setCreatedAt(LocalDateTime.now()); + return article; + } } diff --git a/src/main/java/com/example/demo/domain/Board.java b/src/main/java/com/example/demo/domain/Board.java index 992e2c6..2f5c366 100644 --- a/src/main/java/com/example/demo/domain/Board.java +++ b/src/main/java/com/example/demo/domain/Board.java @@ -1,10 +1,23 @@ package com.example.demo.domain; +import jakarta.persistence.*; + +import java.util.List; + +import static jakarta.persistence.CascadeType.ALL; + +@Entity public class Board { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "board_id") private Long id; private String name; + @OneToMany(mappedBy = "board", orphanRemoval = true, cascade = ALL) + private List
articles; + public Board(Long id, String name) { this.id = id; this.name = name; @@ -14,6 +27,10 @@ public Board(String name) { this.name = name; } + public Board() { + + } + public Long getId() { return id; } @@ -29,4 +46,8 @@ public String getName() { public void update(String name) { this.name = name; } + + public List
getArticles() { + return articles; + } } diff --git a/src/main/java/com/example/demo/domain/Member.java b/src/main/java/com/example/demo/domain/Member.java index fe80d6b..d2085c0 100644 --- a/src/main/java/com/example/demo/domain/Member.java +++ b/src/main/java/com/example/demo/domain/Member.java @@ -1,11 +1,23 @@ package com.example.demo.domain; +import jakarta.persistence.*; + +import java.util.List; + +import static jakarta.persistence.CascadeType.ALL; + +@Entity public class Member { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "member_id") private Long id; private String name; private String email; private String password; + @OneToMany(mappedBy = "member", orphanRemoval = true, cascade = ALL) + private List
articles; public Member(Long id, String name, String email, String password) { this.id = id; @@ -20,6 +32,11 @@ public Member(String name, String email, String password) { this.password = password; } + public Member() { + + } + + public void update(String name, String email) { this.name = name; this.email = email; @@ -44,4 +61,8 @@ public String getEmail() { public String getPassword() { return password; } + + public List
getArticles() { + return articles; + } } diff --git a/src/main/java/com/example/demo/exception/errorcode/CommonErrorCode.java b/src/main/java/com/example/demo/exception/errorcode/CommonErrorCode.java new file mode 100644 index 0000000..0d61442 --- /dev/null +++ b/src/main/java/com/example/demo/exception/errorcode/CommonErrorCode.java @@ -0,0 +1,25 @@ +package com.example.demo.exception.errorcode; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; + +@Getter +@RequiredArgsConstructor +public enum CommonErrorCode implements ErrorCode { + EMAIL_ALREADY_EXIST(HttpStatus.CONFLICT, "이미 존재하는 이메일입니다."), + GET_ARTICLE_NOT_EXIST(HttpStatus.NOT_FOUND, "입력한 ID에 해당하는 게시물이 존재하지 않습니다."), + GET_MEMBER_NOT_EXIST(HttpStatus.NOT_FOUND, "입력한 ID에 해당하는 멤버가 존재하지 않습니다."), + GET_BOARD_NOT_EXIST(HttpStatus.NOT_FOUND, "입력한 ID에 해당하는 게시판이 존재하지 않습니다."), + POST_ARTICLE_NOT_EXIST(HttpStatus.BAD_REQUEST, "입력한 ID에 해당하는 게시물이 존재하지 않습니다."), + POST_MEMBER_NOT_EXIST(HttpStatus.BAD_REQUEST, "입력한 ID에 해당하는 멤버가 존재하지 않습니다."), + POST_BOARD_NOT_EXIST(HttpStatus.BAD_REQUEST, "입력한 ID에 해당하는 게시판이 존재하지 않습니다."), + UPDATE_BOARD_NOT_EXIST(HttpStatus.BAD_REQUEST,"입력한 ID에 해당하는 게시판이 존재하지 않습니다." ), + UPDATE_NAME_NULL(HttpStatus.BAD_REQUEST, "변경할 이름을 입력해주세요"), + UPDATE_EMAIL_NULL(HttpStatus.BAD_REQUEST, "변경할 이메일을 입력해주세요"), + DELETE_ARTICLE_EXIST_IN_MEMBER(HttpStatus.BAD_REQUEST, "해당 멤버가 작성한 게시물이 존재합니다."), + DELETE_ARTICLE_EXIST_IN_BOARD(HttpStatus.BAD_REQUEST, "해당 게시판에 게시물이 존재합니다."); + + private final HttpStatus httpStatus; + private final String message; +} diff --git a/src/main/java/com/example/demo/exception/errorcode/ErrorCode.java b/src/main/java/com/example/demo/exception/errorcode/ErrorCode.java new file mode 100644 index 0000000..498d758 --- /dev/null +++ b/src/main/java/com/example/demo/exception/errorcode/ErrorCode.java @@ -0,0 +1,9 @@ +package com.example.demo.exception.errorcode; + +import org.springframework.http.HttpStatus; + +public interface ErrorCode { + String name(); + HttpStatus getHttpStatus(); + String getMessage(); +} diff --git a/src/main/java/com/example/demo/exception/exception/RestApiException.java b/src/main/java/com/example/demo/exception/exception/RestApiException.java new file mode 100644 index 0000000..b95bcb8 --- /dev/null +++ b/src/main/java/com/example/demo/exception/exception/RestApiException.java @@ -0,0 +1,11 @@ +package com.example.demo.exception.exception; + +import com.example.demo.exception.errorcode.ErrorCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class RestApiException extends RuntimeException{ + private final ErrorCode errorCode; +} diff --git a/src/main/java/com/example/demo/exception/handler/GlobalExceptionHandler.java b/src/main/java/com/example/demo/exception/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..fec8fe5 --- /dev/null +++ b/src/main/java/com/example/demo/exception/handler/GlobalExceptionHandler.java @@ -0,0 +1,65 @@ +package com.example.demo.exception.handler; + +import com.example.demo.exception.errorcode.CommonErrorCode; +import com.example.demo.exception.errorcode.ErrorCode; +import com.example.demo.exception.exception.RestApiException; +import com.example.demo.exception.response.ErrorResponse; +import com.example.demo.exception.response.ErrorResponse.ValidationError; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@RestControllerAdvice +@Slf4j +public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { + + @ExceptionHandler(RestApiException.class) + public ResponseEntity handleCustonException(RestApiException e) { + return handleExceptionInternal(e.getErrorCode()); + } + + private ResponseEntity handleExceptionInternal(ErrorCode errorCode) { + return ResponseEntity.status(errorCode.getHttpStatus()) + .body(makeErrorResponse(errorCode)); + } + + private ErrorResponse makeErrorResponse(ErrorCode errorCode) { + return ErrorResponse.builder() + .code(errorCode.name()) + .message(errorCode.getMessage()) + .build(); + } + + @Override + protected ResponseEntity handleMethodArgumentNotValid( + MethodArgumentNotValidException ex, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + List validationErrors = ex.getBindingResult() + .getFieldErrors() + .stream() + .map(ValidationError::of) + .collect(Collectors.toList()); + + ErrorResponse errorResponse = ErrorResponse.builder() + .code("VALIDATION_ERROR") + .message("Validation failed for the request") + .errors(validationErrors) + .build(); + + return ResponseEntity.badRequest().body(errorResponse); + } +} diff --git a/src/main/java/com/example/demo/exception/response/ErrorResponse.java b/src/main/java/com/example/demo/exception/response/ErrorResponse.java new file mode 100644 index 0000000..25861d4 --- /dev/null +++ b/src/main/java/com/example/demo/exception/response/ErrorResponse.java @@ -0,0 +1,35 @@ +package com.example.demo.exception.response; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.FieldError; + +import java.util.List; + +@Getter +@Builder +@RequiredArgsConstructor +public class ErrorResponse { + private final String code; + private final String message; + + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private final List errors; + + @Getter + @Builder + @RequiredArgsConstructor + public static class ValidationError { + private final String field; + private final String message; + + public static ValidationError of(final FieldError fieldError) { + return ValidationError.builder() + .field(fieldError.getField()) + .message(fieldError.getDefaultMessage()) + .build(); + } + } +} diff --git a/src/main/java/com/example/demo/repository/ArticleRepository.java b/src/main/java/com/example/demo/repository/ArticleRepository.java index be3ebd4..469549d 100644 --- a/src/main/java/com/example/demo/repository/ArticleRepository.java +++ b/src/main/java/com/example/demo/repository/ArticleRepository.java @@ -3,20 +3,9 @@ import java.util.List; import com.example.demo.domain.Article; +import org.springframework.data.jpa.repository.JpaRepository; -public interface ArticleRepository { - - List
findAll(); - - List
findAllByBoardId(Long boardId); - - List
findAllByMemberId(Long memberId); - - Article findById(Long id); - - Article insert(Article article); - - Article update(Article article); - - void deleteById(Long id); +public interface ArticleRepository extends JpaRepository { + List
findAllByBoardId(Long id); + List
findAllByMemberId(Long id); } diff --git a/src/main/java/com/example/demo/repository/ArticleRepositoryJdbc.java b/src/main/java/com/example/demo/repository/ArticleRepositoryJdbc.java index c9a272e..0ca6acf 100644 --- a/src/main/java/com/example/demo/repository/ArticleRepositoryJdbc.java +++ b/src/main/java/com/example/demo/repository/ArticleRepositoryJdbc.java @@ -1,3 +1,4 @@ +/* package com.example.demo.repository; import java.sql.PreparedStatement; @@ -106,3 +107,4 @@ public void deleteById(Long id) { """, id); } } +*/ diff --git a/src/main/java/com/example/demo/repository/ArticleRepositoryJpa.java b/src/main/java/com/example/demo/repository/ArticleRepositoryJpa.java new file mode 100644 index 0000000..0a17ad7 --- /dev/null +++ b/src/main/java/com/example/demo/repository/ArticleRepositoryJpa.java @@ -0,0 +1,63 @@ +/* +package com.example.demo.repository; + +import com.example.demo.domain.Article; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.TypedQuery; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Primary +@Repository +public class ArticleRepositoryJpa implements ArticleRepository { + + @PersistenceContext + EntityManager em; + @Override + public List
findAll() { + List
articles = em.createQuery("select a from Article a", Article.class).getResultList(); + return articles; + } + + @Override + public List
findAllByBoardId(Long boardId) { + TypedQuery
query = em.createQuery("select a from Article a where a.board.id = :boardId", Article.class); + query.setParameter("boardId", boardId); + return query.getResultList(); + + } + + @Override + public List
findAllByMemberId(Long memberId) { + TypedQuery
query = em.createQuery("select a from Article a where a.member.id = :authorId", Article.class); + query.setParameter("authorId", memberId); + return query.getResultList(); + } + + @Override + public Article findById(Long id) { + Article article = em.find(Article.class, id); + return article; + } + + @Override + public Article insert(Article article) { + em.persist(article); + return article; + } + + @Override + public Article update(Article article) { + return null; + } + + @Override + public void deleteById(Long id) { + Article article = em.find(Article.class, id); + em.remove(article); + } +} +*/ diff --git a/src/main/java/com/example/demo/repository/ArticleRepositoryMemory.java b/src/main/java/com/example/demo/repository/ArticleRepositoryMemory.java index 13ba78b..61ebede 100644 --- a/src/main/java/com/example/demo/repository/ArticleRepositoryMemory.java +++ b/src/main/java/com/example/demo/repository/ArticleRepositoryMemory.java @@ -1,3 +1,4 @@ +/* package com.example.demo.repository; import java.util.HashMap; @@ -68,3 +69,4 @@ public void deleteById(Long id) { articles.remove(id); } } +*/ diff --git a/src/main/java/com/example/demo/repository/BoardRepository.java b/src/main/java/com/example/demo/repository/BoardRepository.java index cc2dfd0..439813f 100644 --- a/src/main/java/com/example/demo/repository/BoardRepository.java +++ b/src/main/java/com/example/demo/repository/BoardRepository.java @@ -1,18 +1,10 @@ package com.example.demo.repository; import java.util.List; +import java.util.Optional; import com.example.demo.domain.Board; +import org.springframework.data.jpa.repository.JpaRepository; -public interface BoardRepository { - - List findAll(); - - Board findById(Long id); - - Board insert(Board board); - - void deleteById(Long id); - - Board update(Board board); +public interface BoardRepository extends JpaRepository { } diff --git a/src/main/java/com/example/demo/repository/BoardRepositoryJdbc.java b/src/main/java/com/example/demo/repository/BoardRepositoryJdbc.java index c4fd6f6..fd2982b 100644 --- a/src/main/java/com/example/demo/repository/BoardRepositoryJdbc.java +++ b/src/main/java/com/example/demo/repository/BoardRepositoryJdbc.java @@ -1,3 +1,4 @@ +/* package com.example.demo.repository; import java.sql.PreparedStatement; @@ -70,3 +71,4 @@ public Board update(Board board) { ); } } +*/ diff --git a/src/main/java/com/example/demo/repository/BoardRepositoryJpa.java b/src/main/java/com/example/demo/repository/BoardRepositoryJpa.java new file mode 100644 index 0000000..b0f7a0c --- /dev/null +++ b/src/main/java/com/example/demo/repository/BoardRepositoryJpa.java @@ -0,0 +1,48 @@ +//package com.example.demo.repository; +// +//import com.example.demo.domain.Board; +//import jakarta.persistence.EntityManager; +//import jakarta.persistence.PersistenceContext; +//import org.springframework.context.annotation.Primary; +//import org.springframework.stereotype.Repository; +// +//import java.util.List; +//import java.util.Optional; +// +//@Primary +//@Repository +//public class BoardRepositoryJpa implements BoardRepository{ +// @PersistenceContext +// EntityManager em; +// +// @Override +// public Optional findById(Long id) { +// Board board = em.find(Board.class, id); +// return board; +// } +// +// @Override +// public List findAll() { +// List boards = em.createQuery("select b from Board b", Board.class).getResultList(); +// return boards; +// } +// +// @Override +// public Board insert(Board board) { +// em.persist(board); +// return board; +// } +// +// @Override +// public Board update(Board board) { +// Board findBoard = em.find(Board.class, board.getId()); +// findBoard.update(board.getName()); +// return findBoard; +// } +// +// @Override +// public void deleteById(Long id) { +// Board board = em.find(Board.class, id); +// em.remove(board); +// } +//} diff --git a/src/main/java/com/example/demo/repository/BoardRepositoryMemory.java b/src/main/java/com/example/demo/repository/BoardRepositoryMemory.java index 8cf5ecf..99bfe6a 100644 --- a/src/main/java/com/example/demo/repository/BoardRepositoryMemory.java +++ b/src/main/java/com/example/demo/repository/BoardRepositoryMemory.java @@ -1,3 +1,4 @@ +/* package com.example.demo.repository; import java.util.HashMap; @@ -48,3 +49,4 @@ public Board update(Board board) { return boards.put(board.getId(), board); } } +*/ diff --git a/src/main/java/com/example/demo/repository/MemberRepository.java b/src/main/java/com/example/demo/repository/MemberRepository.java index 8e2ad14..c399cb9 100644 --- a/src/main/java/com/example/demo/repository/MemberRepository.java +++ b/src/main/java/com/example/demo/repository/MemberRepository.java @@ -3,16 +3,8 @@ import java.util.List; import com.example.demo.domain.Member; +import org.springframework.data.jpa.repository.JpaRepository; -public interface MemberRepository { +public interface MemberRepository extends JpaRepository { - List findAll(); - - Member findById(Long id); - - Member insert(Member member); - - Member update(Member member); - - void deleteById(Long id); } diff --git a/src/main/java/com/example/demo/repository/MemberRepositoryJdbc.java b/src/main/java/com/example/demo/repository/MemberRepositoryJdbc.java index 30d2262..efcc8cb 100644 --- a/src/main/java/com/example/demo/repository/MemberRepositoryJdbc.java +++ b/src/main/java/com/example/demo/repository/MemberRepositoryJdbc.java @@ -1,8 +1,12 @@ +/* package com.example.demo.repository; import java.sql.PreparedStatement; import java.util.List; +import com.example.demo.exception.errorcode.CommonErrorCode; +import com.example.demo.exception.exception.RestApiException; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.support.GeneratedKeyHolder; @@ -21,36 +25,38 @@ public MemberRepositoryJdbc(JdbcTemplate jdbcTemplate) { } private static final RowMapper memberRowMapper = (rs, rowNum) -> new Member( - rs.getLong("id"), - rs.getString("name"), - rs.getString("email"), - rs.getString("password") + rs.getLong("id"), + rs.getString("name"), + rs.getString("email"), + rs.getString("password") ); @Override public List findAll() { return jdbcTemplate.query(""" - SELECT id, name, email, password - FROM member - """, memberRowMapper); + SELECT id, name, email, password + FROM member + """, memberRowMapper); } @Override public Member findById(Long id) { return jdbcTemplate.queryForObject(""" - SELECT id, name, email, password - FROM member - WHERE id = ? - """, memberRowMapper, id); + SELECT id, name, email, password + FROM member + WHERE id = ? + """, memberRowMapper, id); } @Override public Member insert(Member member) { KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(con -> { - PreparedStatement ps = con.prepareStatement(""" - INSERT INTO member (name, email, password) VALUES (?, ?, ?) - """, new String[]{"id"}); + PreparedStatement ps = con.prepareStatement(""" + INSERT INTO member (name, email, password) + VALUES (?, ?, ?) + """, new String[]{ + "id"}); ps.setString(1, member.getName()); ps.setString(2, member.getEmail()); ps.setString(3, member.getPassword()); @@ -62,18 +68,20 @@ INSERT INTO member (name, email, password) VALUES (?, ?, ?) @Override public Member update(Member member) { jdbcTemplate.update(""" - UPDATE member - SET name = ?, email = ? - WHERE id = ? - """, member.getName(), member.getEmail(), member.getId()); + UPDATE member + SET name = ?, email = ? + WHERE id = ? + """, member.getName(), member.getEmail(), member.getId + ()); return findById(member.getId()); } @Override public void deleteById(Long id) { jdbcTemplate.update(""" - DELETE FROM member - WHERE id = ? - """, id); + DELETE FROM member + WHERE id = ? + """, id); } } +*/ diff --git a/src/main/java/com/example/demo/repository/MemberRepositoryJpa.java b/src/main/java/com/example/demo/repository/MemberRepositoryJpa.java new file mode 100644 index 0000000..32f8b84 --- /dev/null +++ b/src/main/java/com/example/demo/repository/MemberRepositoryJpa.java @@ -0,0 +1,50 @@ +/* +package com.example.demo.repository; + +import com.example.demo.domain.Member; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Primary +@Repository +public class MemberRepositoryJpa implements MemberRepository{ + + @PersistenceContext + EntityManager em; + + @Override + public Member findById(Long id) { + Member member = em.find(Member.class, id); + return member; + } + + @Override + public List findAll() { + List members = em.createQuery("select m from Member m", Member.class).getResultList(); + return members; + } + + @Override + public Member insert(Member member) { + em.persist(member); + return member; + } + + @Override + public Member update(Member member) { + Member findMember = em.find(Member.class, member.getId()); + findMember.update(member.getName(), member.getEmail()); //Transactional의 변경감지 + return findMember; + } + + @Override + public void deleteById(Long id) { + Member findMember = em.find(Member.class, id); + em.remove(findMember); + } +} +*/ diff --git a/src/main/java/com/example/demo/repository/MemberRepositoryMemory.java b/src/main/java/com/example/demo/repository/MemberRepositoryMemory.java index b4cf722..383a713 100644 --- a/src/main/java/com/example/demo/repository/MemberRepositoryMemory.java +++ b/src/main/java/com/example/demo/repository/MemberRepositoryMemory.java @@ -1,3 +1,4 @@ +/* package com.example.demo.repository; import java.util.HashMap; @@ -50,3 +51,4 @@ public void deleteById(Long id) { members.remove(id); } } +*/ diff --git a/src/main/java/com/example/demo/service/ArticleService.java b/src/main/java/com/example/demo/service/ArticleService.java index 7f8610b..4ed470c 100644 --- a/src/main/java/com/example/demo/service/ArticleService.java +++ b/src/main/java/com/example/demo/service/ArticleService.java @@ -1,7 +1,10 @@ package com.example.demo.service; import java.util.List; +import java.util.Optional; +import com.example.demo.exception.errorcode.CommonErrorCode; +import com.example.demo.exception.exception.RestApiException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -34,45 +37,42 @@ public ArticleService( } public ArticleResponse getById(Long id) { - Article article = articleRepository.findById(id); - Member member = memberRepository.findById(article.getAuthorId()); - Board board = boardRepository.findById(article.getBoardId()); - return ArticleResponse.of(article, member, board); + Optional
article; + article = articleRepository.findById(id); + return article.map(a -> ArticleResponse.of(a, a.getMember(), a.getBoard())).orElseThrow(() -> new RestApiException(CommonErrorCode.GET_ARTICLE_NOT_EXIST)); } public List getByBoardId(Long boardId) { List
articles = articleRepository.findAllByBoardId(boardId); return articles.stream() .map(article -> { - Member member = memberRepository.findById(article.getAuthorId()); - Board board = boardRepository.findById(article.getBoardId()); - return ArticleResponse.of(article, member, board); + return ArticleResponse.of(article, article.getMember(), article.getBoard()); }) .toList(); } @Transactional public ArticleResponse create(ArticleCreateRequest request) { - Article article = new Article( - request.authorId(), - request.boardId(), - request.title(), - request.description() - ); - Article saved = articleRepository.insert(article); - Member member = memberRepository.findById(saved.getAuthorId()); - Board board = boardRepository.findById(saved.getBoardId()); + Member member; + Board board; + + member = memberRepository.findById(request.authorId()).orElseThrow(() -> new RestApiException(CommonErrorCode.GET_MEMBER_NOT_EXIST)); + board = boardRepository.findById(request.boardId()).orElseThrow(() -> new RestApiException(CommonErrorCode.GET_BOARD_NOT_EXIST)); + + Article article = Article.createArticle(request.title(), request.content(), member, board); + Article saved = articleRepository.save(article); + return ArticleResponse.of(saved, member, board); } @Transactional public ArticleResponse update(Long id, ArticleUpdateRequest request) { - Article article = articleRepository.findById(id); - article.update(request.boardId(), request.title(), request.description()); - Article updated = articleRepository.update(article); - Member member = memberRepository.findById(updated.getAuthorId()); - Board board = boardRepository.findById(article.getBoardId()); - return ArticleResponse.of(article, member, board); + Article article = articleRepository.findById(id).orElseThrow(() -> new RestApiException(CommonErrorCode.GET_ARTICLE_NOT_EXIST)); + Board board; + board = boardRepository.findById(request.boardId()).orElseThrow(() -> new RestApiException(CommonErrorCode.GET_BOARD_NOT_EXIST)); + + article.update(board, request.title(), request.description()); + return ArticleResponse.of(article, article.getMember(), board); } @Transactional diff --git a/src/main/java/com/example/demo/service/BoardService.java b/src/main/java/com/example/demo/service/BoardService.java index ffff891..7ecf522 100644 --- a/src/main/java/com/example/demo/service/BoardService.java +++ b/src/main/java/com/example/demo/service/BoardService.java @@ -1,7 +1,12 @@ package com.example.demo.service; import java.util.List; +import java.util.Optional; +import com.example.demo.domain.Article; +import com.example.demo.exception.errorcode.CommonErrorCode; +import com.example.demo.exception.exception.RestApiException; +import com.example.demo.repository.ArticleRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,9 +21,11 @@ public class BoardService { private final BoardRepository boardRepository; + private final ArticleRepository articleRepository; - public BoardService(BoardRepository boardRepository) { + public BoardService(BoardRepository boardRepository, ArticleRepository articleRepository) { this.boardRepository = boardRepository; + this.articleRepository = articleRepository; } public List getBoards() { @@ -28,27 +35,35 @@ public List getBoards() { } public BoardResponse getBoardById(Long id) { - Board board = boardRepository.findById(id); - return BoardResponse.from(board); + Optional board; + board = boardRepository.findById(id); + return board.map(BoardResponse::from).orElseThrow(() -> new RestApiException(CommonErrorCode.GET_BOARD_NOT_EXIST)); } @Transactional public BoardResponse createBoard(BoardCreateRequest request) { Board board = new Board(request.name()); - Board saved = boardRepository.insert(board); + Board saved = boardRepository.save(board); return BoardResponse.from(saved); } @Transactional public void deleteBoard(Long id) { + Boolean isArticleExist = articleRepository + .findAllByBoardId(id) + .stream() + .findAny() + .isPresent(); + if(isArticleExist) { + throw new RestApiException(CommonErrorCode.DELETE_ARTICLE_EXIST_IN_BOARD); + } boardRepository.deleteById(id); } @Transactional public BoardResponse update(Long id, BoardUpdateRequest request) { - Board board = boardRepository.findById(id); + Board board = boardRepository.findById(id).orElseThrow(() -> new RestApiException(CommonErrorCode.GET_BOARD_NOT_EXIST)); board.update(request.name()); - Board updated = boardRepository.update(board); - return BoardResponse.from(updated); + return BoardResponse.from(board); } } diff --git a/src/main/java/com/example/demo/service/MemberService.java b/src/main/java/com/example/demo/service/MemberService.java index 04c1bc8..e078f02 100644 --- a/src/main/java/com/example/demo/service/MemberService.java +++ b/src/main/java/com/example/demo/service/MemberService.java @@ -1,7 +1,13 @@ package com.example.demo.service; import java.util.List; +import java.util.Optional; +import com.example.demo.domain.Article; +import com.example.demo.exception.errorcode.CommonErrorCode; +import com.example.demo.exception.exception.RestApiException; +import com.example.demo.repository.ArticleRepository; +import jakarta.validation.Valid; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,14 +22,17 @@ public class MemberService { private final MemberRepository memberRepository; + private final ArticleRepository articleRepository; - public MemberService(MemberRepository memberRepository) { + public MemberService(MemberRepository memberRepository, ArticleRepository articleRepository) { this.memberRepository = memberRepository; + this.articleRepository = articleRepository; } public MemberResponse getById(Long id) { - Member member = memberRepository.findById(id); - return MemberResponse.from(member); + Optional member; + member = memberRepository.findById(id); + return member.map(MemberResponse::from).orElseThrow(() -> new RestApiException(CommonErrorCode.GET_MEMBER_NOT_EXIST)); } public List getAll() { @@ -35,7 +44,7 @@ public List getAll() { @Transactional public MemberResponse create(MemberCreateRequest request) { - Member member = memberRepository.insert( + Member member = memberRepository.save( new Member(request.name(), request.email(), request.password()) ); return MemberResponse.from(member); @@ -43,14 +52,22 @@ public MemberResponse create(MemberCreateRequest request) { @Transactional public void delete(Long id) { + // 삭제 시 article이 참조하고 있는 경우 삭제를 못하게 해야됨. + Boolean isArticleExist = articleRepository.findAllByMemberId(id).stream() + .findAny() + .isPresent(); + + if(isArticleExist) { + throw new RestApiException(CommonErrorCode.DELETE_ARTICLE_EXIST_IN_MEMBER); + } + memberRepository.deleteById(id); } @Transactional public MemberResponse update(Long id, MemberUpdateRequest request) { - Member member = memberRepository.findById(id); + Member member = memberRepository.findById(id).orElseThrow(() -> new RestApiException(CommonErrorCode.GET_MEMBER_NOT_EXIST)); member.update(request.name(), request.email()); - memberRepository.update(member); return MemberResponse.from(member); } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ff69a9e..2142af7 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -2,5 +2,5 @@ spring: datasource: url: jdbc:mysql://localhost:3306/bcsd # 본인의 환경에 맞게 수정한다. username: root # 본인의 환경에 맞게 수정한다. - password: qwer1234 # 본인의 환경에 맞게 수정한다. + password: "6235" # 본인의 환경에 맞게 수정한다. driver-class-name: com.mysql.cj.jdbc.Driver