问题
I am trying to use bean validation in Webflux. This is what I have so far:
@PostMapping("contact")
fun create(@RequestBody @Valid contact: Mono<Contact>) : Mono<Contact> {
return contact.flatMap { contactRepository.save(it) }
.doOnError{ Error("test") }
}
The The validation doesn't work... I would expect that the Error("test")
would be shown...
Does someone has a working example(Java or Kotlin)?
UPDATE
Here is a repository so it can be reproducted: https://github.com/jwz104/webflux-validation-test
Request:
curl --request POST \
--url http://localhost:8080/tickets \
--header 'content-type: application/json' \
--data '{
"email": "",
"name": "",
"message": ""
}'
Renamed contact to ticket, but everything is still the same.
回答1:
The annotations you have placed in the example project are actually annotations on the constructor parameters of the Ticket
class. For Spring validation, you need to annotate the fields instead. You can do this in Kotlin by using annotation use-site targets.
In this specific case, your Ticket class should look like this:
data class Ticket(
@field:Id
@field:JsonSerialize(using = ToStringSerializer::class)
val id: ObjectId = ObjectId.get(),
@field:Email
@field:Max(200)
@field:NotEmpty
val email: String,
@field:NotEmpty
@field:Size(min = 2, max = 200)
val name: String,
@field:NotEmpty
@field:Size(min = 10, max = 2000)
val message: String
)
This, along with the following controller function will work and return errors as expected:
@PostMapping("tickets")
fun create(@RequestBody @Valid contact: Mono<Ticket>) : Mono<Ticket> {
return contact.flatMap { ticketRepository.save(it) }
.doOnError{ Error("test") }
}
回答2:
I had to combine few of the answers from SO to get the validation correct. What I did was:
Made my data class as suggested here.
- Then i used
javax.validation.Validator
class to validate the data class.
- Then i used
import javax.validation.Validator
import javax.validation.ConstraintViolationException
@Service
open class MyService {
@Autowired
lateinit var repository: UserRepository
@Autowired
lateinit var validator: Validator
open fun createUser(user: User): Mono<User> {
val violations = validator.validate(user)
//if it violates our constraints, it will throw an exception, which we
//handle using global exception handler
if(violations.isNotEmpty()){
throw ConstraintViolationException(violations)
}
return repo.save(user)
}
. . .
}
- Add these lines in application.properties.
spring.mvc.throw-exception-if-no-handler-found=true spring.resources.add-mappings=false
And to catch the exceptions.
@RestControllerAdvice
open class ExceptionHandlers {
@ExceptionHandler(ConstraintViolationException::class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
fun throwConstraintViolationExcetion(ex: ConstraintViolationException): ApiResponse {
return ApiResponse (message= ex.message.toString(), data= null);
}
}
p.s ApiResponse
is just a data class that takes server message & data as parameters.
No need to handle errors in @Controller
as it will be thrown by the @Service
class
回答3:
You need to also add bindingResult: BindingResult
to as an extra parameter. When the method begins you can do something like bindingResult.isValid()
. We use an aspect over all controller methods to return an error message with the validation errors to the user.
来源:https://stackoverflow.com/questions/48439953/spring-webflux-bean-validation-not-working