随笔-124  评论-49  文章-56  trackbacks-0

JSF学习笔记

 

JSF事件驱动型的MVC框架,与流行的struts比较学习,易于理解。jsf component event事件是指从浏览器由用户操作触发的事件,Struts application event 是用Action来接受浏览器表单提交的事件,一个表单只能对应一个事件,application eventcomponent event相比是一种粗粒度的事件。优点:事件粒度细化,方便实现。

 

JSF配置文件

 

一 web.xml

所有的请求都透过FacesServlet来处理,通过web.xml启用jsf服务

<servlet>

        <servlet-name>Faces Servlet</servlet-name>

        <servlet-class>

            javax.faces.webapp.FacesServlet

        </servlet-class>

        <load-on-startup>1</load-on-startup>

    </servlet>

  

    <servlet-mapping>

        <servlet-name>Faces Servlet</servlet-name>

        <url-pattern>*.faces</url-pattern>

    </servlet-mapping>

</servlet>

JSF预设会读取faces-config.xml的定义,如果想要自行设置定义档的名称,我们是在web.xml中提供javax.faces.CONFIG_FILES参数,例如:

<web-app>

   <context-param>

      <param-name>javax.faces.CONFIG_FILES</param-name>

      <param-value>/WEB-INF/beans.xml</param-value>

   </context-param>

 </web-app>

  定义档可以有多个,中间以 "," 区隔,例如:

/WEB-INF/navigation.xml,/WEB-INF/beans.xml

 

faces-config.xml配置bean定义

 <managed-bean>

    <managed-bean-name>user</managed-bean-name>

        <managed-bean-class>

            onlyfun.caterpillar.UserBean

        </managed-bean-class>

    <managed-bean-scope>session</managed-bean-scope>

 </managed-bean>

<managed-bean-name>JSFJSF表示语言使用

<managed-bean-class>对应java

<managed-bean-scope>设定Bean的存活范围

类中获取Bean对象

如果要在其它类别中取得Bean对象,则可以先取得javax.faces.context.FacesContext,它代表了JSF目前的执行环境对象,接着尝试取得javax.faces.el.ValueBinding对象,从中取得指定的Bean对象,例如:

FacesContext context = FacesContext.getCurrentInstance();

 ValueBinding binding =

    context.getApplication().createValueBinding("#{user}");

 UserBean user = (UserBean) binding.getValue(context);

如果只是要尝试取得Bean的某个属性,则可以如下:

FacesContext context = FacesContext.getCurrentInstance();

 ValueBinding binding =

    context.getApplication().createValueBinding("#{user.name}");

 String name = (String) binding.getValue(context);

设置属性的初始值

如果有必要在启始Bean时,自动设置属性的初始值,则可以如下设定:

 <managed-bean>

    <managed-bean-name>user</managed-bean-name>

        <managed-bean-class>

            onlyfun.caterpillar.UserBean

        </managed-bean-class>

    <managed-bean-scope>session</managed-bean-scope>

    <managed-property>

        <property-name>name</property-name>

        <value>caterpillar</value>

    </managed-property>

    <managed-property>

        <property-name>password</property-name>

        <value>123456</value>

    </managed-property>

 </managed-bean>

如果要设定属性为 null 值,则可以使用<null-value/>标签,例如:

    <managed-property>

        <property-name>name</property-name>

        <null-value/>

    </managed-property>

 

ListMap型态的属性

如果您的Bean上有接受ListMap型态的属性,则您也可以在组态档案中直接设定这些属性的值,一个例子如下:

 <managed-bean>

    <managed-bean-name>someBean</managed-bean-name>

    <managed-bean-class>

       onlyfun.caterpillar.SomeBean

    </managed-bean-class>

    <managed-bean-scope>session</managed-bean-scope>

 

    <managed-property>

        <property-name>someProperty</property-name>

        <list-entries>

            <value-class>java.lang.Integer</value-class>

            <value>1</value>

            <value>2</value>

            <value>3</value>

        </list-entries>

    </managed-property>

 </managed-bean>

  这是一个设定接受List型态的属性,我们使用<list-entries>卷标指定将设定一个List对象,其中<value-class>指定将存入List的型态,而<value>指定其值,如果是基本型态,则会尝试使用指定的 <value-class>来作Wrapper类别。

  设定Map的话,则是使用<map-entries>标签,例如:

