일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- APM
- 티스토리챌린지
- Kubernetes
- CloudWatch
- kotlin coroutine
- Linux
- 정보처리기사실기 기출문제
- PETERICA
- 기록으로 실력을 쌓자
- kotlin spring
- Elasticsearch
- 오블완
- AWS EKS
- AI
- Pinpoint
- mysql 튜닝
- 코틀린 코루틴의 정석
- 정보처리기사 실기 기출문제
- Spring
- minikube
- kotlin
- IntelliJ
- CKA 기출문제
- CKA
- Java
- 정보처리기사 실기
- kotlin querydsl
- aws
- MySQL
- 공부
- Today
- Total
피터의 개발이야기
[Kotlin] Spring Validation 이용한 입력 데이터 유효성 검증 본문
ㅁ 들어가며
ㅇ 입력값에 대한 유효성 검증을 코드상에서 하나하나 처리하는 것은 번거롭다.
ㅇ Spring에서 제공하는 Validation 기능을 사용하면 Controller 단과 별개로 입력값을 간편하게 검증할 수 있다.
ㅇ 이 글에서는 Spring Validation을 Kotlin에서 사용하는 방법을 정리한다.
ㅇ Kotlin, Spring Validation 이용한 입력 데이터 유효성 검증의 글을 보고 실습을 수행하였다.
ㅁ Gradle 설정
implementation("org.springframework.boot:spring-boot-starter-validation")
ㅇ Spring Boot 2.3 버전부터 spring-boot-starter-validation 의존성을 명시해야 @Valid를 사용할 수 있다.
ㅁ Valid 사용
import jakarta.validation.constraints.NotNull
import java.time.LocalDate
data class ValidRequestDto(
@field:NotNull(message = "value는 필수 입력값입니다.")
val value: String? = null,
@field:NotNull(message = "createdAt은 필수 입력값입니다.")
val createdAt: LocalDate? = null,
@field:NotNull(message = "number는 필수 입력값입니다.")
val number: Long? = null
)
ㅇ Kotlin에서는 @field:를 prefix로 붙여야 한다. 그렇지 않으면 Java로 변환 시 constructor에 Valid 어노테이션이 붙게 된다.
ㅁ 클래스 멤버 필드는 nullable로 지정
data class ValidRequestDto(
@field:NotNull(message = "value는 필수 입력값입니다.")
val value: String
)
ㅇ Kotlin에서는 변수 선언 시 nullable한 타입으로 선언해야 한다.
ㅇ NotNull을 적용할 때 nullable 타입으로 선언하지 않으면, 요청 시 해당 필드를 입력하지 않았을 때 NullPointerException이 발생하게 된다.
Constructor threw exception; nested exception is java.lang.NullPointerException; Parameter specified as non-null is null
ㅁ Controller 단에 Validation 적용
@RestController
@RequestMapping("/valid")
class ValidController() {
@GetMapping("/get")
fun getParam(
@Valid @ModelAttribute validRequestDto: ValidRequestDto,
bindingResult: BindingResult
) {
if (bindingResult.hasErrors()) {
println("errors : ${bindingResult.fieldErrors}")
throw RuntimeException("errors ${bindingResult.fieldErrors}")
}
}
}
ㅇ BindingResult는 @Valid가 적용된 @ModelAttribute, @RequestBody 바로 뒤에 argument로 설정해야 한다.
ㅇ @Valid와 BindingResult 사이 다른 인자가 존재하면 에러 발생 시 BindingResult에 에러메시지가 담기지 않는다.
ㅁ Controller 내 여러 Validation 형태
ㅇ Validation 적용 방식에 따라 미묘한 차이가 발생한다.
@ModelAttribute
@GetMapping("/get")
fun getParam(
@Valid @ModelAttribute validRequestDto: ValidRequestDto
) {
// ...
}
ㅇ 유효성 검증 에러가 발생하면 기본적으로 400 응답 코드를 반환하며, BindException이 발생한다.
@RequestBody
@PostMapping("/post")
fun postRequestBody(
@Valid @RequestBody validRequestDto: ValidRequestDto
) {
// ...
}
ㅇ 유효성 검증 에러가 발생하면 400 응답 코드를 반환하며, MethodArgumentNotValidException이 발생한다.
@RequestParam, @PathVariable
@RestController
@Validated
class ValidationController {
@GetMapping("/get")
fun getParam(
@NotNull(message = "필수값입니다.") @RequestParam("value") value: String?
): String? {
// ...
}
}
ㅇ @RequestParam은 클래스 단계에서 @Validated 어노테이션이 필요하다.
ㅇ 기본적으로 500 응답 코드를 반환하며, ConstraintViolationException이 발생한다.
ㅁ Exception Handler
@ExceptionHandler(BindException::class)
fun handleNotValidException(
e: BindException,
bindingResult: BindingResult
): ResponseEntity<ErrorDto> {
logger.error("validation errors : ${bindingResult.fieldErrors}")
val defaultMessage = bindingResult.fieldError?.defaultMessage
val code = bindingResult.fieldError?.code
return ResponseEntity.badRequest()
.body(
ErrorDto(
message = defaultMessage,
validCode = code,
description = e.message
)
)
}
ㅇ BindingResult, MethodArgumentNotValidException에 대한 exception handler에서 BindingResult를 직접 받아올 수 있다.
ㅁ 테스트
@WebMvcTest
class ValidControllersTests(@Autowired val mockMvc: MockMvc) {
@Test
fun `get ModelAttribute`(){
mockMvc.perform(
get("/valid")
.accept(MediaType.APPLICATION_JSON)
.param("createdAt", LocalDate.now().toString())
.param("number", "10")
// .param("value", "value")
)
.andExpect(status().isOk)
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
}
}
/** 출력
errors : [Field error in object 'validRequestDto' on field 'value': rejected value [null]; codes [NotNull.validRequestDto.value,NotNull.value,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [validRequestDto.value,value]; arguments []; default message [value]]; default message [value는 필수 입력값입니다.]]
*/
ㅁ 마무리
Spring Validation을 사용하면 입력값에 대한 유효성 검증을 간편하게 처리할 수 있다.
Kotlin에서는 @field: 어노테이션을 사용하고, nullable 타입으로 선언해야 한다.
Controller 단에서 BindingResult를 사용하여 유효성 검증 에러를 처리할 수 있다.
ㅁ 함께 보면 좋은 사이트
ㅇ base source 참조 - https://spring.io/guides/tutorials/spring-boot-kotlin
'Programming > Kotlin' 카테고리의 다른 글
[Kotlin] Spring MVC, Circular view path 에러 (0) | 2024.08.04 |
---|---|
[Kotlin] Spring Boot와 Kotlin으로 QueryDSL 페이징 처리하기 (0) | 2024.08.04 |
[kotlin] Constructor threw exception; nested exception is java.lang.NullPointerException; 에러 해결방법 (0) | 2024.07.29 |
[Kotlin]JPA의 더티 체킹 (Dirty Checking) (0) | 2024.07.28 |
[Kotlin] QueryDSL와 MapStruct를 사용하여 DTO에서 필요한 부분만 업데이트하기 (0) | 2024.07.27 |