-
Notifications
You must be signed in to change notification settings - Fork 3
[2주차 과제제출] #7
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
base: main
Are you sure you want to change the base?
[2주차 과제제출] #7
Changes from all commits
7eec086
6f3348b
86a67b6
9d7bfd8
6fac3f6
76a5f2a
dc45e96
03c77a0
3301448
3c15a4d
d218f49
e361665
a97e503
5b2571c
9db357a
1b9bee4
df7abd6
50df128
7cd4f9c
f478dbe
29b5421
83dbd37
6ebff2e
a2be24f
a843165
a13e4ad
e00b7cd
5b63bc5
fa46e03
7e1abc7
a735fb9
9d778d4
d53b1b8
3674dfc
afcaf58
2aa6510
3409fc2
975d82d
6c04b1e
55ebefb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| package study.todolist.controller; | ||
|
|
||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.web.bind.annotation.*; | ||
| import study.todolist.dto.TodoDto; | ||
| import study.todolist.global.Envelope; | ||
| import study.todolist.entity.todo.TodoList; | ||
| import study.todolist.service.TodoService; | ||
|
|
||
| import java.util.List; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| @RestController | ||
| @RequiredArgsConstructor | ||
| @RequestMapping("/api/todo") | ||
| public class TodoController { | ||
|
|
||
| private final TodoService todoService; | ||
|
|
||
|
|
||
| // 생성 | ||
| @PostMapping("/create/{id}") | ||
| public Envelope createTodo(@PathVariable("id") Long id, | ||
| @RequestBody TodoDto.Request request){ | ||
|
|
||
| TodoList todo = todoService.createTodo(id, request.getTitle()); | ||
|
|
||
| TodoDto.Response response = TodoDto.Response.of(todo); | ||
|
|
||
| return Envelope.success(response); | ||
| } | ||
|
|
||
| @PostMapping("/create/bulk/{id}") | ||
| public Envelope<List> bulkCreate(@PathVariable("id") Long id, | ||
| @RequestParam int count){ | ||
|
|
||
| List<TodoDto.Response> response = todoService.bulkTodo(id, count); | ||
|
|
||
| return Envelope.success(response); | ||
| } | ||
|
|
||
| // 단건조회 | ||
| @GetMapping("/find/{id}") | ||
| public Envelope findById(@PathVariable("id") Long id){ | ||
|
|
||
| TodoList todo = todoService.findById(id); | ||
|
|
||
| TodoDto.Response response = TodoDto.Response.of(todo); | ||
|
|
||
| return Envelope.success(response); | ||
| } | ||
|
|
||
| // 전체조회 | ||
| @GetMapping("/find/all") | ||
| public Envelope findAll(){ | ||
|
|
||
| List<TodoDto.Response> responseList = todoService.findAll().stream() | ||
| .map(TodoDto.Response::of) | ||
| .collect(Collectors.toList()); | ||
|
|
||
| return Envelope.success(responseList); | ||
| } | ||
|
|
||
| // 수정 | ||
| @PatchMapping("/update/{id}") | ||
| public Envelope updateTodo(@PathVariable Long id, | ||
| @RequestBody TodoDto.Request request){ | ||
|
|
||
| Long findId = todoService.updateTitle(id, request.getTitle()); | ||
| TodoList todo = todoService.findById(findId); | ||
|
|
||
| TodoDto.Response response = TodoDto.Response.of(todo); | ||
|
|
||
| return Envelope.success(response); | ||
| } | ||
|
|
||
| // check | ||
| @PatchMapping("/check/{id}") | ||
| public Envelope checkTodo(@PathVariable Long id, | ||
| @RequestBody TodoDto.ChangeStatus status){ | ||
|
|
||
| todoService.updateStatus(id, status.getStatus()); | ||
| TodoDto.Response response = TodoDto.Response.of(todoService.findById(id)); | ||
|
|
||
| return Envelope.success(response); | ||
| } | ||
|
|
||
| // 삭제 | ||
| @DeleteMapping("/delete/{id}") | ||
| public Envelope deleteTodo(@PathVariable Long id){ | ||
|
|
||
| todoService.delete(id); | ||
| TodoDto.Response response = TodoDto.Response.of(todoService.findById(id)); | ||
|
|
||
| return Envelope.success(response); | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package study.todolist.dto; | ||
|
|
||
| import lombok.AllArgsConstructor; | ||
| import lombok.Builder; | ||
| import lombok.Data; | ||
| import lombok.NoArgsConstructor; | ||
| import study.todolist.entity.todo.Status; | ||
| import study.todolist.entity.todo.TodoList; | ||
|
|
||
| public class TodoDto { | ||
|
|
||
| @Data | ||
| public static class Request{ | ||
| private String title; | ||
| } | ||
|
|
||
| @Data | ||
| public static class ChangeStatus{ | ||
| private Status status; | ||
| } | ||
|
|
||
| @Data @Builder | ||
| @NoArgsConstructor @AllArgsConstructor | ||
| public static class Response{ | ||
| private Long id; | ||
| private String title; | ||
| private Status status; | ||
|
|
||
| public static Response of(TodoList todoList) { | ||
|
|
||
| return Response.builder() | ||
| .id(todoList.getId()) | ||
| .title(todoList.getTitle()) | ||
| .status(todoList.getStatus()) | ||
| .build(); | ||
| } | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package study.todolist.entity.member; | ||
|
|
||
| import jakarta.persistence.*; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
| import study.todolist.entity.todo.TodoList; | ||
|
|
||
| @Entity @Getter | ||
| @NoArgsConstructor @AllArgsConstructor | ||
| public class Member { | ||
|
|
||
| @Id | ||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| private Long id; | ||
|
|
||
| private String username; | ||
|
|
||
| @OneToOne | ||
| @JoinColumn(name = "todo_id") | ||
| private TodoList todoList; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| package study.todolist.entity.todo; | ||
|
|
||
| public enum Status { | ||
|
|
||
| BEFORE, PROGRESS, COMPLETE | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package study.todolist.entity.todo; | ||
|
|
||
| import jakarta.persistence.*; | ||
| import lombok.Builder; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
| import study.todolist.entity.member.Member; | ||
|
|
||
| @Entity | ||
| @Getter | ||
| @NoArgsConstructor | ||
| public class TodoList{ | ||
|
|
||
| @Id @Column(name = "todo_id") | ||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| private Long id; | ||
| private String title; | ||
| @Enumerated(value = EnumType.STRING) | ||
| private Status status; | ||
|
|
||
| @OneToOne(mappedBy = "todoList") | ||
| private Member member; | ||
|
|
||
| public void updateTitle(String title){ | ||
| this.title = title; | ||
| } | ||
|
|
||
| public void updateStatus(Status status){ | ||
| this.status = status; | ||
| } | ||
|
|
||
| @Builder | ||
| public TodoList(String title, Status status, Member member) { | ||
| this.title = title; | ||
| this.status = status; | ||
| this.member = member; | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package study.todolist.global; | ||
|
|
||
|
|
||
| import lombok.AllArgsConstructor; | ||
| import lombok.Builder; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
| import org.springframework.http.HttpStatus; | ||
|
|
||
| @Getter @Builder | ||
| @NoArgsConstructor @AllArgsConstructor | ||
| public class Envelope<T> { | ||
|
|
||
| private T data; | ||
| private int error; | ||
| private String message; | ||
|
|
||
| public static <T> Envelope<T> of (T data, int error, String message){ | ||
|
|
||
| return new Envelope<>(data, error, message); | ||
| } | ||
|
|
||
| public static <T> Envelope<T> success (T data){ | ||
|
|
||
| return of(data, HttpStatus.OK.value(), "성공"); | ||
| } | ||
|
|
||
| public static <T> Envelope<T> fail (int error, String message){ | ||
|
|
||
| return of(null, error, message); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package study.todolist.global.error; | ||
|
|
||
| import lombok.Getter; | ||
| import org.springframework.http.HttpStatus; | ||
|
|
||
| @Getter | ||
| public enum ErrorCode { | ||
|
|
||
| NOT_FOUND_TODO(HttpStatus.NOT_FOUND, "T-001", "TODO를 찾을 수 없습니다."), | ||
| OVER_MAX_COUNT(HttpStatus.BAD_REQUEST, "T-002", "한번에 생성 가능한 수를 초과하였습니다."), | ||
|
|
||
| NOT_FOUNT_MEMBER(HttpStatus.NOT_FOUND, "M-001", "Member를 찾을 수 없습니다.") | ||
| ; | ||
|
|
||
|
|
||
| ErrorCode(HttpStatus httpStatus, String errorCode, String message) { | ||
| this.httpStatus = httpStatus; | ||
| this.errorCode = errorCode; | ||
| this.message = message; | ||
| } | ||
|
|
||
| private HttpStatus httpStatus; | ||
| private String errorCode; | ||
| private String message; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| package study.todolist.global.error; | ||
|
|
||
| import lombok.Builder; | ||
| import lombok.Getter; | ||
| import org.springframework.validation.BindingResult; | ||
| import org.springframework.validation.FieldError; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @Getter | ||
| @Builder | ||
| public class ErrorResponse { | ||
|
|
||
| private String errorCode; | ||
| private String errorMessage; | ||
|
|
||
| public static ErrorResponse of(String errorCode, String errorMessage){ | ||
|
|
||
| return ErrorResponse.builder() | ||
| .errorCode(errorCode) | ||
| .errorMessage(errorMessage) | ||
| .build(); | ||
| } | ||
|
|
||
| public static ErrorResponse of(String errorCode, BindingResult bindingResult){ | ||
|
|
||
| return ErrorResponse.builder() | ||
| .errorCode(errorCode) | ||
| .errorMessage(createErrorMessage(bindingResult)) | ||
| .build(); | ||
| } | ||
|
|
||
| private static String createErrorMessage(BindingResult bindingResult) { | ||
|
|
||
| StringBuilder sb = new StringBuilder(); | ||
| boolean isFirst = true; | ||
|
|
||
| List<FieldError> fieldErrors = bindingResult.getFieldErrors(); | ||
|
|
||
| for (FieldError error : fieldErrors){ | ||
|
|
||
| if (!isFirst){ | ||
| sb.append(", "); | ||
| } else isFirst = false; | ||
|
|
||
| sb.append("["); | ||
| sb.append(error.getField()); | ||
| sb.append("]"); | ||
| sb.append(error.getDefaultMessage()); | ||
| } | ||
|
|
||
| return sb.toString(); | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package study.todolist.global.error; | ||
|
|
||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.springframework.http.HttpStatus; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.ExceptionHandler; | ||
| import org.springframework.web.bind.annotation.RestControllerAdvice; | ||
| import study.todolist.global.Envelope; | ||
| import study.todolist.global.error.exception.BusinessException; | ||
| import study.todolist.global.error.exception.EntityNotFoundException; | ||
| import study.todolist.global.error.exception.OverMaxCountException; | ||
|
|
||
| @Slf4j | ||
| @RestControllerAdvice | ||
| public class GlobalExceptionHandler { | ||
|
|
||
| /** | ||
| * EntityNotFoundException 발생 메시지 처리 | ||
| */ | ||
| @ExceptionHandler(EntityNotFoundException.class) | ||
| public Envelope handleEntityNotFoundException(EntityNotFoundException e){ | ||
| log.error("EntityNotFoundException", e); | ||
|
|
||
| return Envelope.fail(e.getErrorCode().getHttpStatus().value(), e.getMessage()); | ||
| } | ||
|
|
||
| @ExceptionHandler(OverMaxCountException.class) | ||
| public Envelope handleOverMaxCountException(OverMaxCountException e){ | ||
| log.error("OverMaxCountException", e); | ||
|
|
||
| return Envelope.fail(e.getErrorCode().getHttpStatus().value(), e.getMessage()); | ||
| } | ||
|
|
||
| @ExceptionHandler(BusinessException.class) | ||
| protected Envelope handleException(BusinessException e){ | ||
| log.error("Exception", e); | ||
|
|
||
| return Envelope.fail(e.getErrorCode().getHttpStatus().value(), e.getMessage()); | ||
| } | ||
| } |
|
Collaborator
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. 다른 exception들이 BusinessException을 상속받는데 ErrorCode와 메시지를 함께 쓰기 위해서 인가요 ?? 의도가 궁금합니다 ㅎㅎ
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네 맞습니다! |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package study.todolist.global.error.exception; | ||
|
|
||
| import lombok.Getter; | ||
| import study.todolist.global.error.ErrorCode; | ||
|
|
||
| @Getter | ||
| public class BusinessException extends RuntimeException{ | ||
|
|
||
| private ErrorCode errorCode; | ||
|
|
||
| public BusinessException(ErrorCode errorCode){ | ||
| super(errorCode.getMessage()); | ||
| this.errorCode = errorCode; | ||
| } | ||
| } |
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.
DTO 잘 작성하셨네요!
현재 코드에선 TodoDto.Request, TodoDto.ChangeStatus, TodoDto.Response가 모두 TodoDto 클래스 내에 정의되어있는데 저는 클래스로 분리해서 사용하고 있습니다
@DaTa를 붙여서 하는 방법도 있었네요 ㅎㅎ 배워갑니다.
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.
DTO활용은 개인차가 좀 있다보니 제 방식이 조금 생소할수도 있다고 느껴졌는데 좋게 봐주셔서 감사합니다 :)
@DaTa 어노테이션은 @Getter, @Setter, @tostring이 합쳐져있다고만 알고 있어 간단하게 사용하고자 붙였습니다!
@Setter 활용을 좋아하지 않는 분들도 많으셔서 저도 사용하는데 좀 고민이 되는 부분이네요 ㅎㅎ