어제에 이어 spring validation 입니다. 오늘 강의 영상은 custom validation 부분인데, 어제 실습도 안 했으니 그것도 겸합니다.
마음같아선 진도를 더 나가고 싶긴 한데, 구정인 것도 있고 해서 일단 강의 하나와 더는 미룰 수 없는 실습 정도로 만족해야겠습니다.
검증은 스펙이다
저번에 언뜻 보고 Hibernate 의 구현체를 사용하는 거까진 봤는데, 알고보니 표준? 이라고 해야하나? 공통 스펙이 있고 그걸 구현하는 형태인 모양이더라구요. 유독 자바가 이런 게 많네요? 험난한 길을 먼저 앞서서 달렸다보니 이런거려나요.
hibernate 의 구현체는 spring boot starter validationm 에 구현체로서 포함되어있다고 합니다. 어노테이션 자동완성을 켜면 꼭 두 개가 나오던데 hibernate 쪽의 어노테이션은 deprecated 처리가 되어있더라구요. 표준화되었기 때문이라고 봐야겠죠...?
참고: https://meetup.toast.com/posts/223 (오버뷰용으로도 좋음, 중복 검증이 성능을 저하시킬 수 있다는 걸 강조하는 게 인상적)
Kotlin 에서 data class 에 validation 을 달려면 @field:Anno 로
저번 강의에서 실습을 안 해봤어서 몰랐습니다.
kotlin 에서 DTO 라면 거의 순수 데이터 같은 객체니까 data class지! 라고 생각해서 생성자이자 필드에 어노테이션을 달면 생성자에 어노테이션을 단 걸로 취급됩니다. 그래서 @field:어노테이션 형태로 달아야 합니다.
import javax.validation.constraints.Email
import javax.validation.constraints.Size
data class UserData(
@field:Size(min=5)
var name: String,
@field:Email
var email: String,
@field:PineapplePizza
var favourite: String?,
)
많은 분들이 이 문제를 겪으셨는지 금방 검색에 나오더라구요. 참고:
- https://blog.leocat.kr/notes/2020/12/10/kotest-bean-validation-in-kotlin
- https://velog.io/@lsb156/SpringBoot-Kotlin%EC%97%90%EC%84%9C-Valid%EA%B0%80-%EB%8F%99%EC%9E%91%ED%95%98%EC%A7%80-%EC%95%8A%EB%8A%94-%EC%9B%90%EC%9D%B8JSR-303-JSR-380
- https://stackoverflow.com/questions/36515094/kotlin-and-valid-spring-annotation
- https://kotlinlang.org/docs/annotations.html#annotation-use-site-targets
Custom Validation
커스텀 검증은 두 가지 방법을 사용할 수 있습니다.
- @AssertTrue / @AssertFalse - 같은 클래스에 메서드를 하나 만들어 검증합니다.
- 커스텀 어트리뷰트 만들기 - 어트리뷰트를 만들고, 실제 검증 로직이 들어간 클래스를 만든 뒤 두 개를 이어줘야 합니다.
Custom Validation - @AssertTrue
강의 중에 메서드 이름에 is가 빠져서 안 되는 일이 있었습니다. 저는 여기서 더 나아가 아예 is 빼고 나머지를 필드명과 무관하게 만들어봤는데, 되더라구요. is만 있으면 됩니다. (사실 이 부분을 좀 더 검색해봐야 하는데... 해봐야하는데...)
class UserData {
@AssertTrue
fun isMyCustom(): Boolean = false
}
Custom Validation - 커스텀 어트리뷰트 만들기
어트리뷰트와 로직 클래스 두 개를 짜야합니다.
Custom Validation - 커스텀 어트리뷰트 만들기 - 어트리뷰트 클래스
첫 번째로 어트리뷰트를 만들어야 합니다. - @Constraint( validatedBy = { 아래에서_만든_클래스.javaClass } )
kotlin 이라면 만드는 방법이 조금 다릅니다. 언어 차원에서 좀 예쁘게 만들게 해주려나보네요.
- 클래스는 KClass 로 바꿔써야 합니다. (컴파일 될 때 바꿔준다고 합니다.)
- 각 패러미터는 전부 있어야 정상적으로 동작합니다. (ConstraintDefinitionException)
- PineapplePizza contains Constraint annotation, but does not contain a message parameter.
- PineapplePizza contains Constraint annotation, but does not contain a groups parameter.
- PineapplePizza contains Constraint annotation, but does not contain a payload parameter.
import javax.validation.Constraint
import javax.validation.Payload
import kotlin.reflect.KClass
@Constraint( validatedBy = [PineapplePizzaValidator::class] )
annotation class PineapplePizza(
val awesomeThingIs: String = "pineapple pizza",
// val message: String = "{javax.validation.constraints.Email.message}",
val message: String = "파인애플 피자가 최고의 음식입니다.",
val groups: Array<KClass<*>> = [],
val payload: Array<KClass<out Payload>> = [],
)
- https://gist.github.com/vbsteven/b2311c51b2686cbacf037b0fffb2eb06
- https://kotlinlang.org/docs/annotations.html
두 번째로, 어트리뷰트에서 호출할 검증 메서드가 있는 클래스를 만들어야 합니다.
import javax.validation.ConstraintValidator
import javax.validation.ConstraintValidatorContext
class PineapplePizzaValidator: ConstraintValidator<PineapplePizza, String> {
lateinit var definedAwesomeThing: String
override fun isValid(value: String?, context: ConstraintValidatorContext?): Boolean {
return value?.lowercase() == "pineapple pizza"
}
override fun initialize(constraintAnnotation: PineapplePizza) {
// take value from anno
super.initialize(constraintAnnotation)
definedAwesomeThing = constraintAnnotation.awesomeThingIs
}
}
검증 패러미터와 http 반환값
저번 강의에서 http 리턴값이 뭐가 나오는지 확실히 보지 못했었습니다. 직접 해보니, 반환값에 관계없이 패러미터에 bindingResult 가 있으면 본문이 실행되고 그렇지 않으면 검증 실패시 함수 본문은 실행되지 않고 대신 400을 떨굽니다.
컬렉션이 필드에 있다면 검증하려면 @Valid 를 붙여라
사소하지만 중요한 내용으로 끝부분에 이게 언급되더라구요.
미뤄둔 실습을 오늘 몰아서 하려니까 양이 좀 많고, 시행착오도 좀 있네요. 원래는 공식 문서를 찾아보고 싶었는데 생각외로 검색결과의 블로그들이 잘 정리되어있어서 거기까지 갈 생각이 안 나더라구요. 이런 습관은 매우 나쁜데... 공식이 설명하는 거하고 블로그에서 설명하는 거하고 확 다른데...
본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.
패스트캠퍼스: https://bit.ly/37BpXiC
#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #한번에끝내는JavaSpring웹개발마스터초격차패키지Online
오늘은 막 집에 돌아온 참이고 해서 정신이 좀 없어서, 마음은 진도를 빼고 싶었지만 딱 강의 하나를 보고 끝내야 했습니다. 내일은 좀 더 짧은 시간에 집중해서 할 수 있도록 일찍 일어나던지 해야...
이...게 강의가 DB 관련까지는 진행이 되어야 뭘 만들어보던지 하는데 커리큘럼을 보니 이 뒤에 swagger 나 예외처리 등의 기초가탄탄 같은 내용들이 있네요. 좋은데 답답한데 좋은데 답답하네요...
'FastCampus - 한번에 끝내는 Java|Spring 웹 개발 > 03 스프링 입문' 카테고리의 다른 글
스프링 Ch 6-5 Filter / Interceptor - 패스트캠퍼스 챌린지 11일차 (0) | 2022.02.03 |
---|---|
스프링 Ch 6-3 Exception 처리 + alpha - 패스트캠퍼스 챌린지 10일차 (0) | 2022.02.02 |
스프링 Ch 6-1 validation - 패스트캠퍼스 챌린지 8일차 (0) | 2022.01.31 |
스프링 Ch 5 OM/Annotation 정리 - 패스트캠퍼스 챌린지 7일차 (0) | 2022.01.30 |
스프링 Ch 5 스프링 좀 더 - AOP (2) - 패스트캠퍼스 챌린지 6일차 (0) | 2022.01.29 |