[Spring] Spring Boot로 ToDoApp만들기(투두 앱) (3)

728x90

데이터 베이스 스키마 설계

Todo

//Column
data class Todo(
    var index: Int? = null,                 // 일정 index
    var title: String? = null,              // 일정 title
    var description: String? = null,        // 일정 설명
    var schedule: LocalDateTime? = null,    // 일정 시간
    var createdAt: LocalDateTime? = null,   // 생성 시간
    var updatedAt: LocalDateTime? = null,   // 업데이트 시간
)

fun Todo.convertTodo(todoDto: TodoDto): Todo {
    return Todo().apply {
        this.index = todoDto.index
        this.title = todoDto.title
        this.description = todoDto.description
        this.schedule = LocalDateTime.parse(todoDto.schedule, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
        this.createdAt = todoDto.updatedAt
    }
}

TodoApiController

Api Controller 세부 내용 구현(CRUD)

@RestController
@RequestMapping("/api/todo")
class TodoApiController(

    //주입 받는다
    val todoService: TodoService
) {

    // 없으면 전체조회, 있으면 단건 조회, required -> 필수값 아닌지 정하기, Optional이므로 Valid할 필요 없다.
    // Read(One)
    @GetMapping(path = [""])
    fun read(@RequestParam(required = false) index: Int?): ResponseEntity<Any?> {
        // Index 있을 경우
        return index?.let {
            todoService.read(it)
        }?.let {
            return ResponseEntity.ok(it)
        }   // Index 없는 경우
            ?: kotlin.run {
                return ResponseEntity
                    .status(HttpStatus.MOVED_PERMANENTLY)
                    .header(HttpHeaders.LOCATION, "/api/todo/all")
                    .build()    // 301에러 일으켜서 readAll로 보낸다
            }
    }

    // ReadAll(List)
    @GetMapping(path = ["/all"])
    fun readAll(): MutableList<TodoDto> {
        return todoService.readAll()
    }

    // C
    @PostMapping(path = [""])
    fun create(@RequestBody todoDto: TodoDto): ResponseEntity<Any> {  // Body설계 -> Model , 들어오는 동시에 검증(Valid)
        return ResponseEntity
            .status(200)
            .body(todoService.create(todoDto))
    }


    // U
    @PutMapping(path = [""])    // create = 201, update = 200
    fun update(@Valid @RequestBody todoDto: TodoDto): ResponseEntity<Any> {
        return ResponseEntity
            .status(201)
            .body(todoService.update(todoDto))
    }


    // D
    @DeleteMapping(path = ["/{index}"])
    fun delete(@PathVariable(name = "index") _index: Int): ResponseEntity<Any> {

        if (!todoService.delete(_index)) {
            return ResponseEntity.status(500).build()
        }
        return ResponseEntity.ok().build()
    }
}

TodoDto

// CRUD 하는데 필요한 Body 설계
data class TodoDto(

    var index: Int? = null,

    @field:NotBlank
    var title: String? = null,

    var description: String? = null,

    @field:NotBlank
    // yyyy-MM-dd HH:mm:ss
    var schedule: String? = null,

    var createdAt: LocalDateTime? = null,

    var updatedAt: LocalDateTime? = null

) {
    // TODO 이전 학습한 custom annotation으로 변경 -> Test필요
    @AssertTrue(message = "yyyy-MM-dd HH:mm:ss 포맷이 맞지 않습니다.")
    fun validSchedule(): Boolean {
        return try {
            LocalDateTime.parse(
                schedule,
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
            )   // 파싱해서 성공 -> true, 실패 -> false
            true
        } catch (e: Exception) {
            false
        }
    }
}

fun TodoDto.convertTodoDto(todo: Todo): TodoDto {

    return TodoDto().apply {
        this.index = todo.index
        this.title = todo.title
        this.description = todo.description
        this.schedule = todo.schedule?.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
        this.createdAt = todo.createdAt
        this.updatedAt = todo.updatedAt
    }
}

TodoService

/*
* 현업에서 이렇게 변환할 때 사용하는 라이브러
* model mapper
* kotlin reflection
*/
@Service
class TodoService(
    val todoRepositoryImpl: TodoRepositoryImpl
) {

    // C
    fun create(todoDto: TodoDto): TodoDto? {   // Todo는 DB스키마이기 때문에, dto형태로 내려주는게 좋은 코드다
        return todoDto.let {
            Todo().convertTodo(it)
        }.let {
            todoRepositoryImpl.save(it)
        }?.let {    // ?는 무조건 있기 때문에
            TodoDto().convertTodoDto(it)
        }
    }

    // R
    fun read(index: Int): TodoDto? {
        return todoRepositoryImpl.findOne(index)?.let {
            TodoDto().convertTodoDto(it)
        }
    }

    fun readAll(): MutableList<TodoDto> {
        return todoRepositoryImpl.findAll().map {
            TodoDto().convertTodoDto(it)
        }.toMutableList()

    }

    // U
    fun update(todoDto: TodoDto): TodoDto? {
        return todoDto.let {
            Todo().convertTodo(it)
        }.let {
            todoRepositoryImpl.save(it)
        }?.let {    // ?는 무조건 있기 때문에
            TodoDto().convertTodoDto(it)
        }
    }

    // D
    fun delete(index: Int): Boolean {
        return todoRepositoryImpl.delete(index)
    }
}
728x90

댓글

Designed by JB FACTORY