本文介绍FCKeditor在Java环境下的使用方法。
一、简介
功能:所见即所得,支持图片和Flash,工具栏可*配置,使用简单
兼容性:IE 5.5+、Firefox 1.5+、Safari 3.0+、Opera 9.50+、Netscape 7.1+、 Camino 1.0+
成熟度:使用广泛,被Baidu、CSDN等选用
二、下载
官方下载首页:http://www.fckeditor.net/download
/
,当前版本为2.6Beta,需要下载FCKeditor 2.6Beta(FCKeditor_2.6b.zip
)和FCKeditor.Java(FCKeditor-2.3.zip
)。
三、部署
本例以WebRoot作为应用根路径,部署后的目录结构如下图所示:
1、FCKeditor_2.5.1.zip解压,将fckeditor文件夹复制到/WebRoot/下
2、
FCKeditor-2.3.zip解压,将commons-fileupload.jar和FCKeditor-2.3.jar复制到/WebRoot
/WEB-INF/lib/下,将src下面的FCKeditor.tld复制到/WebRoot/WEB-INF/下,把src目录下的java类的复
制到project的src目录下
3、修改/WebRoot/WEB-INF/web.xml文件,只定义了两个Servlet映射,并
且对上传文件的目录和允许哪些文件上传、拒绝哪些文件上传做了设置,请注意,这两个servlet的url-pattern我都在原来代码的前面加上了
/fckeditor,这是表示FCKeditor的根目录。另外SimpleUploader中的enabled属性要改成true,允许上传,增加内
容如下:
<
servlet
>
<
servlet-name
>
Connector
</
servlet-name
>
<
servlet-class
>
com.fredck.FCKeditor.connector.ConnectorServlet
</
servlet-class
>
<
init-param
>
<
param-name
>
baseDir
</
param-name
>
<
param-value
>
/UserFiles/
</
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
>
/UserFiles/
</
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
>
4、修改/WebRoot/fckeditor/fckconfig.js,修改部分如下:
FCKConfig.BasePath + "filemanager/browser/default/browser.html?Connector=connectors/jsp/connector" ;
FCKConfig.BasePath + "filemanager/browser/default/browser.html?Type=Image&Connector=connectors/jsp/connector" ;
FCKConfig.BasePath + "filemanager/browser/default/browser.html?Type=Flash&Connector=connectors/jsp/connector" ;
FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=File' ;
FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=Image' ;
FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=Flash' ;
注意
:步骤
3、4设置了文件浏览和上传的配置,web.xml中Servlet的<url-pattern>要和fckconfig.js中的URL引
用一致。另外,我也把FCKeditor目录\fckeditor\editor\filemanager\下的connectors文件夹移到了
\fckeditor\editor\filemanager\browser\default\目录下,我也不知道这样做有什么用处,但好像不这样做就
会发生错误,希望大家指教。
四、使用
本例使用最直接的js方式,API和TagLib方式参见FCKeditor-2.3.zip解压后_samples下的例子。
fckdemo.jsp:
<%
@ page contentType
=
"
text/html;charset=GBK
"
%>
<
html
>
<
head
>
<
title
>
FCKeditor Test
</
title
>
<
script
type
="text/javascript"
src
="fckeditor/fckeditor.js"
></
script
>
</
head
>
<
body
>
<
form
action
="fckdemo.jsp"
method
="post"
>
<%
String
content
=
request.getParameter(
"
content
"
);
%>
<
table
width
=80%
>
<
tr
>
<
td
colspan
=4
style
='text-align:center'
>
<
span
>
<
script
type
="text/javascript"
>
var
oFCKeditor
=
new
FCKeditor('content');
//
表单的name,取值的依据
oFCKeditor.BasePath
=
'
fckeditor
/
';
//
指定FCKeditor根路径,也就是fckeditor.js所在的路径
oFCKeditor.Height
=
'200
';/
/指定高度
oFCKeditor.ToolbarSet
=
'Demo';
//
指定工具栏,这里使用了自定义的
oFCKeditor.Value
=
"
<%=content==null?
""
:(content.replaceAll(
"
\
""
,
"
'
"
))
%>
"
;//
默认值
oFCKeditor.Create();
</script>
</span>
</td>
</tr>
<tr><td align=center><input type=
"
submit
"
value=
"
提交
"
></td></tr>
<tr><td> </td></tr>
<tr><td>取值(可直接保存至数据库):</td></tr>
<tr><td style=
"
padding:10px;
"
><%=content%></td></tr>
</table>
</form>
</body>
</html>
效果图:
五、配置文件fckconfig.js
1、DefaultLanguage:缺省语言,可更改为“zh-cn”
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、自定义工具栏:可修改或增加ToolbarSets,例如:
FCKConfig.ToolbarSets[
"
Demo
"
]
=
[
['Bold','Italic','
-
','OrderedList','UnorderedList','
-
','Link','Unlink','
-
','TextColor','BGColor','
-
','Style','
-
','Image','Flash','Table']
] ;
4、EnterMode和ShiftEnterMode:“回车”和“Shift+回车”的换行行为,注释提示了可选模式
5、EditorAreaCss:编辑区样式文件
6、其他参数:
AutoDetectLanguage
=
true/false 自动检测语言
BaseHref
=
""
相对链接的基地址
ContentLangDirection
=
"
ltr/rtl
"
默认文字方向
ContextMenu
=
字符串数组
,
右键菜单的内容
CustomConfigurationsPath
=
""
自定义配置文件路径和名称
Debug
=
true/false 是否开启调试功能
,
这样
,
当调用FCKDebug.Output()时
,
会在调试窗中输出内容
EnableSourceXHTML
=
true/false 为TRUE时
,
当由可视化界面切换到代码页时
,
把HTML处理成XHTML
EnableXHTML
=
true/false 是否允许使用XHTML取代HTML
FillEmptyBlocks
=
true/false 使用这个功能
,
可以将空的块级元素用空格来替代
FontColors
=
""
设置显示颜色拾取器时文字颜色列表
FontFormats
=
""
设置显示在文字格式列表中的命名
FontNames
=
""
字体列表中的字体名
FontSizes
=
""
字体大小中的字号列表
ForcePasteAsPlainText
=
true/false 强制粘贴为纯文本
ForceSimpleAmpersand
=
true/false 是否不把&符号转换为XML实体
FormatIndentator
=
""
当在源码格式下缩进代码使用的字符
FormatOutput
=
true/false 当输出内容时是否自动格式化代码
FormatSource
=
true/false 在切换到代码视图时是否自动格式化代码
FullPage
=
true/false 是否允许编辑整个HTML文件
,
还是仅允许编辑BODY间的内容
GeckoUseSPAN
=
true/false 是否允许SPAN标记代替B
,
I
,
U标记
IeSpellDownloadUrl
=
""
下载拼写检查器的网址
ImageBrowser
=
true/false 是否允许浏览服务器功能
ImageBrowserURL
=
""
浏览服务器时运行的URL
ImageBrowserWindowHeight
=
""
图像浏览器窗口高度
ImageBrowserWindowWidth
=
""
图像浏览器窗口宽度
LinkBrowser
=
true/false 是否允许在插入链接时浏览服务器
LinkBrowserURL
=
""
插入链接时浏览服务器的URL
LinkBrowserWindowHeight
=
""
链接目标浏览器窗口高度
LinkBrowserWindowWidth
=
""
链接目标浏览器窗口宽度
Plugins
=
object 注册插件
PluginsPath
=
""
插件文件夹
ShowBorders
=
true/false 合并边框
SkinPath
=
""
皮肤文件夹位置
SmileyColumns
=
12
图符窗列数
SmileyImages
=
字符数组 图符窗中图片文件名数组
SmileyPath
=
""
图符文件夹路径
SmileyWindowHeight 图符窗口高度
SmileyWindowWidth 图符窗口宽度
SpellChecker
=
"
ieSpell/Spellerpages
"
设置拼写检查器
StartupFocus
=
true/false 开启时FOCUS到编辑器
StylesXmlPath
=
""
设置定义CSS样式列表的XML文件的位置
TabSpaces
=
4
TAB键产生的空格字符数
ToolBarCanCollapse
=
true/false 是否允许展开/折叠工具栏
ToolbarSets
=
object 允许使用TOOLBAR集合
ToolbarStartExpanded
=
true/false 开启是TOOLBAR是否展开
UseBROnCarriageReturn
=
true/false 当回车时是产生BR标记还是P或者DIV标记
六、自定义样式
工具栏的Style选项,是由fckconfig.js指定的配置文件来产生的:
FCKConfig.StylesXmlPath
=
FCKConfig.EditorPath
+
'fckstyles.xml' ;
可修改fckstyles.xml来自定义样式。
七、如何获取编辑器中插入的图片
从文章开头的功能设计我们可以看出,当用户编辑完文章后,我们应该能获取文章中插入的图片信息。怎样获取编辑器中的插入的图片呢?IT进行时
在他的文章FCKeditor的几点重要改进和使用心得,值得分享
中是这样做的:在上传图片的对话框的JavaScript中添加代码,使得当用户插入图片点OK后通知列表框,代码如下:
try
{
var
obj
=
window.dialogArguments.Editor.parent.document;
obj.getElementById(
"
tip.c_tip_has_pic
"
).value
=
"
1
"
;
}
catch
(e)
{
}
我认为这个方法不好,第一,这个方法是侵入性的,需要修改FCKeditor的代码;第二,这种方法能够在用户插入图片的时候获得图片信息,但是如果用户插入的图片,接着又把图片从文章中删除了呢?这时候是无法跟踪的。
正确的思路应该是在编辑器失去焦点的时候,获取编辑器中的文档,通过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的文档的反复阅读,发现FCKeditor自带的API没有办法实现这样的功能,所以,修改的重点还是在FCKeditor.java中。我们可以对源代码进行如下修改:
1、打开FCKeditor-2.3\src\com\fredck\FCKeditor\uploader目录下的SimpleUploaderServlet.java文件,找到SimpleUploaderServlet类的doPost方法,它的代码如下:
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
if
(debug) System.out.println(
"
--- BEGIN DOPOST ---
"
);
response.setContentType(
"
text/html; charset=UTF-8
"
);
response.setHeader(
"
Cache-Control
"
,
"
no-cache
"
);
PrintWriter out
=
response.getWriter();
String typeStr
=
request.getParameter(
"
Type
"
);
String currentPath
=
baseDir
+
typeStr;
String userName
=
request.getSession().getUser().getName();
currentPath
=
currentPath
+
userName
+
"
/
"
;
String currentDirPath
=
getServletContext().getRealPath(currentPath);
currentPath
=
request.getContextPath()
+
currentPath;
if
(debug) System.out.println(currentDirPath);
String retVal
=
"
0
"
;
String newName
=
""
;
String fileUrl
=
""
;
String errorMessage
=
""
;
if
(enabled) {
DiskFileUpload upload
=
new
DiskFileUpload();
try
{
List items
=
upload.parseRequest(request);
Map fields
=
new
HashMap();
Iterator iter
=
items.iterator();
while
(iter.hasNext()) {
FileItem item
=
(FileItem) iter.next();
if
(item.isFormField())
fields.put(item.getFieldName(),item.getString());
else
fields.put(item.getFieldName(),item);
}
FileItem uplFile
=
(FileItem)fields.get(
"
NewFile
"
);
String fileNameLong
=
uplFile.getName();
fileNameLong
=
fileNameLong.replace(
'
\
'
,
'
/
'
);
String[] pathParts
=
fileNameLong.split(
"
/
"
);
String fileName
=
pathParts[pathParts.length
-
1
];
String nameWithoutExt
=
getNameWithoutExtension(fileName);
String ext
=
getExtension(fileName);
File pathToSave
=
new
File(currentDirPath,fileName);
fileUrl
=
currentPath
+
"
/
"
+
fileName;
if
(extIsAllowed(typeStr,ext)) {
int
counter
=
1
;
while
(pathToSave.exists()){
newName
=
nameWithoutExt
+
"
(
"
+
counter
+
|