【问题标题】:Setter of h:selectOneMenu is not invoked [duplicate]未调用 h:selectOneMenu 的设置器 [重复]
【发布时间】:2013-09-04 14:10:12
【问题描述】:

我只是尝试更改选择输入框的值。加载页面会进入 pubcategory 属性的 getter 方法的断点。目前很好。更改值,不会调用 setter 方法。我触发了 Richfaces ajax 处理。我确认,所有 JSF 阶段都已完成(我还看到了 JPA-SQL 选择查询,我希望在其中使用更新语句来更改值 - 好吧,如果未触发 setter 方法,则不可能)。这是我的 selectOneMenu 代码

<h:selectOneMenu id="pubCategoryId" converter="#{pubCategoryConverter}" value="#{pubController.pubCategory}">                           
<f:selectItems value="#{listPubCategoryController.pubCategories}" var="category" itemLabel="#{category.name}" itemValue="#{category}" />
<a4j:ajax event="change" execute="@this" />
</h:selectOneMenu>
<h:message for="pubCategoryId" style="color:red" />

两次都调用我的转换器。 getAsString 方法,当我加载页面和 getAsObject 时触发 on-change 操作。由此我得出结论,更改确实可以追溯到服务器。但是 - 再一次 - 它永远不会触发 setter 方法。

@ManagedBean(name = "pubCategoryConverterController")
@FacesConverter(value = "pubCategoryConverter")
//@Named 
public class PubCategoryConverter implements Converter {
@Inject
private PubCategoryRepository pubCategoryRepository;

public PubCategoryConverter() {
}

// from page to backing bean
@Override
public Object getAsObject(FacesContext ctx, UIComponent component,
        String value) {

    PubCategory pubCat = pubCategoryRepository.getPubCategoryById(new Long(
            value));
    return pubCat;
}

// from backing bean to page
@Override
public String getAsString(FacesContext fc, UIComponent uic, Object o) {
    PubCategory pubCat = ((PubCategory) o);
    return pubCat.getId().toString();
}
}

如果我用@Named 而不是@FacesConverter/@ManagedBean 来注释转换器,情况也是如此。有任何线索或提示吗?

使用 JBoss 7.1.1、Richfaces 4.3.3、JSF 2.0

【问题讨论】:

  • 你试过用&lt;f:ajax/&gt;代替&lt;a4j:ajax event="change" execute="@this" /&gt;吗?
  • 不。以前试过。没什么区别。相同的行为:遍历所有 JSF 面,但不触发 setter 方法。 (无论如何感谢您的反馈)
  • 服务器日志中是否有任何消息,我的意思是,尝试将 id 添加到 h:message 中,如下所示:&lt;h:message id="myMessageId" for="pubCategoryId" style="color:red" /&gt; 并使用 &lt;f:ajax render="myMessageId"/&gt; 呈现它
  • 删除@ManagedBean(name = "pubCategoryConverterController") 注释。 @FacesConverter 就足够了,将其引用为converter="pubCategoryConverter"。尝试将选择作为对象获取时,您的转换器可能会失败,因此请调试它并查看会发生什么。
  • @XtremeBiker 如果我删除了“@ManagedBean”,则“@Inject”或“@EJB”注释不会注入 bean。

标签: jsf-2 richfaces


【解决方案1】:

转换器在JSF lifecycle 的“流程验证”阶段调用,而设置器稍后在“更新模型值”阶段调用。每个阶段都会遍历整个页面,这意味着 any 组件中的验证错误将阻止 all 模型更新。如果您没有在页面上看到验证错误,请尝试检查您的消息标签。

生命周期阶段的跳过是通过调用FacesContext.renderResponse() 完成的。详情请参阅UIInput.executeValidate() 和LifeCycleImpl.execute()。

【讨论】:

    【解决方案2】:

    我连接了相位监听器并打印了event.getFacesContext().getMessageList()。而且,虽然没有打印到&lt;h:Message for="pubCategoryId"/&gt;,但有一个错误。错误是msg j_idt18:pubFormE:pubCategoryId: Validation Error: Value is not valid

    package com.foo;
    
    import java.util.List;
    import java.util.logging.Logger;
    import javax.faces.event.PhaseEvent;
    import javax.faces.event.PhaseListener;
    import javax.faces.application.FacesMessage;
    import javax.faces.context.FacesContext;
    
    public class PhaseTracker implements PhaseListener {
    
        private static final Logger logger = Logger.getLogger("org.exadel.helper");
    
        public void beforePhase(PhaseEvent e) {
            List<FacesMessage> msgs = e.getFacesContext().getMessageList();
            for (FacesMessage msg : msgs) {
                logger.info("before msg " + msg.getSummary() + " :: " + msg.getDetail());
            }
            logger.info("BEFORE " + e.getPhaseId());
        }
    
        public void afterPhase(PhaseEvent e) {
            logger.info("AFTER " + e.getPhaseId());
        }
    }
    

    问题在于模型对象中的 equals(Object o) 方法(有些人称之为 DTO)。正如许多论坛中所述,您在此方法中比较的值不得看起来像例如this.id == o.id,因为它比较的是实例而不是内部状态。使用等于 this.id.equals(o.id)。一旦修复,错误Value is not valid 就会消失。

    毕竟,我注意到以下内容。如果您想使用带有标签属性 converter 而不是 &lt;f:converter ../&gt; 的 selectOneMenu,例如...

    <h:selectOneMenu value="#{pubController.pubCategory}" converter="#{pubCategoryConverterController}">
    

    ...除了@FacesConverter 之外,您还需要将转换器注释为@ManagedBean 实例,例如

    @ManagedBean(name="pubCategoryConverterController")
    @FacesConverter(value = "pubCategoryConverter")
    

    另一方面,如果您想使用&lt;f:converter converterId="pubCategoryConverter"&gt; 标签,您需要引用faces 转换器名称——而不是托管bean 的实例。请注意,转换器名称周围没有 EL #{...}。但是,在这种情况下,您不能将 bean 注入转换器。因此,在您的转换器 bean 中,您需要从应用程序上下文中实例化一个控制器以使用 EJB 服务。例如

    PubCategoryController pubCategoryController = ctx.getApplication().evaluateExpressionGet(ctx, "#{pubCategoryController}", PubCategoryController.class);
    

    【讨论】:

    • 您应该删除 @FacesConverter 注释才能像这样使用它。这是不必要的。
    • 是的。这是一种进步。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-28
    • 2023-04-01
    • 2020-07-21
    • 2012-11-01
    • 1970-01-01
    • 2012-11-22
    相关资源
    最近更新 更多