<managed-bean>

    <managed-bean-name>someBean</managed-bean-name>

    <managed-bean-class>

       onlyfun.caterpillar.SomeBean

    </managed-bean-class>

    <managed-bean-scope>session</managed-bean-scope>

 

    <managed-property>

        <property-name>someProperty</property-name>

        <map-entries>

            <value-class>java.lang.Integer</value-class>

            <map-entry>

                <key>someKey1</key>

                <value>100</value>

            </map-entry>

            <map-entry>

                <key>someKey2</key>

                <value>200</value>

            </map-entry>

        </map-entries>

    </managed-property>

 </managed-bean>

  由于Map对象是以key-value对的方式来存入,所以我们在每一个<map-entry>中使用<key><value>标签来分别指定。

  您也可以直接像设定Bean一样,设定一个ListMap对象,例如在JSF附的范例中,有这样的设定:

   <managed-bean>

    <description>

      Special expense item types

    </description>

    <managed-bean-name>specialTypes</managed-bean-name>

    <managed-bean-class>

        java.util.TreeMap

    </managed-bean-class>

    <managed-bean-scope>application</managed-bean-scope>

    <map-entries>

      <value-class>java.lang.Integer</value-class>

      <map-entry>

        <key>Presentation Material</key>

        <value>100</value>

      </map-entry>

      <map-entry>

        <key>Software</key>

        <value>101</value>

      </map-entry>

      <map-entry>

        <key>Balloons</key>

        <value>102</value>

      </map-entry>

</map-entries>

 

faces-config.xml配置页面流转

 

<navigation-rule>

        <from-view-id>/pages/index.jsp</from-view-id>

        <navigation-case>

            <from-action>#{user.verify}</from-action>

            <from-outcome>success</from-outcome>

            <to-view-id>/pages/welcome.jsp</to-view-id>

        </navigation-case>

</navigation-rule>

JSF每一个视图(View)都有一个独特的识别(identifier),称之为View ID,在JSF中的View ID是从Web应用程序的环境相对路径开始计算,设定时都是以/作为开头,如果您请求时的路径是/pages/index.faces,则JSF会将扩展名改为/pages/index.jsp,以此作为view-id

  <from-view-id>是个选择性的定义,它规定了来源页面的条件,<navigation-case>中定义各种导览条件,<from-outcome>定义当窗体结果符合的条件时,各自改导向哪一个目的页面,目的页面是在<to-view-id>中定义。

可以在<navigation-case>中加入<from-action>,进一步规范窗体结果必须根据哪一个动作方法(action method),当中是使用 JSF Expression Language 来设定

<from-view-id>可以没有设定,表示来源网页不作限制,您也可以使用 * 显式的在定义档中表明

 

faces-config.xml配置自定义组件

 

<component>

 <component-type>MyComponentType</component-type>

 <component-class>customcomponent1.StrRepeat</component-class>

</component>

1.    创建组件类
a)   
创建一个Java类,命名为StrRepeat,放在customcomponent1包中,修改其声明,使继承UIComponentBase类;
代码如程序清单所示

b)    定义textnumber属性及其gettersetter方法;
c)   
覆盖父类的encodeEnd()方法;[encodeBegin()encodeChildren()encodeEnd()]

public class StrRepeat extends UIComponentBase{

    @Override

    public String getFamily() {

        throw new UnsupportedOperationException("Not supported yet.");

    }

    @Override

    public void encodeEnd(javax.faces.context.FacesContext context)

            throws IOException {

        ResponseWriter writer = context.getResponseWriter();

        for(int i = 0; i < this.getNumber(); i++) {

            writer.writeText(this.getText(), "text");

        }

    }

    private String text;

    public String getText() { return text; }

    public void setText(String text) { this.text = text; }

 

    private int number;

    public int getNumber() { return number; }

    public void setNumber(int number) { this.number = number; }

}


2.   
创建标签处理器类
a)   
创建一个Java类,命名为StrRepeatTag,放在customcomponent1包中,修改其声明,使继承UIComponentELTag类;
b)   
创建text属性和number属性,以及它们的gettersetter方法;
c)   
实现getComponentType()方法,使返回字符串“MyComponentType”
d)   
实现getRendererType()方法,使返回null
e)   
覆盖setProperties()方法。
代码如程序清单所示。

