【问题标题】:JSF issue with back button [duplicate]后退按钮的 JSF 问题[重复]
【发布时间】:2012-05-18 05:04:08
【问题描述】:

我在使用后退按钮时遇到问题,没有将数据保存在请求范围 bean 上的 JSF 中的动态下拉列表中。

我有一个带有 2 个下拉列表的表单,其中 dropdown2 是基于在 dropdown1 中选择的动态的。下面是这些下拉菜单的代码。

<h:selectOneMenu id="group" label="group" value="#{queryBacking.groupInternalId}">
    <f:ajax event="valueChange" render="membership" />
    <f:selectItems value="#{supportBean.groupInstitutions}" var="group" itemValue="#{group.institutionInternalId}" itemLabel="#{group.institutionName}" />
</h:selectOneMenu>

<h:selectOneMenu id="membership" label="Membership" value="#{queryBacking.institutionInternalId}">
    <f:selectItem itemLabel="Select One" itemValue="0" />
    <f:selectItems value="#{queryBacking.groupMembershipInstitutions}" var="institution" itemValue="#{institution.institutionInternalId}" itemLabel="#{institution.institutionShortName}" />
</h:selectOneMenu>

我的代码运行良好,但如果您提交表单然后单击后退按钮,则 dropdown2 不包含任何值。如何解决这个问题?

【问题讨论】:

  • 将范围更改为会话或使用会话中的值初始化页面加载上的值
  • 我已经尝试将范围更改为会话并且可行,但我不喜欢会话范围的原因是因为如果用户打开了 2 个选项卡,如果他们打开会话范围会弄乱数据在选项卡 1 中运行新搜索,然后刷新选项卡 2。
  • 我知道从请求到会话范围的问题,这就是为什么我还说您可以使用会话中的值初始化页面上的值。另外,您使用的 JSF 版本是什么?
  • 我不确定你的意思是用会话中的值初始化页面上的值。你能详细说明吗?我正在使用 JSF 2.0

标签: jsf back-button


【解决方案1】:

您可以在 bean 构造函数中初始化页面的值:

TestBean 类

@ManagedBean
@ViewScope
public class TestBean {
    private String name;

    public TestBean() {
        //initialize the name attribute

        //recover the value from session
        HttpSession session = (HttpSession)FacesContext.getCurrentInstance()
            .getExternalContext().getSession(false);
        name = session.getAttribute("name");
        if (name == null) {
            name = "Luiggi";
        }
    }

    public String someAction() {
        //save the value in session
        HttpSession session = (HttpSession)FacesContext.getCurrentInstance()
            .getExternalContext().getSession(false);
        session.setAttribute("name", name);
        return "Test";
    }

    //getters and setters...
}

Test.xhtml

<ui:composition
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html">
    <h:body>
        <h:outputText value="Hello " />
        <h:outputText value="#{testBean.name}" />
        <h:form>
            <h:outputText value="Write your name: " />
            <h:inputText value="#{testBean.name}" />
            <br />
            <h:commandButton value="Change name" action="#{testBean.someAction}" />
        </h:form>
    </h:body>
</ui:composition>

添加示例以在导航到 Text.xhtml 之前删除会话属性

SomeBean 类

@ManagedBean
@RequestScope
public class SomeBean {
    public SomeBean() {
    }
    public String gotoTest() {
        //removes an item from session
        HttpSession session = (HttpSession)FacesContext.getCurrentInstance()
            .getExternalContext().getSession(false);
        session.removeAttribute("name");
        return "Test";
    }
}

SomeBean.xhtml

<ui:composition
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html">
    <h:body>
        <h:form>
            <!-- Every time you navigate through here, your "name" 
                 session attribute will be removed. When you hit the back
                 button to get Test.xhtml you will see the "name"
                 session attribute that is actually stored. -->
            <h:commandButton value="Go to Test" action="#{someBean.gotoTest}" />
        </h:form>
    </h:body>
</ui:composition>

【讨论】:

  • 这不起作用,因为它是视图范围的,所以当您点击搜索按钮时,您会转到一个新视图,因此 bean 会死掉。当您点击后退按钮时,bean 会再次重新创建。
  • 等等,但是仅仅因为 viewscoped bean 死了,这是否意味着会话中的任何东西也死了,还是会话数据仍然存在?
  • 是的,当您点击后退按钮时,请求和查看范围会重新创建,但会话仍然存在,直到它过期(检查 web.xml 中的会话超时)或浏览器关闭(当然, 本例中不使用 cookie)。
  • 好的,这似乎可行,但我仍然遇到的问题是,如果您打开另一个选项卡,下拉列表中会填充来自会话的数据。
  • 在导航/重定向到您的页面之前,您应该检查会话变量是否不存在。
【解决方案2】:

你是指浏览器中的后退按钮吧?

浏览器可能会从浏览器缓存中加载页面。因此,您需要使用过滤器禁用缓存:

public class NoCacheFilter implements Filter {
    private FilterConfig config;

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpReq = (HttpServletRequest) request;
        HttpServletResponse httpRes = (HttpServletResponse) response;

        if (!httpReq.getRequestURI().startsWith(
                httpReq.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { 

            httpRes.setHeader("Cache-Control",
                    "no-cache, no-store, must-revalidate"); // HTTP 1.1.
            httpRes.setHeader("Pragma", "no-cache"); // HTTP 1.0.
            httpRes.setDateHeader("Expires", 0); // Proxies.
        }

        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        config = null;
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        this.config = config;
    }
}

然后将这个添加到web.xml中:

<filter>
  <filter-name>NoCacheFilter</filter-name>
  <filter-class>yourpackage.NoCacheFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>NoCacheFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

您可以在&lt;url-pattern&gt; &lt;/url-pattern&gt;中指定要过滤的页面

【讨论】:

  • 我们在元语句中有这些标签,但没有被看到。如上所述在过滤器中将其添加到响应标头中使其工作。谢谢!
猜你喜欢
  • 2011-01-25
  • 2011-12-19
  • 2014-08-29
  • 2014-10-07
  • 2011-01-15
  • 2010-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多