隨筆-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.properties、basename_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 閱讀(1271) 評論(2)  編輯  收藏 所屬分類: struts2/struts1.3/JSF

          評論:
          # re: JSF入門 2011-10-21 08:51 | 朱寶祥
          怎么不見你更新了,好久都沒更新了  回復  更多評論
            
          # re: JSF入門 2013-07-07 22:09 | 忘仙電腦版
          大大能不能詳細說一下jQuery?  回復  更多評論
            
          主站蜘蛛池模板: 神农架林区| 绥德县| 旬邑县| 祁东县| 横山县| 深州市| 陆丰市| 淳安县| 嘉鱼县| 桐乡市| 北宁市| 旌德县| 安福县| 铜陵市| 兴化市| 隆尧县| 佛学| 曲周县| 湾仔区| 遵义市| 枝江市| 三明市| 尚志市| 贵定县| 会宁县| 哈巴河县| 榆林市| 荣昌县| 河北省| 贵州省| 繁峙县| 远安县| 昌吉市| 新干县| 岫岩| 巢湖市| 新乡县| 陇西县| 承德市| 土默特左旗| 武乡县|