Web 2.0時(shí)代時(shí)代的Web項(xiàng)目,是無論如何也少不了一個(gè)在線編輯器的,因此在我們的項(xiàng)目中整合一個(gè)Web編輯器就顯得至關(guān)重要。在這里,我依然以前面的xkland項(xiàng)目為例,來探討在項(xiàng)目中整合FCKeditor的方方面面。
一、關(guān)于用戶發(fā)表文章的功能設(shè)計(jì)
用戶發(fā)表文章的功能,大家見過不少,也用過不少,最簡單的,莫過于提供一個(gè)文本框,數(shù)據(jù)提交后直接寫入數(shù)據(jù)庫了事,稍復(fù)雜一點(diǎn)的最少也要提供一個(gè)輸入標(biāo)題和選擇分類的功能。當(dāng)然,我們也可以把我們的功能設(shè)計(jì)得更有特色。在這個(gè)示例項(xiàng)目中,我假設(shè)開發(fā)的是一個(gè)以圖文為中心的網(wǎng)絡(luò)社區(qū),我們每一篇文章都需要用戶在它上傳的圖片中選擇一個(gè)作為主題圖片,那么,在網(wǎng)站首頁的文章列表上,大家看到的將不僅僅只是一個(gè)文字的標(biāo)題,還有主題圖片的縮略圖。
先來看看數(shù)據(jù)表的結(jié)構(gòu),創(chuàng)建數(shù)據(jù)表的SQL語句如下:
CREATE
?
TABLE
?`topics`?(
??`id`?
int
(
11
)?
NOT
?
NULL
?auto_increment,
??`catalogid`?
int
(
11
)?
NOT
?
NULL
,
??`subject`?
varchar
(
60
)?
default
?
NULL
,
??`content`?
text
,
??`pictures`?
varchar
(
2000
)?
NOT
?
NULL
,
??`mainpicture`?
varchar
(
40
)?
NOT
?
NULL
,
??`userid`?
int
(
11
)?
NOT
?
NULL
,
??`time`?
timestamp
?
NOT
?
NULL
?
default
?
CURRENT_TIMESTAMP
?
on
?
update
?
CURRENT_TIMESTAMP
,
??`lastedittime`?
timestamp
?
NOT
?
NULL
?
default
?
'
2007-01-01?00:00:00
'
,
??`lastreplytime`?
timestamp
?
NOT
?
NULL
?
default
?
'
2007-01-01?00:00:00
'
,
??`visitcount`?
int
(
11
)?
NOT
?
NULL
,
??
PRIMARY
?
KEY
??(`id`),
??
KEY
?`subject`?(`subject`),
??
KEY
?`userid`?(`userid`),
??
KEY
?`time`?(`time`),
??
KEY
?`lastreplytime`?(`lastreplytime`)
)?ENGINE
=
InnoDB?
DEFAULT
?CHARSET
=
utf8?
|
其中,catalogid字段為文章分類,subject字段為標(biāo)題,content字段為正文。比較特殊的是pictures字段和mainpicture字段,pictures保存文章中包含的所有圖片的url,以“|”符號分割,如“001.jpg|002.jpg|003.jpg...”,而mainpicture就是主題圖片的url了。有人會問:“保存主題圖片的url就夠了,為什么還要保存所有的圖片url呢?”,這樣設(shè)計(jì)主要是為了考慮到用戶有時(shí)候會修改文章,重新選擇別的圖片作為主題圖片,這個(gè)時(shí)候pictures字段就派上用場了,因?yàn)樗梢韵蛴脩籼峁┖蜻x項(xiàng)。
這樣的功能設(shè)計(jì)應(yīng)該提供如下的用戶界面,該頁面文件名為EditPosts.jsp:

在這里,我們還沒有Web編輯器可用,暫時(shí)用一個(gè)文本區(qū)域代替。
二、初識FCKeditor
在聽說FCKeditor之前,我用過一個(gè)在線編輯器eWebEditor,提供ASP/JSP/PHP等好幾個(gè)版本,功能是非常的好,文檔也很詳細(xì),但是聽說只支持IE瀏覽器;而FCKeditor在網(wǎng)上大名鼎鼎,是一個(gè)受關(guān)注非常高的開源項(xiàng)目,并且能夠跨瀏覽器支持。因此我選擇FCKeditor。FCKeditor的最新版本是2.4,大家可以到
http://www.fckeditor.net/download這里下載,如下圖

下載并解壓縮到fckeditor文件夾,打開該文件夾,我們可以看到如下文件及目錄:

其中_samples目錄下是示例,_testcases目錄下是測試用例,editor目錄下是編輯器的主要文件;此外,從該目錄中的文件不難看出,F(xiàn)CKeditor提供支持asp、php、perl、python等等各種服務(wù)器技術(shù)的版本,但不支持.net和Java Web。不過不要擔(dān)心,F(xiàn)CKeditor與Java Web之間的整合早就有人做好了,稍后我們就會用到。
了解瀏覽器技術(shù)的人都不難想到,Web編輯器其實(shí)應(yīng)該是客戶端技術(shù),它是通過JavaScript來控制頁面上的元素和通過彈出窗口來模擬對話框而做到的;只有在提交文章或者上傳文件的時(shí)候才需要跟服務(wù)器端交互。因此,要將該編輯器快速整合到項(xiàng)目中以看到效果,是非常簡單的。
三、使用JavaScript整合FCKeditor
將剛剛解壓得到的fckeditor目錄拷貝到我們的項(xiàng)目中的src\main\webapp目錄下,打開剛才建立的EditPosts.jsp,加入如下代碼:
1
<
script?src
=
"
fckeditor/fckeditor.js
"
></
script
>
2
<
script?language
=
"
javascript
"
>
3
window.onload?
=
?
function
()
{
4
????
var
?oFCKeditor?
=
?
new
?FCKeditor(?'myTextArea'?)?;
5
????oFCKeditor.BasePath?
=
?
"
fckeditor/
"
;
6
????oFCKeditor.ReplaceTextarea();
7
}?
????? </scrip>
在這里,第一行代碼是引入fckeditor中的fckeditor.js文件,其中定義了FCKeditor類,第四行就是利用該類創(chuàng)建一個(gè)編輯器對象,而myTextArea是表單中文本區(qū)域的名字,在第六行,通過FCKeditor類的ReplaceTextArea方法,文本區(qū)域就被替換成了Web編輯器。刷新頁面,就可以看到效果:

FCKeditor類提供幾個(gè)基本屬性,可以讓我們對編輯器進(jìn)行簡單的控制,它們是:
InstanceName:返回編輯器示例的名字
Width:設(shè)置編輯器的寬度,默認(rèn)為100%
Height:設(shè)置編輯器的高度,默認(rèn)值為200
ToolbarSet:設(shè)置編輯器的工具條集合,默認(rèn)值為"default",稍后會講到怎樣自定義工具條
Value:設(shè)置顯示在編輯器中的內(nèi)容(包含HTML),默認(rèn)值為空
BasePath:編輯器的目錄,一定要設(shè)置正確,否則編輯器會找不到它需要的文件,在本例中,由于我們直接將fckeditor目錄放到項(xiàng)目的根目錄下,因此設(shè)置為"fckeditor/"
CheckBrowser:設(shè)置是否檢測瀏覽器,默認(rèn)為true
DisplayErrors:設(shè)置是否顯示錯(cuò)誤信息,默認(rèn)為true
此外,F(xiàn)CKeditor類還有一個(gè)集合屬性
Config[ key ] = value,通過該集合屬性,我們可以進(jìn)行一個(gè)更高級的設(shè)置,如設(shè)置默認(rèn)語言、更換皮膚等等。
綜上所述,下面的代碼將重新設(shè)置編輯器的高和寬、將工具條設(shè)置為基本工具條,將皮膚設(shè)置為office2003樣式:
<script?src="fckeditor/fckeditor.js"></script>
<script?language="javascript">

window.onload?=?function()
{
????var?oFCKeditor?=?new?FCKeditor(?'myTextArea'?)?;
????
????oFCKeditor.BasePath?=?"fckeditor/";
????oFCKeditor.Width?=?"800";
????oFCKeditor.Height?=?"300";
????oFCKeditor.ToolbarSet?=?"Basic";
????
????oFCKeditor.Config["SkinPath"]?=?"skins/office2003/";
????
????oFCKeditor.ReplaceTextarea();
}
</script> 效果圖:
四、通過FCKeditor.java整合FCKeditor
使用JavaScript整合FCKeditor,我們很快就能看到編輯器的效果,并進(jìn)行文章的編輯。但是,在需要和服務(wù)器端進(jìn)行交互的時(shí)候(比如上傳圖片),就會出錯(cuò)。因此,我們不得不在服務(wù)器端做一點(diǎn)手腳。這里,我們需要使用的是FCKeditor.java,其最新版本是2.3,還是在剛才的下載頁面,找到下載鏈接,如下圖:

將下載文件解壓,我們可以看到有doc目錄,有src目錄,甚至還有一個(gè)build.xml,讓我們可以重新構(gòu)建項(xiàng)目;但是,這些我們統(tǒng)統(tǒng)都不需要,我們只要web\WEB-INF目錄下的東西,在這個(gè)目錄下,提供了一個(gè)web.xml,同時(shí)在lib目錄下提供了兩個(gè).jar文件,這便是全部。看到這里,大家肯定能夠想到,Java Web項(xiàng)目的靈魂是什么?那就是web.xml。我們所要做的,就是把lib目錄下的兩個(gè).jar文件拷貝到我們項(xiàng)目的src/main/webapp/WEB-INF/lib下,同時(shí)將web.xml中的內(nèi)容整合到我們項(xiàng)目的src/main/webapp/WEB-INF/web.xml中。
web.xml中的內(nèi)容很簡單,只定義了兩個(gè)Servlet映射,并且對上傳文件的目錄和允許哪些文件上傳、拒絕哪些文件上傳做了設(shè)置,如下:
<servlet>
????????<servlet-name>Connector</servlet-name>
????????<servlet-class>com.fredck.FCKeditor.connector.ConnectorServlet</servlet-class>
????????<init-param>
????????????<param-name>baseDir</param-name>
????????????<param-value>/UploadFiles/</param-value>
????????</init-param>
????????<init-param>
????????????<param-name>debug</param-name>
????????????<param-value>true</param-value>
????????</init-param>
????????<load-on-startup>1</load-on-startup>
????</servlet>

????<servlet>
????????<servlet-name>SimpleUploader</servlet-name>
????????<servlet-class>com.fredck.FCKeditor.uploader.SimpleUploaderServlet</servlet-class>
????????<init-param>
????????????<param-name>baseDir</param-name>
????????????<param-value>/UploadFiles/</param-value>
????????</init-param>
????????<init-param>
????????????<param-name>debug</param-name>
????????????<param-value>true</param-value>
????????</init-param>
????????<init-param>
????????????<param-name>enabled</param-name>
????????????<param-value>true</param-value>
????????</init-param>
????????<init-param>
????????????<param-name>AllowedExtensionsFile</param-name>
????????????<param-value></param-value>
????????</init-param>
????????<init-param>
????????????<param-name>DeniedExtensionsFile</param-name>
????????????<param-value>php|php3|php5|phtml|asp|aspx|ascx|jsp|cfm|cfc|pl|bat|exe|dll|reg|cgi</param-value>
????????</init-param>
????????<init-param>
????????????<param-name>AllowedExtensionsImage</param-name>
????????????<param-value>jpg|gif|jpeg|png|bmp</param-value>
????????</init-param>
????????<init-param>
????????????<param-name>DeniedExtensionsImage</param-name>
????????????<param-value></param-value>
????????</init-param>
????????<init-param>
????????????<param-name>AllowedExtensionsFlash</param-name>
????????????<param-value>swf|fla</param-value>
????????</init-param>
????????<init-param>
????????????<param-name>DeniedExtensionsFlash</param-name>
????????????<param-value></param-value>
????????</init-param>
????????<load-on-startup>1</load-on-startup>
????</servlet>

??????<servlet-mapping>
????????<servlet-name>Connector</servlet-name>
????????<url-pattern>/fckeditor/editor/filemanager/browser/default/connectors/jsp/connector</url-pattern>
??????</servlet-mapping>
??
??????<servlet-mapping>
????????<servlet-name>SimpleUploader</servlet-name>
????????<url-pattern>/fckeditor/editor/filemanager/upload/simpleuploader</url-pattern>
??????</servlet-mapping>? 請注意,這兩個(gè)servlet的url-pattern我都在原來代碼的前面加上了/fckeditor。
然后,我們就可以拋開JavaScript,而在服務(wù)器端使用標(biāo)簽來創(chuàng)建Web編輯器了。先在EditPosts.jsp中引入標(biāo)簽庫:

<%
@?taglib?uri="http://fckeditor.net/tags-fckeditor"?prefix="FCK"?%> 再在原來放textarea的地方,放如下代碼:
<FCK:editor?id="EditorDefault"?basePath="/xkland/fckeditor/"
????????imageBrowserURL="/xkland/fckeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/jsp/connector"
????????linkBrowserURL="/xkland/fckeditor/editor/filemanager/browser/default/browser.html?Connector=connectors/jsp/connector"
????????flashBrowserURL="/xkland/fckeditor/editor/filemanager/browser/default/browser.html?Type=Flash&Connector=connectors/jsp/connector"
????????imageUploadURL="/xkland/fckeditor/editor/filemanager/upload/simpleuploader?Type=Image"
????????linkUploadURL="/xkland/fckeditor/editor/filemanager/upload/simpleuploader?Type=File"
????????flashUploadURL="/xkland/fckeditor/editor/filemanager/upload/simpleuploader?Type=Flash">
????????????This?is?some?<strong>sample?text</strong>.?You?are?using?<a?href="http://www.fredck.com/fckeditor/">FCKeditor</a>.
????</FCK:editor>
這里有一點(diǎn)一定要注意,那就是這里的屬性都要避免使用相對路徑。
刷新頁面,又見編輯器,此時(shí),可以順利的上傳文件了。整合編輯器的任務(wù)到此完成。下一步,就是怎樣對編輯器進(jìn)行更多的控制了。
五、對編輯器進(jìn)行更多控制
1、自定義工具條:打開fckeditor目錄下的fckconfig.js文件,添加如下代碼:
FCKConfig.ToolbarSets["Usable"]?=?[
????['Source','Preview'],
????['Undo','Redo','-','SelectAll','Cut','Copy','Paste','-','RemoveFormat','-','Find','Replace'],
????['Link','Unlink','Anchor'],
????['FitWindow','-','About'],
????'/',
????['Bold','Italic','Underline','StrikeThrough','-','Subscript','Superscript'],
????['OrderedList','UnorderedList','-','Outdent','Indent'],
????['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],
????['Image','Flash','Table','Rule','Smiley'],
????'/',
????['Style','FontFormat','FontName','FontSize'],
????['TextColor','BGColor']
]?;
2、添加常用的中文字體:在上面打開的文件中找到
FCKConfig.FontNames?=?'Arial;Comic?Sans?MS;Courier?New;Tahoma;Times?New?Roman;Verdana'?;加上幾種我們常用的字體
FCKConfig.FontNames?=?'宋體;黑體;隸書;楷體_GB2312;Arial;Comic?Sans?MS;Courier?New;Tahoma;Times?New?Roman;Verdana'?; 3、更改JSP頁面中定義編輯器的標(biāo)簽,如下:
<FCK:editor?id="EditorDefault"?basePath="/xkland/fckeditor/"
????????skinPath="/xkland/fckeditor/editor/skins/office2003/"
????????toolbarSet="Usable"
????????imageBrowserURL="/xkland/fckeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/jsp/connector"
????????linkBrowserURL="/xkland/fckeditor/editor/filemanager/browser/default/browser.html?Connector=connectors/jsp/connector"
????????flashBrowserURL="/xkland/fckeditor/editor/filemanager/browser/default/browser.html?Type=Flash&Connector=connectors/jsp/connector"
????????imageUploadURL="/xkland/fckeditor/editor/filemanager/upload/simpleuploader?Type=Image"
????????linkUploadURL="/xkland/fckeditor/editor/filemanager/upload/simpleuploader?Type=File"
????????flashUploadURL="/xkland/fckeditor/editor/filemanager/upload/simpleuploader?Type=Flash">
????????????This?is?some?<strong>sample?text</strong>.?You?are?using?<a?href="http://www.fredck.com/fckeditor/">FCKeditor</a>.
????</FCK:editor>?
刷新頁面,可以看到編輯器的效果如下:

六、如何獲取編輯器中插入的圖片
從文章開頭的功能設(shè)計(jì)我們可以看出,當(dāng)用戶編輯完文章后,我們應(yīng)該能獲取文章中插入的圖片信息。怎樣獲取編輯器中的插入的圖片呢?IT進(jìn)行時(shí)在他的文章FCKeditor的幾點(diǎn)重要改進(jìn)和使用心得,值得分享 中是這樣做的:在上傳圖片的對話框的JavaScript中添加代碼,使得當(dāng)用戶插入圖片點(diǎn)OK后通知列表框,代碼如下:

try??
{????????
?????????var??obj??=??window.dialogArguments.Editor.parent.document;
????????obj.getElementById(?"?tip.c_tip_has_pic?"?).value??=???"?1?"?;

????}?catch?(e)??
{}?
我認(rèn)為這個(gè)方法不好,第一,這個(gè)方法是侵入性的,需要修改FCKeditor的代碼;第二,這種方法能夠在用戶插入圖片的時(shí)候獲得圖片信息,但是如果用戶插入的圖片,接著又把圖片從文章中刪除了呢?這時(shí)候是無法跟蹤的。
正確的思路應(yīng)該是在編輯器失去焦點(diǎn)的時(shí)候,獲取編輯器中的文檔,通過DOM取得文章中所有的圖片。代碼如下:
function?FCKeditor_OnComplete(?editorInstance?)


{
????editorInstance.Events.AttachEvent(?'OnBlur',?onEditorBlur?)?;
}


function?onEditorBlur()
{
????var?oSelect?=?$("img_select");

????for(var?i=oSelect.options.length-1;?i>0;?i--)
{
????????oSelect.options[i]?=?null;
????}
????oEditor?=?FCKeditorAPI.GetInstance('EditorDefault');
????var?imgs?=?oEditor.EditorDocument.body.all.tags("img");

????for(var?i=0;?i?<?imgs.length;?i++)
{
????????var?oOption?=?document.createElement("option");
????????oOption.appendChild(document.createTextNode(imgs[i].src));
????????oSelect.appendChild(oOption);
????}
}
上面是我在探索FCKeditor中的一些心得,有問題的地方,歡迎大家探討。