public class StrRepeatTag extends UIComponentELTag{

    @Override

    public String getComponentType() {

        return "MyComponentType";

    }

 

    @Override

    public String getRendererType() {

        return null;

        //throw new UnsupportedOperationException("Not supported yet.");

    }

  

    @Override

    protected void setProperties(UIComponent component) {

        super.setProperties(component);

        component.getAttributes().put("text", this.getText());

        component.getAttributes().put("number", this.getNumber());

    }

  

    private String text;

    public String getText() { return text; }

    public void setText(String text) { this.text = text; }

 

    private int number;

    public int getNumber() { return number; }

    public void setNumber(int number) { this.number = number; }

}

 

4.    创建标签库描述符
a)    NetBeans中新建一个文件,类别选择Web文件类型选择标记库描述符
b)
    NetBeans打开新建标记库描述符对话框,在其中输入文件名如mytld
c)
    在根元素<taglib>内添加一个<tag>元素;
d)
    <tag>元素内,用<name>元素定义标签名,用<tag-class>元素定义标签处理器类,用<attribute>元素定义标签属性。
代码如图所示

   <tag>

       <name>repeatText</name>

       <tag-class>customcomponent1.StrRepeatTag</tag-class>

       <attribute>

           <name>text</name>

       </attribute>

       <attribute>

           <name>number</name>

       </attribute>

   </tag>

5.    配置自定义UI组件
a)   
打开faces-config.xml,并且切换到XML显示格式;
b)   
将程序清单 10所示的代码添加到faces-config.xml中,置于根元素<faces-config>之下;
faces-config.xml
的完整代码如图 13所示(折叠了managed-bean的定义),其中高亮部分为自定义UI组件的定义。

<component>

      <component-type>MyComponentType</component-type>

      <component-class>customcomponent1.StrRepeat</component-class>

</component>

6.    编写JSF页面
a)   
打开NetBeans自动创建Page1页面,并切换到JSP显示方式;
b)   
<jsp:root>标签内加入前缀x的定义xmlns:x="/WEB-INF/tlds/mytld"
c)   
<webuijsf:form>标签之下加入<x:repeatText text="asdadf" number="3"/>

 

 

五 JSF的国际化

资源文件的名称是.properties,而内容是名称与值的配对,资源文件名称由basename加上语言与地区来组成,例如:

basename.propertiesbasename_en.propertiesbasename_zh_TW.properties

  没有指定语言与地区的basename是预设的资源档名称,JSF会根据浏览器送来的Accept-Language header中的内容来决定该使用哪一个资源档名称,例如:

Accept-Language: zh_TW, en-US, en

如果找不到对应的讯息资源文件,则会使用预设的讯息资源文件。

使用<f:loadBundle>卷标来指定加载讯息资源,一个例子如下:

<f:loadBundle basename="messages" var="msgs"/>

<h:outputText value="#{msgs.titleText}"/>

  如果您的浏览器预设接受zh_TW语系的话,则页面上就可以显示中文,否则预设将以英文显示,也就是messages.properties的内容,为了能显示多国语系,我们设定网页编码为UTF8

  <f:view>可以设定locale属性,直接指定所要使用的语系,例如:

<f:view locale="zh_TW">

 <f:loadBundle basename="messages" var="msgs"/>

  直接指定以上的话,则会使用繁体中文来显示,JSF会根据<f:loadBundle>basename属性加上

 

JSF标签

 

一 JSF核心标签

二 JSF表单标签

详细资料http://www.web-tag.net

 

 

JSF生命周期FacesServlet代码阅读)

private FacesContextFactory facesContextFactory = null;

private Lifecycle lifecycle = null;

Init方法:

facesContextFactory =

(FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);

LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);

String lifecycleId ;

// First look in the servlet init-param set

if (null == (lifecycleId = servletConfig.getInitParameter(LIFECYCLE_ID_ATTR))) {

// If not found, look in the context-param set

lifecycleId = servletConfig.getServletContext().getInitParameter (LIFECYCLE_ID_ATTR);

}

if (lifecycleId == null) {

lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;

}

lifecycle = lifecycleFactory.getLifecycle(lifecycleId);

service方法:

 FacesContext context = facesContextFactory.getFacesContext (servletConfig.getServletContext(), request, response, lifecycle);

