當團隊成員完成新的工作時,通過將這些更改提交到資源庫來共享他們的工作。類似地,當他們希望獲得最新可用的工作成果時,就可以根據(jù)資源庫中的更改,更新自己的本地工作空間。這意味著項目資源庫會因團隊成員提交新工作成果而經(jīng)常發(fā)生更改。換句話說,資源庫應(yīng)該表示項目的當前狀態(tài)。任何時候,團隊成員都要能夠根據(jù)資源庫更新自己的工作空間,并確信它們是最新的。
維護歷史記錄也很重要,那樣就可以將當前工作與先前版本進行比較,如有必要,還可以回復(fù)到先前版本。協(xié)調(diào)團隊的工作,以便只存在唯一的當前項目狀態(tài)定義,以及包含團隊已集成的工作,這些對于管理版本控制也是十分必要的。這種協(xié)調(diào)有可能是最難實現(xiàn)的目標。
最理想的模型是:團隊的任何成員都可以對自己有權(quán)訪問的任何資源進行更改。因為兩個團隊成員可以提交對同一資源的更改,所以有可能發(fā)生沖突,必須解決這種沖突。這種模型假定沖突具有唯一性。但遺憾的是,沒有任何源代碼是孤立地存在的;通常它包含與其它資源隱式或顯式的相關(guān)性。源代碼引用了在其它源代碼資源中描述的構(gòu)件。但源代碼管理軟件的工作就到此為止了,因為它并不能取代項目管理。項目管理者必須履行其職責:協(xié)調(diào)其它成員的工作以及負責進度、項目階段和發(fā)布日期。此外,源代碼管理也不能替代開發(fā)人員之間的交流。
Eclipse 平臺如何支持代碼管理
Eclipse 平臺提供了作為團隊在軟件項目中共享代碼和工作的能力。Eclipse 廣泛地支持各種代碼管理解決方案,這要歸功于它的插件體系結(jié)構(gòu)(不過,現(xiàn)已推出了對 CVS 的支持)。Eclipse 平臺體系結(jié)構(gòu)的重點在于工作空間。工作空間維護構(gòu)建和測試軟件項目所需的一切。它包含對象(源代碼和資源)。它還保存了用于項目、IDE 和插件的配置設(shè)置。工作空間是在開發(fā)人員的機器上本地進行維護的,而團隊通過外部資源庫進行協(xié)作,不同開發(fā)人員的代碼在資源庫進行匯集。可以經(jīng)由因特網(wǎng)通過“客戶機-服務(wù)器”體系結(jié)構(gòu)訪問資源庫。
Eclipse 平臺提供了對于直接從工作空間進行團隊開發(fā)操作的支持。這種支持允許開發(fā)人員并發(fā)地與幾個獨立的資源庫以及不同版本的代碼或項目進行交互。工作空間中的資源允許團隊支持組件處理版本和配置管理問題。當然,單個工作空間可以同時訪問不同類型的資源庫。Eclipse 平臺并沒有提供它自己的代碼管理解決方案;它總是依靠外部系統(tǒng)。Eclipse 平臺只對一個(但也是最流行的一個)源代碼管理系統(tǒng)提供內(nèi)置支持:并發(fā)版本控制系統(tǒng)(Concurrent Versions System,CVS)。對第三方代碼管理應(yīng)用程序的支持一節(jié)中描述了使用第三方插件支持其它資源庫。
CVS 是什么?
CVS 誕生于 1986 年,當時作為一組 shell 腳本而出現(xiàn),但它現(xiàn)在已經(jīng)發(fā)展成了最流行的針對軟件開發(fā)人員的源代碼版本管理解決方案。CVS 是用于代碼版本管理的開放源碼的客戶機/服務(wù)器解決方案,它可用于各種平臺,包括 Linux 和 Windows NT/2000/XP。請參閱本文末尾的參考資料,其中有 CVS 客戶機、服務(wù)器和源代碼的下載鏈接。
通常,CVS 的主要功能是記錄源文件的歷史。當一組開發(fā)人員從事同一個項目時,CVS 將他們彼此隔離開來。每個開發(fā)人員都在他/她自己的目錄中獨立工作,然后使用 CVS 資源庫(不時地)合并工作結(jié)果。
Eclipse 擁有與 Eclipse 平臺 IDE 緊密集成的內(nèi)置 CVS 客戶機,它是作為一個單獨透視圖(CVS Repository Exploring 透視圖)而實現(xiàn)的,用于與 CVS 的交互。用于 CVS 的通用 Eclipse 設(shè)置(General Eclipse settings for CVS)位于 Window -> Preferences window -> Team 下。在切換到 CVS Repository Exploring 透視圖之后,就可以使用所有 CVS 操作了(轉(zhuǎn)至 Window -> Open Perspective -> Other -> CVS Repository Exploring 菜單 — 請參閱圖 1 和圖 2)。
圖 1. 切換到 CVS Repository Exploring 透視圖
首先設(shè)置資源庫的位置,它將定義用于選定 CVS 服務(wù)器/資源庫的連接參數(shù)。請確保使用 SSH 隧道(extssh
)。
圖 2. 瀏覽 CVS Repository Exploring 透視圖中的 CVS 資源庫
Eclipse/CVS 的源代碼工作流
在 CVS 團隊協(xié)作模型中,團隊成員彼此獨立地在他們各自的工作臺上完成自己的所有工作。最后,他們希望共享其工作。他們通過 CVS 資源庫實現(xiàn)這一點。CVS 使用分支(branch)模型來支持彼此獨立而又高度相互依賴的多個工作流程(course of work)。這些分支是開發(fā)團隊用來共享和集成正在進行中的工作的地方。可以認為分支是一個共享的工作臺,當團隊成員對源代碼進行更改時就更新這個工作臺。這個模型允許從事 CVS 團隊項目的每個開發(fā)人員在進行更改時與其他成員共享其工作,以及在項目進展期間訪問其他成員的工作。
一個稱為 HEAD 的特殊分支用來表示資源庫中的主要工作流程(HEAD 通常被稱為主干)。當團隊成員將資源提交給該分支時,會影響這些相關(guān)性。確保相關(guān)性的完整性是很重要的,因為該分支表示了當前項目的狀態(tài)。當然,任何時候,團隊成員都可以使用該分支的內(nèi)容作為新工作的基礎(chǔ)。
那些規(guī)則不僅適用于 CVS:無論使用哪種版本控制軟件,團隊項目中都有一些用于源代碼管理的常見步驟。下面是一個使用 Eclipse 內(nèi)置的 CVS 支持的示例工作流:
1. 啟動新的團隊項目
每個新的空 Eclipse 項目都可以通過 CVS(或受支持的任何其它源代碼管理系統(tǒng))進行共享。開發(fā)人員也可以通過將其現(xiàn)有的代碼遷移到資源庫來共享它。要進行共享,單擊項目主文件夾,在顯示的上下文菜單中使用 Team -> Share Project 選項,如圖 3 所示。
另一個選項是通過從選定的 CVS 資源庫分支導(dǎo)入代碼來創(chuàng)建新的工作臺項目。只要選擇適當分支(或 HEAD),然后選擇從 CVS Repository Exploring 透視圖中的上下文菜單中選擇“Checkout As Project”選項,如圖 4 所示。
圖 4. 從現(xiàn)有的 CVS 資源庫創(chuàng)建新項目
2. 使用代碼并進行更改
開發(fā)人員通過 Eclipse 工作臺在本地使用代碼,包括的工作有創(chuàng)建新資源、修改現(xiàn)有資源、編寫注釋,并在他們使用后在本地保存這些內(nèi)容。
3. 使本地更改與 CVS 資源庫同步
如果一個項目開發(fā)人員準備提交他/她的工作,那么首先要執(zhí)行更新操作。這會針對引入的更改核對資源庫,并將這些更改添加到該開發(fā)人員的本地工作臺。這樣確保了開發(fā)人員知道這些更改可能會影響他/她將要提交的工作的完整性。使用項目上下文菜單中的 Compare With... 選項將本地版本與資源庫中存儲的代碼進行比較(請參閱圖 5)。
下一步是解決最后出現(xiàn)的任何沖突,并設(shè)法再次編譯代碼。如果一切正常,那么從項目上下文菜單使用 Team -> Commit... 選項執(zhí)行提交操作,如圖 6 所示。這會使所有更改都集成到資源庫中。
4. 管理資源庫
CVS 允許開發(fā)人員將更改隔離在開發(fā)的某些獨立路徑之內(nèi),這些路徑稱為分支。當一個開發(fā)人員更改某個分支上的文件時,這種更改不會出現(xiàn)在主干或其它分支上。那些分支被命名為子版本(subversion)或代碼分叉(code fork)。稍后,由合并操作將更改從一個分支遷移到另一個分支(或主干)。然后提交這些修訂。這樣就有效地將更改復(fù)制到了另一個分支上。使用項目上下文菜單的 Team -> Branch... 選項,Eclipse 使開發(fā)分支之間的遷移變得容易。
當然,當開發(fā)團隊維護大型資源庫時,有必要控制項目內(nèi)的提交和合并操作。Eclipse/CVS 集成提供了一種特殊的視圖:CVS Repository History(請參閱圖 7)。它給出了關(guān)于團隊成員在資源庫中所執(zhí)行更改的快速預(yù)覽。
圖 7. 在 CVS Resource History 窗口中查看帶注釋的修訂歷史記錄
Eclipse 平臺提供了幾個支持代碼管理的實用程序。最有用的是補丁功能。它將出自兩個來源(譬如本地工作臺和資源庫)的代碼進行比較,然后創(chuàng)建一個包含代碼差異的類似 UNIX 的補丁文件(請參閱圖 8)。可以將該文件發(fā)送給開發(fā)人員以將源代碼升級到最新版本。
5. 斷開項目與 CVS 的連接
當項目開發(fā)已經(jīng)結(jié)束,并且團隊希望凍結(jié)源代碼時,可以從 HEAD 資源庫刪除該項目的最終版本。斷開項目與 CVS 的連接將在該項目及其資源上禁用資源庫操作,并刪除與該項目相關(guān)聯(lián)的 CVS 信息(這一操作是可選的)。
可以通過項目上下文菜單中的 Team -> Disconnect 選項執(zhí)行斷開連接操作。通過選擇這個選項,會打開 Confirm Disconnect from CVS 對話框。在將該項目與資源庫的連接斷開之后,該團隊必須確定如何處理 CVS 信息。第一個選項是“Delete the CVS meta information”;它將禁用 CVS 團隊菜單操作并從文件系統(tǒng)中刪除CVS 文件夾及其內(nèi)容。第二個選項是“Do not delete the CVS meta information”;它將禁用 CVS 團隊菜單操作,但保留 CVS 元信息。
對第三方代碼管理應(yīng)用程序的支持
CVS 有幾個重要的限制:它不能確定單個文件或整個文件集范圍內(nèi)同時進行的更改,它也不能檢測文件之間的邏輯沖突。其沖突概念純粹是文本意義上的,當對于同一基本文件的兩個更改時間上非常非常接近,從而使合并命令受到干擾時,就會發(fā)生沖突。CVS 也不能提供任何類似于消息傳遞這樣的交互式協(xié)作工具。幸運的是,CVS 并不是 Eclipse 平臺所支持的唯一的源代碼管理軟件。開發(fā)人員可以通過插件擴展 Eclipse 平臺的功能,而且目前(到 2003 年 3 月 4 日為止)已有 16 個可用于團隊開發(fā)軟件的插件。所有插件都是由 Eclipse 社區(qū)或商業(yè)軟件供應(yīng)商創(chuàng)建的。這些插件中的大多數(shù)添加了對第三方、商業(yè)源代碼管理系統(tǒng)的支持。最有價值的插件是那些支持流行的企業(yè)代碼管理系統(tǒng)(如 Merant PVCS 和 Rational ClearCase)的插件。例如,CVS-SSH2 插件允許通過 SSH2 會話訪問 CVS,而 Microsoft Visual SourceSafe(VSS)團隊提供程序插件添加了對 MS VSS 產(chǎn)品的支持(也可以在諸如 Linux 這樣的非 Windows 平臺上使用)。
但是,我本人所偏愛的插件是 Koi(請參閱參考資料以獲取鏈接)。盡管它并非嚴格用于源代碼控制,但這個創(chuàng)新的工具給協(xié)作開發(fā)注入了許多新的活力。其當前版本支持工作臺到工作臺的消息傳遞、共享標記、沖突更改通知、共享日歷和事件通知。Koi 將 XML-RPC 用作其客戶機-服務(wù)器體系結(jié)構(gòu)中的通信模型。客戶機是與“協(xié)作服務(wù)器”通信的單個 Eclipse 平臺實例,而協(xié)作服務(wù)器也是一個 Eclipse 插件。Koi 使用以 JDBC 訪問的關(guān)系數(shù)據(jù)庫作為數(shù)據(jù)存儲。可在參考資料中找到指向完整的、經(jīng)過分類的 Eclipse 插件注冊表的鏈接。
關(guān)于作者 Pawel Leszek 是 Studio B 的一位作家,他是一位專長于 Linux/Win/Mac OS 系統(tǒng)體系結(jié)構(gòu)和管理的獨立軟件顧問和作家。他具有許多操作系統(tǒng)、編程語言和網(wǎng)絡(luò)協(xié)議方面的經(jīng)驗,尤其是 Lotus Domino 和 DB2 方面。Pawel 還在 LinuxWorld 上發(fā)表過一系列文章,他是 PC World 波蘭版的 Linux 專欄作家。Pawel 和他的妻子以及可愛的小女兒住在華沙。歡迎提問并提出意見;您可以通過 pawel.leszek@ipgate.pl 與 Pawel 聯(lián)系。 |
何謂“持久層”
持久層(Persistence Layer),即專注于實現(xiàn)數(shù)據(jù)持久化應(yīng)用領(lǐng)域的某個特定系統(tǒng)的一個邏輯層面,將數(shù)據(jù)使用者和數(shù)據(jù)實體相關(guān)聯(lián)。
何謂“對象數(shù)據(jù)映射(ORM)”
ORM-Object/Relational Mapper,即“對象-關(guān)系型數(shù)據(jù)映射組件”。對于O/R,即 Object(對象)和 Relational(關(guān)系型數(shù)據(jù)),表示必須同時使用面向?qū)ο蠛完P(guān)系型數(shù)據(jù)進行開發(fā)。
備注:建模領(lǐng)域中的 ORM 為 Object/Role Modeling(對象角色建模)。另外這里是“O/R Mapper”而非“O/R Mapping”。相對來講,O/R Mapping 描述的是一種設(shè)計思想或者實現(xiàn)機制,而 O/R Mapper指以O(shè)/R原理設(shè)計的持久化框架(Framework),包括 O/R機制還有 SQL自生成,事務(wù)處理,Cache管理等。
除了 ORM 技術(shù),還有以下幾種持久化技術(shù)
主動域?qū)ο竽J?br />它是在實現(xiàn)中封裝了關(guān)系數(shù)據(jù)模型和數(shù)據(jù)訪問細節(jié)的一種形式。在 J2EE 架構(gòu)中,EJB 組件分為會話 EJB 和實體 EJB。會話 EJB 通常實現(xiàn)業(yè)務(wù)邏輯,而實體 EJB 表示業(yè)務(wù)實體。實體 EJB 又分為兩種:由 EJB 本身管理持久化,即 BMP(Bean-Managed Persistence);有 EJB 容器管理持久化,即 CMP(Container-Managed Persistence)。BM P就是主動域?qū)ο竽J降囊粋€例子,BMP 表示由實體 EJB 自身管理數(shù)據(jù)訪問細節(jié)。
主動域?qū)ο蟊旧砦挥跇I(yè)務(wù)邏輯層,因此采用主動域?qū)ο竽J綍r,整個應(yīng)用仍然是三層應(yīng)用結(jié)構(gòu),并沒有從業(yè)務(wù)邏輯層分離出獨立的持久化層。
JDO 模式
Java Data Objects(JDO)是 SUN 公司制定的描述對象持久化語義的標準API。嚴格的說,JDO 并不是對象-關(guān)系映射接口,因為它支持把對象持久化到任意一種存儲系統(tǒng)中,包括 關(guān)系數(shù)據(jù)庫、面向?qū)ο蟮臄?shù)據(jù)庫、基于 XML 的數(shù)據(jù)庫,以及其他專有存儲系統(tǒng)。由于關(guān)系數(shù)據(jù)庫是目前最流行的存儲系統(tǒng),許多 JDO 的實現(xiàn)都包含了對象-關(guān)系映射服務(wù)。
CMP 模式
在 J2EE 架構(gòu)中,CMP(Container-Managed Persistence)表示由 EJB 容器來管理實體 EJB 的持久化,EJB 容器封裝了對象-關(guān)系的映射及數(shù)據(jù)訪問細節(jié)。CMP 和 ORM 的相似之處在于,兩者都提供對象-關(guān)系映射服務(wù),都把對象持久化的任務(wù)從業(yè)務(wù)邏輯中分離出來。區(qū)別在于 CMP 負責持久化實體 EJB 組件,而 ORM 負責持久化 POJO,它是普通的基于 Java Bean 形式的實體域?qū)ο蟆?/p>
一般把基于 Java Bean 形式的實體域?qū)ο蠓Q為 POJO(Plain Old Java Object),意為又普通又古老的 Java 對象的意思。隨著各種 ORM 映射工具的日趨成熟和流行,POJO有重現(xiàn)光彩,它和基于 CMP 的實體 EJB 相比,即簡單又具有很高的可移植性,因此聯(lián)合使用 ORM 映射工具和 POJO,已經(jīng)成為一種越來越受歡迎的且用來取代 CMP 的持久化方案。POJO 的缺點就是無法做遠程調(diào)用,不支持分布式計算。
為什么要做持久化和ORM設(shè)計
在目前的企業(yè)應(yīng)用系統(tǒng)設(shè)計中,MVC,即 Model(模型)- View(視圖)- Control(控制)為主要的系統(tǒng)架構(gòu)模式。MVC 中的 Model 包含了復(fù)雜的業(yè)務(wù)邏輯和數(shù)據(jù)邏輯,以及數(shù)據(jù)存取機制(如 JDBC的連接、SQL生成和Statement創(chuàng)建、還有ResultSet結(jié)果集的讀取等)等。將這些復(fù)雜的業(yè)務(wù)邏輯和數(shù)據(jù)邏輯分離,以將系統(tǒng)的緊耦合關(guān)系轉(zhuǎn)化為松耦合關(guān)系(即解耦合),是降低系統(tǒng)耦合度迫切要做的,也是持久化要做的工作。MVC 模式實現(xiàn)了架構(gòu)上將表現(xiàn)層(即View)和數(shù)據(jù)處理層(即Model)分離的解耦合,而持久化的設(shè)計則實現(xiàn)了數(shù)據(jù)處理層內(nèi)部的業(yè)務(wù)邏輯和數(shù)據(jù)邏輯分離的解耦合。而 ORM 作為持久化設(shè)計中的最重要也最復(fù)雜的技術(shù),也是目前業(yè)界熱點技術(shù)。
簡單來說,按通常的系統(tǒng)設(shè)計,使用 JDBC 操作數(shù)據(jù)庫,業(yè)務(wù)處理邏輯和數(shù)據(jù)存取邏輯是混雜在一起的。
一般基本都是如下幾個步驟:
1、建立數(shù)據(jù)庫連接,獲得 Connection 對象。
2、根據(jù)用戶的輸入組裝查詢 SQL 語句。
3、根據(jù) SQL 語句建立 Statement 對象 或者 PreparedStatement 對象。
4、用 Connection 對象執(zhí)行 SQL語句,獲得結(jié)果集 ResultSet 對象。
5、然后一條一條讀取結(jié)果集 ResultSet 對象中的數(shù)據(jù)。
6、根據(jù)讀取到的數(shù)據(jù),按特定的業(yè)務(wù)邏輯進行計算。
7、根據(jù)計算得到的結(jié)果再組裝更新 SQL 語句。
8、再使用 Connection 對象執(zhí)行更新 SQL 語句,以更新數(shù)據(jù)庫中的數(shù)據(jù)。
7、最后依次關(guān)閉各個 Statement 對象和 Connection 對象。
由上可看出代碼邏輯非常復(fù)雜,這還不包括某條語句執(zhí)行失敗的處理邏輯。其中的業(yè)務(wù)處理邏輯和數(shù)據(jù)存取邏輯完全混雜在一塊。而一個完整的系統(tǒng)要包含成千上萬個這樣重復(fù)的而又混雜的處理過程,假如要對其中某些業(yè)務(wù)邏輯或者一些相關(guān)聯(lián)的業(yè)務(wù)流程做修改,要改動的代碼量將不可想象。另一方面,假如要換數(shù)據(jù)庫產(chǎn)品或者運行環(huán)境也可能是個不可能完成的任務(wù)。而用戶的運行環(huán)境和要求卻千差萬別,我們不可能為每一個用戶每一種運行環(huán)境設(shè)計一套一樣的系統(tǒng)。
所以就要將一樣的處理代碼即業(yè)務(wù)邏輯和可能不一樣的處理即數(shù)據(jù)存取邏輯分離開來,另一方面,關(guān)系型數(shù)據(jù)庫中的數(shù)據(jù)基本都是以一行行的數(shù)據(jù)進行存取的,而程序運行卻是一個個對象進行處理,而目前大部分數(shù)據(jù)庫驅(qū)動技術(shù)(如ADO.NET、JDBC、ODBC等等)均是以行集的結(jié)果集一條條進行處理的。所以為解決這一困難,就出現(xiàn) ORM 這一個對象和數(shù)據(jù)之間映射技術(shù)。
舉例來說,比如要完成一個購物打折促銷的程序,用 ORM 思想將如下實現(xiàn)(引自《深入淺出Hibernate》):
業(yè)務(wù)邏輯如下:
public Double calcAmount(String customerid, double amount)
{
??? // 根據(jù)客戶ID獲得客戶記錄
??? Customer customer = CustomerManager.getCustomer(custmerid);
??? // 根據(jù)客戶等級獲得打折規(guī)則
??? Promotion promotion = PromotionManager.getPromotion(customer.getLevel());
??? // 累積客戶總消費額,并保存累計結(jié)果
??? customer.setSumAmount(customer.getSumAmount().add(amount);
??? CustomerManager.save(customer);
??? // 返回打折后的金額
??? return amount.multiply(protomtion.getRatio());
}
這樣代碼就非常清晰了,而且與數(shù)據(jù)存取邏輯完全分離。設(shè)計業(yè)務(wù)邏輯代碼的時候完全不需要考慮數(shù)據(jù)庫JDBC的那些千篇一律的操作,而將它交給 CustomerManager 和 PromotionManager 兩個類去完成。這就是一個簡單的 ORM 設(shè)計,實際的 ORM 實現(xiàn)框架比這個要復(fù)雜的多。
目前有哪些流行的 ORM 產(chǎn)品
目前眾多廠商和開源社區(qū)都提供了持久層框架的實現(xiàn),常見的有
Apache OJB (http://db.apache.org/ojb/)
Cayenne (http://objectstyle.org/cayenne/)
Jaxor (http://jaxor.sourceforge.net)
Hibernate (http://www.hibernate.org)
iBatis (http://www.ibatis.com)
jRelationalFramework (http://ijf.sourceforge.net)
mirage (http://itor.cq2.org/en/oss/mirage/toon)
SMYLE (http://www.drjava.de/smyle)
TopLink (http://otn.oracle.com/products/ias/toplink/index.html)
其中 TopLink 是 Oracle 的商業(yè)產(chǎn)品,其他均為開源項目。
其中 Hibernate 的輕量級 ORM 模型逐步確立了在 Java ORM 架構(gòu)中領(lǐng)導(dǎo)地位,甚至取代復(fù)雜而又繁瑣的 EJB 模型而成為事實上的 Java ORM 工業(yè)標準。而且其中的許多設(shè)計均被 J2EE 標準組織吸納而成為最新 EJB 3.0 規(guī)范的標準,這也是開源項目影響工業(yè)領(lǐng)域標準的有力見證。
參考文獻:1、《深入淺出Hibernate》
???????? 2、《精通Hibernate:Java對象持久化技術(shù)詳解》
內(nèi)容摘要:
CVS是一個C/S系統(tǒng),多個開發(fā)人員通過一個中心版本控制系統(tǒng)來記錄文件版本,從而達到保證
文件同步的目的。工作模式如下:
CVS服務(wù)器(文件版本庫)
/ | \
(版 本 同 步)
/ | \
開發(fā)者1 開發(fā)者2 開發(fā)者3
作為一般開發(fā)人員挑選2,6看就可以了,CVS的管理員則更需要懂的更多一些,最后還簡單介紹了
一些Windows下的cvs客戶端使用,CVS遠程用戶認證的選擇及與BUG跟蹤系統(tǒng)等開發(fā)環(huán)境的集成
問題。
一個系統(tǒng)20%的功能往往能夠滿足80%的需求,CVS也不例外,以下是CVS最常用的功能,可能還不
到它全部命令選項的20%,作為一般開發(fā)人員平時會用cvs update和cvs commit就夠了,更多的需求在
實際應(yīng)用過程中自然會出現(xiàn),不時回頭看看相關(guān)文檔經(jīng)常有意外的收獲。
tcsh
setenv CVSROOT /path/to/cvsroot
bash
CVSROOT=/path/to/cvsroot ; export CVSROOT
后面還提到遠程CVS服務(wù)器的設(shè)置:
CVSROOT=:ext:$USER@test.server.address#port:/path/to/cvsroot CVS_RSH=ssh;
export CVSROOT CVS_RSH
初始化:CVS版本庫的初始化。
cvs init
一個項目的首次導(dǎo)入
cvs import -m "write some comments here" project_name vendor_tag release_tag
執(zhí)行后:會將所有源文件及目錄導(dǎo)入到/path/to/cvsroot/project_name目錄下
vender_tag: 開發(fā)商標記
release_tag: 版本發(fā)布標記
項目導(dǎo)出:將代碼從CVS庫里導(dǎo)出
cvs checkout project_name
cvs 將創(chuàng)建project_name目錄,并將最新版本的源代碼導(dǎo)出到相應(yīng)目錄中。這個checkout和Virvual SourceSafe中的check out不是一個概念,相對于Virvual SourceSafe的check out是cvs update,
check in是cvs commit。
注意:第一次導(dǎo)出以后,就不是通過cvs checkout來同步文件了,而是要進入剛才cvs checkout
project_name導(dǎo)出的project_name目錄下進行具體文件的版本同步(添加,修改,刪除)操作。
將文件同步到最新的版本
cvs update
不制定文件名,cvs將同步所有子目錄下的文件,也可以制定某個文件名/目錄進行同步
cvs update file_name
最好每天開始工作前或?qū)⒆约旱墓ぷ鲗?dǎo)入到CVS庫里前都要做一次,并養(yǎng)成“先同步 后修改”的習
慣,和Virvual SourceSafe不同,CVS里沒有文件鎖定的概念,所有的沖突是在commit之前解決,如果
你修改過程中,有其他人修改并commit到了CVS 庫中,CVS會通知你文件沖突,并自動將沖突部分用
>>>>>>
content on cvs server
<<<<<<
content in your file
>>>>>>
標記出來,由你確認沖突內(nèi)容的取舍。
版本沖突一般是在多個人修改一個文件造成的,但這種項目管理上的問題不應(yīng)該指望由CVS來解決。
確認修改寫入到CVS庫里
cvs commit -m "write some comments here" file_name
注意:CVS的很多動作都是通過cvs commit進行最后確認并修改的,最好每次只修改一個文件。在確認
的前,還需要用戶填寫修改注釋,以幫助其他開發(fā)人員了解修改的原因。如果不用寫-m "comments"而
直接確認`cvs commit file_name` 的話,cvs會自動調(diào)用系統(tǒng)缺省的文字編輯器(一般是vi)要求你寫入注釋。
注釋的質(zhì)量很重要:所以不僅必須要寫,而且必須寫一些比較有意義的內(nèi)容:以方便其他開發(fā)人員能
夠很好的理解不好的注釋,很難讓其他的開發(fā)人員快速的理解:比如: -m "bug fixed" 甚至 -m ""
好的注釋,甚至可以用中文: -m "在用戶注冊過程中加入了Email地址校驗"
修改某個版本注釋:每次只確認一個文件到CVS庫里是一個很好的習慣,但難免有時候忘了指定文件
名,把多個文件以同樣注釋commit到CVS庫里了,以下命令可以允許你修改某個文件某個版本的注釋:
cvs admin -m 1.3:"write some comments here" file_name
添加文件
創(chuàng)建好新文件后,比如:touch new_file
cvs add new_file
注意:對于圖片,Word文檔等非純文本的項目,需要使用cvs add -kb選項按2進制文件方式導(dǎo)入(k表示
擴展選項,b表示binary),否則有可能出現(xiàn)文件被破壞的情況
比如:
cvs add -kb new_file.gif
cvs add -kb readme.doc
如果關(guān)鍵詞替換屬性在首次導(dǎo)入時設(shè)置錯了怎么辦?
cvs admin -kkv new_file.css
然后確認修改并注釋
cvs ci -m "write some comments here"
刪除文件
將某個源文件物理刪除后,比如:rm file_name
cvs rm file_name
然后確認修改并注釋
cvs ci -m "write some comments here"
以上面前2步合并的方法為:
cvs rm -f file_name
cvs ci -m "why delete file"
注意:很多cvs命令都有縮寫形式:commit=>ci; update=>up; checkout=>co/get; remove=>rm;
添加目錄
cvs add dir_name
查看修改歷史
cvs log file_name
cvs history file_name
查看當前文件不同版本的區(qū)別
cvs diff -r1.3 -r1.5 file_name
查看當前文件(可能已經(jīng)修改了)和庫中相應(yīng)文件的區(qū)別
cvs diff file_name
cvs的web界面提供了更方便的定位文件修改和比較版本區(qū)別的方法,具體安裝設(shè)置請看后面的cvsweb
使用
正確的通過CVS恢復(fù)舊版本的方法:
如果用cvs update -r1.2 file.name
這個命令是給file.name加一個STICK TAG: "1.2" ,雖然你的本意只是想將它恢復(fù)到1.2版本
正確的恢復(fù)版本的方法是:cvs update -p -r1.2 file_name >file_name
如果不小心已經(jīng)加成STICK TAG的話:用cvs update -A 解決
移動文件/文件重命名
cvs里沒有cvs move或cvs rename,因為這兩個操作是可以由先cvs remove old_file_name,然后cvs add new_file_name實現(xiàn)的。
刪除/移動目錄
最方便的方法是讓管理員直接移動,刪除CVSROOT里相應(yīng)目錄(因為CVS一個項目下的子目錄都是
獨立的,移動到$CVSROOT目錄下都可以作為新的獨立項目:好比一顆樹,其實砍下任意一枝都能獨
立存活),對目錄進行了修改后,要求其開發(fā)人員重新導(dǎo)出項目cvs checkout project_name 或者用
cvs update -dP同步。
項目發(fā)布導(dǎo)出不帶CVS目錄的源文件
做開發(fā)的時候你可能注意到了,每個開發(fā)目錄下,CVS都創(chuàng)建了一個CVS/目錄。里面有文件用于記錄
當前目錄和CVS庫之間的對應(yīng)信息。但項目發(fā)布的時候你一般不希望把文件目錄還帶著含有CVS信息
的CVS目錄吧,這個一次性的導(dǎo)出過程使用cvs export命令,不過export只能針對一個TAG或者日期導(dǎo)出,比如:
cvs export -r release1 project_name
cvs export -D 20021023 project_name
cvs export -D now project_name
cvs tag release_1_0
開始一個新的里程碑:
cvs commit -r 2 標記所有文件開始進入2.x的開發(fā)
注意:CVS里的revsion和軟件包的發(fā)布版本可以沒有直接的關(guān)系。但所有文件使用和發(fā)布版本一致的
版本號比較有助于維護。
版本分支的建立
在開發(fā)項目的2.x版本的時候發(fā)現(xiàn)1.x有問題,但2.x又不敢用,則從先前標記的里程碑:release_1_0導(dǎo)出
一個分支 release_1_0_patch
cvs rtag -b -r release_1_0 release_1_0_patch proj_dir
一些人先在另外一個目錄下導(dǎo)出release_1_0_patch這個分支:解決1.0中的緊急問題,
cvs checkout -r release_1_0_patch
而其他人員仍舊在項目的主干分支2.x上開發(fā)
在release_1_0_patch上修正錯誤后,標記一個1.0的錯誤修正版本號
cvs tag release_1_0_patch_1
如果2.0認為這些錯誤修改在2.0里也需要,也可以在2.0的開發(fā)目錄下合并release_1_0_patch_1中的修改到
當前代碼中:
cvs update -j release_1_0_patch_1
常見的登陸格式如下:
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的端口
使用的樣例可以看:http://www.freebsd.org/cgi/cvsweb.cgi
CVSWEB的下載:CVSWEB從最初的版本已經(jīng)演化出很多功能界面更豐富的版本,這個是我個人感
覺安裝設(shè)置比較方便的:
原先在:http://www.spaghetti-code.de/software/linux/cvsweb/,但目前已經(jīng)刪除,目前仍可以在本站下載CVSWEB,其實最近2年FreeBSD的CVSWeb項目已經(jīng)有了更好的發(fā)展吧,而當初沒有用FreeBSD那個
版本主要就是因為沒有彩色的文件Diff功能。
下載解包:
tar zxf cvsweb.tgz
把配置文件cvsweb.conf放到安全的地方(比如和apache的配置放在同一個目錄下),
修改:cvsweb.cgi讓CGI找到配置文件:
$config = $ENV{'CVSWEB_CONFIG'} || '/path/to/apache/conf/cvsweb.conf';
轉(zhuǎn)到/path/to/apache/conf下并修改cvsweb.conf:
CVSWEB可不能隨便開放給所有用戶,因此需要使用WEB用戶認證:
先生成 passwd:
/path/to/apache/bin/htpasswd -c cvsweb.passwd user
修改httpd.conf: 增加
<Directory "/path/to/apache/cgi-bin/cvsweb/">
AuthName "CVS Authorization"
AuthType Basic
AuthUserFile /path/to/cvsweb.passwd
require valid-user
</Directory>
幾個常用的缺省文件:
default.php
<?php
/*
* Copyright (c) 2002 Company Name.
* $Header: /home/cvsroot/tech/cvs_card.html,v 1.9 2003/11/09 07:57:11
chedong Exp $
*/
?>
====================================
Default.java: 注意文件頭一般注釋用 /* 開始 JAVADOC注釋用 /** 開始的區(qū)別
/*
* Copyright (c) 2002 MyCompany Name.
* $Header: /home/cvsroot/tech/cvs_card.html,v 1.9 2003/11/09 07:57:11
chedong Exp $
*/
package com.mycompany;
import java.;
/**
* comments here
*/
public class Default {
/**
* Comments here
* @param
* @return
*/
public toString() {
}
}
====================================
default.pl:
#!/usr/bin/perl -w
# Copyright (c) 2002 Company Name.
# $Header: /home/cvsroot/tech/cvs_card.html,v 1.9 2003/11/09 07:57:11
chedong Exp $
# file comments here
use strict;
CVS沒有文件鎖定模式,VSS在check out同時,同時記錄了文件被導(dǎo)出者鎖定。
CVS的update和commit, VSS是get_lastest_version和check in
對應(yīng)VSS的check out/undo check out的CVS里是edit和unedit
在CVS中,標記自動更新功能缺省是打開的,這樣也帶來一個潛在的問題,就是不用-kb方式添加
binary文件的話在cvs自動更新時可能會導(dǎo)致文件失效。
$Header: /home/cvsroot/tech/cvs_card.html,v 1.5 2003/03/09 08:41:46 chedong Exp $ $Date: 2003/11/09
07:57:11 $這樣的標記在Virsual SourceSafe中稱之為Keyword Explaination,缺省是關(guān)閉
的,需要通過OPITION打開,并指定需要進行源文件關(guān)鍵詞掃描的文件類型:*.txt,*.java, *.html...
對于Virsual SourceSafe和CVS都通用的TAG有:
$Header: /home/cvsroot/tech/cvs_card.html,v 1.5 2003/03/09 08:41:46 chedong Exp $
$Author: chedong $
$Date: 2003/11/09 07:57:11 $
$Revision: 1.9 $
我建議盡量使用通用的關(guān)鍵詞保證代碼在CVS和VSS都能方便的跟蹤。
cvs Windows客戶端:目前穩(wěn)定版本為1.2
http://cvsgui.sourceforge.net
ssh Windows客戶端
http://www.networksimplicity.com/openssh/
安裝好以上2個軟件以后:
WinCVS客戶端的admin==>preference設(shè)置
1 在general選單里
設(shè)置CVSROOT: username@192.168.0.123:/home/cvsroot
設(shè)置Authorization: 選擇SSH server
2 Port選單里
鉤上:check for alternate rsh name
并設(shè)置ssh.exe的路徑,缺省是裝在 C:\Program Files\NetworkSimplicity\ssh\ssh.exe
然后就可以使用WinCVS進行cvs操作了,所有操作都會跳出命令行窗口要求你輸入服務(wù)器端的認
證密碼。
當然,如果你覺得這樣很煩的話,還有一個辦法就是生成一個沒有密碼的公鑰/私鑰對,并設(shè)置
CVS使用基于公鑰/私鑰的SSH認證(在general 選單里)。
可以選擇的diff工具:examdiff
下載:
http://www.prestosoft.com/examdiff/examdiff.htm
還是在WinCVS菜單admin==>preference的WinCVS選單里
選上:Externel diff program
并設(shè)置diff工具的路徑,比如:C:\Program Files\ed16i\ExamDiff.exe
在對文件進行版本diff時,第一次需要將窗口右下角的use externel diff選上。
這里首先說一下CVS的pserver模式下的用戶認證,CVS的用戶認證服務(wù)是基于inetd中的:
cvspserver stream tcp nowait apache /usr/bin/cvs cvs --allow-root=/home/cvsroot pserver
一般在2401端口(這個端口號很好記:49的平方)
CVS用戶數(shù)據(jù)庫是基于CVSROOT/passwd文件,文件格式:
[username]:[crypt_password]:[mapping_system_user]
由于密碼都用的是UNIX標準的CRYPT加密,這個passwd文件的格式基本上是apache的htpasswd格式
的擴展(比APACHE的 PASSWD文件多一個系統(tǒng)用戶映射字段),所以這個文件最簡單的方法可
以用
apache/bin/htpasswd -b myname mypassword
創(chuàng)建。注意:通過htpasswd創(chuàng)建出來的文件會沒有映射系統(tǒng)用戶的字段
例如:
new:geBvosup/zKl2
setup:aISQuNAAoY3qw
test:hwEpz/BX.rEDU
映射系統(tǒng)用戶的目的在于:你可以創(chuàng)建一個專門的CVS服務(wù)帳號,比如用apache的運行用戶apache,
并將/home/cvsroot目錄下的所有權(quán)限賦予這個用戶,然后在passwd文件里創(chuàng)建不同的開發(fā)用戶帳號,
但開發(fā)用戶帳號最后的文件讀寫權(quán)限都映射為apache用戶,在SSH模式下多個系統(tǒng)開發(fā)用戶需要在
同一個組中才可以相互讀寫CVS庫中的文件。
進一步的,你可以將用戶分別映射到apache這個系統(tǒng)用戶上。
new:geBvosup/zKl2:apache
setup:aISQuNAAoY3qw:apache
test:hwEpz/BX.rEDU:apache
CVSTrac很好的解決了CVSROOT/passwd的管理問題,而且包含了BUG跟蹤報告系統(tǒng)和集成WIKI交
流
功能等,使用的 CGI方式的安裝,并且基于GNU Public License:
在inetd里加入cvspserver服務(wù):
cvspserver stream tcp nowait apache /usr/bin/cvs cvs --allow-root=/home/cvsroot pserver
xietd的配置文件:%cat cvspserver
service cvspserver
{
disable = no
socket_type = stream
wait = no
user = apache
server = /usr/bin/cvs
server_args = -f --allow-root=/home/cvsroot pserver
log_on_failure += USERID
}
注意:這里的用戶設(shè)置成apache目的是和/home/cvsroot的所有用戶一致,并且必須讓這個這個用戶對/home/cvsroot/下的 CVSROOT/passwd和cvstrac初始化生成的myproj.db有讀取權(quán)限。
安裝過程
修改登錄密碼,進行BUG報告等,
更多使用細節(jié)可以在使用中慢慢了解。
對于前面提到的WinCVS在perference里設(shè)置:
CVSROOT欄輸入:username@ip.address.of.cvs:/home/cvsroot
Authenitication選擇:use passwd file on server side
就可以了從服務(wù)器上進行CVS操作了。
CVS的權(quán)限管理分2種策略:
Linux上通過ssh連接CVS服務(wù)器的多個開發(fā)人員:通過都屬于apache組實現(xiàn)文件的共享讀寫開發(fā)人員
有開發(fā)服務(wù)器上的系統(tǒng)帳號:sysuser1 sysuser2,設(shè)置讓他們都屬于apache組,因為通過cvs新導(dǎo)入的
項目都是對組開放的:664權(quán)限的,這樣無論那個系統(tǒng)用戶導(dǎo)入的項目文件,只要文件的組宿主是apache,所有其他同組系統(tǒng)開發(fā)用戶就都可以讀寫;基于ssh遠程認證的也是一樣。
? ?apache(system group)
/ ? ? ? ? ? ?| ? ? ? ? ? \
sysuser1 ? sysuser2 ? ? sysuser3
Windows上通過cvspserver連接CVS服務(wù)器的多個開發(fā)人員:通過在passwd文件種映射成 apache用戶
實現(xiàn)文件的共享讀寫
他們的帳號通過CVSROOT/passwd和readers writers這幾個文件管理;通過cvstrac設(shè)置所有
虛擬用戶都映射到apache用戶上即可。
? ?apache(system user)
/ ? ? ? ? ? ?| ? ? ? ? ? ?\
windev1 ? ? windev2 ? ? ?windev3? ? ? ? ? ? ?
利用CVS WinCVS/CVSWeb/CVSTrac 構(gòu)成了一個相對完善的跨平臺工作組開發(fā)版本控制環(huán)境。
相關(guān)資源:
CVS HOME:
http://www.cvshome.org
CVS FAQ:
http://www.loria.fr/~molli/cvs-index.html
相關(guān)網(wǎng)站:
http://directory.google.com/Top/Computers/Software/Configuration_Management/Tools/Concurrent_
Versions_System/
CVS--并行版本系統(tǒng)
http://www.soforge.com/cvsdoc/zh_CN/book1.html
CVS 免費書:
http://cvsbook.red-bean.com/
CVS命令的速查卡片 refcards.com/refcards/cvs/
WinCVS:
http://cvsgui.sourceforge.net/
CVSTrac: A Web-Based Bug And Patch-Set Tracking System For CVS
http://www.cvstrac.org
StatCVS:基于CVS的代碼統(tǒng)計工具:按代碼量,按開發(fā)者的統(tǒng)計表等
http://sourceforge.net/projects/statcvs
首先,由于其他所有的GUI工具都是基于CVS基本協(xié)議的,而且他們可能會提供CVS的命令行或者等價形
式作為顯示的一部分,所以你應(yīng)該對命令行操作有所了解。如果你還沒有一個cvs。exe的命令行程序,從
www.cvsnt.org你可以得到一個cvsnt的下載連接,其中就包含了一個命令行的cvs.exe程序。我們先從它開始
(為了作為一個client使用,你不需要安裝cvsnt的server組件)。CVSNT的cvs.exe是專門為windows編寫的,你
需要把cvs.exe放在你的path里面。
1.進入命令行方式。和VSS一樣,你也需要在本地有一個工作目錄對應(yīng)于一個repository。假設(shè)這個目錄是'd:\works\sandbox'。
請切換到這個目錄。輸入"cvs"。你會看到:
這些提示信息告訴您關(guān)于cvs的基本語法。cvs后面跟著的是全局參數(shù),然后是命令,最后是命令的參數(shù)。2.login
正確的login不會有任何輸出,否則會告訴你錯誤原因。
如果login失敗,則可以先嘗試命令:set cvsroot=:pserver:cao@IP或者計算機名字/CVSRoot
3.下面我們看看這個CVS server中有哪些module。
4.假設(shè)現(xiàn)在我們工作的項目是projectX,下面我們需要得到它下面的全部文件。
現(xiàn)在讓我們看一下我們得到了什么。
在d:/works/sandbox目錄下,你可以看到有一個projectX目錄。這就是你得到的所有文件。
這個目錄下你會發(fā)現(xiàn)一個叫做 CVS的目錄。危險!請不要刪除這個目錄,或者改名,或者改動其中的
任何文件,除非你知道你在做什么。這個目錄是CVS的控制目錄。如果你用過source safe,你一定很熟悉。scc這個文件,CVS目錄的作用就和這個控制文件一樣,都是用來記錄你訪問服務(wù)器的參數(shù)。
這里我們需要解釋一下cvs和VSS的名詞差別。在VSS中,checkout意味著你將獲得一個文件的修改權(quán),而
cvs中checkout的這個含義取消了,僅僅指取得文件的新版本。很多cvs server會有一個anonymous用戶,他
只有checkout權(quán)限,也就意味著它只讀。???
5.讓我們試著加入一個文件:
在d:/works/sandbox/projectX下,新建一個文件newfile.txt,
然后,在這個目錄下執(zhí)行:
你需要commit它才能被sever接受。
一個notepad窗口彈出請您輸入注釋。
這是commit完成的結(jié)果。現(xiàn)在的版本號是1.1。
6.好了,現(xiàn)在假設(shè)您需要改一下這個文件的內(nèi)容。
CVS可以幫助您比較現(xiàn)在您的版本和repository中的版本有什么不同。
好了,現(xiàn)在您可以提交您的新文件。
CVS會幫您保留您的各個版本。在commit之后,現(xiàn)在我們來看一看各個版本的history。
7.最后,為了完成這個試驗,請把這個newfile文件刪去。
我們現(xiàn)在認識了一些最基本的CVS入門級指令。
其實CVS是非常強大的,我們并沒有用到一些更復(fù)雜的功能,請參閱cvs的手冊來得到更為詳盡的幫助。
轉(zhuǎn)載至:http://www.redsaga.com/CVS_newbie_win32/
5、打開一個cmd窗口,輸入命令set cvsroot=:pserver:sunxdd@server/Root(sunxdd是剛才建立的用戶名,server是安裝的計算機名稱或者IP,/Root是剛才建立的文件夾別名,每次登陸之前都要這樣告訴系統(tǒng)建立這樣一個環(huán)境變量)
cvs login
密碼為空
這時會登錄成功
改密碼
cvs passwd
到這里CVSNT服務(wù)器基本上搞定了。
有用的資源:
http://edu.tmn.cn/html/5/47/185/2005210/104247.htm
http://www.redsaga.com/CVS_newbie_win32/#tortoisecvs
http://sunxdd.blogchina.com/2338489.html
加入WAP書簽
<?xml version="1.0"?> <!DOCTYPE CHARACTERISTIC-LIST SYSTEM "/DTD/characteristic_list.xml"> <CHARACTERISTIC-LIST> <CHARACTERISTIC TYPE="ADDRESS"> <PARM NAME="BEARER" VALUE="GPRS"/> <PARM NAME="PROXY" VALUE="10.0.0.172"/> <PARM NAME="PORT" VALUE="9201"/> <PARM NAME="GPRS_ACCESSPOINTNAME" VALUE="wap.02826.com"/> <PARM NAME="PPP_AUTHTYPE" VALUE="PAP"/> </CHARACTERISTIC> <CHARACTERISTIC TYPE="NAME"> <PARM NAME="NAME" VALUE="wmzsoft GPRS"/> </CHARACTERISTIC> <CHARACTERISTIC TYPE="BOOKMARK"/> <PARM NAME="NAME" VALUE="02826"/> <PARM NAME="URL" VALUE=" http://wap.02826.com "/> </CHARACTERISTIC> </CHARACTERISTIC-LIST> |
<body>
<?php
$title=$_POST["title"];
$text=$_POST["text"];
$name=$_POST["name"];
$count=$_POST["i"];
include_once("數(shù)據(jù)庫連接文件");
if (empty($title)||empty($text)||empty($bar_name)){
?echo "標題或內(nèi)容不能空
?die("<br /><a href=\"index.php\">重新來過</a>");
}
/*這里是數(shù)據(jù)查詢語言取出要用的數(shù)據(jù)*/
if(in_array("0", $_FILES['userfile']['error'])){//上傳文件開始
?$uploaddir= 'attfile/';//設(shè)置上傳的文件夾地址
?$FILES_EXT=array('.gif','.jpg','.mp3','.3gp');//設(shè)置允許上傳文件的類型
?$MAX_SIZE = 20000000;//設(shè)置文件上傳限制20000000byte=2M
?for ($i=0;$i<$count;$i++){
??$FILES_NAME=$_FILES['userfile']['name'][$i];//客戶端文件名
??//取出文件后綴名,strrpos()從標記開始前字節(jié)個數(shù)(不算標記),substr()顯示從第strrpos()之后的字符
??$file_ext=substr($FILES_NAME,strrpos($FILES_NAME,"."));
??//檢查文件大小
??if($_FILES['userfile']['size'][$i]>$MAX_SIZE){
???echo "文件大小超程序允許范圍!";
???exit;
??}
??//檢查文件類型
??if(in_array($file_ext, $FILES_EXT)){
???$_FILES['userfile']['name'][$i]=date("YmdHis").rand(10000,1000000).$file_ext;
???//echo $_FILES['userfile']['name'][$i];
???$uploadfile = $uploaddir.$_FILES['userfile']['name'][$i];//上傳后文件的路徑及文件名
???//echo $uploadfile;
???//用move函數(shù)生成臨時文件名,并按照 $_FILES['userfile']['name']上傳到$uploaddir下
???if (move_uploaded_file($_FILES['userfile']['tmp_name'][$i], $uploadfile)) {
????//將上傳后的路徑寫入到數(shù)據(jù)庫中
????$post_id=(int)$post_id;
????$uploadfile="attfile/".$_FILES['userfile']['name'][$i];
????$sql=插入語句
????$stmt=$db->prepare($sql);
????$stmt->execute();
????print "<br />文件\n{$FILES_NAME}\n上傳成功!";
???} else {
????print "上傳錯誤!? 以下是上傳的信息:\n";
????print_r($_FILES);
???}
??}
??else{
???echo "{$FILES_NAME}\n不是允許上傳的文件類型!";
???exit;
??}
?}
}
?>
</body>
</html>
Echo?? "上傳文件大小:";
echo $_FILES['userfile']['size'];
//已上傳文件的大小,單位為字節(jié)。
echo "<br>";
Echo?? "文件上傳后被臨時儲存為:";
echo $_FILES['userfile']['tmp_name'];
//文件被上傳后在服務(wù)端儲存的臨時文件名。
echo "<br>";
$Erroe=$_FILES['userfile']['error'];
switch($Erroe){
?case 0:
?Echo?? "上傳成功"; break;
?case 1:
?Echo?? "上傳的文件超過了 php.ini 中 upload_max_filesize 選項限制的值."; break;
?case 2:
?Echo?? "上傳文件的大小超過了 HTML 表單中 MAX_FILE_SIZE 選項指定的值。";?? break;
?case 3:
?Echo?? "文件只有部分被上傳";break;
?case 4:
?Echo?? "沒有文件被上傳";break;
}
?>
(2)<?php
$uploaddir= '../attfile/';//設(shè)置上傳的文件夾地址
$FILES_EXT=array('.gif','.jpg','.bmp');//設(shè)置允許上傳文件的類型
$MAX_SIZE = 20000000;//設(shè)置文件上傳限制20000000byte=2M
for ($i=0;$i<count($userfile);$i++){
?$FILES_NAME=$_FILES['userfile']['name'][$i];//客戶端文件名
}
//echo $FILES_NAME;
//取出文件后綴名,strrpos()從標記開始前字節(jié)個數(shù)(不算標記),substr()顯示從第strrpos()之后的字符
$file_ext=substr($FILES_NAME,strrpos($FILES_NAME,"."));
//echo $file_ext;
//檢查文件大小
if($_FILES['userfile']['size']>$MAX_SIZE){
?echo "文件大小超程序允許范圍!";
?exit;
}
//檢查文件類型
if(in_array($file_ext, $FILES_EXT)){
?$_FILES['userfile']['name']=date("YmdHis").rand().$file_ext;
?$uploadfile = $uploaddir.$_FILES['userfile']['name'];//上傳后文件的路徑及文件名
?//將上傳后的路徑寫入到數(shù)據(jù)庫中
?//用move函數(shù)生成臨時文件名,并按照 $_FILES['userfile']['name']上傳到$uploaddir下
?if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
??print "\n上傳成功!";
?} else {
??print "上傳錯誤!? 以下是上傳的信息:\n";
??print_r($_FILES);
?}
}
else{
?echo "{$file_ext}不是允許上傳的文件類型!";
?exit;
}
?>
小技巧>>1、當在提交時,希望確認是否要提交可以在<form>里如這樣加入:<form onsubmit="return confirm('你真的要提交嗎?')">
2、在php里希望返回時所有在文本框里的東西都保留可以這樣:<a href=javascript:history.back(1)>重新來過</a>。