JSF 2.X UI组件使用ValueExpression

时间:2012-08-06 15:35:21

标签: jsf-2

我正在尝试构建一个简单的组件来理解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}”,表示该值已在页面和组件之间成功传输。然而,表达式的评估结果为“无效”。

这似乎表明此时支持bean不可用,尽管页面正确验证并部署。所以我95%肯定豆子在运行时就在那里。

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

所以我的问题是我应该在哪里获取和评估模型的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();
    }

}

UIComponent ---

/**
 * 
 */
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>

1 个答案:

答案 0 :(得分:0)

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


  

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

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

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


  

所以我的问题是我应该在哪里获取和评估模型的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属性的值。