익일 예비군으로 하루 빨리 과제를 제출했습니다.
필수구현 단계의 경우 Entity가 하나이다 보니, 각 Entity 간 관계를 고려하지 않아도 되어 비교적 수월하였습니다만 .. 강의를 보지 않고 과제를 진행했더라면 정해진 기한 내로 제출하지 못했을거라 생각하여 Controller, Model, Dto, Service 등 하나하나 뜯어보며 이해하는 중입니다..
이해하지 않으면 말짱 도루묵이니, 차주 선택구현 과제까지 완벽하게 이해하고 진행하기 위해 TIL로 내용을 회고해봅니다..!
Github 링크
https://github.com/JinkownHong/todoList
GitHub - JinkownHong/todoList
Contribute to JinkownHong/todoList development by creating an account on GitHub.
github.com
과제 (To do List 만들어보기)
과제 내용은 아래와 같습니다.
1. 할일카드 작성 기능
* 할 일 제목, 할일 내용, 작성일, 작성자 이름 을 저장 가능
* 저장된 할 일의 정보를 반환 받아 확인 가능
2. 선택한 할 일 조회 기능
* 선택한 할 일의 정보 조회 가능
* 반환 받은 할 일 정보에는 할 일 제목,할일 내용, 작성일, 작성자 이름 정보가 들어가 있습니다.
3. 할 일 카드 목록 조회 기능
* 등록된 할 일 전체를 조회
* 조회된 할 일 목록은 작성일 기준 내림차순으로 정렬
4. 선택한 할 일 수정 기능
* 선택한 할 일의 할 일 제목, 작성자명, 작성 내용을 수정할 수 있습니다.
* 수정된 할 일의 정보를 반환 받아 확인 가능
5. 선택한 할 일 삭제 기능
* 선택한 게시글을 삭제 가능
금일은 Controller 부분만 다뤄볼 예정이며,
선택구현 과제까지 모두 완료한 후 전체적으로 과제 회고를 작성해보려 합니다..!
과제 (To do List 만들어보기)
package com.teamsparta.todolist.domain.todo.controller
import com.teamsparta.todolist.domain.todo.dto.CreateTodoRequest
import com.teamsparta.todolist.domain.todo.dto.ErrorResponse
import com.teamsparta.todolist.domain.todo.dto.TodoResponse
import com.teamsparta.todolist.domain.todo.dto.UpdateTodoRequest
import com.teamsparta.todolist.domain.todo.exception.ModelNotFoundException
import com.teamsparta.todolist.domain.todo.exception.RequestBodyEmptyException
import com.teamsparta.todolist.domain.todo.service.TodoService
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
@RequestMapping("/api/v1/todos/")
@RestController
class TodoController(
private val todoService: TodoService
) {
@GetMapping
fun getTodoList(): ResponseEntity<List<TodoResponse>> {
return ResponseEntity.status(HttpStatus.OK).body(todoService.getAllTodoList())
}
@GetMapping("/{todoId}")
fun getTodo(@PathVariable todoId: Long): ResponseEntity<TodoResponse> {
return ResponseEntity.status(HttpStatus.OK).body(todoService.getTodoById(todoId))
}
@PostMapping
fun createTodo(@RequestBody createTodoRequest: CreateTodoRequest): ResponseEntity<TodoResponse> {
return ResponseEntity.status(HttpStatus.CREATED).body(todoService.createTodo(createTodoRequest))
}
@PutMapping("/{todoId}")
fun updateTodo(
@PathVariable todoId: Long, @RequestBody updateTodoRequest: UpdateTodoRequest
): ResponseEntity<TodoResponse> {
return ResponseEntity.status(HttpStatus.OK).body(todoService.updateTodo(todoId, updateTodoRequest))
}
@DeleteMapping("/{todoId}")
fun deleteTodo(@PathVariable todoId: Long): ResponseEntity<Unit> {
todoService.deleteTodo(todoId)
return ResponseEntity.status(HttpStatus.NO_CONTENT).build()
}
@ExceptionHandler(ModelNotFoundException::class)
fun handleModelNotFoundException(e: ModelNotFoundException): ResponseEntity<ErrorResponse> {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(ErrorResponse(message = e.message))
}
@ExceptionHandler(RequestBodyEmptyException::class)
fun handleRequestBodyException(e: RequestBodyEmptyException): ResponseEntity<ErrorResponse> {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(ErrorResponse(message = e.message))
}
}
(위 Github 내용을 참고하여 읽어주시면 감사하겠습니다!)
Controller?
웹 사이트에서 받은 사이트 주소를 Mapping 시키고, 받은 정보들을 Service에 전달해주는 배달원 역할을 수행합니다. Service와 어떤 과정을 거쳐 통신하는지 정리해보면,
1) 사용자가 사이트 내 Request를 보냅니다.
2) Request URL에 알맞은 Controller가 요청을 수신합니다.
3) Controller는 넘어온 요청을 처리하기 위해 Service를 호출합니다.
4) Service는 알맞은 정보를 가공하여 Controller에게 데이터를 넘깁니다.
5) Controller는 Service의 결과물을 Client에게 전달해준다.
Controller 내 작성한 코드를 순차적으로 살펴보면,
@RequestMapping을 통해 uri를 정의하고, @RestController Annotation을 통해 Controller를 정의합니다.
@RequestMapping?
우리는 특정 uri로 요청을 보내면 Controller에서 어떠한 방식으로 처리할지 정의를 하는데, 이때 들어온 요청을 특정 메서드와 매핑하기 위해 사용하는 것이 @RequestMapping입니다.
지금처럼 Controller Class 위 해당 어노테이션을 생성하는 경우 클래스 내부에 있는 메서드와 요청 URL 매핑을 시켜줄 때 앞에 "/api/v1/todos/" 를 생략하여 코드를 보다 간결하게 작성할 수 있습니다.
이후 의존성 주입을 위해 TodoService를 생성자로 선언하고, 각 CRUD에 맞는 Annotation을 매핑하여 매서드를 작성해줍니다. 각 메서드 내 들어간 Annotation을 살펴보겠습니다.
@PathVariable
경로 변수를 표시하기 위해 메서드에 매개변수에 사용되며 경로 변수는 중괄호{id}로 둘러싸인 값을 나타냅니다.
URL 경로에서 변수 값을 추출하여 매개변수에 할당하며 값이 없는 경우 404 응답으로 오류가 발생합니다.
* 위에서는 할 일 목록 중 특정 할 일을 필요로 하는 경우 해당 어노테이션을 사용했습니다. (특정 할 일을 선택하여 조회하는 경우, 수정하는 경우, 삭제하는 경우)
@RequestBody
해당 어노테이션이 붙은 파라미터에는 http요청의 본문(body)이 그대로 전달됩니다.
@RequestBody Annotation을 Controller 메서드의 파라미터로 설정하면,
HttpMessageConverter가 HTTP Request body를 읽고 이를 역직렬화(deserialization)하여 자바 객체로 변환해 줍니다.
(이때 @RequestBody로 선언한 파라미터 타입과 클라이언트에서 보낸 데이터가 일치해야 합니다.)
해당 과제를 진행하면서 RequestBody 내 각 메서드 별 필요한 정보들을 담은 Dto를 생성하여 해당 Dto를 매개변수로 사용하였습니다.
쉽게 정리하자면, @RequestBody를 통해 사용자에게 해당 메서드를 진행하기 위해 필요한 정보를 담은 Dto를 전달하며
때문에 '조회'와 같이 사용자가 별다른 정보를 입력할 필요가 없는 경우 해당 어노테이션은 거의 사용되지 않습니다!
ResponseEntity
Spring Framework에서 제공하는 클래스 중 HttpEntity라는 클래스가 존재하는데,
ResponseEntity란 httpentity를 상속받는, 결과 데이터와 HTTP 상태 코드를 작접 제어할 수 있는 클래스입니다.
ResponseEntity에는 사용자의 HttpRequest에 대한 응답 데이터가 포함됩니다.
위에서는 Response Dto를 data class로 생성, 응답에 필요한 정보를 담아 ResponseEntity 내 활용해보았습니다.