JSF開發(fā)實戰(zhàn)(一)
JSF將是J2EE5.0中所包含的web開發(fā)框架,這應(yīng)該是第一個成為jcp標準,并且隨j2eesdk一起發(fā)布的web框架,可以看出sun對它的期望很高。JSF最大的競爭對手是tapestry,是apache的產(chǎn)品,但是apache又弄出了個myfaces,是對jsf標準的一個實現(xiàn)。也許你也和我一樣,在jsf和tapestry之間猶豫很久,將來從apache的態(tài)度上應(yīng)該可以看出二者的走向。在tss上有一篇比較jsf 1.0與tapestry 3.0的文章,內(nèi)容很扎實到位:
http://www.theserverside.com/articles/article.tss?l=JSFTapestryJSF的競爭對手不是struts/webwork之流,它們基本上已經(jīng)是不同階段上的東西了,放在一起比較意義不大。
JSF的開發(fā)流程和asp.net中所倡導(dǎo)的code behind方式很相似,核心是事件驅(qū)動,組件和標簽的封裝程度非常高,很多典型應(yīng)用已經(jīng)不需要開發(fā)者去處理http。頁面操作會被自動映射到對應(yīng)的java bean中,后臺邏輯只需要同java bean發(fā)生交互。整個過程是通過“依賴注入(DI)”來實現(xiàn)的,看來這是目前解偶合的最佳途徑啊,spring的影響真是深遠。不過正式因為jsf采用了這樣的方式,導(dǎo)致開發(fā)工作和以前的jsp/struts等都有非常大的不同,需要一定的時間去學(xué)習(xí)。學(xué)習(xí)之前建議先對依賴注入有比較清楚的認識,可以參考我的learn Spring in spring系列的第一篇。
本系列將以兩個例子來講解jsf的基本開發(fā),第一個例子當然是hello world。目前可用的jsf ide不多,ibm要到06年才能放出支持jsf的wtp版本。所以我們的例子基本以手寫為主,這樣也能讓我們有更清楚的認識,同時推薦目前最好的jsf開發(fā)工具:myeclipse 4.0 GA。后面的例子將會有jsf和hibernate的內(nèi)容,它都能給予很好的支持。由于myeclipse并不免費,所以我們除了講解在ide中如何操作外,還會敘述手動操作的具體內(nèi)容,以免過于依賴開發(fā)工具。用什么服務(wù)器都可以,這里采用了jboss 4.0.2。如果你的服務(wù)器是高版本的tomcat(5.5+),那么必須要刪除它自帶的一些包才能很好的支持jsf,具體細節(jié)請查看它的文檔。
請自行下載jsf ri和JSTL 1.1。
廢話少說,開始了。
在myeclipse 4.0GA中新建一個web項目,命名為hello,為項目增加對JSTL的支持:
在JSTL的版本中選擇1.1。
該操作實際上是把jstl.jar和standard.jar加到工程中。
采用類似的操作為項目添加對jsf的支持:myeclipse?add jsf capabilities
如圖:

