JSF 2.0:重定向后如何保存视图(target = blank)

时间:2011-03-24 21:19:15

标签: jsf redirect jsf-2 target

想象一下,我有jsf表单和打印表单数据报表的按钮。该按钮需要在新页面上打开数据(目标=空白),但 h:按钮不适合我需要在报告之前保存数据页面打开。因此,我使用 h:commandButton 进行保存操作,然后重定向到报告页面:

<h:commandLink styleClass="reportButton" action="#{polisBean.doReportPrint}"
                    target="_blank" id="reportListLink">
                    Print report
                </h:commandLink>

@ViewScoped
@Named
public class PolisBean
  ...
  public Object doReportPrint() {        
    if (canEdit() && this.submit() == null) {
        return null;
    }

    return "printReport";
}
<navigation-case>
        <from-outcome>printReport</from-outcome>
        <to-view-id>/polises/reportList.xhtml</to-view-id>
        <redirect include-view-params="true">
            <view-param>
                <name>id</name>
                <value>#{polis.id}</value>
            </view-param>
        </redirect>
    </navigation-case>

实体保存完好,新页面随报告打开。好。但是当我回到初始表单页面并尝试再次保存时 - 视图已过期并由new构建(因为这不是回发请求,这对JSF来说是一个全新的请求,因为我只是从这个重定向页!)。虽然重定向是在打开第二页时完成的,但这并不能防止丢失所有视图范围的bean数据..

我尝试了来自CDI的长时间运行的 conversationScope ,但当我转回到它时,它会抛出“ContextNotActiveException:WELD-001303范围类型javax.enterprise.context.ConversationScoped没有活动上下文”异常初始页......

有人解决了这个问题吗?如何通过重定向(到新页面)提交表单但不会丢失初始数据?

2 个答案:

答案 0 :(得分:2)

如果有人有兴趣,我找到了解决方法。不是很漂亮,但允许使用重定向到“空白”页面:

收据是在新窗口中打开链接后刷新初始页面(参见 onclick ):

<h:commandLink styleClass="reportButton" action="#{polisBean.doReportPrint()}" onclick="window.setTimeout(refreshPage, 2000)"
                    target="_blank" id="reportListLink" >
                    print report
                </h:commandLink>

但这并不像看起来那么简单,我不能使用简单的location.reload()或类似的smth。在 doReportPrint()方法中,我执行保存操作,如果实体不存在,则创建它。当我对我的应用程序使用GET参数化请求时,我需要使用以下 id 参数的地址刷新页面:

/polises/polis.jsf?id=80

因此,需要完成新的jsf请求,而不是简单的JS刷新,它包含新创建的实体的id。所以我使用这种方法:

doReportPrint 中,我将新创建的ID保存到会话中:

public Object doReportPrint() {        
    if (canEdit() && this.submit() == null) {
        return null;
    }
    context().getExternalContext().getSessionMap().put("justUpdatedPolisId", entity.getId());        
    return "printReport";
}

初始页面的刷新按以下方式完成:

public Object doRefresh() {
    Object justUpdatedPolisId = context().getExternalContext().getSessionMap().get("justUpdatedPolisId");
    if (justUpdatedPolisId != null) {
        entity.setId((Long)justUpdatedPolisId);
        context().getExternalContext().getSessionMap().remove("justUpdatedPolisId");
        return "save";
    }
    // If for some reasons we have not found it - moving to polises table
    return "polises?faces-redirect=true";
}

保存结果会导致polis.jsf重新打开(使用faces-config导航),并且ID会自动从 entity.id 附加

另一个技巧是如何从JS调用JSF动作。我试图模仿 h:commandLink 点击(只是为链接复制了生成的JS代码),但这不起作用,因为视图被重新创建并且bean和它的属性相同,操作简单没被叫。所以我在PrimeFaces p:commandLink 中使用了JS代码,它对我很有用(别忘了将“更新”设置为@none并将“处理”设置为@this):

<script type="text/javascript"> 
   function refreshPage() {
                        PrimeFaces.ajax.AjaxRequest('/KaskoCalculator/polises/polis.jsf',{formId:'polisForm',async:false,global:true,source:'polisForm:doRefresh',process:'polisForm:doRefresh',update:'@none'});
                        }
   </script>

现在,报告保存并在新窗口中打开后,初始页面将在2秒内刷新。太丑了,太累了,但它对我有用。可能会帮助其他人。

答案 1 :(得分:0)

我面临同样的问题。 使用p:commandLink或h:commandLink with target = _blank,初始页面支持bean数据在打开新窗口后消失。

刷新将返回页面的初始状态而不进行ajax更新。但是我需要在点击打印命令之前保持相同的状态。