在弹簧过滤器中设置视图名称
Posted
技术标签:
【中文标题】在弹簧过滤器中设置视图名称【英文标题】:Setting view name in spring filter 【发布时间】:2011-04-06 17:11:39 【问题描述】:我有一个ErrorFilter
,它扩展了弹簧GenericFilterBean
。如果发生错误,我想显示一个用瓷砖装饰的错误页面。
有没有办法从过滤器中设置视图名称?
<filter>
<filter-name>errorFilter</filter-name>
<filter-class>com.abc.filter.ErrorFilter</filter-class>
<init-param>
<param-name>errorPage</param-name>
<param-value>/jsp/errorpage.jsp</param-value>
</init-param>
</filter>
这是web.xml
中的配置,errorfilter
中的doFilter
方法如下:
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException
HttpServletRequest httpReq = (HttpServletRequest) req;
StringBuffer reqUrl = httpReq.getRequestURL();
try
chain.doFilter(req, resp);
catch (Exception ex)
String requestRepresentation = createRequestRepresentation(req);
errorService.handleException(reqUrl.toString(), ex, requestRepresentation);
req.getRequestDispatcher(
getFilterConfig().getInitParameter("errorPage")).forward(req, resp);
catch (Error er)
errorService.handleError(reqUrl.toString(), er);
req.getRequestDispatcher(
getFilterConfig().getInitParameter("errorPage")).forward(req, resp);
当前错误页面没有用瓷砖装饰,所以我想用普通的页眉和页脚装饰它,并从过滤器中调用该视图名称。
有可能吗?
编辑: 基本上我们希望能够做一些类似于控制器方法的事情,即 return "view name";
已经试过了:
httpResponse.sendRedirect("errorPageView"); 不起作用,它重定向到http://server/fooerrorPageView request.getRequestDispatcher("errorPageView").forward(request, response); 也没有,和上面类似(没有http重定向,但是给出了相同的“没有这样的页面错误”内容)李>【问题讨论】:
【参考方案1】:只需检查您的重定向网址。您可以使用 url 访问页面。
public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
throws IOException
String redirectUrl = request.getContextPath() + url;
redirectUrl = response.encodeRedirectURL(redirectUrl);
if (logger.isDebugEnabled())
logger.debug("Redirecting to '" + redirectUrl + "'");
response.sendRedirect(redirectUrl);
【讨论】:
【参考方案2】:过滤器出现在 Spring 之前。 Spring bean 可以使用 ApplicationContextAware 机制注入到 Filter 中,但是形成 Spring MVC 视图意味着您必须在 Filter 中获取整个 Spring MVC 框架。我认为这是不可能的,您将不得不使用 RequestDispatcher 将请求转发到弹簧视图,而不是您自己的自定义视图。
【讨论】:
【参考方案3】:为什么不用spring的错误处理机制呢?这里是关于它的好帖子(带有示例) - https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
除此之外,不确定是否有一种干净的方法可以做到这一点。其他建议可能是调用您的应用程序以获取错误页面响应并用它替换响应输出(在这种情况下,您还需要使用“缓冲”http 响应以确保流尚未刷新)或进行重定向到错误网址。
【讨论】:
如果提问者想从控制器显示错误页面,您的建议有效。他想要的是在请求传递到控制器之前从 Servlet 过滤器中构建一个错误页面。所以,异常处理在这里不起作用。不过,您的第二个建议值得注意。 感谢您的回复和评价,但是为什么您认为servlet过滤器无法捕获spring控制器中或spring控制器执行后抛出的异常(换句话说,在控制器执行后返回的路上) )? 我回答的重点是: - 如果可以,请使用 sring 功能 - 如果您(无论出于何种原因)无法使用它,重定向或响应解析(在过滤器中)仍然是一个选项.但这可能只有在尚未提交响应的情况下才有效。有意义吗? 我完全按照你的描述做了。在我的自定义身份验证过滤器中,我检查了身份验证,如果出现任何异常,我将请求转发到控制器,将错误属性添加到请求对象。在转发时,我检查了响应是否已经提交。我还增加了缓冲区限制以避免无意刷新。在控制器中,我从请求对象中获取添加的属性并从那里返回错误页面视图。您能否指导我从过滤器中创建错误页面视图?我可以在过滤器中处理异常吗?【参考方案4】:我认为这是不可能的,因为这是一个 servlet 过滤器,它将在应用 spring 请求映射器 servlet 之后应用。所以基本上,请求映射器 servlet 认为它已经完成,并将请求传递回 servlet 容器。
视图名称只能在 spring 内部工作 - 在 spring 之外,在 servlet 容器中,您将不得不谈论 url,而不是视图名称。
重定向到特定的 url 会起作用。为此,您必须了解重定向和转发之间的区别。
重定向将以下标头发送到客户端:
位置:http://server/new/location
连同状态码301(永久重定向,让客户端知道它可以缓存此信息)或307(临时重定向,告诉客户端下次应该再次询问,因为重定向可能会改变)
请求分派器上的转发基本上模拟了一个新请求,您可以将请求发送到同一容器中的任何 servlet。这意味着,您还必须考虑上下文路径,这意味着@iimuhin 给出的答案:
response.sendRedirect(
request.getContextPath() +
getFilterConfig().getInitParameter("errorPage"));
实际上是正确的方法。您可以(应该)添加日志记录以查看实际发生的情况以及实际使用的路径。
另外 - 你必须注意缓冲。 servlet 响应通常是缓冲的,在缓冲区满或整个处理完成之前,不会向客户端发送任何内容。
当它被刷新时,标题首先被写入。这意味着在刷新响应后更改标头是不可能的,因为它们已经发送出去了。
这就是 servlet 可以强制刷新但通常不应该强制刷新的原因。
在您的情况下,您可能希望增加响应的缓冲区大小:
response.setBufferSize(int size)
在调用 chain.doFilter() 之前避免过早刷新。
【讨论】:
非常感谢您对此事的详细解释。 +1 提及重定向和转发之间的区别。【参考方案5】:Spring MVC 一定有办法做到这一点,但我想重定向就足够了。
try
chain.doFilter(req, resp);
catch (Exception ex)
if (response.isCommitted())
log(ex); // at least a part of the response is already sent to the client, you can't do much about it
else
session.setAttribute("last.exception", ex);
response.sendRedirect(request.getContextPath() + getFilterConfig().getInitParameter("errorPage"));
附:不要捕获错误!
【讨论】:
sendRedirect 只会将客户端浏览器重定向到指定的 URL,绕过任何视图名称解析。以上是关于在弹簧过滤器中设置视图名称的主要内容,如果未能解决你的问题,请参考以下文章
sharepoint 2013列表视图Webpart过滤器下拉列表