当 JSF 2 的视图中存在元数据转换器时,为啥 JSTL-JSF2 不能正常工作

Posted

技术标签:

【中文标题】当 JSF 2 的视图中存在元数据转换器时,为啥 JSTL-JSF2 不能正常工作【英文标题】:Why JSTL-JSF2 not work fine when exists metadata converter in the view in JSF 2当 JSF 2 的视图中存在元数据转换器时,为什么 JSTL-JSF2 不能正常工作 【发布时间】:2012-06-01 06:04:01 【问题描述】:

仅当在 JSF 视图中我删除 JSTL 代码时,按钮才会调用操作方法,我知道这是生命周期,但我不明白原因/问题。我喜欢妥协,因为它会引发这种行为。

查看代码工作正常

    <f:metadata>            
<f:viewParam name="idAsociacion" value="#msgUsuario.asociacion" converter="#
               asociacionConverter"
        converterMessage="#msg['aplicacion.asociacion.error.converter']" required="true" 
        requiredMessage="#msg['aplicacion.asociacion.error.required']" />
<f:viewParam name="idMsg" value="#msgUsuario.mensajeRespondido" converter="#
     mensajeConverter" converterMessage="#msg['aplicacion.mensaje.error.converter']" 
     required="true" requiredMessage="#msg['aplicacion.mensaje.error.required']" />
    </f:metadata>

    <ui:decorate template="/WEB-INF/templates/mainUsuario-template.xhtml">
    <ui:define name="title">        
    <h:outputFormat value="#msg['usuario.escribirMsj.title']">
        <f:param value="#msgUsuario.asociacion.nombre" />
    </h:outputFormat>
    </ui:define>

    <ui:param name="descripcionView" value="#msg['usuario.escribirMsj.descripcion']" />

     <ui:define name="content">
<h:panelGroup layout="block"
          id="escribirMensajeContainer"styleClass="escribirMensajeContainer">
    <h:form>
        <p:panelGrid>
        <p:row>
        <p:column>
        <h:outputLabel for="texto" value="#msg['usuario.escribirMsj.mensaje']" 
                 styleClass="labelInput" />
        </p:column>
        </p:row>

        <p:row>
        <p:column>
        <p:inputTextarea  autoResize="true" cols="80" rows="15" id="texto" 
             maxlength="500" value="#msgUsuario.texto">

        </p:inputTextarea>
            </p:column>
        </p:row>

        <p:row>
    <p:column>
    <h:message for="texto" id="messageMensajeError" styleClass="messageError" />
    </p:column>                         
        </p:row>


        <p:row>         
             <p:column>
    <p:commandButton action="#msgUsuario.enviar" 
                tabindex="2" title="#
      fn:replace(msg['usuario.escribirMsj.title.enviar'],0,msgUsuario.asociacion.nombre)" 
       value="#msg['usuario.escribirMsj.enviar']" />
</p:column>                         
    </p:row>                            
    </p:panelGrid>
    </h:form>
    </h:panelGroup>         
    </ui:define>
    </ui:decorate>
    </html>

但是,如果我添加 JSTL,我将在下面显示。视图渲染良好,因为消息没有得到响应,但按钮从不调用操作方法并且视图重新加载。

      <c:choose>
      <c:when test="#msgUsuario.mensajeRespondido.respondido==false">
        <h:form>
        <p:panelGrid>
        <p:row>
        <p:column>
        <h:outputLabel for="texto" value="#msg['usuario.escribirMsj.mensaje']" 
                 styleClass="labelInput" />
        </p:column>
        </p:row>

        <p:row>
        <p:column>
        <p:inputTextarea  autoResize="true" cols="80" rows="15" id="texto" 
             maxlength="500" value="#msgUsuario.texto">

        </p:inputTextarea>
            </p:column>
        </p:row>

        <p:row>
    <p:column>
    <h:message for="texto" id="messageMensajeError" styleClass="messageError" />
    </p:column>                         
        </p:row>


        <p:row>         
             <p:column>
    <p:commandButton action="#msgUsuario.enviar" 
                tabindex="2" title="#
      fn:replace(msg['usuario.escribirMsj.title.enviar'],0,msgUsuario.asociacion.nombre)" 
       value="#msg['usuario.escribirMsj.enviar']" />
</p:column>                         
    </p:row>                            
    </p:panelGrid>
    </h:form>
    </c:when>
    <c:otherwise>
         <h:outputText value="MESSAGE RESPONSED" />
    </c:otherwise>
    </c:choose>

