JSF和Struts的區別概述

聽說JSF的主要負責人就是struts的主要做者,因此兩者的類似點仍是有不少的。
  • 都採用taglib來處理表示層:在jsp頁面中,兩者都是採用一套標記庫來處理頁面的表示和model層的交互。
  • 兩者都採用了bean來做爲和jsp頁面對應的model層。該model層保存了jsp頁面上的數據,同時能夠做一些驗證工做,在struts中就是FormBean,在JSF中就是back bean。
  • 都採用bean做爲控制層,Struts中採用ActionBean來處理業務邏輯,對於簡單的應用能夠直接在ActionBean中編寫業務邏輯代碼,也能夠調用另外的bean或者EJB來處理業務邏輯;對於JSF則採用backing bean來處理業務邏輯,一樣,backing bean也能夠直接編寫業務邏輯或者調用其餘的bean來處理業務邏輯。
  • 都採用xml配置文件來處理bean的配置,頁面導航等問題,增長了系統的靈活性。
  • 都採用資源文件來處理國際化和本地化的問題。
然而,兩者的不一樣點也不少,下面分別說明:
  1. 首先兩者的側重點不一樣,Struts側重於控制層,側重於如何分派和處理用戶的請求,因此表示層的taglib功能不夠強大。而JSF則側重於表示層,實現了大量的標準組件,容許開發人員對錶示層有更多的控制權,同時JSF實現了一個開放的架構,容許開發人員建立本身的組件,或者在現有的組件上繼承,開發功能更強大的組件。本人認爲這是JSF最大的一個特點。(有點相似於vcl和.net組件)
  2. 和jsp 對應的model層,在Struts中採用FormBean來保存用戶輸入的數據,基本上通常字段的類型都是String。並且能夠進行簡單的驗證,固然若是採用動態的FormBean就不能在FormBean中進行驗證了。在Struts中,jsp和FormBean是緊密結合在一塊兒的,只要寫一個 jsp就必須對應一個FormBean,同時jsp上的每一個組件都對應FormBean中相同名字的字段。本人認爲這裏不太靈活,好比,開發頁面的時候就必須考慮後臺的FormBean的實現,但此時若是該頁面沒有FormBean的化則程序運行時會出錯。在JSF中,JSP頁面中的組件經過value屬性和backing bean的字段關聯,這樣就有比較大的靈活性,頁面上的每一個組件能夠對應相同的backing bean,也能夠對應不一樣的backing bean(固然本人認爲在通常的應用中,一個頁面上的組件仍是都對應到一個backing bean較好),並且在設計頁面的時候能夠不考慮backing bean如何設計,能夠在設計完頁面以後再考慮backing bean的實現問題。
  3. 關於數據驗證,Struts能夠採用在FormBean中的驗證函數中進行驗證,也可使用validator進行驗證(關於這種驗證方法,本人沒有測試過,不知效果如何,但願有經驗的朋友指教!)。在JSF中,提供了一些標準的validator。能夠對輸入的數據作一些簡單的驗證,例如驗證數值數據的範圍,字段是否必填等。但其驗證的反饋信息爲英文。若是該信息不能自定義的化,那麼針對國內的應用就不太適合了,目前本人尚未找到該反饋信息是否可以自定義的辦法。另外對於input類型的組件能夠經過validator屬性關聯到backing bean的一個驗證方法上。在事件處理方法中進行驗證也是一個辦法。
    在JSF中還有一個問題就是在JSF生成的頁面中,組件的Id命名比較怪異,全部的組件的id都相似於「form:compnentid」即form的名稱+「:」 +組件的id。這樣經過javascript訪問組件就不是很方便,經過form.id形式好像不能訪問到組件。不知道各位有沒有好的解決方案。                                                                         
  4. 控制層:Struts 中經過form的action來提交請求,經過ActionServlet來分發請求,最後由ActionBean來處理請求,在Action中實現業務邏輯或者調用其餘的業務邏輯bean來完成用戶的請求並返回客戶端。在這裏,一個form只有一個action,即一個頁面只能提交到一個action Bean。對於頁面上有多個按鈕都須要提交的狀況就須要使用一些變通的方法了。和傳統的web開發的模式比較接近。
    對於JSF,採用了事件模式來處理用戶提交的請求。JSF實現了事件監聽器來監測事件,例如當用戶單擊了一個按鈕就會觸發一個按鈕單擊事件,還有valuechange事件監聽器來監測數值改變的事件等。例如在頁面中經過經過CommandButton按鈕的action屬性來關聯到backing bean的方法來執行相應的操做。每一個不一樣的按鈕均可以關聯不一樣的方法,固然也能夠關聯相同的方法(這樣就和Action Bean很是相似了)。這中開發模式比較接近於傳統的c/s模式或者Asp.net的開發模式。對於那些從c/s架構程序或者Asp.net架構轉過來的開發者來講,這種方式可能更天然一些。
    在JSF的一些簡單的示例程序中,一般把和jsp對應的model層和jsp所提交的action放在同一個backing bean中,即業務邏輯和業務邏輯所處理的數據在同一個bean中。本人認爲,這樣的結構只能用在簡單的應用中,對於企業級的開發並不適合。應該將頁面所關聯的數據和頁面所作的action分開,這樣的結構更好一些,比較相似於struts的結構。
    JSF的backing bean中的方法訪問session,request等沒有struts中的直觀。筆者找了不少例子才知道如何訪問session中的數據。
  5. 頁面的導航:關於頁面的導航,struts和JSF比較相似。都是在xml的配置文件中配置導航規則。每一個要跳轉的頁面都有一個別名,在程序中經過別名進行跳轉。另外Struts中的跳轉是在ActionBean中發生,execute方法最後返回一個actionForward來進行跳轉。而JSF則在事件處理方法中最後返回一個字符串,由系統在xml文件中匹配自動進行跳轉。在JSF中也能夠經過在JSP頁面的CommandButton的action 屬性中直接填寫跳轉的別名直接跳轉,而沒必要通過事件處理方法的處理。
  6. 資源文件的管理:Struts和JSF對於資源文件的管理比較相似,Struts中在struts-config.xml中對資源文件進行配置,實現整個程序的統一管理。而對於JSF則能夠在每一個JSP頁面中分別定義資源文件,而後經過資源文件的別名來訪問資源文件中的內容。二者的格式也不相同,在 Struts中,格式爲: grade1.grade2.grade3 = your information,經過「.」來表示級別。而在JSF中則必須經過下劃線來表示級別,例如grade1_grade2_grade3= your information。本人認爲仍是struts的方案更直觀一些。另外在Struts的資源文件中能夠定義信息的顯示格式,例如: error.header,error.footer。而JSF中如何定義還不太清楚,或者能夠經過定義Messages標記的屬性來定義。 
