如何处理在Spring MVC中呈现视图时抛出的exception?

我有一个Spring MVC应用程序,它使用FreeMarker作为View技术(但也许视图技术对我的问题并不重要)。 我需要拦截在请求期间可能抛出的所有exception。

我已经实现了HandlerExceptionResolver,但只有在控制器中发生exception时才会执行此解析程序。 但是当控制器返回ModelAndView并且在渲染视图时发生exception(因为找不到变量或类似的东西),则不会调用exception解析器,而是在浏览器窗口中获得堆栈跟踪。

我还尝试在控制器中使用exception处理程序方法,该方法返回视图并使用@ExceptionHandler对其进行注释,但这也不起作用(很可能是因为exception不会在控制器中抛出但在视图中)。

那么是否有一些Spring机制可以注册一个捕获视图错误的exception处理程序?

提前说一句:如果你只需要一个没有太多逻辑和模型准备的“静态”错误页面,那么将 -Tag放在你的web.xml就足够了(参见下面的例子)。

否则,可能有更好的方法来做到这一点,但这对我们有用:

我们在web.xml中使用servlet 来捕获所有Exceptions并调用我们的自定义ErrorHandler,我们在Spring HandlerExceptionResolver中使用它。

  errorHandlerFilter org.example.filter.ErrorHandlerFilter   errorHandlerFilter /*  

实现看起来基本上是这样的:

 public class ErrorHandlerFilter implements Filter { ErrorHandler errorHandler; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { try { filterChain.doFilter(request, response); } catch (Exception ex) { // call ErrorHandler and dispatch to error jsp String errorMessage = errorHandler.handle(request, response, ex); request.setAttribute("errorMessage", errorMessage); request.getRequestDispatcher("/WEB-INF/jsp/error/dispatch-error.jsp").forward(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { errorHandler = (ErrorHandler) WebApplicationContextUtils .getRequiredWebApplicationContext(filterConfig.getServletContext()) .getBean("defaultErrorHandler"); } // ... } 

我相信这应该对FreeMarker模板几乎一样。 当然,如果您的错误视图引发错误,那么您或多或少都会出现选项。

为了捕获像404这样的错误并为它准备模型,我们使用映射到ERROR调度程序的filter:

  errorDispatcherFilter org.example.filter.ErrorDispatcherFilter   errorDispatcherFilter /* ERROR   404 /WEB-INF/jsp/error/dispatch-error.jsp   java.lang.Exception /WEB-INF/jsp/error/dispatch-error.jsp  

doFilter-Implementation看起来像这样:

 @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) servletRequest; // handle code(s) final int code = (Integer) request.getAttribute("javax.servlet.error.status_code"); if (code == 404) { final String uri = (String) request.getAttribute("javax.servlet.error.request_uri"); request.setAttribute("errorMessage", "The requested page '" + uri + "' could not be found."); } // notify chain filterChain.doFilter(servletRequest, servletResponse); } 

您可以扩展DispatcherServlet。

在您的web.xml中,替换您自己的类的通用DispatcherServlet。

  springmvc com.controller.generic.DispatcherServletHandler 1  

稍后创建自己的类DispatcherServletHandler并从DispatcherServlet扩展:

 public class DispatcherServletHandler extends DispatcherServlet { private static final String ERROR = "error"; private static final String VIEW_ERROR_PAGE = "/WEB-INF/views/error/view-error.jsp"; @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { try{ super.doService(request, response); } catch(Exception ex) { request.setAttribute(ERROR, ex); request.getRequestDispatcher(VIEW_ERROR_PAGE).forward(request, response); } } } 

在该页面中,我们只需向用户显示一条消息。

不确定我的解决方案是否适用于您遇到的问题。 我只是发布我捕获exception的方式,以确保浏览器中没有显示堆栈跟踪:

我创建了一个AbstractController类,其方法可以处理特定的冲突,如下所示:

 public class AbstractController { @ResponseStatus(HttpStatus.CONFLICT) @ExceptionHandler({OptimisticLockingFailureException.class}) @ResponseBody public void handleConflict() { //Do something extra if you want } } 

这样,每当发生exception时,用户将看到默认的HTTPResponse状态。 (例如,404 Not Found等…)

我在所有控制器类上扩展此类,以确保将错误重定向到AbstractController。 这样我就不需要在特定的控制器上使用ExceptionHandler,但我可以将全局添加到我的所有控制器。 (通过扩展AbstractController类)。

编辑:继续你的问题后,我注意到你的视图中出现了错误。 不确定这种方式是否会捕获该错误..

希望这可以帮助!!