-
Notifications
You must be signed in to change notification settings - Fork 13
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
[김영찬] 3차 과제 제출 #4
Changes from all commits
b0376ea
dd535a8
ead8092
c766514
56d2a7e
3752df4
e0bd52c
8ca08ce
b8c07d0
4f0df14
9418252
accb3c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,10 @@ | ||
package cotato.backend.common.exception; | ||
|
||
import java.util.NoSuchElementException; | ||
|
||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.MethodArgumentNotValidException; | ||
import org.springframework.web.bind.annotation.ExceptionHandler; | ||
import org.springframework.web.bind.annotation.RestControllerAdvice; | ||
|
||
|
@@ -19,6 +22,16 @@ public ResponseEntity<Object> handleApiException(ApiException e) { | |
return makeErrorResponseEntity(e.getHttpStatus(), e.getMessage(), e.getCode()); | ||
} | ||
|
||
@ExceptionHandler(MethodArgumentNotValidException.class) | ||
public ResponseEntity<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e){ | ||
return makeErrorResponseEntity(HttpStatus.BAD_REQUEST, e.getBindingResult().getAllErrors().get(0).getDefaultMessage(), "POST-001"); | ||
} | ||
|
||
@ExceptionHandler(NoSuchElementException.class) | ||
public ResponseEntity<Object> handleNoSuchElementException(NoSuchElementException e){ | ||
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 makeErrorResponseEntity(HttpStatus.BAD_REQUEST, e.getMessage(), "POST-002"); | ||
} | ||
|
||
private ResponseEntity<Object> makeErrorResponseEntity(HttpStatus httpStatus, String message, String code) { | ||
return ResponseEntity | ||
.status(httpStatus) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,57 @@ | ||
package cotato.backend.domains.post; | ||
|
||
import java.util.Map; | ||
|
||
import cotato.backend.domains.post.dto.request.SavePostRequest; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.Setter; | ||
|
||
@Entity | ||
@Getter | ||
@Setter | ||
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. 무분별한 setter 사용은 지양하는게 좋다고 들었습니다! |
||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class Post { | ||
|
||
} | ||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@Column(nullable = false) | ||
private String title; | ||
|
||
@Column(nullable = false) | ||
private String content; | ||
|
||
@Column(nullable = false) | ||
private String name; | ||
|
||
@Column(nullable = false) | ||
private int views; | ||
kych4n marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
public Post(String title, String content, String name) { | ||
this.title = title; | ||
this.content = content; | ||
this.name = name; | ||
this.views = 0; | ||
} | ||
|
||
public static Post createdFrom(SavePostRequest request) { | ||
return new Post(request.getTitle(), request.getContent(), request.getName()); | ||
} | ||
|
||
public static Post createdFrom(Map<String, String> row) { | ||
return new Post(row.get("title"), row.get("content"), row.get("name")); | ||
} | ||
|
||
public void increaseViews() { | ||
this.views += 1; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package cotato.backend.domains.post; | ||
|
||
import java.sql.PreparedStatement; | ||
import java.sql.SQLException; | ||
import java.util.List; | ||
|
||
import org.springframework.jdbc.core.BatchPreparedStatementSetter; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@RequiredArgsConstructor | ||
@Repository | ||
public class PostBulkRepository { | ||
|
||
private static final int BATCH_SIZE = 500; | ||
|
||
private final JdbcTemplate jdbcTemplate; | ||
|
||
public void saveAllByExcel(List<Post> posts) { | ||
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. 데이터베이스 저장 작업을 하기 때문에 Transactional 어노테이션을 고려하는 것도 좋을 거 같습니다! |
||
jdbcTemplate.batchUpdate( | ||
"INSERT INTO post (title, content, name, views) VALUES (?, ?, ?, ?)", | ||
new BatchPreparedStatementSetter() { | ||
@Override | ||
public void setValues(PreparedStatement ps, int i) throws SQLException { | ||
ps.setString(1, posts.get(i).getTitle()); | ||
ps.setString(2, posts.get(i).getContent()); | ||
ps.setString(3, posts.get(i).getName()); | ||
ps.setLong(4, posts.get(i).getViews()); | ||
} | ||
|
||
@Override | ||
public int getBatchSize() { | ||
return BATCH_SIZE; | ||
} | ||
} | ||
kych4n marked this conversation as resolved.
Show resolved
Hide resolved
|
||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,22 @@ | ||
package cotato.backend.domains.post; | ||
|
||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.data.domain.Sort; | ||
import org.springframework.data.web.PageableDefault; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.DeleteMapping; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import cotato.backend.common.dto.DataResponse; | ||
import cotato.backend.domains.post.dto.request.SavePostRequest; | ||
import cotato.backend.domains.post.dto.request.SavePostsByExcelRequest; | ||
import cotato.backend.domains.post.dto.response.FindPostResponse; | ||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@RestController | ||
|
@@ -17,10 +26,34 @@ public class PostController { | |
|
||
private final PostService postService; | ||
|
||
@PostMapping | ||
public ResponseEntity<DataResponse<Void>> savePost(@RequestBody @Valid SavePostRequest request){ | ||
postService.savePost(request); | ||
return ResponseEntity.ok(DataResponse.ok()); | ||
} | ||
|
||
@PostMapping("/excel") | ||
public ResponseEntity<DataResponse<Void>> savePostsByExcel(@RequestBody SavePostsByExcelRequest request) { | ||
postService.saveEstatesByExcel(request.getPath()); | ||
|
||
return ResponseEntity.ok(DataResponse.ok()); | ||
} | ||
|
||
@GetMapping("/{id}") | ||
public ResponseEntity<FindPostResponse> findPost(@PathVariable Long id) { | ||
return ResponseEntity.ok(postService.findPostById(id)); | ||
} | ||
|
||
@GetMapping("/list") | ||
public ResponseEntity<?> findPosts(@PageableDefault(size = 10, sort = "views", direction = Sort.Direction.DESC) | ||
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. @PageableDefault 어노테이션으로도 처리가 가능하네요 !! 배워갑니당 |
||
Pageable pageable) { | ||
return ResponseEntity.ok(DataResponse.from(postService.findPostsWithPaging(pageable))); | ||
} | ||
|
||
@DeleteMapping("/{id}") | ||
public ResponseEntity<DataResponse<String>> deletePost(@PathVariable Long id){ | ||
postService.deletePostById(id); | ||
|
||
return ResponseEntity.ok(DataResponse.from("게시글이 성공적으로 삭제되었습니다.")); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package cotato.backend.domains.post; | ||
|
||
import org.springframework.data.domain.Page; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
public interface PostRepository extends JpaRepository<Post, Long> { | ||
|
||
@Override | ||
Page<Post> findAll(Pageable pageable); | ||
|
||
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 comment
The reason will be displayed to describe this comment to others. Learn more.
ErrorCode를 사용하지 않고, 직접 POST-001 처럼 code를 명시한 전역 예외 핸들러를 구현하신 이유가 궁금합니다!