Struts和JSF/Tapestry都屬於表現層框架,這兩種分屬不一樣性質的框架,後者是一種事件驅動型的組件模型,而Struts只是單純的MVC模式框架,老外老是急吼吼說事件驅動型就比MVC模式框架好,何以見得,咱們下面進行詳細分析比較一下究竟是怎麼回事?
  首先事件是指從客戶端頁面(瀏覽器)由用戶操做觸發的事件,Struts使用Action來接受瀏覽器表單提交的事件,這裏使用了Command模式,每一個繼承Action的子類都必須實現一個方法execute。
  在struts中,實際是一個表單Form對應一個Action類(或DispatchAction),換一句話說:在Struts中實際是一個表單只能對應一個事件,struts這種事件方式稱爲application event,application event和component event相比是一種粗粒度的事件。
  struts重要的表單對象ActionForm是一種對象,它表明了一種應用,這個對象中至少包含幾個字段,這些字段是Jsp頁面表單中的input字段,由於一個表單對應一個事件,因此,當咱們須要將事件粒度細化到表單中這些字段時,也就是說,一個字段對應一個事件時,單純使用Struts就不太可能,固然經過結合JavaScript也是能夠轉彎實現的。
  而這種狀況使用JSF就能夠方便實現,
<h:inputText id="userId" value="#{login.userId}">
  <f:valueChangeListener type="logindemo.UserLoginChanged" />
</h:inputText>
  #{login.userId}表示從名爲login的JavaBean的getUserId得到的結果,這個功能使用struts也能夠實現,name="login" property="userId"
  關鍵是第二行,這裏表示若是userId的值改變而且肯定提交後,將觸發調用類UserLoginChanged的processValueChanged(...)方法。
  JSF能夠爲組件提供兩種事件:Value Changed和 Action. 前者咱們已經在上節見識過用處,後者就至關於struts中表單提交Action機制,它的JSF寫法以下:
<h:commandButton id="login" commandName="login">
  <f:actionListener type=」logindemo.LoginActionListener」 />
</h:commandButton>
  從代碼能夠看出,這兩種事件是經過Listerner這樣觀察者模式貼在具體組件字段上的,而Struts此類事件是原始的一種表單提交Submit觸發機制。若是說前者比較語言化(編程語言習慣作法相似Swing編程);後者是屬於WEB化,由於它是來自Html表單,若是你起步是從Perl/PHP開始,反而容易接受Struts這種風格。
基本配置
  Struts和JSF都是一種框架,JSF必須須要兩種包JSF核心包、JSTL包(標籤庫),此外,JSF還將使用到Apache項目的一些commons包,這些Apache包只要部署在你的服務器中既可。
  JSF包下載地址: [url]http://java.sun.com/j2ee/javaserverfaces/download.html[/url] 選擇其中Reference Implementation。
  因此,從JSF的驅動包組成看,其開源基因也佔據很大的比重,JSF是一個SUN夥伴們工業標準和開源之間的一個混血兒。
  上述兩個地址下載的jar合併在一塊兒就是JSF所須要的所有驅動包了。與Struts的驅動包同樣,這些驅動包必須位於Web項目的WEB-INF/lib,和Struts同樣的是也必須在web.xml中有以下配置:
