我有一个使用的FreeMarker作为View技术在Spring MVC应用程序(但是,也许从技术上看并不重要,我的问题)。 我需要拦截可能的请求时抛出的所有异常。
我实现了一个HandlerExceptionResolver但当异常的控制器内发生时,才会执行此解析器。 但是,当一个控制器返回一个ModelAndView并在渲染视图(因为一个变量没有被发现或类似这样的东西),那么异常解析器不叫出现异常,而是我得到在浏览器窗口中的堆栈跟踪。
我使用它返回视图控制器内的异常处理方法还试图与@ExceptionHandler注解,但这个也行不通(很可能再次因为异常没有在控制器,但在视图中抛出)。
所以有一些弹簧机构在那里我可以注册拍摄观点错误的异常处理程序?
一个字前期:如果你只需要没有太多的逻辑和模型制作一个“静态”的错误页面,它应该足以把<error-page>
-Tag在web.xml
(见下面的例子)。
否则,可能会有更好的方式来做到这一点,但是这为我们工作:
我们使用servlet <filter>
在web.xml
来捕获所有异常并调用我们自定义的ErrorHandler,我们春节HandlerExceptionResolver内使用相同的。
<filter>
<filter-name>errorHandlerFilter</filter-name>
<filter-class>org.example.filter.ErrorHandlerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>errorHandlerFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
实现基本是这样的:
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>
<filter-name>errorDispatcherFilter</filter-name>
<filter-class>org.example.filter.ErrorDispatcherFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>errorDispatcherFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/jsp/error/dispatch-error.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/WEB-INF/jsp/error/dispatch-error.jsp</location>
</error-page>
在doFilter的-实施看起来是这样的:
@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会为自己的类。
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>com.controller.generic.DispatcherServletHandler</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
后来创建自己的类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);
}
}
}
而在这页我们只显示一条消息给用户。
如果我的解决方案与您遇到的问题工作不能确定。 生病只是后我明白我的例外,以确保没有堆栈跟踪是在浏览器中显示的方式:
我做了一个AbstractController类,将处理这样的具体冲突的方法:
public class AbstractController {
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler({OptimisticLockingFailureException.class})
@ResponseBody
public void handleConflict() {
//Do something extra if you want
}
}
这样,每当发生异常时,用户将看到一个默认类HTTPResponse状态。 (例如404未找到等。)
我向我所有的控制器类这个类,以确保错误被重定向到一个AbstractController。 这样我就不需要使用的ExceptionHandler特定的控制器上,但我可以在全球范围添加到我的所有控制器。 (通过扩展一个AbstractController类)。
编辑:在您的问题别的去了之后,我注意到你要在你的观点的错误。 不知道这样会赶上这个错误..
希望这可以帮助!!