ADF af:showPrintablePageBehavior 将所有后续导航命令发送到新的 window

ADF af:showPrintablePageBehavior sends all subsequent navigation commands to a new window

我有一个打印图标,可以呈现表单的可打印版本。

<af:link id="printButton" icon="/images/printer.png">
   <af:showPrintablePageBehavior/>
</af:link>

这部分工作正常,但在您关闭由 <af:showPrintablePageBehavior/> 创建的选项卡后,任何重定向到新页面的尝试都会创建一个新的浏览器选项卡。

执行重定向的按钮是这样定义的,

<af:button text="Search" action="#{backing.searchAction}" 
           partialSubmit="false" immediate="true" id="ab1" />

public String searchAction() {
    return "search" 
}

"search" 是一个导航规则,它在 faces-config.xml 中定义并且如果您在单击按钮之前不调用 <af:showPrintablePageBehavior/> 则可以正常工作。

我试过使用ExternalContext.redirect(page)。我还尝试将 targetFrame 属性定义为 _self,将 _parent 定义为 <af:button>。错误行为与这些方法中的每一种都是一致的。

在您的示例中,万恶之源是 immediate="true" 属性。如果你把它去掉,你的问题就解决了。

但是,为了解释原因,让我们首先从 <af:showPrintablePageBehaviour> 组件和 trinidad-config.xml 文件(嵌套在 WEB-INF 文件夹中)开始。

trinidad-config.xml 文件列出了一个名为 <output-mode> 的元素。默认情况下,它不存在,但您可以手动添加。该元素支持三个值:

  • "default"(或null):默认输出方式
  • "printable":适合可打印页面的输出模式
  • "email": 一种适合通过电子邮件发送页面内容的输出模式

为了将页面内容显示为可打印,output-mode 更改(通常由底层框架)为 "printable"。因此,每次单击 <af:link> 组件时,<output-mode> 值都会设置为 "printable"

trinidad-config.xml的好处是我们可以在其中使用EL表达式,这意味着我们可以动态改变<output-mode>元素的值。例如,可以从 @ManagedBean:

中读取值
 <output-mode>#{printableBehaviorBean.outputMode}</output-mode>

been 本身可以是一个完全简单的 (@RequestScoped) bean。请注意,我使用的是注释而不是基于 XML 的配置,因为您提到您使用的是 ADF 12c,它构建在 JSF-2 之上。

@RequestScoped
@ManagedBean(name = "printableBehaviorBean")
public class PrintableBehaviorBean {
    private String outputMode;

    public void setOutputMode(String outputMode) {
        this.outputMode = outputMode;
    }

    public String getOutputMode() {
        return outputMode;
    }
}

然后,我们可以在另一个bean中注入这个bean,这将帮助我们在Search时导航到"search" activity按钮被按下。该 bean 将有一个嵌套的 @ManagedProperty 成员,它将包含前面的 printableBehaviorBean bean 的一个实例。此外,navigationBean 将引入一个 search() 方法,我们将从 Search 按钮的 action 属性中引用该方法。

这里的技巧是在实际返回导航结果之前,我们将更改 printableBehaviorBeanoutputMode 属性 的值。请记住,这个新值将覆盖现有的 <output-mode> 值,如果 <output-mode> 值之前设置为 "printable",它将恢复为 "default"(这将发生每次我们点击 Search 按钮时)。

@RequestScoped
@ManagedBean(name = "navigationBean")
public class NavigationBean {

    @ManagedProperty(name = "printableBehaviorBean", value="#{printableBehaviorBean}")
    private PrintableBehaviorBean printableBehaviorBean;

    public void setPrintableBehaviorBean(PrintableBehaviorBean printableBehaviorBean) {
        this.printableBehaviorBean = printableBehaviorBean;
    }

    public PrintableBehaviorBean getPrintableBehaviorBean() {
        return printableBehaviorBean;
    }

    public String search() {
        printableBehaviorBean.setOutputMode("default");
        return "search";
    }

}

最后,Search 按钮定义将稍微更改为:

<af:button text="Search" action="#{navigationBean.search}" immediate="true" id="ab1" />

现在,另一个感兴趣的问题是 “为什么删除 immediate="true" 可以解决问题?

immediate="true" 修饰的 UICommand 组件将使框架跳过 "Process validations"、"Update model values" 和 "Invoke application" JSF 生命周期阶段(即第三、四、五期)。我对你的问题的假设是,在 "Invoke application" 阶段之前,ADF 实现 检查 命令组件是否装饰有 <af:showPrintablePageBehaviour> 组件,如果是,然后它以编程方式更改 <output-mode> 元素的值。由于 "Search" 按钮上有 immediate="true",因此该值将保留为 "printable"。这就是为什么当您返回表单时,它会触发一个新标签。

因此,总而言之,或者 删除 immediate="true" 属性, 遵循我建议的 bean 的解决方法。

由于您使用的是 ADF 12c 且 Konstantin Yovkov 描述了该问题,也许您可​​以删除 inmediate 属性并放入 af:button

<af:target events="@all" execute="@this" render="@all"/>