Kotlin和Spring引导请求主体验证
我刚刚开始使用kotlin和Spring Boot一起开发一个简单的web应用程序 让我们看一个简单的数据类对象Kotlin和Spring引导请求主体验证,spring,validation,spring-boot,kotlin,httprequest,Spring,Validation,Spring Boot,Kotlin,Httprequest,我刚刚开始使用kotlin和Spring Boot一起开发一个简单的web应用程序 让我们看一个简单的数据类对象 @Entity data class User (name: String) { @Id @GeneratedValue(strategy = GenerationType.AUTO) var id: Long = -1 } 和一个控制器 @RequestMapping(method = arrayOf(RequestMethod.POST)) fun
@Entity
data class User (name: String) {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
var id: Long = -1
}
和一个控制器
@RequestMapping(method = arrayOf(RequestMethod.POST))
fun createUser (@RequestBody user: User): User {
return userService.createUser(user)
}
嗯,使用任何请求体发出请求都会抛出http 400错误
未找到合适的构造函数,无法从对象值反序列化(缺少默认构造函数或创建者,或者可能需要添加/启用类型信息?);嵌套异常是com.fasterxml.jackson.databind.JsonMappingException
为了消除此错误,我发现我们需要为构造函数参数提供一些默认值,以便:
name: String = ""
或者可能:
name: String? = null
现在,响应体上的输入完全没有验证,这意味着,如果响应体中的JSON不遵守用户类的语法,将使用默认值并存储在数据库中
如果请求体JSON输入不符合用户类参数而不需要手动执行,是否有任何方法验证该输入以抛出错误的请求
在本例中,只有一个参数,但是手动处理较大的类似乎不是一个好方法
提前感谢是的,有一些方法可以“自动”验证请求主体JSON
是其中之一,有几种实现。包括它,所以这可能是您的第一选择,因为Spring Boot将它包装得非常好。我认为对于
Spring Boot 2.x
,可以采用以下由两部分组成的解决方案:
API外观配置
验证机制
@服务
类ValidationService(validator:validator){
private val log=LoggerFactory.getLogger(ValidationService::class.java)
@抛出(BodyValidationException::类)
乐趣验证(o:T){
val冲突=验证程序。验证(o)
if(inflictions.isEmpty())返回
抛出BodyValidationException.of(inflictions.stream())
.map{v:ConstraintViolation->“${v.propertyPath}${v.message}”
.collect(收集器.toSet()).toMutableSet())
}
有趣的句柄(e:BodyValidationException):Mono=
handleInternal(错误响应(例如错误))
私人娱乐handleInternal(响应:ErrorResponse):Mono=
Mono.just(回应)
.doOnNext{res->log.warn(res.errors.joinToString(“,”)}
.flatMap{res->
badRequest().contentType(应用程序_JSON)
.bodyValue(res)
}
数据类错误响应(val错误:设置)
类BodyValidationException私有构造函数(变量错误:Set):IllegalArgumentException(){
伴星{
(错误:集合)的乐趣:BodyValidationException{
返回BodyValidationException(错误)
}
}
}
}
是的,您可以在User类的构造函数中或在userService调用的validations方法中执行此操作。您应该查看和(快速介绍)。它们使Spring+Kotlin数据类更容易接受。至于如何验证,如果您不介意繁重的模式文档,可以使用JsonSchema。这里有一个基本的例子,你注册了jackson kotlin模块()吗?一旦您这样做了,您就可以使用普通的javax.validation注释(只需记住注释使用站点目标)她的回答很有魅力。这与Paul Hicks提到的无参数构造函数有关,所以,感谢你们两位抽出时间来帮助我。如果需要更多的验证,JSON模式也可以工作needed@MiguelAnciães看看这个
@Configuration
class ValidationRouter(
val validationService: ValidationService
) {
@Bean
fun router() = router {
accept(APPLICATION_JSON).nest {
"/api".nest {
POST("/validation") { req ->
req.bodyToMono(ValidatingBody::class.java)
.doOnNext(validationService::validate)
.flatMap { ServerResponse.ok().build() }
.onErrorResume(BodyValidationException::class.java, validationService::handle)
}
}
}
}
data class ValidatingBody(
@get:NotBlank(message = "should not be blank")
var mandatoryText: String?,
@get:Size(min = 2, max = 10, message = "should contain more than 2 and less than 10 characters")
@get:NotBlank(message = "should not be blank")
var sizedText: String?,
@get:Min(value = 1, message = "should be no less than 1")
@get:Max(value = 10, message = "should be no greater than 10")
@get:NotNull(message = "should be specified")
var limitedNumber: Int?
)
}
@Service
class ValidationService(val validator: Validator) {
private val log = LoggerFactory.getLogger(ValidationService::class.java)
@Throws(BodyValidationException::class)
fun <T> validate(o: T) {
val violations = validator.validate(o)
if (violations.isEmpty()) return
throw BodyValidationException.of(violations.stream()
.map { v: ConstraintViolation<T> -> "${v.propertyPath} ${v.message}" }
.collect(Collectors.toSet()).toMutableSet())
}
fun handle(e: BodyValidationException): Mono<ServerResponse> =
handleInternal(ErrorResponse(e.errors))
private fun handleInternal(response: ErrorResponse): Mono<ServerResponse> =
Mono.just(response)
.doOnNext { res -> log.warn(res.errors.joinToString(",")) }
.flatMap { res ->
badRequest().contentType(APPLICATION_JSON)
.bodyValue(res)
}
data class ErrorResponse(val errors: Set<String>)
class BodyValidationException private constructor(var errors: Set<String>) : IllegalArgumentException() {
companion object {
fun of(errors: Set<String>): BodyValidationException {
return BodyValidationException(errors)
}
}
}
}