<web-app>
  <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>
</web-app>
  這裏和Struts的web.xml配置何其類似,簡直如出一轍。
  正如Struts的struts-config.xml同樣,JSF也有相似的faces-config.xml配置文件:
<faces-config>
  <navigation-rule>
    <from-view-id>/index.jsp</from-view-id>
    <navigation-case>
      <from-outcome>login</from-outcome>
      <to-view-id>/welcome.jsp</to-view-id>
    </navigation-case>
  </navigation-rule>
  <managed-bean>
    <managed-bean-name>user</managed-bean-name>
    <managed-bean-class>com.corejsf.UserBean</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
  </managed-bean>
</faces-config>
 
  在Struts-config.xml中有ActionForm Action以及Jsp之間的流程關係,在faces-config.xml中,也有這樣的流程,咱們具體解釋一下Navigation:
  在index.jsp中有一個事件:
<h:commandButton label="Login" action="login" />
  action的值必須匹配form-outcome值,上述Navigation配置表示:若是在index.jsp中有一個login事件,那麼事件觸發後下一個頁面將是welcome.jsp
  JSF有一個獨立的事件發生和頁面導航的流程安排,這個思路比struts要很是清晰。
  managed-bean相似Struts的ActionForm,正如能夠在struts-config.xml中定義ActionForm的scope同樣,這裏也定義了managed-bean的scope爲session。
  可是若是你只覺得JSF的managed-bean就這點功能就錯了,JSF融入了新的Ioc模式/依賴性注射等技術。
Ioc模式
  對於Userbean這樣一個managed-bean,其代碼以下:
public class UserBean {
  private String name;
  private String password;
  // PROPERTY: name
  public String getName() { return name; }
  public void setName(String newValue) { name = newValue; }
  // PROPERTY: password
  public String getPassword() { return password; }
  public void setPassword(String newValue) { password = newValue; }
}
<managed-bean>
  <managed-bean-name>user</managed-bean-name>
  <managed-bean-class>com.corejsf.UserBean</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
  <managed-property>
    <property-name>name</property-name>
    <value>me</value>
  </managed-property>
  <managed-property>
    <property-name>password</property-name>
    <value>secret</value>
  </managed-property>
</managed-bean>
  faces-config.xml這段配置實際上是將"me"賦值給name,將secret賦值給password,這是採起 Ioc模式中的Setter注射方式
Backing Beans
  對於一個web form,咱們可使用一個bean包含其涉及的全部組件,這個bean就稱爲Backing Bean, Backing Bean的優勢是:一個單個類能夠封裝相關一系列功能的數據和邏輯。
  說白了,就是一個Javabean裏包含其餘Javabean,互相調用,屬於Facade模式或Adapter模式。
  對於一個Backing Beans來講,其中包含了幾個managed-bean,managed-bean必定是有scope的,那麼這其中的幾個managed-beans如何配置它們的scope呢?
<managed-bean>
  ...
  <managed-property>
    <property-name>visit</property-name>
    <value>#{sessionScope.visit}</value>
  </managed-property>
  這裏配置了一個Backing Beans中有一個setVisit方法,將這個visit賦值爲session中的visit,這樣之後在程序中咱們只管訪問visit對象,從中獲取咱們但願的數據(如用戶登錄註冊信息),而visit是保存在session仍是application或request只須要配置既可。
UI界面
  JSF和Struts同樣,除了JavaBeans類以外,還有頁面表現元素,都是是使用標籤完成的,Struts也提供了struts-faces.tld標籤庫向JSF過渡。
  使用Struts標籤庫編程複雜頁面時,一個最大問題是會大量使用logic標籤,這個logic如同if語句,一旦寫起來,搞的JSP頁面象俄羅斯方塊同樣,可是使用JSF標籤就簡潔優美:
<jia:navigatorItem name="inbox" label="InBox"
  icon="/p_w_picpaths/inbox.gif"
  action="inbox"
  disabled="#{!authenticationBean.inboxAuthorized}"/>
  若是authenticationBean中inboxAuthorized返回是假,那麼這一行標籤就不用顯示,多幹淨利索!
  先寫到這裏,我會繼續對JSF深刻比較下去,若是研究過Jdon框架的人,可能會發現,Jdon框架的jdonframework.xml中service配置和managed-bean同樣都使用了依賴注射,看來對Javabean的依賴注射已經迅速地成爲一種新技術象徵,若是你還不瞭解Ioc模式,趕忙補課。
相關文章
相關標籤/搜索