<f:metadata>、<f:viewParam>和<f:viewAction>可以用来做什么?(涉及IT技术)

158

有人能否澄清一下,我们如何在一般情况下或者一个真实世界的例子中使用这个代码片段?

<f:metadata>
    <f:viewParam id="id" value="#{bean.id}" />
    <f:viewAction action="#{bean.init}" />
</f:metadata>
2个回答

298

处理GET参数

<f:viewParam> 管理GET参数的设置、转换和验证。它类似于 <h:inputText>,但是针对 GET 参数。

以下示例:

<f:metadata>
    <f:viewParam name="id" value="#{bean.id}" />
</f:metadata>

基本上会执行以下操作:

  • 通过名称id获取请求参数值。
  • 必要时进行转换和验证(您可以使用requiredvalidatorconverter属性,并像在<h:inputText>中嵌套<f:converter><f:validator>一样处理)
  • 如果转换和验证成功,则将其设置为由#{bean.id}值表示的bean属性,或者如果不存在value属性,则将其设置为请求属性,名称为id,以便在视图中通过#{id}使用。

因此,当您打开页面作为foo.xhtml?id=10时,参数值10以这种方式设置在bean中,在视图呈现之前。

关于验证,以下示例将参数设置为required="true",并仅允许介于10和20之间的值。任何验证失败都将导致显示消息。

<f:metadata>
    <f:viewParam id="id" name="id" value="#{bean.id}" required="true">
        <f:validateLongRange minimum="10" maximum="20" />
    </f:viewParam>
</f:metadata>
<h:message for="id" />

在GET参数上执行业务操作

您可以使用<f:viewAction>来实现此功能。

<f:metadata>
    <f:viewParam id="id" name="id" value="#{bean.id}" required="true">
        <f:validateLongRange minimum="10" maximum="20" />
    </f:viewParam>
    <f:viewAction action="#{bean.onload}" />
</f:metadata>
<h:message for="id" />

使用

public void onload() {
    // ...
}
< p > <f:viewAction> 自 JSF 2.2 版本开始新增(<f:viewParam> 已经存在于 JSF 2.0)。如果您无法升级,则最好使用 <f:event>

<f:event type="preRenderView" listener="#{bean.onload}" />

然而,这将在每个请求上调用。您需要明确检查请求是否不是postback:

public void onload() {
    if (!FacesContext.getCurrentInstance().isPostback()) {
        // ...
    }
}

如果您希望在出现“转换/验证失败”情况时也跳过,那么请按照以下步骤操作:

public void onload() {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    if (!facesContext.isPostback() && !facesContext.isValidationFailed()) {
        // ...
    }
}

使用<f:event>的方式本质上是一种解决方法/技巧,这就是为什么在JSF 2.2中引入了<f:viewAction>的原因。

将视图参数传递给下一个视图

您可以通过将includeViewParams属性设置为true或添加includeViewParams=true请求参数,在导航链接中“传递”视图参数。

<h:link outcome="next" includeViewParams="true">
<!-- Or -->
<h:link outcome="next?includeViewParams=true">

这将基本上生成与上面的<f:metadata>示例相同的链接。

<a href="next.xhtml?id=10">

保留原始参数值。

这种方法只需要要求next.xhtml上也有一个相同的<f:viewParam>,否则它不会被传递。


在JSF中使用GET表单

<f:viewParam>也可以与"纯HTML" GET表单结合使用。

<f:metadata>
    <f:viewParam id="query" name="query" value="#{bean.query}" />
    <f:viewAction action="#{bean.search}" />
</f:metadata>
...
<form>
    <label for="query">Query</label>
    <input type="text" name="query" value="#{empty bean.query ? param.query : bean.query}" />
    <input type="submit" value="Search" />
    <h:message for="query" />
</form>
...
<h:dataTable value="#{bean.results}" var="result" rendered="#{not empty bean.results}">
     ...
</h:dataTable>

基本上有这个@RequestScoped bean:

private String query;
private List<Result> results;

public void search() {
    results = service.search(query);
}

请注意,<h:message>是为<f:viewParam>而不是普通的HTML <input type="text">!还要注意,当#{bean.query}为空时,输入值会显示#{param.query},因为在验证或转换错误时,否则提交的值将完全不显示。请注意,这种结构对于JSF输入组件无效(它已经在“幕后”执行了此操作)。

