본문으로 바로가기

Kotlin으로 개발하는 Spring Boot Web MVC #2

목차

    실습 환경

    • IntelliJ
    • Kotlin
    • Gradle
    • JDK 11
    • Spring Boot 2.6.2

    실습 코드

    https://github.com/0n1dev/kotlin-spring-practice

     

    GitHub - 0n1dev/kotlin-spring-practice: 인프런 강의

    인프런 강의. Contribute to 0n1dev/kotlin-spring-practice development by creating an account on GitHub.

    github.com

    Spring Boot Validation

    참고: https://beanvalidation.org/2.0-jsr380/spec/#builtinconstraints

     

    Bean Validation specification

    BeanNode, PropertyNode and ContainerElementNode host getContainerClass() and getTypeArgumentIndex(). If the node represents an element that is contained in a container such as Optional, List or Map, the former returns the declared type of the container and

    beanvalidation.org

    기존 DeleteApiController 수정

    @RestController
    @RequestMapping("/api")
    @Validated
    class DeleteApiController {
    
        // 1. path variable
        // 2. request param
    
        @DeleteMapping(path = ["/delete-mapping/name/{name}/age/{age}"])
        fun deleteMappingPath(
            @PathVariable
            @NotNull
            @Size(min = 1, max = 10)
            name: String,
    
            @NotNull(message = "age 값이 누락되었습니다.")
            @Min(value = 20, message = "age는 20보다 커야 합니다.")
            @PathVariable
            age: Int
        ): String {
            return "$name $age"
        }
    
        @DeleteMapping(path = ["/delete-mapping"])
        fun deleteMapping(
            @RequestParam name: String,
            @RequestParam age: Int
        ): String {
            return "$name $age"
        }
    }

    기존 Data Class 수정

    @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class)
    // @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class) PropertyNamingStrategy Class Deprecated
    data class UserRequest(
        // @Size(min = 2, max = 8) // 자바에서 사용하는 방식
        @field:NotEmpty
        @field:Size(min = 2, max = 8) // 코틀린에서 Data Class 필드에 어노테이션을 붙일 때
        var name: String?=null,
    
        @field:PositiveOrZero // 0 이상의 숫자를 검증
        var age: Int?=null,
    
        @field:Email // email 양식
        var email: String?=null,
    
        @field:NotBlank // 공백을 검증
        var address: String?=null,
    
        @field:Pattern(regexp = """^\d{2,3}-\d{3,4}-\d{4}$""") // 정규식 검증
        // @JsonProperty("phone_number") Json에서는 스네이크케이스를 주로 사용해서 서로 매핑되도록 지정.
        var phoneNumber: String?=null // 코틀린에서는 기본적으로 카멜케이스 사용.
    )

    BindingResult 활용

    @RestController
    @RequestMapping("/api")
    class PutApiController {
    
        @PutMapping("/put-mapping")
        fun putMapping(): String {
            return "put-mapping"
        }
    
        @RequestMapping(method = [RequestMethod.PUT], path = ["/request-mapping"])
        fun requestMapping(): String {
            return "put-mapping"
        }
    
        @PutMapping(path = ["/put-mapping/object"])
        fun putMappingObject(@Valid @RequestBody userRequest: UserRequest,
                             bindingResult: BindingResult): ResponseEntity<String> {
    
            if (bindingResult.hasErrors()) {
    
                val msg = StringBuilder()
                bindingResult.allErrors.forEach {
                    val field = it as FieldError
                    val message = it.defaultMessage
    
                    msg.append("${field.field} $message\n")
                }
    
                return ResponseEntity.badRequest().body(msg.toString())
            }
    
    //        // 0. Response
    //        return UserResponse().apply {
    //
    //            // 1. result
    //            Result().apply {
    //                this.resultCode = "OK"
    //                this.resultMessage = "성공"
    //            }
    //
    //
    //        }.apply {
    //
    //            // 2. description
    //            this.description = "@@@@@@"
    //        }.apply {
    //
    //            // 3. user mutable list
    //            val userList = mutableListOf<UserRequest>()
    //
    //            userList.add(userRequest)
    //            userList.add(UserRequest().apply {
    //                this.name = "a"
    //                this.age = 11
    //                this.email = "test@naver.com"
    //                this.address = "dd"
    //                this.phoneNumber = "01018838303"
    //            })
    //
    //            this.userRequest = userList
    //        }
            return ResponseEntity.ok("")
        }
    }