FCKEditor是开源的富文本编辑器,其免费、跨浏览器跨平台的特点使得其在项目中得到了广泛的应用。但是FCKEditor的附件(文件、图片、Flash等)是上传保存到Web服务器的,在只有一台Web服务器的情况下没有什么太大的问题,但是如果我们的系统有多个Web服务器实现NLB(网络负载均衡),那么用户将附件上传到其中一台Web服务器上保存,其他用户在访问另外一台Web服务器时将无法读取文件。对于这种多Web服务器实现NLB的情况,一般来说,我知道的有4种解决方案:
1,将附件保存到SQL Server服务器上,用户访问任何一台Web服务器都是通过连接到数据库,从数据库中读取数据并传输到用户客户端。
2,将附件保存到共享存储上,也就是说让每台Web服务器都有访问共享存储的权限,用户上传附件时直接上传到共享磁盘,其他Web服务器访问时也是直接读取共享磁盘上的附件。
3,建立一台专门的存储服务器,分配一个专门的域名(比如Files.xxx.com)负责对所有附件进行集中管理。这个方案比较好,在大型和集中的应用中可以使用,不过成本也比较高。
4,在多台Web服务器上开启文件同步的服务,用户上传了附件到一台服务器上,通过文件同步服务将所有新上传的附件同步其他所有Web服务器上,这样就会在每台服务器上保存一个附件的副本,及其浪费空间,而且文件的同步还存在延时和失败的情况。
一般来说,比较简单而且易于管理的是第一种方案,直接将附件存储到数据库中,所有Web服务器都访问数据库来读写文件,而且SQL Server 2008中提供了专门的FILESTREAM功能,用于对附件数据库进行优化和管理。
但是FCKEditor没有提供将文件上传到数据库中保存的配置方法,幸好他是开源的,所以我们可以修改其源代码实现将附件保存到数据库中,经过几天的努力我终于将FCKEditor的修改完成了,下面说一说具体的修改思想和方法,并给出修改后的FCKEditor。
1,首先我们要建立文件数据库用于保存上传的附件,数据库中有2个表,一个文件夹表和一个附件表,具体SQL脚本是:
--创建文件夹表
CREATE TABLE [dbo].[Folders](
[FolderID] [int] IDENTITY(1,1) NOT NULL,
[FolderPath] [nvarchar](500) NOT NULL,
CONSTRAINT [PK_Folders] PRIMARY KEY CLUSTERED
(
[FolderID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UQFolderPath] UNIQUE NONCLUSTERED
(
[FolderPath] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
--创建文件表
CREATE TABLE [dbo].[Files](
[FileID] [uniqueidentifier] NOT NULL,
[FileName] [nvarchar](250) NOT NULL,
[FolderID] [int] NOT NULL,
[Data] [varbinary](max) NOT NULL,
[Type] [nvarchar](250) NOT NULL,
[Size] [int] NOT NULL,
CONSTRAINT [PK_Attachment] PRIMARY KEY CLUSTERED
(
[FileID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Files] WITH CHECK ADD CONSTRAINT [FK_Files_Folders] FOREIGN KEY([FolderID])
REFERENCES [dbo].[Folders] ([FolderID])
ON DELETE CASCADE
2,用VS打开FCKEditor的C#源代码,将文件夹和文件的数据库基本操作方法写好,这里我使用LINQ to SQL来进行数据库操作,以提高开发效率。具体方法包括:
读附件、写附件、创建文件夹、读取文件夹下的所有子文件夹和读取文件夹下的所有文件,这里我都写在了DBLogic类中。
3,创建DBConnector.cs、DBFileWorkerBase.cs、DBTypeConfig.cs、DBUploader.cs,这些类我都是在原来类的名字前面加了DB前缀以示区别,实现了原来的类中类似的接口,只是在上传附件时不是保存到Web服务器而是保存到数据库中。
4,创建FileDown.cs,这个类是实现附件的下载的,继承自Page类,在Load时根据URL中的文件ID参数读取数据库,然后将二进制数据输出,具体方法是:
protected override void OnLoad(EventArgs e)
{
if (Request.QueryString["ID"] != null)
{
Response.Clear();
Encoding code = Encoding.GetEncoding("gb2312");
Response.ContentEncoding = code;
Response.HeaderEncoding = code;
var file = DBLogic.GetFile(new Guid(Request.QueryString["ID"].ToString()));
Response.AddHeader("Content-Type", file.Type);
Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + file.FileName + "\"");
Response.BinaryWrite(file.Data.ToArray());
Response.End();
}
}
5,修改fckeditor的aspx文件(fckeditor\editor\filemanager\connectors\aspx文件夹下),将继承的基类修改为FredCK.FCKeditorV2.FileBrowser.DBUploader和FredCK.FCKeditorV2.FileBrowser.DBConnector,这样在上传文件的时候才会去找到我们前面建的类,用我们类中的方法进行上传。
6,在fckeditor文件夹的根文件夹中创建File.aspx,不需要后台cs文件,aspx页面内容只有一句:
<%@ Page Language="c#" Trace="false" Inherits="FredCK.FCKeditorV2.FileBrowser.FileDown" AutoEventWireup="false" %>
这个文件非常重要,所有附件的下载就靠它了。
7,新建Web项目,在Web.Config文件中添加数据库连接字符串,指向我们前面建立数据库的地址:
<connectionStrings> <add name="FileDB" connectionString="server=127.0.0.1;database=Files;uid=sa;pwd=123"/> </connectionStrings>
然后在该Web项目中使用我们修改过的fckeditor文件夹和重新编译的程序集,这样我们的附件就可以保存到数据库中了。
第三步我这里只是一句话带过,实际其中的修改不是一句两句能说清的,总的原则就是要实现原来类的类似接口,让附件保存到数据库中。另外这个修改过程中还涉及到对一个html文件的修改,那就是fckeditor\editor\filemanager\browser\default\frmresourceslist.html,默认情况下用户在浏览服务器上的文件时浏览的文件的链接就是文件夹路径+文件名,但是修改后不能使用这个方式,所以要从服务器端获得文件下载的真实地址,修改该文件大概147行左右,如下:
// var oFileUrlAtt = oNodes[j].attributes.getNamedItem('url') ;
// var sFileUrl = oFileUrlAtt != null ? oFileUrlAtt.value : sCurrentFolderUrl + sFileName ;
var sFileUrl = oNode.attributes.getNamedItem('url').value;
这样修改后,再配合服务器端生成的url内容,就可以实现选中某附件后正常下载。
大家如果需要使用FCKEditor同时需要将附件保存到数据库中,那么可以使用我这个修改的组件,下面给出修改后的完整源代码:/Files/studyzy/FCKEditor.rar