注意:转换在两种情况下都可以正常工作。

ManagedBean 代码

  @ManagedBean(name="msgUsuario")
  @ViewScoped
  public class EscribirMensajeUsuarioView implements Serializable 

private static final long serialVersionUID = 1L;
private static final Logger logger=Logger.getLogger(EscribirMensajeUsuarioView.class);

private Asociacion asociacion;

private Mensaje mensajeRespondido;

private Usuario usuario;


private String texto;

private boolean usuarioBloqueado;

@ManagedProperty(value="#mensajeBO")
private MensajeBO mensajeBo;

@ManagedProperty(value="#usuarioBO")
private UsuarioBO usuarioBo;


/* Never invoked with JSTL code in the view */

public String enviar()
    logger.info("EscribirMensajesUsuarioView.enviar");

    TipoMensaje tipoMensaje=null;
    Mensaje mensaje=this.mensajeRespondido;

    .................
            .................
            .................
      


/* Getters and Setters */
   

我读了这个 Balusc 的评论

“JSF 和 JSTL 不会像您对编码所期望的那样同步运行。JSTL 在视图的构建期间运行(当要填充 JSF 组件树时),而 JSF 在视图的渲染期间运行组件树(当要生成 HTML 输出时)。您可以将其可视化为:JSTL 先从上到下运行,然后将结果交给 JSF,JSF 再从上到下运行。”

例如,我在 dinamyc 数据表中理解这一点,但在这种情况下不是。因为 JSTL 可以很好地呈现 mensajeRepetido 在 JSF 树中退出的视图,但按钮不会调用该方法。但是视图重新加载并且 mensajeRepetido 由转换器再次退出。 p>

亲切的问候。

【问题讨论】:

【参考方案1】:

您的问题是由于您将 JSTL 属性绑定到 view scoped 托管 bean 属性而引起的。这仅在关闭部分状态保存时才有效。打开部分状态保存(默认情况下)后,JSTL 属性将获得其自己的 second 视图范围 bean 实例(所有属性都设置为默认值!),而不是存储在 JSF 视图中的实例状态并被 JSF 组件使用。

只需使用JSF组件的rendered属性而不是通常的方式,并且使用JSTL只控制视图的构建,而不是控制视图的呈现。

<h:form rendered="#not msgUsuario.mensajeRespondido.respondido">
    ...
<h:form>
<h:panelGroup rendered="#msgUsuario.mensajeRespondido.respondido">
     <h:outputText value="MESSAGE RESPONSED" />
</h:panelGroup>      

另见:

JSTL in JSF2 Facelets... makes sense? Communication in JSF 2.0 - @ViewScoped fails in taghandlers

【讨论】:

感谢您的回复。我不明白“仅使用 JSTL 来控制视图的构建,而不是控制视图的呈现”。有什么区别? 视图的构建是将 XHTML 文件转换为 JSF 组件树的步骤,context.getViewRoot() 提供。视图的呈现是通过调用viewRoot.encodeAll(context) 将JSF 组件树转换为HTML 输出的步骤。 JSTL 在构建视图期间运行,并且不存在于 JSF 组件树中。该视图建立在每个 GET 请求之上,并在每个后续 POST 请求中重用,该请求通过隐藏输入字段 javax.faces.ViewState 标识视图。 在 JSF 2.2 中,视图范围是在构建视图之前恢复的,因此 JSTL 和其他构建时标记可以访问视图范围 bean(如果这是一件好事是另一个问题)。 我有更清晰的概念。我阅读了问题 1492,我认为这是一个很好的通知,虽然使用渲染属性解决了这个任务,但最好让 JSTL 更接近。非常感谢……

以上是关于当 JSF 2 的视图中存在元数据转换器时,为啥 JSTL-JSF2 不能正常工作的主要内容,如果未能解决你的问题,请参考以下文章

为啥 UIComponent.setStyleClass() 在 JSF 2.1 转换器中不起作用?

为啥 JSF 将 UI 组件的状态保存在服务器上?

JSF2:在运行时构建 JSF2 视图(整个组件树)

为啥当我将 hbm2ddl.auto 设置为创建时,Hibernate 会抛出 SQLGrammarException 说表/视图不存在?

当通过链接或后退按钮打开时,强制 JSF 刷新页面/视图/表单

为啥我的大型 JSF 数据表不是仅在 IE 中填充?