问题是什么: 单击浏览器后退按钮时会发生什么 - >打开一个页面,其viewscoped-managedbean已被销毁 - >使用grid-record-selections从该页面的commandButton提交请求?
我的期望: 重新创建关联的viewscope-managebean,接收网格记录选择,并处理它们,就像从不涉及浏览器后退按钮一样。
我的体验: 不会重新创建关联的viewscope-managebean,也不会接收网格记录选择。必须重新输入URL,或点击浏览器后退按钮后重新输入F5才能再次正常工作。
所以这是成功方案,所有bean都是视图编组bean:
现在,这是涉及浏览器后退按钮的错误情况(从#6开始发生的不同事情):
是否可以使用带浏览器后退按钮的viewscope-beans获得正常体验(就像没有浏览器后退按钮一样)?
这是我的依赖:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>2.1.3</version>
<scope>compile</scope>
</dependency>
请分享您的想法!
答案 0 :(得分:16)
浏览器似乎从其缓存服务页面而不是向服务器发送完整的HTTP GET请求,而您将JSF状态保存方法设置为server
(这是默认值)。
有两种方法可以解决这个问题:
告诉浏览器不要缓存动态JSF页面。您可以借助filter。
来完成此操作@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (!req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
res.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(request, response);
}
将过滤器映射到FacesServlet
或其相同的网址格式。
将JSF状态保存方法设置为client,以便整个视图状态存储在表单的隐藏字段中,而不是存储在服务器端的会话中。
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
过滤方式更可取。
答案 1 :(得分:0)
禁用页面浏览器缓存的缺点是,如果用户使用浏览器返回导航到上一页,则会看到浏览器错误页面。 所以另一种解决方案是使用javascript来识别页面是来自服务器还是来自浏览器缓存:
首先创建一个简单的支持bean,它提供唯一的id(在我的情况下是当前的系统时间):
@Named("browserCacheController")
@RequestScoped
public class BrowserCacheController implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Returns a unique increasing id for each request
* @return
*/
public long getCacheID() {
return System.currentTimeMillis();
}
}
现在,您可以测试是否从服务器或浏览器提供页面,并在当前页面来自浏览器缓存时重定向用户。请参阅jsf页面中的以下javascript代码,该代码不应由浏览器缓存:
<script type="text/javascript">
// check for latestCacheID
if (!isValidCacheID(#{browserCacheController.cacheID})) {
//redirect to some page
document.location="#{facesContext.externalContext.requestContextPath}/index.jsf";
}
// test cacheID if it comes from the server....
function isValidCacheID(currentCacheID) {
if (!('localStorage' in window && window['localStorage'] !== null))
return true; // old browsers not supported
var latestCacheID=localStorage.getItem("org.imixs.latestCacheID");
if (latestCacheID!=null && currentCacheID<=latestCacheID) {
return false; // this was a cached browser page!
}
// set new id
localStorage.setItem("org.imixs.latestCacheID", currentCacheID);
return true;
}
</script>
脚本也可以放在facelet中,使jsf代码更加干净。