其中的jsf implementation是選擇使用哪中JSF實現(xiàn),我們采用的是sun的jsf ri
JSF config path是配置文件的位置,保持不變
URL pattern是jsf servlet的映射方式,有兩種選擇,具體細節(jié)后面說明。
以上操作上是為項目加入了jsf需要的jar和tld文件,并且創(chuàng)建了一個faces-config.xml的配置文件。涉及到的jar有:commons-beanutils.jar commons-collections.jar commons-digester.jar commons-logging.jar jsf-api.jar jsf-impl.jar
涉及到了jsf中所有的tld文件。
當前的faces-config.xml文件的內(nèi)容是:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
</faces-config>
環(huán)境已經(jīng)建立好了,現(xiàn)在我們要建立一個程序,它的功能是讓用戶在表單中輸入名字,提交后系統(tǒng)會返回一個問候。使用jsf的以后好處是,開發(fā)人員會很自然的把mvc各層分開,不會像使用strtus那樣別扭,這一點在后面的開發(fā)中感覺得到。
首先開發(fā)model層,它是個很簡單的bean:
package org.bromon.jsf.model.hello;
public class SayHello {
public String say(String name)
{
return "你好,"+name;
}
}
在model層中你可以隨意的實現(xiàn)業(yè)務(wù)的數(shù)據(jù)邏輯,不需要與web層有任何的關(guān)系。
下面開發(fā)控制層,它負責存取web層的數(shù)據(jù),并且調(diào)用model層的邏輯:
/**
* jsf的控制層方法
* @author bromon
*/
package org.bromon.jsf.control.hello;
import org.bromon.jsf.model.hello.*;
public class HelloDelegater {
//------屬性---------
private String name;//表單中的文本框數(shù)據(jù)會傳到這里
private String result;//web頁會從這里取得運行結(jié)果
private SayHello sayHello;//model層的對象,并不事例化,由系統(tǒng)注入
//-----set/get--------
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public SayHello getSayHello() {
return sayHello;
}
public void setSayHello(SayHello sayHello) {
this.sayHello = sayHello;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
//-----邏輯方法---------
public String say()
{
this.setResult(sayHello.say(this.getName()));
return "ok";
}
}
需要注意的是,屬性的名字、set/get方法的名字必須嚴格按照java bean規(guī)范編寫,因為它們要被注入依賴時使用。sayHello對象并沒有被實例化,它會在運行時由系統(tǒng)注入。
這兩個bean當然要在系統(tǒng)中申明,否則無法實現(xiàn)DI。在faces-config.xml文件中添加內(nèi)容:
<managed-bean>
<managed-bean-name>SayHello</managed-bean-name>
<managed-bean-class>
org.bromon.jsf.model.hello.SayHello
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>HelloDelegater</managed-bean-name>
<managed-bean-class>
org.bromon.jsf.control.hello.HelloDelegater
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>sayHello</property-name>
<value>#{SayHello}</value>
</managed-property>
</managed-bean>
在后一個bean中,它的sayHello屬性被指定要在運行時注入一個org.bromon.jsf.model.hello.SayHello的實例。
下面要編寫表示層的頁面,只有一個index.jsp:
需要引入兩個標簽庫:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
下面是構(gòu)造jsf標簽:
<body>
<f:view>
<h:form>
<h:panelGrid columns="3">
<h:outputLabel for="name" value="姓名:"/>
<h:inputText id="name" value="#{HelloDelegater.name}" required="true"/>
<h:message for="name"/>
<h:outputLabel value="#{HelloDelegater.result}"/>
</h:panelGrid>
<h:panelGroup>
<h:commandButton action="#{HelloDelegater.say}" value="提交"/>
</h:panelGroup>
</h:form>
</f:view>
</body>
頁面中包含了一個文本框和一個label,他們分別被綁定到了HelloDelegater類的兩個屬性上,具體的綁定工作有系統(tǒng)通過翻轉(zhuǎn)控制的方式調(diào)用對應(yīng)的set/get方式實現(xiàn)。提交按鈕被綁定到了HelloDelegater.say方法,該方法會把計算結(jié)果賦給result屬性,它會在頁面中顯示出來。
因為我們在url pattern中選擇了*.faces,所以我們應(yīng)該訪問如下地址來查看程序:
http://localhost:8080/hello/index.faces
相應(yīng)的,如果你選擇了/faces/*,那么就應(yīng)該是:
http://localhost:8080/hello/faces/index.jsp
程序執(zhí)行結(jié)果如下:
bromon原創(chuàng)
//組件,容器,引擎,框架,平臺
設(shè)計,無外乎抽象
先看一段接口的使用代碼
public class container{
public void excute(Comp c){
c.metod1();
c. metod2 ();
}
}
interface Comp{
public void method1 ();
public void method2 ();
}
class CompImpt{
public void method1 (){
System.out.println(“method1”);
}
public void method2 (){
System.out.println(“method2”);
}
}
這個就是接口的使用,當你把調(diào)用接口的類當作是容器,當作是引擎時,當作是框架時,CompImpt就是組件,你就成為了設(shè)計師,把調(diào)用接口的類當作是平臺時,CompImpt就是插件,你就成了架構(gòu)師
開個玩笑,呵呵!!
使用cvs本身基于pserver的遠程認證很麻煩,需要定義服務(wù)器和用戶組,用戶名,設(shè)置密碼等,
常見的登陸格式如下:
cvs -d :pserver:cvs_user_name@cvs.server.address:/path/to/cvsroot login
例子:
cvs -d :pserver:cvs@samba.org:/cvsroot login
不是很安全,因此一般是作為匿名只讀CVS訪問的方式。從安全考慮,通過系統(tǒng)本地帳號認證并通過SSH傳輸是比較好的辦法,通過在客戶機的 /etc/profile里設(shè)置一下內(nèi)容:
CVSROOT=:ext:$USER@cvs.server.address#port:/path/to/cvsroot CVS_RSH=ssh; export CVSROOT CVS_RSH
所有客戶機所有本地用戶都可以映射到CVS服務(wù)器相應(yīng)同名帳號了。
比如:
CVS服務(wù)器是192.168.0.3,上面CVSROOT路徑是/home/cvsroot,另外一臺開發(fā)客戶機是192.168.0.4,如果 tom在2臺機器上都有同名的帳號,那么從192.168.0.4上設(shè)置了:
export CVSROOT=:ext:tom@192.168.0.3:/home/cvsroot
export CVS_RSH=ssh
tom就可以直接在192.168.0.4上對192.168.0.3的cvsroot進行訪問了(如果有權(quán)限的話)
cvs checkout project_name
cd project_name
cvs update
...
cvs commit
如果CVS所在服務(wù)器的SSH端口不在缺省的22,或者和客戶端與CVS服務(wù)器端SSH缺省端口不一致,有時候設(shè)置了:
:ext:$USER@test.server.address#port:/path/to/cvsroot
仍然不行,比如有以下錯誤信息:
ssh: test.server.address#port: Name or service not known
cvs [checkout aborted]: end of file from server (consult above messages if any)
解決的方法是做一個腳本指定端口轉(zhuǎn)向(不能使用alias,會出找不到文件錯誤):
創(chuàng)建一個/usr/bin/ssh_cvs文件,假設(shè)遠程服務(wù)器的SSH端口是非缺省端口:34567
#!/bin/sh
/usr/bin/ssh -p 34567 "$@"
然后:chmod +x /usr/bin/ssh_cvs
并CVS_RSH=ssh_cvs; export CVS_RSH
注意:port是指相應(yīng)服務(wù)器SSH的端口,不是指cvs專用的pserver的端口
1.環(huán)境: redhat
2.服務(wù)器配置
a.設(shè)置用戶能通過ssh方式登入cvs server
b.確定/etc/service文件有如下兩行
cvspserver 2401/tcp
cvspserver 2401/udp
c.在/etc/xinetd.d目錄下建立cvspserver文件,內(nèi)容如下
service cvspserver
{
disable = no
flags = REUSE
socket_type = stream
wait = no
user = root
env = HOME=
server = /usr/bin/cvs
server_args = -f --allow-root=/opt/cvsroot/REPORT pserver
log_on_failure += USERID
only_from = 127.0.0.1
bin = 127.0.0.1
}
3.客戶端配置
a.用tortoiseCVS做cvs客戶端,protocol選擇"Secure shell (:ext:)"
b.eclipse中protocol選擇extssh即可
c.其他客戶端設(shè)置去問google