英文:
Handle a MethodArgumentNotValidException from a WebSocket message
问题
我正在使用Spring WebSocket,我有一个使用验证注解注释的Model,希望在保存之前捕获其验证消息。考虑我正在测试的这个@Controller
:
@Controller
public class MessageThreadController {
/* 与MessageThread匹配的带有JSON主体的普通XHR post请求。 */
@RequestMapping(
headers={"Accept=application/hal+json", "Content-Type=application/json", "X-Requested-With=XMLHttpRequest"},
method={RequestMethod.POST},
produces="application/hal+json",
value="/api/unsecure/thread/create")
public HttpEntity createPost(@Valid @RequestBody MessageThread messageThread) throws Exception {
return ResponseEntity.ok("valid");
}
/* 与上面相同的请求,但适用于WebSocket。*/
@MessageMapping("/api/secure/thread/create")
@SendToUser("/api/secure/broadcast")
public HttpEntity createMessage(@Valid @RequestBody MessageThread messageThread) throws Exception {
return ResponseEntity.ok("valid");
}
}
我有一个@ControllerAdvice
来捕获可能发生的Exception
:
@ControllerAdvice
public class MessageThreadControllerAdvice {
private static final Logger log = LoggerFactory.getLogger(MessageThreadControllerAdvice.class);
/* 处理MessageThreadController.createPost()验证异常。 */
@ExceptionHandler(org.springframework.web.bind.MethodArgumentNotValidException.class)
public void methodArgumentNotValidExceptionHandler(
org.springframework.web.bind.MethodArgumentNotValidException e) {
log.trace("methodArgumentNotValidExceptionHandler");
}
/* 处理MessageThreadController.createMessage()验证异常。 */
@ExceptionHandler(org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException.class)
@SendToUser("/api/secure/broadcast")
public void methodArgumentNotValidWebSocketExceptionHandler(
org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException e) {
log.trace("methodArgumentNotValidWebSocketExceptionHandler");
}
/* 在这里处理所有异常。 */
@ExceptionHandler
@SendToUser("/api/secure/broadcast")
public void exceptionHandler(Exception e) {
log.trace("exceptionHandler");
}
}
以下是涉及的对象:
@Getter @Setter
public class MessageThread {
@Size(min=1, message="{validation.userIds.empty}")
@NotNull(message="{validation.userIds.null}")
private Set<BigInteger> userIds;
}
如果我在MessageThreadController.createPost()
和MessageThreadController.createMessage()
中发送以下JSON主体:
{"userIds":[]}
则会触发验证。问题是只有MessageThreadController.createPost()
的异常得到处理,而MessageThreadController.createMessage()
的异常未被处理:
2020-08-21 11:54:00.651 ERROR 4444 --- [nboundChannel-4] .WebSocketAnnotationMethodMessageHandler : Unhandled exception from message handler method
org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException: Could not resolve method parameter at index 0 in public void controller.MessageThreadController.createMessage(model.form.MessageThread) throws java.lang.Exception: 1 error(s): [Field error in object 'messageThread' on field 'userIds': rejected value [[]]; codes [Size.messageThread.userIds,Size.userIds,Size.java.util.Set,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [messageThread.userIds,userIds]; arguments []; default message [userIds],2147483647,1]; default message [size must be between 1 and 2147483647]]
我如何处理在WebSocket消息上抛出的MethodArgumentNotValidException
?
英文:
Im using Spring WebSocket and I have a Model annotated with validation annotations and want to capture the validation message it has before saving. Consider this @Controller
I am testing:
@Controller
public class MessageThreadController {
/* A plain XHR post request with a JSON body to match MessageThread. */
@RequestMapping(
headers={"Accept=application/hal+json", "Content-Type=application/json", "X-Requested-With=XMLHttpRequest"},
method={RequestMethod.POST},
produces="application/hal+json",
value="/api/unsecure/thread/create")
public HttpEntity createPost(@Valid @RequestBody MessageThread messageThread) throws Exception {
return ResponseEntity.ok("valid");
}
/* The same request above but for WebSocket.*/
@MessageMapping("/api/secure/thread/create")
@SendToUser("/api/secure/broadcast")
public HttpEntity createMessage(@Valid @RequestBody MessageThread messageThread) throws Exception {
return ResponseEntity.ok("valid");
}
}
And I have a @ControllerAdvice
to capture the Exception
s that may happen:
@ControllerAdvice
public class MessageThreadControllerAdvice {
private static final Logger log = LoggerFactory.getLogger(MessageThreadControllerAdvice.class);
/* MessageThreadController.createPost() validation exception are handled here. */
@ExceptionHandler(org.springframework.web.bind.MethodArgumentNotValidException.class)
public void methodArgumentNotValidExceptionHandler(
org.springframework.web.bind.MethodArgumentNotValidException e) {
log.trace("methodArgumentNotValidExceptionHandler");
}
/* MessageThreadController.createMessage() validation exception are handled here. */
@ExceptionHandler(org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException.class)
@SendToUser("/api/secure/broadcast")
public void methodArgumentNotValidWebSocketExceptionHandler(
org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException e) {
log.trace("methodArgumentNotValidWebSocketExceptionHandler");
}
/* All exceptions are handled here. */
@ExceptionHandler
@SendToUser("/api/secure/broadcast")
public void exceptionHandler(Exception e) {
log.trace("exceptionHandler");
}
}
And here is the object in question:
@Getter @Setter
public class MessageThread {
@Size(min=1, message="{validation.userIds.empty}")
@NotNull(message="{validation.userIds.null}")
private Set<BigInteger> userIds;
}
If I were to send the following JSON body in both MessageThreadController.createPost()
and MessageThreadController.createMessage()
:
{"userIds":[]}
the validation kicks in. The problem is that only the exception from MessageThreadController.createPost()
gets handled while the exception from MessageThreadController.createMessage()
is not handled:
>2020-08-21 11:54:00.651 ERROR 4444 --- [nboundChannel-4] .WebSocketAnnotationMethodMessageHandler : Unhandled exception from message handler method
>
> org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException: Could not resolve method parameter at index 0 in public void controller.MessageThreadController.createMessage(model.form.MessageThread) throws java.lang.Exception: 1 error(s): [Field error in object 'messageThread' on field 'userIds': rejected value [[]]; codes [Size.messageThread.userIds,Size.userIds,Size.java.util.Set,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [messageThread.userIds,userIds]; arguments []; default message [userIds],2147483647,1]; default message [size must be between 1 and 2147483647]]
How can I handle the MethodArgumentNotValidException
that is thrown on a websocket message?
答案1
得分: 2
你可以在你的@ControllerAdvice
方法上加上@MessageExceptionHandler
注解。
@ControllerAdvice
public class MessageThreadControllerAdvice {
private static final Logger log = LoggerFactory.getLogger(MessageThreadControllerAdvice.class);
/* 处理MessageThreadController.createPost()的验证异常。 */
@ExceptionHandler(org.springframework.web.bind.MethodArgumentNotValidException.class)
public void methodArgumentNotValidExceptionHandler(
org.springframework.web.bind.MethodArgumentNotValidException e) {
log.trace("methodArgumentNotValidExceptionHandler");
}
/* 处理MessageThreadController.createMessage()的验证异常。 */
@MessageExceptionHandler(org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException.class)
@SendToUser("/api/secure/broadcast")
public void methodArgumentNotValidWebSocketExceptionHandler(
org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException e) {
log.trace("methodArgumentNotValidWebSocketExceptionHandler");
}
/* 所有异常在此处理。 */
@ExceptionHandler
@SendToUser("/api/secure/broadcast")
public void exceptionHandler(Exception e) {
log.trace("exceptionHandler");
}
}
这个注解也可以应用在@Controller
级别上。
请注意,自Spring 4.2起,这个注解在@ControllerAdvice
级别也是支持的。
英文:
You can annotate your @ControllerAdvice
method with the @MessageExceptionHandler
annotation.
@ControllerAdvice
public class MessageThreadControllerAdvice {
private static final Logger log = LoggerFactory.getLogger(MessageThreadControllerAdvice.class);
/* MessageThreadController.createPost() validation exception are handled here. */
@ExceptionHandler(org.springframework.web.bind.MethodArgumentNotValidException.class)
public void methodArgumentNotValidExceptionHandler(
org.springframework.web.bind.MethodArgumentNotValidException e) {
log.trace("methodArgumentNotValidExceptionHandler");
}
/* MessageThreadController.createMessage() validation exception are handled here. */
@MessageExceptionHandler(org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException.class)
@SendToUser("/api/secure/broadcast")
public void methodArgumentNotValidWebSocketExceptionHandler(
org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException e) {
log.trace("methodArgumentNotValidWebSocketExceptionHandler");
}
/* All exceptions are handled here. */
@ExceptionHandler
@SendToUser("/api/secure/broadcast")
public void exceptionHandler(Exception e) {
log.trace("exceptionHandler");
}
}
This annotation could be also applied at the @Controller
level.
Please, be aware that this annotation is supported at @ControllerAdvice
level since Spring 4.2.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论