不调用h:selectOneMenu的setter

时间:2013-09-01 08:47:34

标签: jsf-2 richfaces

我只是尝试更改选择输入框的值。加载页面会运行到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。从此我得知,改变真的回到了服务器。但是 - 再次 - 它永远不会触发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

2 个答案:

答案 0 :(得分:2)

转换器在&#34;过程验证&#34; JSF lifecycle的阶段,而稍后在&#34;更新模型值&#34;期间调用setter。相。每个阶段都会遍历整个页面,这意味着任何组件中的验证错误都会阻止所有模型更新。如果您在页面上看到验证错误,请尝试检查邮件标记。

通过调用FacesContext.renderResponse()来跳过生命周期阶段。有关详细信息,请参阅UIInput.executeValidate()LifeCycleImpl.execute()

答案 1 :(得分:2)

我连接了阶段监听器并打印了event.getFacesContext().getMessageList()。并且,虽然没有打印到<h:Message for="pubCategoryId"/>但是有错误。错误为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而非<f:converter ../>的selectOneMenu,例如...

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

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

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

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

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