参见:


@Geek:重定向会创建一个新的 GET 请求。源 Bean 和目标 Bean 的作用域无关紧要。然而,对于请求和视图作用域 Bean,您应该考虑到新 GET 请求可能产生的影响。另请参阅 https://dev59.com/fGw05IYBdhLWcg3wykvn#7031941。 - BalusC
@BalusC 你所说的“但是,对于请求和视图作用域的bean,您应该考虑新GET请求的可能影响。”是什么意思? - Geek
@UlukBiy:你在哪里看到<f:event type="preRenderView">不会在每个请求中被调用?它确实会在每个请求中被调用。 - BalusC
请注意,<f:viewAction> 的命名空间已更改,这仅适用于最近版本的JSF等。请参见:https://dev59.com/Nmw15IYBdhLWcg3w0fEV#6377957 - Darrell Teague
@BalusC 对于JSF 2.1,我使用<f:event type="preRenderView" listener="#{bean.onload}" />在从onload中删除@PostContruct后访问视图参数。页面上有一个下拉菜单(非ajax,因为我打算在提交时提交更改)。在页面提交(重定向)时,该下拉列表的更改值重置为默认值(第一项),我可以看到下拉列表setter被调用两次。首先是用户所做的更改,其次是自动重置,如我所说。当我再次回到@PostConstruct时,事情变得正常。Setter仅为用户最后选择调用一次。我该怎么办? - user2918640
显示剩余9条评论

2

将参数从一个视图发送到另一个视图,从发送视图到接收视图使用viewParam和includeViewParams=true

在发送者中

  1. 声明要发送的参数。我们可以发送字符串、对象等。

Sender.xhtml

<f:metadata>
      <f:viewParam name="ID" value="#{senderMB._strID}" />
</f:metadata>
  1. 我们将发送参数ID,它将与“includeViewParams=true”一起包含在单击按钮事件的返回字符串中。单击按钮将使用senderMB._arrData中的dto触发senderMB.clickBtnDetail(dto)。

Sender.xhtml

<p:dataTable rowIndexVar="index" id="dataTale"value="#{senderMB._arrData}" var="dto">
      <p:commandButton action="#{senderMB.clickBtnDetail(dto)}" value="見る" 
      ajax="false"/>
</p:dataTable>

在 senderMB.clickBtnDetail(dto) 中,我们使用从按钮事件 (dto) 获取的参数将 _strID 赋值为该参数,这里参数是 Sender_DTO,并将其分配给 senderMB._strID。
Sender_MB.java
    public String clickBtnDetail(sender_DTO sender_dto) {
        this._strID = sender_dto.getStrID();
        return "Receiver?faces-redirect=true&includeViewParams=true";
    }

当被点击时,链接会变成http://localhost:8080/my_project/view/Receiver.xhtml?*ID=12345* 在Receiver中
  1. 获取viewParam Receiver.xhtml 在Receiver中,我们声明f:viewParam来从get请求(接收)中获取参数,接收方的参数名称必须与发送方(页面)相同

Receiver.xhtml

<f:metadata><f:viewParam name="ID" value="#{receiver_MB._strID}"/></f:metadata>

它将从发送方视图获取参数ID并分配给接收方_MB._strID

  1. 使用viewParam 在接收方,我们希望在页面渲染之前在SQL查询中使用此参数,因此我们使用preRenderView事件。我们不会使用构造函数,因为构造函数将在接收到viewParam之前被调用。 所以我们添加

Receiver.xhtml

<f:event listener="#{receiver_MB.preRenderView}" type="preRenderView" />

标签转换为标签。

Receiver.xhtml

<f:metadata>
<f:viewParam name="ID" value="#{receiver_MB._strID}" />
<f:event listener="#{receiver_MB.preRenderView}"
            type="preRenderView" />
</f:metadata>

现在我们想要在读取数据库的方法中使用这个参数,它可以被使用。
Receiver_MB.java
public void preRenderView(ComponentSystemEvent event) throws Exception {
        if (FacesContext.getCurrentInstance().isPostback()) {
            return;
        }
        readFromDatabase();
    }
private void readFromDatabase() {
//use _strID to read and set property   
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接