问题描述
我正在尝试对记录异常的代码进行分组,并通过几种方法呈现出漂亮的视图。目前,逻辑有时在 @RequestHandler
本身中(在 catch 块中),有时则委托给实用程序类(有效
I'm trying to group the code that logs the exceptions and render a nice view in a few methods. At the moment the logic is sometime in the @RequestHandler
itself (in the a catch block), othertimes is delegated to an utility class (that works but moves the logic away from the place where the exception is thrown).
Spring的 @ExceptionHandler
似乎是解决问题的方法将所有内容都集中在一个位置(控制器本身或父级),并摆脱一些代码(无需将逻辑放在 try-catch 中,并且不需要实用程序类)...直到我意识到 @ExceptionHandler
方法将没有 ModelMap
或 BindingResult
参数自动连线。当前,这些对象用于通过合理的错误消息呈现视图,我们也希望记录这些对象中包含的一些信息。
Spring's @ExceptionHandler
seemed the way to group everything in one place (the controller itself or a parent) and get rid of some code (no need to put logic in the try-catch and no need for an utility class)... until I realized that an @ExceptionHandler
methods won't have the ModelMap
or BindingResult
parameters autowired. Currently those objects are used to render the view with a sensible error message and we want to log some information contained in these objects as well.
为什么Spring不支持 ModelMap
或 BindingResult
这样的方法参数 @ExceptionHandler
?
Why Spring doesn't not support method arguments such ModelMap
or BindingResult
for the @ExceptionHandler
? What is the rationale behind it?
在Spring源代码(3.0.5)中,该方法的参数在 HandlerMethodInvoker.invokeHandlerMethod
中解析。由请求处理程序引发的异常在那里被捕获并重新抛出。 @ExceptionHandler
及其参数在其他位置解析。作为一种解决方法,我认为应检查Exception是否实现了假设的 ModelAware或 BindingResultAware接口,在这种情况下,请在重新抛出之前设置Model和BindingResult属性。
听起来如何?
In the Spring source code (3.0.5) the arguments for the method are resolved in the HandlerMethodInvoker.invokeHandlerMethod
. A an exception thrown by the request handler is caught there and re-thrown. The @ExceptionHandler
and it's parameters are resolved elsewhere. As a workaround I thought to check if the Exception implements an hypothetical "ModelAware" or "BindingResultAware" interface, and in that case set Model and BindingResult attributes before re-throwhing it.How does it sound?
推荐答案
如前所述,可以使用某种方法包装绑定结果对象引发异常
As stated before you can raise an exception wrapping a binding result object in some method of your controller:
if (bindingResult.hasErrors()) {
logBindingErrors(bindingResult);
//return "users/create";
// Exception handling happens later in this controller
throw new BindingErrorsException("MVC binding errors", userForm, bindingResult);
}
例外情况如下所示:
public class BindingErrorsException extends RuntimeException {
private static final Logger log = LoggerFactory.getLogger(BindingErrorsException.class);
private static final long serialVersionUID = -7882202987868263849L;
private final UserForm userForm;
private final BindingResult bindingResult;
public BindingErrorsException(
final String message,
final UserForm userForm,
final BindingResult bindingResult
) {
super(message);
this.userForm = userForm;
this.bindingResult = bindingResult;
log.error(getLocalizedMessage());
}
public UserForm getUserForm() {
return userForm;
}
public BindingResult getBindingResult() {
return bindingResult;
}
}
接下来,您只需从提出然后捕获异常。在这里,假设您在控制器上定义了合适的异常处理程序。它可能在控制器建议中甚至在其他地方。请参阅Spring文档以获取适当的位置。
Next you just have to extract the required information from the raised then caught exception. Here assuming you have a suitable exception handler defined on your controller. It might be in a controller advice instead or even elewhere. See the Spring documentation for suitable and appropriate locations.
@ExceptionHandler(BindingErrorsException.class)
public ModelAndView bindingErrors(
final HttpServletResponse resp,
final Exception ex
) {
if(ex instanceof BindingErrorsException) {
final BindingErrorsException bex = (BindingErrorsException) ex;
final ModelAndView mav = new ModelAndView("users/create", bex.getBindingResult().getModel());
mav.addObject("user", bex.getUserForm());
return mav;
} else {
final ModelAndView mav = new ModelAndView("users/create");
return mav;
}
}
这篇关于为什么Spring MVC不允许将Model或BindingResult公开给@ExceptionHandler?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!