以前公司购买过eWebEditor,功能应该还是不错的,但即便到了现在,也还仅是一个IE only的版本,无法满足现在差异化的需求。故前段时间下了最新的FCKeditor2.3.3版本下来(当然了,连带java的integration),demo来看看,发现有几个地方非常不爽: 1、上载的文件,只能放在URL可及的地方(如默认只能放到嵌入应用路径的/UserFiles/下); 2、没有明确的上载视频的按钮; 3、图片、FLASH、附件上载等,步骤多,复杂度高(想想,用户不都是高手)。 怎么办呢,改! 一、第一个就是增加一个FileLocatorServlet,思路很简单:通过这个服务来定位文件,而不是之间产生链接,既是安全的考虑,也是应用集群的一个重要考虑点。而且原来的几个servlet的配置罗嗦且重叠,难以让人产生美感。所谓代码胜千言,通过下面的web.xml大家应该可以看出修理的要点:
1
<?
xml version="1.0" encoding="ISO-8859-1"
?>
2
3
<!
DOCTYPE web-app
4
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
5
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"
>
6
7
<
web-app
>
8
<
display-name
>
FCKeditor Test Application
</
display-name
>
9
<
context-param
>
10
<!--
setting the FCKecitor context based parameters
-->
11
<!--
baseDir means the root of the uploaded file/image/flash stored
12
the prefix of 'file:/' means strore in a file system root that cannot get from webapp url
13
-->
14
<
param-name
>
baseDir
</
param-name
>
15
<
param-value
>
file:/C:/Temp/FCKeditorUpload/
</
param-value
>
16
</
context-param
>
17
18
<
context-param
>
19
<!--
20
if the baseDir prefix by 'file:/',please set it.
21
-->
22
<
param-name
>
fileLocator
</
param-name
>
23
<
param-value
>
/editor/filemanager/browser/default/service/jsp/filelocator
</
param-value
>
24
</
context-param
>
25
26
<
context-param
>
27
<!--
28
debug setting,true means verbose output to the console.
29
-->
30
<
param-name
>
debug
</
param-name
>
31
<
param-value
>
true
</
param-value
>
32
</
context-param
>
33
34
<
context-param
>
35
<!--
36
enabled setting,true means upload enabled.
37
-->
38
<
param-name
>
enabled
</
param-name
>
39
<
param-value
>
true
</
param-value
>
40
</
context-param
>
41
42
<
context-param
>
43
<!--
44
encoding,the response encoding of the file/image/flash,default is UTF-8
45
-->
46
<
param-name
>
encoding
</
param-name
>
47
<
param-value
>
UTF-8
</
param-value
>
48
</
context-param
>
49
50
<
context-param
>
51
<!--
52
contentTypeMapping,a map for the response ContentType
53
-->
54
<
param-name
>
contentTypeMapping
</
param-name
>
55
<
param-value
>
doc=application/vnd.ms-word
56
|xls=application/vnd.ms-excel
57
|jpg=image/jpeg
58
|gif=image/gif
59
|swf=application/x-shockwave-flash
60
|avi=video/x-msvideo
61
</
param-value
>
62
</
context-param
>
63
64
<
context-param
>
65
<!--
66
allowedExtensionsFile,the logic is 'Not allowed means deny.'
67
-->
68
<
param-name
>
allowedExtensionsFile
</
param-name
>
69
<
param-value
>
doc|xls|pdf|avi
</
param-value
>
70
</
context-param
>
71
72
<
context-param
>
73
<!--
74
allowedExtensionsImage,the logic is 'Not allowed means deny.'
75
-->
76
<
param-name
>
allowedExtensionsImage
</
param-name
>
77
<
param-value
>
jpg|gif|png
</
param-value
>
78
</
context-param
>
79
80
<
context-param
>
81
<!--
82
allowedExtensionsFlash,the logic is 'Not allowed means deny.'
83
-->
84
<
param-name
>
allowedExtensionsFlash
</
param-name
>
85
<
param-value
>
swf|fla
</
param-value
>
86
</
context-param
>
87
88
<
servlet
>
89
<
servlet-name
>
Connector
</
servlet-name
>
90
<
servlet-class
>
com.fredck.FCKeditor.connector.ConnectorServlet
</
servlet-class
>
91
<
load-on-startup
>
1
</
load-on-startup
>
92
</
servlet
>
93
94
<
servlet
>
95
<
servlet-name
>
FileLocator
</
servlet-name
>
96
<
servlet-class
>
com.fredck.FCKeditor.service.FileLocatorServlet
</
servlet-class
>
97
<
load-on-startup
>
1
</
load-on-startup
>
98
</
servlet
>
99
100
<
servlet
>
101
<
servlet-name
>
SimpleUploader
</
servlet-name
>
102
<
servlet-class
>
com.fredck.FCKeditor.uploader.SimpleUploaderServlet
</
servlet-class
>
103
<
load-on-startup
>
1
</
load-on-startup
>
104
</
servlet
>
105
106
<
servlet-mapping
>
107
<
servlet-name
>
Connector
</
servlet-name
>
108
<
url-pattern
>
/editor/filemanager/browser/default/connectors/jsp/connector
</
url-pattern
>
109
</
servlet-mapping
>
110
111
<
servlet-mapping
>
112
<
servlet-name
>
SimpleUploader
</
servlet-name
>
113
<
url-pattern
>
/editor/filemanager/upload/simpleuploader
</
url-pattern
>
114
</
servlet-mapping
>
115
116
<
servlet-mapping
>
117
<
servlet-name
>
FileLocator
</
servlet-name
>
118
<
url-pattern
>
/editor/filemanager/browser/default/service/jsp/filelocator
</
url-pattern
>
119
</
servlet-mapping
>
120
121
</
web-app
>
连带FCKeditorConfigurations.java一并修理,配置统一且singleton。关键代码为:
1
2
/** */
/** 3 * Make the configuration sigleton 4 * @param sc 5 * @return the static configuration map 6 */
7
public
static
Map getContextConfigurationsInstance(ServletContext sc)
{ 8 if (contextConfigurations == null ) { 9 initContextConfigurations(sc);10 } 11 return contextConfigurations; 12 }
13
14
/** */
/** 15 * Init all the FCKeditor configuration.16 * add by zhengxq17 * @param sc 18 */
19
private
static
void
initContextConfigurations(ServletContext sc)
{ 20 if (debug) 21 System.out.println( " /r/n---- FCKeditorConfigurations for java initialization started ---- " ); 22 23 String baseDir = sc.getInitParameter( " baseDir " ); 24 String fileLocator = sc.getInitParameter( " fileLocator " ); 25 String debugStr = sc.getInitParameter( " debug " ); 26 String enabledStr = sc.getInitParameter( " enabled " ); 27 String encoding = sc.getInitParameter( " encoding " ); 28 String contentTypeMapping = sc.getInitParameter( " contentTypeMapping " ); 29 String AllowedExtensionsFile = sc.getInitParameter( " allowedExtensionsFile " ); 30 String AllowedExtensionsImage = sc.getInitParameter( " allowedExtensionsImage " ); 31 String AllowedExtensionsFlash = sc.getInitParameter( " allowedExtensionsFlash " ); 32 33 debug = ( new Boolean(debugStr)).booleanValue(); 34 encoding = (encoding == null || encoding.length() == 0 ) ? " UTF-8 " :encoding; 35 36 if (baseDir == null || baseDir.length() == 0 ) baseDir = defaultBaseDir; 37 String realBaseDir = defaultBaseDir; 38 if (baseDir.startsWith(fileSystemUriPrefix)) { 39 realBaseDir = baseDir.substring(fileSystemUriPrefix.length()); 40 } else { 41 realBaseDir = sc.getRealPath(baseDir); 42 fileLocator = null ; // no use and should set null 43 } 44 File baseFile = new File(realBaseDir); 45 if ( ! baseFile.exists()) { 46 baseFile.mkdir();47 } 48 contextConfigurations = new HashMap(); 49 contextConfigurations.put( " baseDir " ,baseDir); 50 contextConfigurations.put( " realBaseDir " ,realBaseDir); 51 contextConfigurations.put( " fileLocator " ,fileLocator); 52 contextConfigurations.put( " debug " ,debugStr); 53 contextConfigurations.put( " enabled " ,enabledStr); 54 contextConfigurations.put( " encoding " ,encoding); 55 contextConfigurations.put( " contentTypeMapping " ,contentTypeMappingToMap(contentTypeMapping)); 56 contextConfigurations.put( " allowedExtensionsFile " ,stringToArrayList(AllowedExtensionsFile)); 57 contextConfigurations.put( " allowedExtensionsImage " ,stringToArrayList(AllowedExtensionsImage)); 58 contextConfigurations.put( " allowedExtensionsFlash " ,stringToArrayList(AllowedExtensionsFlash)); 59 60 if (debug) 61 System.out.println( " /r/n---- FCKeditorConfigurations for java initialization end ---- " ); 62 63 }
FileLocatorServlet.java也很简单,无非就是文件的物理定位和文件流的输出:
1
String type
=
request.getParameter(
"
Type
"
);
2
String fileName
=
request.getParameter(
"
FileName
"
);
3
4
String realFilePath
=
config.get(
"
realBaseDir
"
)
+
type
+
"
/
"
+
fileName;
5
File file
=
new
File(realFilePath);
6
if
(file.exists())
{ 7 response.setHeader( " Content-Transfer-Encoding " , " base64 " ); 8 response.setHeader( " Cache-Control " , " no-store " ); 9 response.setHeader( " Pragma " , " no-cache " ); 10 response.setDateHeader( " Expires " , 0 ); 11 response.setContentType(getContentTypeByFileExt(fileName.substring(fileName.lastIndexOf( " . " )))); 12 13 ServletOutputStream out = response.getOutputStream(); 14 InputStream in = new FileInputStream(file); 15 BufferedInputStream bis = new BufferedInputStream(in); 16 BufferedOutputStream bos = new BufferedOutputStream(out); 17 byte [] buff = new byte [ 2048 ]; 18 int bytesRead; 19 while ( - 1 != (bytesRead = bis.read(buff, 0 , buff.length))) { 20 bos.write(buff, 0 , bytesRead); 21 } 22 if (bis != null ) { 23 bis.close();24 } 25 if (bos != null ) { 26 bos.close();27 } 28 }
else
{ 29 throw new FileNotFoundException(fileName); 30 }
上述改动已经提交给了FCKeditor,如果大家真的有兴趣,可以去找里面我所提交的patch。 二、至于上述的2、3问题,同样,动手即可解决,在此略过。 过程中倒是碰到几个有意思的问题,成了花絮,其实也是使用FCKeditor的一些心得,写写可能还有点意思: 1、如何取得FCKeditor的值? 答案:这是我们常常干的事情:取得这个值并赋值给某个hidden,再合法性检查+submit等。怎么取得呢?这样:
1
var
oEditor
=
FCKeditorAPI.GetInstance('editor') ;
2
//
Get the editor contents in XHTML.
3
//
alert( oEditor.GetXHTML(true) ) ; // "true" means you want it formatted.
4
document.all(
"
tip.c_content
"
).value
=
oEditor.GetXHTML(
true
);
2、如何使得FCKeditor接收tab键? 答案:我们希望界面元素按照外面的安排进行tab切换,但FCKeditor怎么能做到呢?也有办法:
1
function
focusIframeOnTab(caller, tabTargetId, callEvent)
{ 2 // If keypress TAB and not SHIFT+TAB 3 if (callEvent.keyCode == 9 && ! callEvent.shiftKey) 4 document.getElementById(tabTargetId).contentWindow.focus();5 }
光光有个函数顶个什么用,还要这样:在之前的那个界面元素中加上下面的事件,如使用struts的tag的化,这样就可以了:
<
html:text
property
="tip.c_title"
style
="width:450px"
tabindex
="1"
onkeydown
="focusIframeOnTab(this, 'editor___Frame',event);if(!document.all) return false;"
/>
这点是google了半天最终在FCKeditor的FAQ中找到的,看来以后用开源的软件第一件事情就是看FAQ,错不了! 3、如何希望在FCKeditor加载完毕后做点什么事情? 答案:也很简单,编写自己的FCKeditor_OnComplete函数,如:
function
FCKeditor_OnComplete( editorInstance )
{ window.status = editorInstance.Description ; }
4、如果在图片、FLASH等界面中上载了东西后,希望能告诉自己的表单,怎么做? 答案:这个花了我不少看代码和调试时间!其实这里的关键就是如何获取嵌入FCKeditor的那个window,这样就可以了,在对应的js文件(如editor/dialog/fck_image/fck_image.js)中的ok方法的最后加入:
//
edit by zhengxq
try
{ var obj = window.dialogArguments.Editor.parent.document; obj.getElementById( " tip.c_tip_has_pic " ).value = " 1 " ; }
catch
(e)
{}
关键就是:window.dialogArguments.Editor.parent.document,这个能够找到对应窗口的引用,有了这个,还不会控制吗?!
摘录来源:http://www.blogjava.net/itstarting/archive/2007/03/11/103142.html