-
Controller에서 List 받기(+ dto로 받고 validation)Spring Framework 2023. 3. 22. 00:01
Controller에서 List <String> 받기
Controller 코드 구성
import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController @RestController class TestController { @GetMapping("/test/list") fun inputList( @RequestParam("list") list: List<String> ): String { println(list) return list.toString() } }
Postman으로 요청하기
GET localhost:9090/test/list?list=1,2,3,4,5
Curl으로 요청하기
curl --location --request GET 'localhost:9090/test/list?list=1,2,3,4,5'
요청 결과
[1, 2, 3, 4, 5]
String 대신 직접 만든 객체 사용하기
WrappingString Data 클래스 만들기
data class WrappingString( val value: String, )
Controller String -> WrappingString으로 수정
@GetMapping("/test/list") fun inputList( @RequestParam("list") list: List<WrappingString> ): String { println(list) return list.toString() }
요청 결과
[WrappingString(value=1), WrappingString(value=2), WrappingString(value=3), WrappingString(value=4), WrappingString(value=5)]
직접 만든 객체 Validtion 하기
gradle에 Spring validation 의존성 추가
implementation("org.springframework.boot:spring-boot-starter-validation")
WrappingString Data 클래스에 제약조건 추가
data class WrappingString( @field:Length(min=2,max=4) val value: String,
클래스 단에는 @Validated, 메서드 단에는 @Valid 붙이기
import com.kidsworld.test.request.WrappingString import org.springframework.validation.annotation.Validated import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController import javax.validation.Valid @RestController @Validated class TestController { @GetMapping("/test/list") fun inputList( @Valid @RequestParam("list") list: List<WrappingString> ): String { println(list) return list.toString() } }
curl 요청
curl --location --request GET 'localhost:9090/test/list?list=11,22,33,44,5'
요청 결과
{ "timestamp": "2023-01-01T16:07:51.753+00:00", "status": 500, "error": "Internal Server Error", "path": "/test/list" }
Spring Server Log
javax.validation.ConstraintViolationException: inputList.list[4].value: 길이가 2에서 4 사이여야 합니다
입력 DTO 객체에 새로운 프로퍼티 추가
data class WrappingString( @field:Length(min=2,max=4) val value: String, @field:NotNull val valueLength: String, )
이제 다시 요청을 받으면?
[org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException: no matching editors or conversion strategy found]
매핑 전략을 찾을 수 없다고 나옵니다.
음.. @RequestParam을 활용하여 객체를 매핑시키려면 어떻게 해야 할까요?
@GetMapping("/test/list") fun inputList( @Valid list: WrappingString ): String { println(list) return list.toString() }
우선 List<DTO> 대신 DTO만 선언하고 @RequestParam 어노테이션을 제거하면 잘 동작합니다.
curl 요청
curl --location --request GET 'localhost:9090/test/list?value=111&valueLength=3'
요청 결과
WrappingString(value=111, valueLength=3)
List<DTO>로 받아보기
@GetMapping("/test/list") fun inputList( @Valid list: List<WrappingString> ): String { println(list) return list.toString() }
curl 요청
curl --location --request GET 'localhost:9090/test/list?value=111&valueLength=3&value=111&valueLength=3'
요청 결과
No primary or single unique constructor found for interface java.util.List
코틀린에서 interfaces는 constructor를 생성할 수 없습니다.
코틀린의 문제인가 하고 자바에서 동일하게 구현해보니 동일한 에러가 발생합니다.
List대신 ArrayList를 활용
@GetMapping("/test/list") fun inputList( @Valid list: ArrayList<WrappingString> ): String { println(list) return list.toString() }
에러는 해결되지만.. 반환값은 []로 옵니다.
WrappingString에 부 생성자를 두어보았지만 여전히 해결되지 않았습니다.
현실과 타협
여기에는 적지 않았지만 다음과 같은 새로운 에러들을 만나보는 시간들이었습니다.
Controller The valid characters are defined in RFC 7230 and RFC 3986
이를 해결하기 위한 방안을 생각했습니다.
- GET요청에 HTTP body 값을 실어서 요청을 보내기(설계적인 문제나 클라이언트에서 지원하지 않을 경우가 있을 수 있음)
- POST요청에 HTTP body 값을 실어서 요청을 보내기(POST를 사용하는 순간 GET의 의미가 사라지게 됨)
둘의 장단점을 잘 고려하고 선택해서 사용하면 될 것 같습니다.
참고자료
https://mangkyu.tistory.com/174
'Spring Framework' 카테고리의 다른 글
Spring Boot 2 to Spring Boot 3 마이그레이션 (0) 2023.06.07 ThreadLocal이란? (0) 2023.05.19 Spring 버전에 맞는 Dependency 버전 찾기 (0) 2023.02.06 토비의 스프링 부트 강의 요약 (0) 2023.01.29 @Transactional 어노테이션이란? (0) 2022.09.14