本文介绍了为什么Spring MVC不允许将Model或BindingResult公开给@ExceptionHandler?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试对记录异常的代码进行分组,并通过几种方法呈现出漂亮的视图。目前,逻辑有时在 @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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-24 12:38