2007年1月4日
以前只知道alt+/調(diào)出assist,后來發(fā)現(xiàn)可以所有字母都激活content assist(方法百度上都有,就不在這寫了).用起來果然很爽.但是eclipse還是有些默認的設(shè)置不是很好,比如空格鍵和=號會把第一行的內(nèi)容自動上屏,其實很多時候我就是想輸一個空格或=號而已.這個在設(shè)置里面沒辦法設(shè)置.幸好eclipse是有插件機制的,可以通過修改插件的源碼,然后導(dǎo)出成插件,再替換掉原來的插件來處理
1.先找到相關(guān)的插件
打開Plug-ins View找到插件org.eclipse.jface.text,右鍵點擊,選擇import as Source Project,導(dǎo)入完成后,在你的workspace就可以看到這個project了
2.修改代碼
在
src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java文件中,找到這樣一行代碼
char triggers = t.getTriggerCharacter();
if(contains(triggers,key))
在那行if判斷里面,eclipse會判斷key(就是你按下的鍵)是否在triggers中,如果是,那就觸發(fā)下面的第一行提示上屏的代碼.所以我們要做的就是把空格和=號排除就可以了:
if(key!='='&&key!=0x20&&contains(triggers,key))
3.把修改好的org.eclipse.jface.text導(dǎo)出
右鍵點擊你的workspace里的org.eclipse.jface.text,選擇export-->Deployable plugins and fragments, next,destination 選擇archive file,然后finish.你就可以在zip文件里看到生成好的jar ,用它替換掉eclipse/plugins里面的同名jar包,就可以了
Visio的圖標很多,但是用來設(shè)計web程序的基本沒有,在網(wǎng)上找到了這個,覺得還蠻好用的,共享一下
/Files/yes1983/GUUUI_Web_Prototyping_Tool_3.zip
摘要: 本文分析了Eclipse中多線程程序的實現(xiàn),討論了在Eclipse客戶端程序開發(fā)中應(yīng)用多線程的方法和要注意的問題,同時也討論了多線程程序的一些調(diào)試和問題解決的方法。
閱讀全文
轉(zhuǎn)載自http://blog.csdn.net/shangboerds/archive/2010/01/27/5260783.aspx
CTE:
說起WITH 語句,除了那些第一次聽說WITH語句的人,大部分人都覺得它是用來做遞歸查詢的。其實那只是它的一個用途而已,它的本名正如我們標題寫的那樣,叫做:公共表表達式(Common Table Expression),從字面理解,大家覺得它是用來干嘛的呢?其實,它是用來定義臨時集合的。啊?VALUES語句不是用來定義臨時集合的嗎?怎么WITH語句也用來定義臨時集合呢?它們有什么區(qū)別呢?
VALUES語句是用明確的值來定義臨時集合的,如下:
VALUES (1,2), (1,3),(2,1)
WITH語句是用查詢(也就是select語句)來定義臨時集合的,從這個角度講,有點像視圖,不過不是視圖,大家千萬別誤解。如下:
CREATE TABLE USER (
NAME VARCHAR(20) NOT NULL,---姓名
SEX INTEGER,---性別(1、男 2、女)
BIRTHDAY DATE---生日
);
WITH TEST(NAME_TEST, BDAY_TEST) AS
(
SELECT NAME,BIRTHDAY FROM USER--語句1
)
SELECT NAME_TEST FROM TEST WHERE BDAY_TEST='1949-10-1';--語句2
下面我們來解釋一下,首先語句1執(zhí)行,它會產(chǎn)生一個有兩列(NAME,BIRTHDAY)的結(jié)果集;接著,我們將這個結(jié)果集命名為test,并且將列名重命名為NAME_TEST, BDAY_TEST;最后我們執(zhí)行語句2,從這個臨時集合中找到生日是1949-10-1,也就是共和國的同齡人。
怎么樣?如果你感覺不好理解,請仔細的分析一下上面的語句。下面我們舉個VALUES語句和WITH語句結(jié)合使用的例子,如下:
WITH TEST(NAME_TEST, BDAY_TEST) AS
(
VALUES ('張三','1997-7-1'),('李四','1949-10-1')
)
SELECT NAME_TEST FROM TEST WHERE BDAY_TEST='1949-10-1'
從上面的介紹和WITH語句不為大多數(shù)人所熟悉可以猜測,WITH語句是為復(fù)雜的查詢?yōu)樵O(shè)計的,的確是這樣的,下面我們舉個復(fù)雜的例子,想提高技術(shù)的朋友可千萬不能錯過??紤]下面的情況:
CREATE TABLE USER
(
NAME VARCHAR(20) NOT NULL,--姓名
DEGREE INTEGER NOT NULL,--學歷(1、專科 2、本科 3、碩士 4、博士)
STARTWORKDATE date NOT NULL,--入職時間
SALARY1 FLOAT NOT NULL,--基本工資
SALARY2 FLOAT NOT NULL--獎金
);
假設(shè)現(xiàn)在讓你查詢一下那些 1、學歷是碩士或博士 2、學歷相同,入職年份也相同,但是工資(基本工資+獎金)卻比相同條件員工的平均工資低的員工。(哈哈,可能是要漲工資),不知道你聽明白問題沒有?該怎么查詢呢?我們是這樣想的:
1、查詢學歷是碩士或博士的那些員工得到結(jié)果集1,如下:
SELECT NAME,DEGREE,YEAR(STARTWORKDATE) AS WORDDATE, SALARY1+SALARY2 AS SALARY FROM USER WHERE DEGREE IN (3,4);
2、根據(jù)學歷和入職年份分組,求平均工資 得到結(jié)果集2,如下:
SELECT DEGREE,YEAR(STARTWORKDATE) AS WORDDATE, AVG(SALARY1+SALARY2) AS AVG_SALARY
FROM USER WHERE DEGREE IN (3,4)
GROUP BY DEGREE,YEAR(STARTWORKDATE)
3、以學歷和入職年份為條件 聯(lián)合兩個結(jié)果集,查找工資<平均工資 的員工,以下是完整的SQL:
WITH TEMP1(NAME,DEGREE,WORDDATE,SALARY) AS
(
SELECT NAME,DEGREE,YEAR(STARTWORKDATE) AS WORDDATE, SALARY1+SALARY2 AS SALARY FROM USER WHERE DEGREE IN (3,4)
),
TEMP2 (DEGREE,WORDDATE,AVG_SALARY) AS
(
SELECT DEGREE,YEAR(STARTWORKDATE) AS WORDDATE, AVG(SALARY1+SALARY2) AS AVG_SALARY
FROM USER WHERE DEGREE IN (3,4)
GROUP BY DEGREE,YEAR(STARTWORKDATE)
)
SELECT NAME FROM TEMP1, TEMP2 WHERE
TEMP1.DEGREE=TEMP2.DEGREE
AND TEMP1.WORDDATE=TEMP2.WORDDATE
AND SALARY<AVG_SALARY;
查詢結(jié)果完全正確,但我們還有改善的空間,在查詢結(jié)果集2的時候,我們是從user表中取得數(shù)據(jù)的。其實此時結(jié)果集1已經(jīng)查詢出來了,我們完全可以從結(jié)果集1中通過分組得到結(jié)果集2,而不用從uer表中得到結(jié)果集2,比較上面和下面的語句你就可以知道我說的是什么意思了!
WITH TEMP1(NAME,DEGREE,WORDDATE,SALARY) AS
(
SELECT NAME,DEGREE,YEAR(STARTWORKDATE) AS WORDDATE, SALARY1+SALARY2 AS SALARY FROM USER WHERE DEGREE IN (3,4)
),
TEMP2 (DEGREE,WORDDATE,AVG_SALARY) AS
(
SELECT DEGREE,WORDDATE, AVG(SALARY) AS AVG_SALARY
FROM TEMP1
GROUP BY DEGREE,WORDDATE
)
SELECT NAME FROM TEMP1, TEMP2 WHERE
TEMP1.DEGREE=TEMP2.DEGREE
AND TEMP1.WORDDATE=TEMP2.WORDDATE
AND SALARY<AVG_SALARY;
可能有些朋友會說,我不用WITH語句也可以查出來,的確是這樣,如下:
SELECT U.NAME FROM USER AS U,
(
SELECT DEGREE,YEAR(STARTWORKDATE) AS WORDDATE, AVG(SALARY1+SALARY2) AS AVG_SALARY
FROM USER WHERE DEGREE IN (3,4)
GROUP BY DEGREE,YEAR(STARTWORKDATE)
) AS G
WHERE U.DEGREE=G.DEGREE
AND YEAR(U.STARTWORKDATE)=G.WORDDATE
AND (SALARY1+SALARY2)<G.AVG_SALARY;
那使用WITH 和不使用 WITH,這兩種寫法有什么區(qū)別呢?一般情況下這兩種寫法在性能上不會有太大差異,但是,
1、當USER表的記錄很多
2、碩士或博士(DEGREE IN (3,4))在USER表中的比例很少
當滿足以上條件時,這兩種寫法在性能的差異將會顯現(xiàn)出來,為什么呢?因為不使用WITH寫法的語句訪問了2次USER表,如果DEGREE 字段又沒有索引,性能差異將會非常明顯。
當你看到這時,如果很好的理解了上面的內(nèi)容,我相信你會對WITH語句有了一定的體會。然而WITH語句能做的還不止這些,下面給大家介紹一下,如何用WITH語句做遞歸查詢。遞歸查詢的一個典型的例子是對樹狀結(jié)構(gòu)的表進行查詢,考慮如下的情況:
論壇首頁
--數(shù)據(jù)庫開發(fā)
----DB2
------DB2 文章1
--------DB2 文章1 的評論1
--------DB2 文章1 的評論2
------DB2 文章2
----Oracle
--Java技術(shù)
以上是一個論壇的典型例子,下面我們新建一個表來存儲以上信息。
CREATE TABLE BBS
(
PARENTID INTEGER NOT NULL,
ID INTEGER NOT NULL,
NAME VARCHAR(200) NOT NULL---板塊、文章、評論等。
);
insert into bbs (PARENTID,ID,NAME) values
(0,0,'論壇首頁'),
(0,1,'數(shù)據(jù)庫開發(fā)'),
(1,11,'DB2'),
(11,111,'DB2 文章1'),
(111,1111,'DB2 文章1 的評論1'),
(111,1112,'DB2 文章1 的評論2'),
(11,112,'DB2 文章2'),
(1,12,'Oracle'),
(0,2,'Java技術(shù)');
現(xiàn)在萬事兼?zhèn)淞?,我們開始查詢吧。假設(shè)現(xiàn)在讓你查詢一下‘DB2 文章1’的所有評論,有人說,這還不簡單,如下這樣就可以了。
SELECT * FROM BBS WHERE PARENTID=(SELECT ID FROM BBS WHERE NAME='DB2');
答案完全正確。那么,現(xiàn)在讓你查詢一下DB2的所有文章及評論,怎么辦?傳統(tǒng)的方法就很難查詢了,這時候遞歸查詢就派上用場了,如下:
WITH TEMP(PARENTID,ID,NAME) AS
(
SELECT PARENTID,ID,NAME FROM BBS WHERE NAME='DB2'---語句1
UNION ALL---語句2
SELECT B.PARENTID,B.ID,B.NAME FROM BBS AS B, TEMP AS T WHERE B.PARENTID=T.ID---語句3
)
SELECT NAME FROM TEMP;---語句4
運行后,我們發(fā)現(xiàn),結(jié)果完全正確,那它到底是怎么運行的呢?下面我們詳細講解一下。
1、首先,語句1將會執(zhí)行,它只執(zhí)行一次,作為循環(huán)的起點。得到結(jié)果集:DB2
2、接著,將循環(huán)執(zhí)行語句3,這里我們有必要詳細介紹一下。
首先語句3的意圖是什么呢?說白了,它就是查找語句1產(chǎn)生結(jié)果集(DB2)的下一級,那么在目錄樹中DB2的下一級是什么呢?是‘DB2 文章1’和‘DB2 文章2’,并且把查詢到的結(jié)果集作為下一次循環(huán)的起點,然后查詢它們的下一級,直到?jīng)]有下一級為止。
怎么樣?還沒明白?哈哈,不要緊,我們一步一步來:
首先,語句1產(chǎn)生結(jié)果集:DB2,作為循環(huán)的起點,把它和BBS表關(guān)聯(lián)來查找它的下一級,查詢后的結(jié)果為:‘DB2 文章1’和‘DB2 文章2’
接著,把上次的查詢結(jié)果(也就是‘DB2 文章1’和‘DB2 文章2’)和BBS表關(guān)聯(lián)來查找它們的下一級,查詢后的結(jié)果為:‘DB2 文章1 的評論1’ 和 ‘DB2 文章1 的評論2’。
然后,在把上次的查詢結(jié)果(也就是‘DB2 文章1 的評論1’ 和 ‘DB2 文章1 的評論2’)和BBS表關(guān)聯(lián)來查找它們的下一級,此時,沒有結(jié)果返回,循環(huán)結(jié)束。
3、第三,將執(zhí)行語句2,將所有的結(jié)果集放在一起,最終得到temp結(jié)果集。
4、最后,我們通過語句4 從temp臨時集合中得到我們期望的查詢結(jié)果。
怎么樣,這回理解了吧,如果還沒有理解,那么我也無能為力了。需要特別提醒的是
1、一定要注意語句3的關(guān)聯(lián)條件,否則很容易就寫成死循環(huán)了。
2、語句2必須是UNION ALL
最后請大家猜想一下,把語句1的where子句去掉,將會產(chǎn)生什么樣的結(jié)果呢?
NTE:
SELECT * FROM <TABLE-NAME>;
看到上面的語句了嗎?這是我們在熟悉不過的一條語句,我們中的大多人學習SQL正是從這條語句開始的。所以大多數(shù)人認為FROM語句后只能接一個表或視圖(或者壓根就沒多想),有這種想法的人我非常能理解,因為我曾經(jīng)也是這其中的一員。其實FROM后面可以接任何集合(表)。說到這,關(guān)于集合和表,我特別想多少幾句。SQL的理論基礎(chǔ)是數(shù)學中的集合理論,所以SQL關(guān)注的就是如何對集合進行操作,基于以上原因,我特別喜歡名詞 集合,而不喜歡說表。不過,大家如果不習慣,也可以把集合和表當一個意思來理解,因為我們不是搞理論研究工作的,沒必要深究他們之間的細微差別。說了這么多,我們還是趕快來看個例子吧。
---建表
CREATE TABLE USER
(
NAME VARCHAR(20) NOT NULL,---姓名
BIRTHDAY DATE---生日
);
---例子1
SELECT * FROM
(
SELECT * FROM USER
) AS TEMP1;
---例子2
SELECT NAME,BIRTHDAY FROM
(
SELECT NAME,BIRTHDAY FROM USER
) AS TEMP1;
---例子3
SELECT TEMP1.NAME,TEMP1.BIRTHDAY FROM
(
SELECT NAME,BIRTHDAY FROM USER
) AS TEMP1;
---例子4
SELECT N,B FROM
(
SELECT NAME,BIRTHDAY FROM USER
) AS TEMP1(N,B);
---例子5
SELECT AAA.A,AAA.B,XXX.X,XXX.Y FROM
(
SELECT NAME,BIRTHDAY FROM USER
) AS AAA(A,B),--集合1
(
SELECT NAME,BIRTHDAY FROM USER
) AS XXX(X,Y)--集合2
WHERE AAA.A=XXX.X AND AAA.B=XXX.Y--關(guān)聯(lián)兩個集合
看到上面的例子5了嗎?我們可以給臨時集合命名,還可以給重命名臨時集合的列名,還可以關(guān)聯(lián)兩個臨時集合,總之,操作臨時集合和操作表沒有區(qū)別。
Temporary table
臨時表(TEMPORARY TABLE)通常應(yīng)用在需要定義臨時集合的場合。但是,在大部分需要臨時集合的時候,我們根本就不需要定義臨時表。當我們在一條SQL語句中只使用一次臨時集合時,我們可以使用嵌套表表達式來定義臨時集合;當我們在一條SQL語句中需要多次使用同一臨時集合時,我們可以使用公共表表達式;只有當我們在一個工作單元中的多條SQL語句中使用同一臨時集合時,我們才需要定義臨時表。
可以通過以下三種方式定義臨時表:
方法1:
DECLARE GLOBAL TEMPORARY TABLE SESSION.EMP
(
NAME VARCHAR(10),---姓名
DEPT SMALLINT,---部門
SALARY DEC(7,2)---工資
)
ON COMMIT DELETE ROWS;
方法2:
DECLARE GLOBAL TEMPORARY TABLE session.emp
LIKE staff INCLUDING COLUMN DEFAULTS
WITH REPLACE
ON COMMIT PRESERVE ROWS;
方法3:
DECLARE GLOBAL TEMPORARY TABLE session.emp AS
(
SELECT * FROM staff WHERE <condition>
)
DEFINITION ONLY
WITH REPLACE;
定義了臨時表后,我們可以像使用普通表一樣使用臨時表。臨時表只對定義它的用戶有效,不同用戶可以在同一時間定義同名的臨時表,他們之間互不影響。臨時表的生命周期是SESSION,當SESSION關(guān)閉時,臨時表將自動刪除,這也是臨時表的模式名只能為SESSION的原因。此外,我們還可以給臨時表定義索引。更多細節(jié)請參考DB2 信息中心。
Eclipse的擴展機制是其一個重要特色,但隨著Eclipse功能越做越強,插件越來越多,你會發(fā)現(xiàn)GUI上的圖標越來越多,Menu,toolbar,context menu都被占滿了,其實很多item并不是我們需要的,但是contribute這些item的插件我們是需要的,那怎么去掉它們擴展的那些菜單項呢?
1.在Plugin.xml中定制
這是最簡單的辦法,很多時候我們自己想寫代碼來去掉一些菜單項,但效果并不好.所以能在Plugin.xml中定制的,我們就 盡量寫在plugin.xml里面.下面舉一個右鍵菜單的例子:
擴展右鍵菜單需要擴展org.eclipse.ui.popupMenus擴展點,我們一般都在它下面new一個action,但這個action擴展之后不管在 任何界面都會出現(xiàn),如果我們想在某些條件下隱藏掉它該怎么辦?仔細觀察下org.eclipse.ui.popupMenus擴展點,其實我們還可以新建objectContribution擴展
<extension
point="org.eclipse.ui.popupMenus">
<objectContribution
id="my.example.objectContribution"
nameFilter="*example*"
objectClass="java.io.File">
<action
class="my.example.MyAction"
id="my.example.MyAction"
label="Exe"
menubarPath="additional">
</action>
</objectContribution>
</extension>
objectContribution里面也包含一個action,但這個action在popupmenu里出現(xiàn)是有條件的:我們給它定義了一個nameFilter, 只有當selection()的path中包含了"example"才會顯示,否則這個action是不會出現(xiàn)在 popupmenu里的.這里的selection假設(shè)選中的是一個File,如果選中的是你自己寫的類,那namefilter會在你的類的toString方法里面找keyword.
2.使用Eclipse的Activities擴展
plugin.xml并不能解決所有問題,當我們實在沒有辦法在plugin.xml中限制某些extension的出現(xiàn)的時候,可以考慮使用Eclipse的Activities.Activities的官方定義大家可以google一下eclipse的help.我個人的理解就是它可以和perspective一樣控制UI的顯示,但是Perspective設(shè)計的太易于擴展了,假如Plugin A在perspective上擴展了一個UI,那么Plugin B在每次進入這個perspective的時候就一定可以看得見它,而且在Eclipse的擴展機制下,Plugin B是沒有權(quán)利去刪了Plugin A的contribution的(Eclipse的ExtensionRegistry倒是提供了一個removeExtension方法,但運行的時候會報錯).在這樣的情況下,Activities的價值就體現(xiàn)出來了,你只要給它一個Extension的id,它就可以幫你把這個Extension disable掉.例如:
<extension
point="org.eclipse.ui.activities">
<activity
id="my.example.activity"
name="WizardActivity">
</activity>
<activityPatternBinding
activityId="my.example.activity"
pattern="my\.example/mywizard">
</activityPatternBinding>
</extension>
比較重要的是activityPatternBinding中的pattern屬性,它是由plugin id + "/" + local-id組成.比如在插件my.example中擴展了 org.eclipse.ui.newWizards,id是mywizard,那么上面這個activityPatternBinding就會disable掉my.example的mywizard擴展,你在 GUI中就看不見這個wizard了.pattern是支持正則表達式的,所以如果有"."的話需要用轉(zhuǎn)義字符\.注意,這里的disable的意思并不是說我把mywizard這個擴展刪掉了,而是屏蔽了它,mywizard仍然在 ExtensionRegistry中.
3.用代碼來動態(tài)控制UI
方法2只是隱藏掉一些擴展,但是有一些需求并不是簡單的隱藏就可以了,我最近碰到的一個需求就是:有一個flag,只有當flag==1的時候擴展是可見的,否則是不可見的,需要disable這個擴展.這時就必須要加一些代碼才能實現(xiàn)了,還是以方法2中的mywizard為例:
IWorkbenchActivitySupport workbenchActivitySupport = PlatformUI.getWorkbench().getActivitySupport();
IActivityManager activityManager = workbenchActivitySupport.getActivityManager();
Set enabledActivityIds = new HashSet(activityManager.getEnabledActivityIds());
if(flag==1)
{
if (enabledActivityIds.add("my.example.activity"))
workbenchActivitySupport.setEnabledActivityIds(enabledActivityIds);
}
else{
if(enabledActivityIds.remove("my.example.activity"))
workbenchActivitySupport.setEnabledActivityIds(enabledActivityIds);
}
Activities可以是enable或者disable的,當你在plugin.xml中定義好了一個Activity,缺省它是disable的,就是說activityPatternBinding 匹配的擴展是會被disable的,但你也可以把Activities設(shè)成enable的(在plugin.xml或者用代碼都可以設(shè)置),它匹配的擴展是可以正常使用的.
在上面的code sample中,我們通過activityManager.getEnabledActivityIds()得到所有enable的Activities.如果flag==1,那my.example.activity 也應(yīng)該被加入到enable Activities中,這樣mywizard就可以顯示在界面上,反之,就要在enable Activities中remove掉my.example.activity,它就變成
disable,會把mywizard隱藏.
摘要: Access Path
1.并不是用index就一定快.有時候一個表只有很少的records,那么你直接scan這個表,比你先讀index,再訪問表要快.
2.不過大多數(shù)情況下還是用index快一些(要不然這個技術(shù)就沒有意義了).DB2中index的應(yīng)用需要兩個前提條件:
閱讀全文
TreeViewer的setSelection方法使用后,會在樹上選中并展開方法參數(shù)中對應(yīng)的節(jié)點.但是有時候你發(fā)現(xiàn)它只能選中第一級節(jié)點,下面的子節(jié)點沒有辦法選中.其實這個方法是沒有問題的,它的大概實現(xiàn)算法是:先找到某一個子節(jié)點,然后找到它的父節(jié)點,把父節(jié)點展開,然后又找父節(jié)點的父節(jié)點,做同樣的操作,直到根節(jié)點為止,這樣你才能看到選中的子節(jié)點.所以父節(jié)點如果為null,那肯定你是看不到子節(jié)點了.而我們很多人在實現(xiàn)ITreeContentProvide的接口的時候,是不實現(xiàn)getParent方法的,因為只要實現(xiàn)了getChildren方法就可以看見一棵樹了.包括陳剛的<Eclipse從入門到精通>也是這樣.所以在實現(xiàn)treeViewer的時候,最好還是實現(xiàn)getparent方法.其實也不麻煩,在添加一個child的時候,加一句setparent(this)就可以了
最初java是不支持對文本文件的處理的,為了彌補這個缺憾而引入了Reader和Writer兩個類,這兩個類都是抽象類,Writer中 write(char[] ch,int off,int
length),flush()和close()方法為抽象方法,Reader中read(char[] ch,int off,int length)和close()方法是抽象方法。子類應(yīng)該分別實現(xiàn)他們。
當我們讀寫文本文件的時候,采用Reader是非常方便的,比如FileReader,InputStreamReader和BufferedReader。其中最重要的類是InputStreamReader,
它是字節(jié)轉(zhuǎn)換為字符的橋梁。你可以在構(gòu)造器重指定編碼的方式,如果不指定的話將采用底層操作系統(tǒng)的默認編碼方式,例如GBK等。當使用FileReader讀取文件
的時候。
FileReader fr = new FileReader("ming.txt");
int ch = 0;
while((ch = fr.read())!=-1 )
{
System.out.print((char)ch);
}
其中read()方法返回的是讀取得下個字符。當然你也可以使用read(char[] ch,int off,int length)這和處理二進制文件的時候類似,不多說了。如果使用
InputStreamReader來讀取文件的時候
while((ch = isr.read())!=-1)
{
System.out.print((char)ch);
}
這和FileReader并沒有什么區(qū)別,事實上在FileReader中的方法都是從InputStreamReader中繼承過來的。read()方法是比較好費時間的,如果為了提高效率
我們可以使用BufferedReader對Reader進行包裝,這樣可以提高讀取得速度,我們可以一行一行的讀取文本,使用readLine()方法。
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("ming.txt")));
String data = null;
while((data = br.readLine())!=null)
{
System.out.println(data);
}
當你明白了如何用Reader來讀取文本文件的時候那么用Writer寫文件同樣非常簡單。有一點需要注意,當你寫文件的時候,為了提高效率,寫入的數(shù)據(jù)會先
放入緩沖區(qū),然后寫入文件。因此有時候你需要主動調(diào)用flush()方法。與上面對應(yīng)的寫文件的方法為:
FileWriter fw = new FileWriter("hello.txt");
String s = "hello world";
fw.write(s,0,s.length());
fw.flush();
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("hello2.txt"));
osw.write(s,0,s.length());
osw.flush();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream("hello3.txt")),true);
pw.println(s);
不要忘記用完后關(guān)閉流!下面是個小例子,幫助新手理解。其實有的時候java的IO系統(tǒng)是需要我們多記記的,不然哪天就生疏了。
import java.io.*;
public class TestFile2
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("ming.txt");
char[] buffer = new char[1024];
int ch = 0;
while((ch = fr.read())!=-1 )
{
System.out.print((char)ch);
}
InputStreamReader isr = new InputStreamReader(new FileInputStream("ming.txt"));
while((ch = isr.read())!=-1)
{
System.out.print((char)ch);
}
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("ming.txt")));
String data = null;
while((data = br.readLine())!=null)
{
System.out.println(data);
}
FileWriter fw = new FileWriter("hello.txt");
String s = "hello world";
fw.write(s,0,s.length());
fw.flush();
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("hello2.txt"));
osw.write(s,0,s.length());
osw.flush();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream("hello3.txt")),true);
pw.println(s);
fr.close();
isr.close();
br.close();
fw.close();
osw.close();
pw.close();
}
}
java中多種方式讀文件
一、多種方式讀文件內(nèi)容。
1、按字節(jié)讀取文件內(nèi)容
2、按字符讀取文件內(nèi)容
3、按行讀取文件內(nèi)容
4、隨機讀取文件內(nèi)容
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.Reader;
public class ReadFromFile {
/**
* 以字節(jié)為單位讀取文件,常用于讀二進制文件,如圖片、聲音、影像等文件。
* @param fileName 文件的名
*/
public static void readFileByBytes(String fileName){
File file = new File(fileName);
InputStream in = null;
try {
System.out.println("以字節(jié)為單位讀取文件內(nèi)容,一次讀一個字節(jié):");
// 一次讀一個字節(jié)
in = new FileInputStream(file);
int tempbyte;
while((tempbyte=in.read()) != -1){
System.out.write(tempbyte);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
return;
}
try {
System.out.println("以字節(jié)為單位讀取文件內(nèi)容,一次讀多個字節(jié):");
//一次讀多個字節(jié)
byte[] tempbytes = new byte[100];
int byteread = 0;
in = new FileInputStream(fileName);
ReadFromFile.showAvailableBytes(in);
//讀入多個字節(jié)到字節(jié)數(shù)組中,byteread為一次讀入的字節(jié)數(shù)
while ((byteread = in.read(tempbytes)) != -1){
System.out.write(tempbytes, 0, byteread);
}
} catch (Exception e1) {
e1.printStackTrace();
} finally {
if (in != null){
try {
in.close();
} catch (IOException e1) {
}
}
}
}
/**
* 以字符為單位讀取文件,常用于讀文本,數(shù)字等類型的文件
* @param fileName 文件名
*/
public static void readFileByChars(String fileName){
File file = new File(fileName);
Reader reader = null;
try {
System.out.println("以字符為單位讀取文件內(nèi)容,一次讀一個字節(jié):");
// 一次讀一個字符
reader = new InputStreamReader(new FileInputStream(file));
int tempchar;
while ((tempchar = reader.read()) != -1){
//對于windows下,rn這兩個字符在一起時,表示一個換行。
//但如果這兩個字符分開顯示時,會換兩次行。
//因此,屏蔽掉r,或者屏蔽n。否則,將會多出很多空行。
if (((char)tempchar) != 'r'){
System.out.print((char)tempchar);
}
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
System.out.println("以字符為單位讀取文件內(nèi)容,一次讀多個字節(jié):");
//一次讀多個字符
char[] tempchars = new char[30];
int charread = 0;
reader = new InputStreamReader(new FileInputStream(fileName));
//讀入多個字符到字符數(shù)組中,charread為一次讀取字符數(shù)
while ((charread = reader.read(tempchars))!=-1){
//同樣屏蔽掉r不顯示
if ((charread == tempchars.length)&&(tempchars[tempchars.length-1] != 'r')){
System.out.print(tempchars);
}else{
for (int i=0; i<charread; i++){
if(tempchars[i] == 'r'){
continue;
}else{
System.out.print(tempchars[i]);
}
}
}
}
} catch (Exception e1) {
e1.printStackTrace();
}finally {
if (reader != null){
try {
reader.close();
} catch (IOException e1) {
}
}
}
}
/**
* 以行為單位讀取文件,常用于讀面向行的格式化文件
* @param fileName 文件名
*/
public static void readFileByLines(String fileName){
File file = new File(fileName);
BufferedReader reader = null;
try {
System.out.println("以行為單位讀取文件內(nèi)容,一次讀一整行:");
reader = new BufferedReader(new FileReader(file));
String tempString = null;
int line = 1;
//一次讀入一行,直到讀入null為文件結(jié)束
while ((tempString = reader.readLine()) != null){
//顯示行號
System.out.println("line " + line + ": " + tempString);
line++;
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null){
try {
reader.close();
} catch (IOException e1) {
}
}
}
}
/**
* 隨機讀取文件內(nèi)容
* @param fileName 文件名
*/
public static void readFileByRandomAccess(String fileName){
RandomAccessFile randomFile = null;
try {
System.out.println("隨機讀取一段文件內(nèi)容:");
// 打開一個隨機訪問文件流,按只讀方式
randomFile = new RandomAccessFile(fileName, "r");
// 文件長度,字節(jié)數(shù)
long fileLength = randomFile.length();
// 讀文件的起始位置
int beginIndex = (fileLength > 4) ? 4 : 0;
//將讀文件的開始位置移到beginIndex位置。
randomFile.seek(beginIndex);
byte[] bytes = new byte[10];
int byteread = 0;
//一次讀10個字節(jié),如果文件內(nèi)容不足10個字節(jié),則讀剩下的字節(jié)。
//將一次讀取的字節(jié)數(shù)賦給byteread
while ((byteread = randomFile.read(bytes)) != -1){
System.out.write(bytes, 0, byteread);
}
} catch (IOException e){
e.printStackTrace();
} finally {
if (randomFile != null){
try {
randomFile.close();
} catch (IOException e1) {
}
}
}
}
/**
* 顯示輸入流中還剩的字節(jié)數(shù)
* @param in
*/
private static void showAvailableBytes(InputStream in){
try {
System.out.println("當前字節(jié)輸入流中的字節(jié)數(shù)為:" + in.available());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String fileName = "C:/temp/newTemp.txt";
ReadFromFile.readFileByBytes(fileName);
ReadFromFile.readFileByChars(fileName);
ReadFromFile.readFileByLines(fileName);
ReadFromFile.readFileByRandomAccess(fileName);
}
}
二、將內(nèi)容追加到文件尾部
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* 將內(nèi)容追加到文件尾部
*/
public class AppendToFile {
/**
* A方法追加文件:使用RandomAccessFile
* @param fileName 文件名
* @param content 追加的內(nèi)容
*/
public static void appendMethodA(String fileName,
String content){
try {
// 打開一個隨機訪問文件流,按讀寫方式
RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
// 文件長度,字節(jié)數(shù)
long fileLength = randomFile.length();
//將寫文件指針移到文件尾。
randomFile.seek(fileLength);
randomFile.writeBytes(content);
randomFile.close();
} catch (IOException e){
e.printStackTrace();
}
}
/**
* B方法追加文件:使用FileWriter
* @param fileName
* @param content
*/
public static void appendMethodB(String fileName, String content){
try {
//打開一個寫文件器,構(gòu)造函數(shù)中的第二個參數(shù)true表示以追加形式寫文件
FileWriter writer = new FileWriter(fileName, true);
writer.write(content);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String fileName = "C:/temp/newTemp.txt";
String content = "new append!";
//按方法A追加文件
AppendToFile.appendMethodA(fileName, content);
AppendToFile.appendMethodA(fileName, "append end. n");
//顯示文件內(nèi)容
ReadFromFile.readFileByLines(fileName);
//按方法B追加文件
AppendToFile.appendMethodB(fileName, content);
AppendToFile.appendMethodB(fileName, "append end. n");
//顯示文件內(nèi)容
ReadFromFile.readFileByLines(fileName);
}
}
1.有的時候在project的java build path中定義好了一些jar包依賴,但是project在運行的時候仍然報NoClassDef的錯誤.這是因為project的MANIFEST.MF文件沒有更新.手動在MANIFEST.MF加上那些jar包就可以了.
2.Plugin A 依賴 Plugin B.B也把相應(yīng)的package export出來了,但是A還是找不到B里面定義的類.修改A的MANIFEST.MF文件,在dependence tab里去掉Plugin B,再添加B.此時發(fā)現(xiàn)有5,6個同樣的Plugin B出現(xiàn)在選擇plugin的list中.cancel 掉該對話框,然后重啟eclipse,在A的dependence里面重新加上B,問題解決.
3.當我們通過在plugin.xml中用extension的方式定義action的時候,你會發(fā)現(xiàn)你定義的actionset和action在GUI出現(xiàn)的順序不是你可以控制的,就是說同一個actionset下的多個action不是按你定義的先后順序出現(xiàn)在程序的界面上的,這樣對action進行排序呢?其實仔細觀察一下,你會發(fā)現(xiàn)action在GUI出現(xiàn)的順序是和你定義action的順序相反的,比如你先后定義了3個action A,B,C,那么你就會在GUI上看見action的順序是C,B,A.如果你定義了多個actionset,你會發(fā)現(xiàn)這個規(guī)律不適用與actionset,actionset在界面上出現(xiàn)的順序其實是和它的id的排序相反的.比如你定義了三個actionset,它們的id分別是:seta,setb,setc,你會發(fā)現(xiàn)GUI上出現(xiàn)的順序是setc,setb,seta
4.雙擊激活TreeViewer的celleditor
JFace的Viewer都有單元格編輯功能,但是celleditor默認的實現(xiàn)是單擊激活editor,雙擊選中item.如果需要改成單擊選中item,雙擊激活editor呢?Eclipse的官網(wǎng)上好像也有人問到這個問題,不過目前好像是開了一個bug,期待eclipse的下個版本解決這個問題.但最近找到了一個用SWT來解決這個問題的方法:
Tree tree=treeViewer.getTree();
final TreeEditor editor = new TreeEditor(tree);
editor.horizontalAlignment = SWT.LEFT;
editor.grabHorizontal = true;
// Use a mouse listener, not a selection listener, because you're
// interested
// in the selected column as well as row
tree.addMouseListener(new MouseAdapter() {
public void mouseDoubleClick(MouseEvent event) {
final TreeItem item = tree.getSelection()[0];
// Create a text field to do the editing
final Text text = new Text(tree, SWT.NONE);
text.setText(item.getText());
text.selectAll();
text.setFocus();
text.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent event) {
text.dispose();
}
});
// Set the text field into the editor
editor.setEditor(text, item);
}
});
由于Eclipse的易擴展性,理論上可以有無數(shù)個Action運行在一個RCP 程序中,但是快捷鍵是有限的,尤其是一些常用的,像Ctrl+C,Ctrl+S之類的普通用戶能記得住的就那么幾個,萬一你自定義的Action的快捷鍵和Eclipse默認的發(fā)生了沖突怎么辦?比如Eclipse默認Ctrl+S是Save的快捷鍵,但是你又自定義了一個SaveAction,希望用戶按下Ctrl+S之后執(zhí)行的是自己的SaveAction的run方法.
一般給Action綁定快捷鍵的方法是自定義binding和command,然后在action中指定definition id為command的id.如下:
<extension
point="org.eclipse.ui.bindings">
<key
commandId="myplugin.actions.save"
contextId="org.eclipse.ui.contexts.window"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
sequence="CTRL+S">
</key>
</extension>
<extension
point="org.eclipse.ui.commands">
<command
id="myplugin.actions.save"
name="Save">
</command>
</extension>
這樣的方法一般是不會有沖突的,但是像我們上面提到的情況,如果你自定義一個binding,它的key sequence是Ctrl+S,那就會有問題.由于org.eclipse.ui插件已經(jīng)提供了一個Ctrl+S的快捷鍵,所以系統(tǒng)中會有兩個Ctrl+S,這樣Eclipse會在右下角pop up一個assist dialog,讓你從兩個Action中選擇一個,這樣可能會造成一些用戶使用上的不習慣.
解決辦法:
1.直接改快捷鍵.
這個最簡單了,比如把你自己的save定義成Alt+S.但是這個方法也是最不好的方法,因為很多用戶并不知道Alt+S在你的程序里面就是save.
2.修改自定義action的definition id
我們剛才說過,action的definition id綁定著一個command,而command又對應(yīng)著一個binding,Eclipse通過這樣的方式實現(xiàn)action和快捷鍵的綁定.我們再來看看Eclipse定義的command和key binding(摘自org.eclipse.ui的plugin.xml):
<command
name="%command.save.name"
description="%command.save.description"
categoryId="org.eclipse.ui.category.file"
id="org.eclipse.ui.file.save" />
<key
commandId="org.eclipse.ui.file.save"
sequence="M1+S"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" />
<key
Eclipse的Save Action把definition id指定為org.eclipse.ui.file.save,然后它就和上面的command進行了綁定,而這個command對應(yīng)的key就是"M1+S"(Ctrl + S),這樣就實現(xiàn)了快捷鍵綁定.如果我們也把自定義的Save Action的definition id指定為org.eclipse.ui.file.save,是不是就可以達到目的呢?答案是肯定的.
Eclipse中的Action存在著一個類似"優(yōu)先級"的概念(具體實現(xiàn)是通過action handler).越"具體"的action,優(yōu)先級越高.Eclipse的Save Action明顯是一個global的action,(同樣的global action還有copy, cut,undo,redo等等).而我們自定義的action一般是實現(xiàn)了IWorkbenchWindowActionDelegate接口的,就是說,它是contribute to workbench window的,它是一個workbench action,它的優(yōu)先級就高于任何global action.同理,如果你定義一個editor action或者view action,由于它比workbench還"具體"(workbench可以包含多個editor或view,workbench action對這些editor或view都是有效的;而editor action只對某個具體的editor有效),所以editor action的優(yōu)先級就高于workbench action.這樣,如果自定義的action和eclipse缺省的action都綁定到同一個command,那么eclipse runtim最后會選擇自定義的action來執(zhí)行.
3.終極解決大法:自定義schema
Eclipse 有一個default的快捷鍵schema文件:org.eclipse.ui.defaultAcceleratorConfiguration.它存儲著Eclipse所有的快捷鍵.如果你自定義一個自己的schema文件,并把它設(shè)成當前使用的schema文件,那么Eclipse就會調(diào)用自定義的schema文件.(新的schema文件可以在org.eclipse.ui.bindings擴展點中定義,請注意,在定義新schema的時候由一個parentID屬性,如果你定義了它,新的schema會像類繼承一樣把parent schema里面的key binding全繼承下來.如果不定義,則是一個全新的schema)
假定我們已經(jīng)有了一個新的schema文件,id是myplugin.schema.然后我們在org.eclipse.ui.bindings下定義一個key:
<key
commandId="myplugin.actions.save"
contextId="org.eclipse.ui.contexts.window"
schemaId="myplugin.schema"
sequence="CTRL+S">
</key>
我們已經(jīng)把schemaId換成了myplugin.schema,表示我們把CTRL+S加到了myplugin.schema中,然后把新建的schema文件在product配置文件plugin_customization.ini中設(shè)置成當前的key schema文件:
org.eclipse.ui/KEY_CONFIGURATION_ID=myplugin.schema
這種方法雖然麻煩了一點,但卻可以治標又治本.而且由于可以指定parent schema,我們完全可以把org.eclipse.ui.defaultAcceleratorConfiguration作為parent schema,繼承它全部的快捷鍵配置,只定制幾個會產(chǎn)生沖突的快捷鍵即可
gef中經(jīng)常會有很多連線,這些連線如何和每個node連接,允不允許交叉等等都是用router來控制的.網(wǎng)上有篇文章對這個做了一些介紹:
http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-gef/part2/
我現(xiàn)在做的這個項目需要在兩個node之間同時存在多根線,如果不使用router的話就只能看見一根,在diagram的 figure里面set一個FanRouter作為缺省的router就可以解決這個問題.兩個node之間如果存在多根連線的話,FanRouter會把它們分布成扇形,每根連線都可以看見.但是FanRouter好像只能在diagram的figure里面設(shè)置,如果每根connection你都設(shè)置成FanRouter,反而不會啟效果,這可能跟它的handlecollision方法的算法有關(guān).
但是設(shè)置成FanRouter之后有一個問題:我的項目中還有那種自連接的connection(該connection的source和target是同一個node),原先我是把這種connection的router設(shè)置為bendconnectionrouter,但是后來設(shè)置了FanRouter之后BendConnectionRouter好像就失效了,不管你的connection上面有多少個bendpoint都看不出來效果.
后來終于找到了讓這兩張router和平共處的辦法,只要加一行:fanRouter.setNextRouter(new BendPointConnectionRouter());setNextRouter這個方法有點怪,按照字面的理解,應(yīng)該是fanrouter的下一個router,按理說應(yīng)該是先用fanrouter來layout 連線,然后再使用BendPointConnectionRouter來layout 連線,但是它實際上是先用BendPointConnectionRouter來layout 連線,然后再使用fanRouter.
GEF中自帶有Directeditrequest,所以實現(xiàn)Directedit還是比較容易的,八進制的gef例子里面就有實現(xiàn).但我在給directedit加上content assist的時候卻發(fā)現(xiàn)由一個小bug不太好弄,費了兩天才搞定,現(xiàn)在先記下來,以供參考
directedit是通過一個text celleditor來實現(xiàn)編輯功能的,所以可以在directeditmanager類里面的initCellEditor方法里面加上ContentAssistHandler來實現(xiàn)auto complete.但是加上去之后卻發(fā)現(xiàn)有一個問題:不支持用鼠標來選擇proposal.只能用鍵盤上的上下箭頭來選擇.雖然也可以用,但是終究不是那么的人性化.
為了修復(fù)這個bug,走了不少的彎路,一開始以為是contentassist的問題,因為它是deprecated,所以換了3.3里面的assist api,發(fā)現(xiàn)還是不行.后來才知道是因為celleditor有一個focus listener,當用戶點擊proposals 來選擇一行的時候,celleditor的focus就lost了,就會調(diào)用focusLost方法,導(dǎo)致directedit編輯失敗.所以我重寫了celleditor的focusLost方法,把它設(shè)成當focus在contentassist的popup dialog就什么都不干,否則調(diào)用父類的focusLost方法.理論上是一個好的解決方法,但是contentassist的hasPopupFocus居然一直都返回false,這個方法也失敗了.
最后,在bug.eclipse.org上面有人提到GMF里面的TextDirectEditManager是可以做到用鼠標選擇proposal的,于是又去看gmf的這個類,它也是繼承自DirectEditManager,不過它消除這個bug不是在listener上作文章,而是在commit方法里面,在這個方法里面判斷popup dialog是否是active的,如果是的話則給celleditor加上deactive lock,不允許它deactive,這樣來實現(xiàn)用鼠標選擇proposal.
下面是TextDirectEditManager的方法commit里面的部分代碼:
Shell activeShell = Display.getCurrent().getActiveShell();
if (activeShell != null
&& getCellEditor().getControl().getShell().equals(
activeShell.getParent())) {
Control[] children = activeShell.getChildren();
if (children.length == 1 && children[0] instanceof Table) {
/*
* CONTENT ASSIST: focus is lost to the content assist pop up -
* stay in focus
*/
getCellEditor().getControl().setVisible(true);
((MyTextCellEditor) getCellEditor()).setDeactivationLock(true);
return;
}
}
下面是MyTextCellEditor里面對于deactive lock的應(yīng)用,MyTextCellEditor的deactive之前會判斷一下deactive lock是否為true:
public boolean isDeactivationLocked() {
return deactivationLock;
}
public void deactivate() {
if (! isDeactivationLocked())
super.deactivate();
setDeactivationLock(false);
}
public void setDeactivationLock(boolean deactivationLock) {
this.deactivationLock = deactivationLock;
}
使用java自帶的xml api生成的xml文件,其格式都是沒有縮進的,每個element都是頂?shù)阶钋懊?今天終于找到了比較好的處理方法,趕緊記下來.
使用Java標準的JAXP來輸出可以使用:
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(new DOMSource(document), new StreamResult(outputFile));
中間的紅色代碼是用于設(shè)置縮進的,比較遺憾的是JAXP只抽象出是否設(shè)置縮進(indent: yes|no),但并沒有抽象出設(shè)置縮進量長度的常量(indent-number),所以默認的縮進量長度為0。如果有下面這樣一個xml文檔:<root><a><b>c</b></a></root>會被格式化為:
<root>
<a>
<b>c</b>
</a>
</root>
由于JAXP只是一個Java一個處理XML的框架,根據(jù)實現(xiàn)的不一樣,可以傳入實現(xiàn)特定的某個Key來設(shè)置縮進量。比如在Java 1.4下面,可以通過下面語句將縮進量設(shè)為2:
ransformer.setOutputProperty(
"{http://xml.apache.org/xslt}indent-amount", "2");
或
transformer.setOutputProperty(
"{http://xml.apache.org/xalan}indent-amount", "2");
上面兩句不同之處僅在于命名空間。
而在Java 1.5下面,情況就有些復(fù)雜了。Java 1.5集成了JXAP 1.3(Java 1.4集成的是JXAP 1.1,不同之處參見http://java.sun.com/j2se/1.5.0/docs/guide/xml/jaxp/JAXP-Compatibility_150.html),實現(xiàn)基于Xerces類庫。由于內(nèi)部實現(xiàn)上的Bug,導(dǎo)致了設(shè)置縮進的不同:
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute("indent-number", new Integer(2));
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(new DOMSource(document), new StreamResult(new?BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile)))));
注意紅色代碼的不同之處。第一句設(shè)置TransformerFactory的indent-number屬性,在Java 1.4下面運行會拋出異常,因為其不支持該屬性,而在Java 1.5中卻只能通過該屬性來設(shè)置縮進。后面標為紅色的代碼則是由于Sun實現(xiàn)上的Bug,只有通過StreamResult(Writer)構(gòu)造函數(shù)生成才能正確設(shè)置縮進(通過OutputStream或者File生成的StreamResult是無法設(shè)置縮進的,其實現(xiàn)上會忽略任何非正式的屬性,而僅僅采用rt.jar下面com\sun\org\apache\xml\internal\serializer\output_xml.properties中的配置。詳細可以在com.sun.org.apache.xml.internal.serializer.ToStream類的setOutputStream方法中加斷點進行分析)
?
如果忽略掉可移植性,確認綁定在Sun的JRE實現(xiàn)上面,則可以通過如下代碼來更好的實現(xiàn):
OutputFormat format = new OutputFormat(document);
format.setIndenting(true);
format.setIndent(2);
Writer output = new BufferedWriter( new FileWriter(outputFile) );
XMLSerializer serializer = new XMLSerializer(output, format);
serializer.serialize(document);
但是OutputFormat類和XMLSerializer類都是位于com.sun.org.apache.xml.internal.serialize包下。
如果應(yīng)用對增加一個300K左右的jar包不敏感的話,我還是強烈推薦用dom4j來處理xml,其API設(shè)計的非常易用,寫出來的代碼比用JXAP寫出來的代碼漂亮多了,也容易維護,也不會出現(xiàn)上面那種兩個Java版本不兼容的問題。
Java 對文件進行讀寫操作的例子很多,讓初學者感到十分困惑,我覺得有必要將各種方法進行
一次分析,歸類,理清不同方法之間的異同點。
一.在 JDK 1.0 中,通常是用 InputStream & OutputStream 這兩個基類來進行讀寫操作的。
InputStream 中的 FileInputStream 類似一個文件句柄,通過它來對文件進行操作,類似的,在
OutputStream 中我們有 FileOutputStream 這個對象。
用FileInputStream 來讀取數(shù)據(jù)的常用方法是:
FileInputStream fstream = new FileInputStream(args[0]);
DataInputStream in = new DataInputStream(fstream);
用 in.readLine() 來得到數(shù)據(jù),然后用 in.close() 關(guān)閉輸入流。
完整代碼見 Example 1。
用FileOutputStream 來寫入數(shù)據(jù)的常用方法是:
FileOutputStream out out = new FileOutputStream("myfile.txt");
PrintStream p = new PrintStream( out );
用 p.println() 來寫入數(shù)據(jù),然后用 p.close() 關(guān)閉輸入。
完整代碼見 Example 2。
二.在 JDK 1.1中,支持兩個新的對象 Reader & Writer, 它們只能用來對文本文件進行操作,而
JDK1.1中的 InputStream & OutputStream 可以對文本文件或二進制文件進行操作。
用FileReader 來讀取文件的常用方法是:
FileReader fr = new FileReader("mydata.txt");
BufferedReader br = new BufferedReader(fr);
用 br.readLing() 來讀出數(shù)據(jù),然后用br.close() 關(guān)閉緩存,用fr.close() 關(guān)閉文件。
完整代碼見 Example 3。
用 FileWriter 來寫入文件的常用方法是:
FileWriter fw = new FileWriter("mydata.txt");
PrintWriter out = new PrintWriter(fw);
在用out.print 或 out.println 來往文件中寫入數(shù)據(jù),out.print 和 out.println的唯一區(qū)別是后者寫
入數(shù)據(jù)或會自動開一新行。寫完后要記得 用out.close() 關(guān)閉輸出,用fw.close() 關(guān)閉文件。
完整代碼見 Example 4。
-------------------------------------------------------------- following is the source code of examples------------------------------------------------------
Example 1:
// FileInputDemo
// Demonstrates FileInputStream and DataInputStream
import java.io.*;
class FileInputDemo {
public static void main(String args[]) {
// args.length is equivalent to argc in C
if (args.length == 1) {
try {
// Open the file that is the first command line parameter
FileInputStream fstream = new FileInputStream(args[0]);
// Convert our input stream to a DataInputStream
DataInputStream in = new DataInputStream(fstream);
// Continue to read lines while there are still some left to read
while (in.available() !=0) {
// Print file line to screen
System.out.println (in.readLine());
}
in.close();
} catch (Exception e) {
System.err.println("File input error");
}
}
else
System.out.println("Invalid parameters");
}
}
Example 2:
// FileOutputDemo
// Demonstration of FileOutputStream and PrintStream classes
import java.io.*;
class FileOutputDemo
{
public static void main(String args[]) {
FileOutputStream out; // declare a file output object
PrintStream p; // declare a print stream object
try {
// connected to "myfile.txt"
out = new FileOutputStream("myfile.txt");
// Connect print stream to the output stream
p = new PrintStream( out );
p.println ("This is written to a file");
p.close();
} catch (Exception e) {
System.err.println ("Error writing to file");
}
}
}
Example 3:
// FileReadTest.java
// User FileReader in JDK1.1 to read a file
import java.io.*;
class FileReadTest {
public static void main (String[] args) {
FileReadTest t = new FileReadTest();
t.readMyFile();
}
void readMyFile() {
String record = null;
int recCount = 0;
try {
FileReader fr = new FileReader("mydata.txt");
BufferedReader br = new BufferedReader(fr);
record = new String();
while ((record = br.readLine()) != null) {
recCount++;
System.out.println(recCount + ": " + record);
}
br.close();
fr.close();
} catch (IOException e) {
System.out.println("Uh oh, got an IOException error!");
e.printStackTrace();
}
}
}
Example 4:
// FileWriteTest.java
// User FileWriter in JDK1.1 to writer a file
import java.io.*;
class FileWriteTest {
public static void main (String[] args) {
FileWriteTest t = new FileWriteTest();
t.WriteMyFile();
}
void WriteMyFile() {
try {
FileWriter fw = new FileWriter("mydata.txt");
PrintWriter out = new PrintWriter(fw);
out.print(“hi,this will be wirte into the file!”);
out.close();
fw.close();
} catch (IOException e) {
System.out.println("Uh oh, got an IOException error!");
e.printStackTrace();
}
}
}
10)使用ISMP 11.5的project file
ISMP 11.5的project file是uip格式的,IA不能直接打開它。我們可以在ISMP 11.5中導(dǎo)出一種DIM file,然后在
IA的organization-->DIM Reference-->add DIM Reference中使用它。ISMP 11 sp1之前的版本IA不再兼容
11)installer運行時參數(shù)
你可以在installer運行的時候添加一些參數(shù),比如
installer.exe -i console //在console模式下運行
//在silent模式下運行,由于silent模式不會有任何界面,所以你可以
//設(shè)置一些安裝的屬性,格式如下:
installer.exe -i silent <propertyname>=<value>
//具體實例:
installer.exe -i silent USER_INSTALL_DIR=C:\Mydirectory
//如果你屬性很多,你可以都寫在一個文件中,然后引用就可以了
installer.exe -i silent -f <path to the properties file>
12)用代碼啟動IA的build
稍微復(fù)雜一點的java項目在編譯打包的時候都少不了要用到ant。如果我們要在ant中啟動IA來制作安裝程序該怎么做呢
IA的安裝目錄下有一個build.exe,用它就可以了。
build.exe <path to IA project file>
13)source path
在Edit菜單里面可以設(shè)置source path。感覺它跟ISMP的alias是一樣的。無非就是讓你設(shè)置IA_HOME,PROJECT_HOME等等。
和alias不同的是,source path都是global,沒有project類型的。source path存放在C:\Documents and Settings\Administrator\InstallAnywhere\80\Enterprise\preferences中
14)merge modules
當我們需要有一個project包含其他project的時候,就要用到merge modules。最典型的例子就是office包含word,powerpoint
,excel等。merge modules最少要有兩個project,一個parent project,若干個child project。merge modules主要有以下幾種:
i. design time merge module
這種merge module直接把child project拷貝到了parent project中,child project中的panel和action都會在parent project
的安裝過程中出現(xiàn),并且你可以在parent project中修改它們。如果原來的child project做了某些變化,parent project中的child project不會有任何變化。
這種merge module只生成一個uninstaller,它會卸載掉整個軟件產(chǎn)品。如果要只卸載child project,好像可以通過把child project
設(shè)成feature來實現(xiàn),但我目前還沒有實驗過。
ii. dynamic time merge module
這種merge module不拷貝child project到parent project中,它只鏈接到child project。所以child project的任何變化都會反映到
parent project中。但是你不能在parent project中修改child project的panel和action,因為你只是鏈接到child project。
這種merge module會生成多個uninstaller,分別用來卸載parent project 和child projects。
iii. build time merge module
和dynamic time merge module類似,不同的是build time merge module不會出現(xiàn)child project的panel。換句話說,child project是以silent模式安裝的。
怎么在具體的項目中用merge module呢?首先,你需要把child project build成merge module,會生成一個文件。然后在parent project的
orgnization-->Modules 導(dǎo)入就可以了
15)Custom Code
IA的advanced designer已經(jīng)可以滿足大部分用戶的需要了,如果你所要的功能advanced designer還無法實現(xiàn),你可以自己編寫Custom Code來實現(xiàn)。可以說
Custom Code是IA的more advanced designer。
Custom Code分成以下幾種:
i.custom code actions
ii.custom code panels
iii.custom code consoles
iv.custom code rules
在IA的安裝目錄下有一個javadoc目錄,里面有IA提供的api的文檔,跟java的api的文檔的使用方法是一樣的。IA為以上四種Custom Code提供了四個
缺省的類來實現(xiàn),分別是CustomCodeAction,CustomCodePanel,CustomCodeConsoleAction,CustomCodeRule,你可以去繼承它們并添加你需要的
功能。
代碼寫好了之后不能直接用于IA中,還需要編譯,打包。打包有兩種方法
一)打包成類的JAR包
先寫好代碼,然后用javac命令編譯(當然你也可以用eclipse,netbean來得到class文件),最后把class file壓成jar包。
點擊Add Action-->Execute Custom Code,指定你的jar包的位置,如果用到了第三方的jar包,記得把它們添加到“Dependencies”中
ps:點擊Add Action,你會看到有四個tab:General,Panels,Consoles,Plug-ins。如果你是Custom Code Action,要選擇General里面的
Execute Custom Code,如果你是custom code panels,你要選擇Panels里面的Execute Custom Code,如果是custom code consoles,
要選擇Consoles里面的Execute Custom Code,如果是custom code rules,不能通過Add Action添加,你需要點擊Add Rule-->evaluate custom code
來執(zhí)行
二)打包成plugin
先寫好代碼,然后用javac命令編譯(當然你也可以用eclipse,netbean來得到class文件)。
創(chuàng)建一個properties文件,然后把這個properties文件打包成一個jar包??梢娕c第一種方法的區(qū)別就是多了一個屬性文件
舉一個屬性文件的例子:
plguin.name=my custom action
plugin.main.class=MySampleAction
plugin.type=action
//如果你寫了preinstall,那在preinstall view中Add Action-->Plugin里面可以看見這個plugin,否則是看不見的。
plugin.available=preinstall,install,postinstall
//property.myproperty=this value
property.database=localhost
打包完成后,把jar包拷貝到IA安裝目錄下的plugins文件夾,然后重啟IA(eclipse的用戶肯定很熟悉這個操作吧,呵呵)
然后你就可以在Add Action-->Plug-Ins里面發(fā)現(xiàn)你自己寫的plugin了。
最后列一下IA提供的api中比較重要的方法(IA提供了一個zip包IAClasses.zip在IA安裝目錄下)
public class MySampleAction extends CustomCodeAction
{
public void install(InstallerProxy ip)
{
}
}
subsititue(String var)-recursively gets the variable value
getVariable(String var)- jaut gets the variable value
for example:
database_name=$user_install_dir$/mydir
subsititue(String var) C:\pf\macrovision\mydir
getVariable(String var)
$user_install_dir$/mydir
public class MyCustom Panel extend CustomCodePanel{
public boolean setupUI(CustomCodePanelProxy ccpp){
//execute some condition or logic
return true or false;//if true ,display,or don't display
public voidpanelIsDisplayed()
{//you will put controls and logic for displaying the panel
//this is where you will use java's swing classes to display controls on your dialogs
//just for text area,if you wanna add a button to the bottom,then you need
//to create a new dialog by swing ,
}
public boolean okToContinue()
{
}
}
}
public class MyCustomConsole extend CustomCodeConsoleAction{
public boolean setup(CustomCodePanelProxy ccpp){
//any validation you want to execute before displaying this console panel
you will put here
}
}
}
public class MyCustomRule extends CustomCodeRule{
public void evaluateRule()
{
//in this method,you can put the logic to evaulate this custom rule
//return true or false
}
}
}
在IA安裝目錄下的Custom Code文件夾,你可以找到一些sample code,更多的sample code可以到
它的網(wǎng)站上查詢。
最后,引用training teacher的一句話作為本文的結(jié)尾“不管你的產(chǎn)品有多好,用戶第一印象是看你的安裝程序,如果你的安裝程序不夠人性化,甚至安裝失敗了,那用戶對它的評價就不會高”
不知道你是否注意過,當你安裝java jdk的時候,當你安裝微軟office的時候,當你裝db2的時候,你都會看到一個熟悉的標記---installshield。installshield可以說是當今安裝程序解決方案的巨無霸了,功能十分強大,你可以用它制作出你想要的安裝程序。但是功能的強大也帶來一個壞處,就是要上手非常難。所以公司特意請macrovision(就是制作installshield的公司)的人給我們進行了一個training,感覺收獲還是很大的,所以把我認為重要的地方紀錄下來,一方面萬一自己忘了可以查一查,另一方面說不定對別人也有幫助。
先從版本說起。installshield有專門用于制作java安裝程序的產(chǎn)品,由于java是跨平臺的語言,所以installshield對應(yīng)的產(chǎn)品就叫installshield multiple platform,簡稱ismp。我接觸的最早版本是ismp 5.0,后來又出了ismp 11.5,再后來ismp改名字叫Install Anywhere(以下簡稱IA)。目前我們training用的版本是IA 8.0,相信應(yīng)該是最新的版本了。IA是共享軟件,不注冊的話有21天的試用期。
安裝程序是一個可定制性非常強的東西,每個軟件作者的需求都不一樣。有的推崇簡單就是美,一般只需要用戶選擇安裝的目錄,然后就一路next就裝完了;但有的軟件非常復(fù)雜,比如需要設(shè)置參數(shù),需要選擇安裝哪些部分,甚至需要啟動windows的系統(tǒng)服務(wù)。這時候就需要比較復(fù)雜的配置了。installshield針對兩種用戶設(shè)計了不同的開發(fā)環(huán)境:一種是common designer,另一種是Advanced Designer。當你第一次打開IA的時候,缺省的是common designer,你只需要做一些簡單的配置,比如產(chǎn)品的名稱,需要安裝的文件,要不要綁定虛擬機等等,然后就可以build出一個安裝程序了。Advanced Designer是為高級用戶設(shè)置的,提供了更多,更豐富的功能,你可以用它來打造你所需要的安裝程序。本文主要是針對Advanced Designer進行一些說明。
1)安裝模式(install modes)
gui:這是最常用的一種模式,在安裝過程中會彈出若干個panel,比如welcome panel,license panel,destination panel等等。
console:用這種模式安裝程序時,不會出現(xiàn)panel。它的所有信息都在控制臺中出現(xiàn)。說的再通俗一點,就是整個安裝過程只有一個dos窗口,這個窗口先會顯示一行信息歡迎你安裝本軟件,然后是讓你選擇destination,再安裝,最后會顯示一行安裝成功的信息
silent:顧名思義,這種模式在安裝的時候不會彈出任何窗口,它會安靜地裝上軟件,所以用戶也不能自己設(shè)定安裝目錄,一般都市由安裝程序安裝到固定的目錄上
2)install sets
很多安裝程序都有完全安裝,最小安裝,自定義安裝等選項,這一般是用features來實現(xiàn)的。你可以把你的產(chǎn)品分成幾個features,然后由用戶來選擇一部分進行安裝。
3)actions
IA中很多操作被稱為actions,常見的有copy files,delete files,modifying registry, creating service, modifying configurations files等
4)variable
IA中很重要的一個概念,你可以用variable來存放屬性信息,比如安裝目錄,用戶名等等。比如
安裝目錄可能會在很多地方都用到,如果你安裝目錄是硬編碼的,萬一將來要修改就要改
很多地方,容易出錯;如果用variable來保存的話,只要修改變量值就可以了。注意一點:variable
的值基本上都是string類型的
5)magic folders
IA里面獨有的概念,但感覺沒什么新意,就是variables的一種,專門用于定義folder的
variable而已
6)InstallAnywhere registry
不同于windows的registry,這是InstallAnywhere自己的registry。每個用IA制作的安裝程序,在安裝的過程中
都會把自己注冊到這個InstallAnywhere registry(注意:你只能在InstallAnywhere registry找到安裝的
component,找不到product)。它的一個典型應(yīng)用就是當你需要檢查這個機器上是否安裝過某個軟件的時候,就可以
用search這個IA registry。不過如果你是用其他工具制作的安裝程序,IA registry就不會有記錄了。
7)execute command&execute script
execute command是用來執(zhí)行command,常用的dos命令(copy,cd等)你都可以寫在這里。execute script其實就是
execute command的加強版:如果你有多個命令,不需要建多個execute command,把它們寫在execute script就好了
8)計算所需空間
在IA中,默認的空間大小是用byte來計算的,所以如果你的軟件比較大的話,那一長串的阿拉伯數(shù)字會把用戶嚇倒的
解決方法是,在pre-install summary panel的配置項中,有一個是Edit Custom Field。在那里新建一個field。Variable
name是顯示給用戶看的內(nèi)容,比如你可以寫disk space。variable value是你的軟件所需的硬盤大小。你可以先算出來
,存在一個變量中,然后讓variable value等于這個變量就可以了。
9)results variable
用來存放用戶的選擇。比如在show message dialog中,有一個results variable是$CHOSEN_DIALOG_BUTTON$
它用來存放用戶按的是OK 還是Cancel
摘要: How to understand and use Eclipse Production Configuration
...
閱讀全文
摘要: 1.在tabbedProperties(eclipse3.2以上支持)中,如果要建立一個treeview,且想要click任何一列都可以實現(xiàn)celledit,需要在創(chuàng)建treeview的時候加上style: SWT.FULL_SELECTION
2.tabbedProperties中section的大小現(xiàn)在無法做到根據(jù)widget的大小自動調(diào)整,目前只能用getMinimumHeight()返回一個固定值
閱讀全文
很多人在開發(fā)RCP時,發(fā)現(xiàn)開發(fā)時都沒問題,但導(dǎo)出成包時卻報找不到第三方庫中類的錯誤。主要原因就是沒有將第三方庫配置好?,F(xiàn)在我給出一個實現(xiàn)項目的配置為示例,以供參考?!≡某鎏?http://www.eclipseworld.org/bbs/read.php?tid=1133 環(huán)境:Eclipse3.2M3 一個RCP的實際項目
一、
最關(guān)鍵的就是plugin.xml和MANIFEST.MF 所有界面上的最后操作,結(jié)果都是保存在這兩個文件中。注意:“.classpath”文件只是開發(fā)時對引用第三庫有用,打包發(fā)行之后它的作用就沒有了,還得靠plugin.xml和MANIFEST.MF。
1、plugin.xml文件
<?xml version="1.0" encoding="GB2312"?>
<?eclipse version="3.0"?>
<plugin>
?? <extension
???????? id="AdminConsole"
???????? point="org.eclipse.core.runtime.applications">
??????? <application>
??????????? <run class="com.wxxr.management.admin.console.AdminConsole"/>
??????? </application>
?? </extension>
?
?? <extension id="AdminConsole" point="org.eclipse.core.runtime.products">
? <product name="%productName" application="com.wxxr.management.admin.console.AdminConsole">
?? <property name="appName" value="%swtAppName"/>
?? <property name="windowImages" value="icons/eclipse.gif,icons/eclipse32.gif"/>
?? <property name="aboutText" value="%aboutText"/>
?? <property name="aboutImage" value="icons/eclipse_lg.gif"/>
?? <property name="windowImages" value="icons/alt16.gif,icons/eclipse.gif"/>
? </product>
?? </extension>
??
?? <extension
????? point="org.eclipse.ui.perspectives">
????? <perspective
??????????? class="com.wxxr.management.admin.console.monitor.MonitorPerspective"
??????????? name="%perspectiveName"
??????????? id="com.wxxr.management.admin.console.monitor.MonitorPerspective"/>
????? <perspective
??????????? class="com.wxxr.management.admin.console.configure.ConfigurePerspective"
??????????? name="%configurePerspectiveName"
??????????? id="com.wxxr.management.admin.console.configure.ConfigurePerspective"/>
????? <perspective
??????????? class="com.wxxr.management.admin.console.jmx.JMXPerspective"
??????????? name="%jmxPerspectiveName"
??????????? id="com.wxxr.management.admin.console.jmx.JMXPerspective"/>
?? </extension>
?<extension
?? point="org.eclipse.ui.editors">
?? <editor
?? name="事件列表"
?? icon="icons/alt16.gif"
?? class="com.wxxr.management.admin.console.log.ui.LogEditor"
?? id="com.wxxr.management.admin.console.log.ui.LogEditor">
?? </editor>
?? <editor
?? name="地圖"
?? icon="icons/map_view.gif"
?? class="com.wxxr.management.admin.console.map.MapEditor"
?? id="com.wxxr.management.admin.console.map.MapEditor">
?? </editor>
?</extension>
?? <extension
???????? point="org.eclipse.ui.views">
????? <category
??????????? id="com.wxxr.management.admin.console.monitor.view"
??????????? name="%views.category.name"/>
????? <view
??????????? id="com.wxxr.management.admin.console.navigator.ui.StationExploreView"
??????????? name="工作站"
??????????? icon="icons/eclipse.gif"
??????????? class="com.wxxr.management.admin.console.navigator.ui.StationExploreView"
??????????? category="com.wxxr.management.admin.console.monitor.view"/>
????? <view
??????????? name="事件細節(jié)"
??????????? icon="icons/eclipse.gif"
??????????? category="com.wxxr.management.admin.console.monitor.view"
??????????? class="com.wxxr.management.admin.console.monitor.eventview.EventDetailView"
??????????? id="com.wxxr.management.admin.console.monitor.eventview.EventDetailView" />
????? <view
??????????? name="事件統(tǒng)計"
??????????? icon="icons/eclipse.gif"
??????????? category="com.wxxr.management.admin.console.monitor.view"
??????????? class="com.wxxr.management.admin.console.monitor.view.SystemEventStatisticsView"
??????????? id="com.wxxr.management.admin.console.monitor.view.SystemEventStatisticsView" />
????? <view
??????????? name="緊急事件處理"
??????????? icon="icons/eclipse.gif"
??????????? category="com.wxxr.management.admin.console.monitor.view"
??????????? class="com.wxxr.management.admin.console.emergency.ui.EmergencyEventReceiverView"
??????????? id="com.wxxr.management.admin.console.emergency.ui.EmergencyEventReceiverView" />
????? <category
??????????? id="com.wxxr.management.admin.console.jmx.view"
??????????? name="%views.category.name"/>
????? <view
??????????? name="JMX Connections"
??????????? icon="icons/eclipse.gif"
??????????? category="com.wxxr.management.admin.console.jmx.view"
??????????? class="com.wxxr.management.admin.console.jmx.ui.JMXExploreView"
??????????? id="com.wxxr.management.admin.console.jmx.ui.JMXExploreView" />
????? <view
??????????? name="JMX Attributes View"
??????????? icon="icons/eclipse.gif"
??????????? category="com.wxxr.management.admin.console.jmx.view"
??????????? class="com.wxxr.management.admin.console.jmx.ui.AttributesView"
??????????? id="com.wxxr.management.admin.console.jmx.ui.AttributesView" />
????? <view
??????????? name="JMX Operations View"
??????????? icon="icons/eclipse.gif"
??????????? category="com.wxxr.management.admin.console.jmx.view"
??????????? class="com.wxxr.management.admin.console.jmx.ui.OperationsView"
??????????? id="com.wxxr.management.admin.console.jmx.ui.OperationsView" />
????? <view
??????????? name="JMX MBean View"
??????????? icon="icons/eclipse.gif"
??????????? category="com.wxxr.management.admin.console.jmx.view"
??????????? class="com.wxxr.management.admin.console.jmx.ui.MBeanView"
??????????? id="com.wxxr.management.admin.console.jmx.ui.MBeanView" />
?? </extension>
?? <extension
???????? id="AdminConsole"
???????? point="org.eclipse.core.runtime.products">
????? <product
??????????? application="com.wxxr.management.admin.console.AdminConsole"
??????????? name="AdminConsole"/>
?? </extension>
??
</plugin>
?
2、
META-INF\MANIFEST.MF文件
??? 注意:(1)這里require-bundle定義了項目依賴的插件。
(2)Bundle-ClassPath定義了引用的第三方庫,別忘了把AdminConolse項目自己console.jar加進去,否則連自己項目里的類都會找不到。
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: com.wxxr.management.admin.console; singleton:=true
Bundle-Version: 1.0.0
Bundle-Activator: com.wxxr.management.admin.console.AdminConsolePlugin
Bundle-Localization: plugin
Require-Bundle: org.eclipse.ui,
?org.eclipse.core.runtime,
?org.eclipse.core.resources,
?org.eclipse.gef,
?org.eclipse.ui.forms,
?org.eclipse.ui.console
Eclipse-AutoStart: true
Bundle-Vendor: %providerName
Bundle-ClassPath: console.jar,
?lib/commons-codec-1.3.jar,
?lib/jboss.jar,
?lib/jbossall-client.jar,
?lib/jboss-jmx.jar,
?lib/jboss-system.jar,
?lib/log4j-1.2.8.jar,
?lib/wxxr-common-1.0-b1.jar,
?lib/wxxr-common-jboss-1.0-b1.jar,
?lib/wxxr-db-persistence-1.0-b1.jar,
?lib/wxxr-jboss-controller-1.0-b1.jar,
?lib/wxxr-jboss-workstation-1.0-b1.jar,
?lib/wxxr-remoting-1.0-b1.jar,
?lib/wxxr-security-1.0-b1.jar,
?lib/xerces-2.6.2.jar,
?lib/xmlParserAPIs-2.2.1.jar,
?lib/xmlrpc-2.0.jar
?3、build.properties文件。
這個文件主要是用Eclipse導(dǎo)出包的時候用。
source.console.jar = src/
output.console.jar = bin/
bin.includes = plugin.xml,\
?????????????? *.jar,\
?????????????? console.jar, \
?????????????? plugin.properties
??????????????
pluginName = Admin Console Plug-in
providerName = WXXR.com.cn
perspectiveName = Admin Console
configurePerspectiveName= Configure
jmxPerspectiveName= JMX Console
??????????????
jars.extra.classpath = lib/commons-codec-1.3.jar,\
?????????????????????? lib/jboss.jar,\
?????????????????????? lib/jbossall-client.jar,\
?????????????????????? lib/jboss-jmx.jar,\
?????????????????????? lib/jboss-system.jar,\
?????????????????????? lib/log4j-1.2.8.jar,\
?????????????????????? lib/wxxr-common-1.0-b1.jar,\
?????????????????????? lib/wxxr-common-jboss-1.0-b1.jar,\
?????????????????????? lib/wxxr-db-persistence-1.0-b1.jar,\
?????????????????????? lib/wxxr-jboss-controller-1.0-b1.jar,\
?????????????????????? lib/wxxr-jboss-workstation-1.0-b1.jar,\
?????????????????????? lib/wxxr-security-1.0-b1.jar,\
?????????????????????? lib/wxxr-remoting-1.0-b1.jar,\
?????????????????????? lib/xerces-2.6.2.jar,\
?????????????????????? lib/xmlParserAPIs-2.2.1.jar,\
?????????????????????? lib/xmlrpc-2.0.jar
4、plugin.properties,這個放一些上面幾個文件用到的變量。
pluginName= WXXR Admin Console
providerName= wxxr.com.cn
?
productName= WXXR SMS Operation Platform
appName= WXXR Admin Console
perspectives.browser.name= WXXR Admin Console
views.category.name= WXXR Admin Console
views.browser.name= Browser
views.history.name= History
views.stationexplore.name= Stations
views.tasklist.name= Task List
views.loglist.name= Workstation Monitor
monitor.message.detail=Monitor Message Detail
monitor.message.statistics=????
?
swtAppName= AdminConsole
aboutText= WXXR Admin Console \n\n\
(c) Copyright WXXR Ltd. and others 2003, 2004.? All rights reserved.\n\
Visit
http://www.wxxr.com.cn?二、圖形方式 有時直接編輯plugin.xml等文件容易出錯(全角空格什么的),那么可以用圖形編輯方式來,不過最后結(jié)果還是反映到plugin.xml等文件中的。我把plugin.xml打開,然后一個項一個項的把圖截下來,以供大家參考。