lifecycle.execute(context);   

lifecycle.render(context);

Lifecycle类负责JSF请求处理的全过程,主要是通过执行其中的execute方法和render方法实现的

lifecycle.execute方法
private Phase[] phases = {
        
null// ANY_PHASE placeholder, not a real Phase
        new RestoreViewPhase(),
        
new ApplyRequestValuesPhase(),
        
new ProcessValidationsPhase(),
        
new UpdateModelValuesPhase(),
        
new InvokeApplicationPhase(),
        response
    };

for (int i = 1, len = phases.length -1 ; i < len; i++) { 
          if (context.getRenderResponse() ||
              context.getResponseComplete()) {
                 break;
             }
            phases[i].doPhase(context, this, listeners.listIterator());
  }

而在LifeCycleexecute方法中,是用一个for循环顺序执行几个Phase。在每一个Phase执行完之后,都会检查FaceContext对象中是否设置了停止后续处理直接呈现响应的标志(renderResponse)或者已经完成了响应无需后续处理也不需要经过呈现响应阶段了(responseComplete),如果标志为true,那么就不再执行后续Phase

 

lifecycle.render方法

if (!context.getResponseComplete()) {
      response.doPhase(context, 
this,listeners.listIterator());
}

LifeCyclerender方法中,也会检查FacesContextresponseComplete状态,如果为true,那么就不再执行render Phase。于是我们此刻知道了在我们自己所写的一些代码或者JSF库里面的一些代码中,调用FacesContextresponseComplete方法和renderResponse得作用原理。

最后,可以看到对于每一个phase都调用了doPhase方法,同时把LifeCycleFacesContext当做参数传入了。值得注意的是,所谓的phaseListener,也传入了phasedoPhase方法中,由此大约能够想明白这个阶段监听器的道理了。

 

JSF事件

 

一 分类

1 动作事件Action Event普通动作响应

command组件通过注册actionListener均可出发此事件侦听响应

2 即时事件Immediate Event立即处理,

不验证/转换/更新模型值(bean不会保存属性)立即触发,需要一个为被注册的UI组件binding到后台bean中,常用来做bean层面即时服务,以执行action为主要目的。 inputcommand都有一个immediate属性,只要将其设定为true,就可以直接响应actionListener事件。

3 值改变事件Value Change Event

直接设定JSF输入元件的valueChangeListener属性

4 阶段事件Phase Event监听响应的JSF生命周期

JSF的运行大致分为6个阶段,每个阶段会触发该事件

 

二 编码

 

1 属性方式

 

<h:commandLink

actionListener="#{bean.linkActivated}"

actionListener="#{bean.linkActivated}">

</h:commandLink>

对应类的处理方法

public void listen(ActionEvent e) {}

 
2 tag方式
 

<h:commandButton image="mountrushmore.jpg" action="#{rushmore.act}">

    <f:actionListener type="com.corejsf.RushmoreListener"/>

</h:commandButton>

对应的处理类

public class ChangeLocaleBean implements ActionListener {

   public void processAction(ActionEvent e) {

      FacesContext context = FacesContext.getCurrentInstance();

      Map requestParams = context.getExternalContext().getRequestParameterMap();

      String locale = (String) requestParams.get("locale");

      if ("english".equals(locale))

          context.getViewRoot().setLocale(Locale.UK);

      else if("german".equals(locale))

         context.getViewRoot().setLocale(Locale.GERMANY);

   }

}

 
3 phase事件

<faces-config>

    <lifecycle>

        <phase-listener>com.corejsf.PhaseTracker</phase-listener>

    </lifecycle>

</faces-config>

对应的处理类

public class PhaseTracker implements PhaseListener {

  public PhaseId getPhaseId() {}

    public void beforePhase(PhaseEvent e) {}

    public void afterPhase(PhaseEvent e) {}

}

 

 

posted on 2011-05-30 21:48 junly 阅读(1254) 评论(2)  编辑  收藏 所属分类: struts2/struts1.3/JSF

评论:
# re: JSF入门 2011-10-21 08:51 | 朱宝祥
怎么不见你更新了,好久都没更新了  回复  更多评论
  
# re: JSF入门 2013-07-07 22:09 | 忘仙电脑版
大大能不能详细说一下jQuery?  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: