0

我正在尝试构建一个简单的组件来了解 JSF 2.X 如何以及为什么会以它的方式工作。我一直在使用较新的注释,并试图拼凑出一个清晰的例子。

所以我已经构建了我的组件并将其部署在一个 xhtml 文件中,如下所示:

<kal:day value="K.Day" title="Kalendar" model="#{kalendarDay}"/>

在 UIComponent 中,我执行以下操作:

ValueExpression ve      = getValueExpression("model");
if (ve != null) 
{
    System.out.println("model expression "+ve.getExpressionString());
    model = (KalendarDay) ve.getValue(getFacesContext().getELContext());
    System.out.println("model "+model);
}

表达式“#{kalendarDay}”正确显示,表明该值已在页面和组件之间成功传输。但是,表达式的评估结果为“null”。

这似乎表明此时支持 bean 不可用,尽管页面正确验证和部署。所以我有 95% 的把握 bean 在运行时就在那里。

所以也许这是一个阶段的事情?我应该在渲染器的解码中对此进行评估并在属性映射中设置值吗?对于实际值和值表达式的组合,我仍然有些困惑。

所以我的问题是我应该在哪里获取和评估模型的 valueExpression,我应该将评估结果存储在 UIComponent 中还是应该每次都简单地评估它?

下面的 SSCCE 文件我认为这些是演示问题所需的唯一文件

Bean接口-----

/**
 * 
 */
package com.istana.kalendar.fixture;

import java.util.Date;

/**
 * @author User
 *
 */
public interface KalendarDay
{
    public      Date        getDate();
}

Bean 实现 ---

/**
 * 
 */
package com.istana.kalendar.session.wui;

import java.util.Calendar;
import java.util.Date;

import javax.ejb.Stateful;
import javax.inject.Named;

import com.istana.kalendar.fixture.KalendarDay;

/**
 * @author User
 *
 */
@Named      ("kalendarDay")
@Stateful
public class KalKalendarDay
    implements KalendarDay
{

    private     Calendar        m_date  =   Calendar.getInstance();

    /* (non-Javadoc)
     * @see com.istana.kalendar.fixture.KalendarDay#getDate()
     */
    @Override
    public      Date            getDate()
    {
        return m_date.getTime();
    }

}

界面组件 ---

/**
 * 
 */
package com.istana.kalendar.fixture.jsf;

import javax.el.ValueExpression;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIOutput;

import com.istana.kalendar.fixture.KalendarDay;

/**
 * @author User
 *
 */
@FacesComponent     (value=UIDay.COMPONENT_TYPE)
public class UIDay  extends UIOutput
{
    static      final
    public      String          COMPONENT_TYPE      =   "com.istana.kalendar.fixture.jsf.Day";

    static      final
    public      String          COMPONENT_FAMILY    =   "com.istana.kalendar.fixture.jsf.Day";

    private     KalendarDay     m_model;

    private     String          m_title;

    @Override
    public      String          getRendererType() 
    {
        return UIDayRenderer.RENDERER_TYPE;
    }

    @Override
    public      String          getFamily() 
    {
        return COMPONENT_FAMILY;
    }

    public      KalendarDay     getModel()
    {
        KalendarDay     model = (KalendarDay) getStateHelper().eval("model");

        System.out.println("model "+model);

        return model;
    }

    public      void            setModel(KalendarDay model)
    {
        getStateHelper().put("model",model);
    }

    public      String          getTitle()
    {
        return (String) getStateHelper().eval("title");
    }

    public      void            setTitle(String title)
    {
        getStateHelper().put("title",title);
    }
}

UIComponentRenderer ---

/**
 * 
 */
package com.istana.kalendar.fixture.jsf;

import java.io.IOException;

import javax.el.ValueExpression;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import javax.faces.render.Renderer;

import com.istana.kalendar.fixture.KalendarDay;

/**
 * @author User
 *
 */
@FacesRenderer  (componentFamily    = UIDay.COMPONENT_FAMILY
                ,rendererType       = UIDayRenderer.RENDERER_TYPE
                )
public class UIDayRenderer extends Renderer
{
    static      final
    public      String      RENDERER_TYPE   =   "com.istana.kalendar.fixture.jsf.DayRenderer";

    @Override
    public      void        encodeBegin (FacesContext context,UIComponent component) 
        throws IOException 
    {
        UIDay uic = (UIDay) component;

        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("p", uic);
        /*
         * This is the call that triggers the println
         */
        writer.write("Day - "+uic.getModel().getDate());
    }

    @Override
    public      void        encodeEnd   (FacesContext context,UIComponent component) 
            throws IOException 
    {
        ResponseWriter writer = context.getResponseWriter();
        writer.endElement("p");
        writer.flush();
    }
}

kalendar.taglib.xml ---

<facelet-taglib 
    id="kalendar"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
    version="2.0"
>

    <namespace>http://istana.com/kalendar</namespace>
    <tag>
        <tag-name>day</tag-name>
        <component>
            <component-type>com.istana.kalendar.fixture.jsf.Day</component-type>
        </component>
    </tag>

</facelet-taglib>
4

1 回答 1

0

我不确定为什么会这样null,但症状表明#{kalendarDay}是在视图渲染期间指定的,而您试图在视图构建期间对其进行评估。


所以也许这是一个阶段的事情?我应该在渲染器的解码中对此进行评估并在属性映射中设置值吗?对于实际值和值表达式的组合,我仍然有些困惑。

您应该使用encodeXxx()组件的方法或关联的渲染器(如果有)根据组件的属性/属性生成 HTML。

您应该使用decode()组件的方法或相关的渲染器(如果有的话)根据与 HTML 表单提交一起发送的 HTTP 请求参数来设置组件的属性/属性。


所以我的问题是我应该在哪里获取和评估模型的 valueExpression,我应该将评估结果存储在 UIComponent 中还是应该每次都简单地评估它?

从 JSF 2.x 开始,建议显式指定组件属性的 getter 和 setter,这些属性依次委托给UIComponent#getStateHelper().

public String getValue() {
    return (String) getStateHelper().eval("value");
}

public void setValue(String value) {
    getStateHelper().put("value", value);
}

public String getTitle() {
    return (String) getStateHelper().eval("title");
}

public void setTitle(String title) {
    getStateHelper().put("title", title);
}

public Object getModel() {
    return getStateHelper().eval("model");
}

public void setModel(Object model) {
    getStateHelper().put("model", model);
}

这就是您基本上所需要的(请注意,getter 和 setter 必须与 Javabeans 规范中的属性名称完全匹配)。然后在encodeXxx()方法中调用getModel()来获取(和评估)model属性的值。

于 2012-08-06T15:55:25.843 回答