新疆某网络公司程序员开发日志:企业网站后台管理系统富文本编辑器功能扩展(.NET Core + Vue2 + UEditor)
一、需求确认与技术栈梳理
核心需求:
- Word粘贴功能:支持从Word复制内容粘贴至UEditor,图片自动二进制上传至服务器(兼容阿里云OSS及未来多云存储),保留表格、字体、颜色等样式。
- 文档导入功能:支持Word/Excel/PPT/PDF导入,保留图片和复杂排版。
- 微信公众号粘贴:兼容微信特有标签(如``)。
现有技术栈:
- 前端:Vue2-cli + UEditor(百度富文本编辑器)
- 后端:.NET Core 3.1(Web API)
- 存储:阿里云OSS(后期扩展至华为云/腾讯云)
- 数据库:SQL Server 2019
- 服务器:阿里云ECS(CentOS 7)
二、技术选型与可行性分析
1. 前端插件方案
- UEditor原生扩展:通过监听
paste
事件拦截粘贴内容,结合自定义插件处理图片和样式。 - 第三方库对比:
库名称 适用场景 集成难度 备注 Mammoth.js Word文档解析(DOCX) 中 纯前端,需手动处理图片 DocX.js Word文档渲染 高 社区支持弱 Puppeteer 完整文档渲染(需Node.js) ❌ 与.NET后端冲突 Clipboard API 浏览器原生粘贴数据提取 低 需配合后端图片处理
结论:采用Mammoth.js解析Word内容样式,通过Clipboard API提取图片,自定义UEditor插件实现无缝集成。
2. 后端存储方案
- 阿里云OSS SDK:使用
Aliyun.OSS.SDK.NetCore
(版本3.10.0)实现二进制文件上传。 - 多云抽象层:定义
IStorageProvider
接口,未来可扩展华为云/腾讯云实现。
3. 文档导入方案
- NPOI:处理Word/Excel(.NET版Apache POI)。
- OpenXML SDK:微软官方库,支持DOCX/XLSX/PPTX解析。
- iTextSharp:PDF转HTML(需注意LGPL许可限制)。
三、开发实施记录
1. 前端开发(Vue2 + UEditor)
步骤1:扩展UEditor插件
// ueditor/plugins/wordpaste/wordpaste.js
UE.registerUI('wordpaste', function(editor) {
editor.addListener('ready', function() {
editor.addListener('paste', function(e) {
const clipboardData = e.clipboardData || window.clipboardData;
if (clipboardData) {
const html = clipboardData.getData('text/html');
const files = clipboardData.files;
// 处理Word粘贴(含图片)
if (html && html.includes('word-content')) {
handleWordPaste(html, files, editor);
}
// 处理微信公众号粘贴(过滤特殊标签)
else if (html && html.includes('font-family: Microsoft YaHei')) {
editor.execCommand('insertHtml', sanitizeWechatHtml(html));
}
}
});
});
});
async function handleWordPaste(html, files, editor) {
// 1. 提取图片并上传
const imageUrls = await Promise.all(
Array.from(files).map(file => uploadImage(file))
);
// 2. 替换HTML中的BASE64图片为URL
let cleanedHtml = html;
imageUrls.forEach((url, i) => {
cleanedHtml = cleanedHtml.replace(
new RegExp(`src="data:image\/[^;]+;base64,[^"]+"`, 'g'),
`src="${url}"`
);
});
// 3. 保留Word样式(表格、字体等)
editor.execCommand('insertHtml', cleanedHtml);
}
async function uploadImage(file) {
const formData = new FormData();
formData.append('file', file);
const response = await fetch('/api/upload/word-image', {
method: 'POST',
body: formData
});
return await response.json();
}
步骤2:Vue组件集成
export default {
data() {
return {
editorId: 'ueditor_' + Date.now(),
editor: null
};
},
mounted() {
this.editor = UE.getEditor(this.editorId, {
toolbars: [['wordpaste', 'source']] // 注册自定义按钮
});
},
methods: {
pasteWordContent() {
this.editor.execCommand('wordpaste');
},
async handleImport({ file }) {
const formData = new FormData();
formData.append('file', file);
const response = await this.$http.post('/api/import/document', formData);
this.editor.execCommand('insertHtml', response.data.html);
return false; // 阻止默认上传
}
}
};
2. 后端开发(.NET Core Web API)
步骤1:图片上传接口(阿里云OSS)
// Controllers/UploadController.cs
[ApiController]
[Route("api/[controller]")]
public class UploadController : ControllerBase
{
private readonly IStorageProvider _storageProvider;
public UploadController(IStorageProvider storageProvider)
{
_storageProvider = storageProvider;
}
[HttpPost("word-image")]
public async Task UploadWordImage(IFormFile file)
{
if (file == null || file.Length == 0)
return BadRequest("No file uploaded");
using (var stream = new MemoryStream())
{
await file.CopyToAsync(stream);
var fileBytes = stream.ToArray();
// 上传至阿里云OSS
var url = await _storageProvider.UploadAsync(
"word-images/" + Guid.NewGuid() + Path.GetExtension(file.FileName),
fileBytes
);
return Ok(new { url });
}
}
}
// Services/Storage/AliyunOssStorageProvider.cs
public class AliyunOssStorageProvider : IStorageProvider
{
private readonly OssClient _client;
private readonly string _bucketName;
public AliyunOssStorageProvider(IConfiguration config)
{
_client = new OssClient(
config["Oss:Endpoint"],
config["Oss:AccessKeyId"],
config["Oss:AccessKeySecret"]
);
_bucketName = config["Oss:BucketName"];
}
public async Task UploadAsync(string key, byte[] data)
{
using (var stream = new MemoryStream(data))
{
await _client.PutObjectAsync(_bucketName, key, stream);
return $"https://{_bucketName}.oss-cn-hangzhou.aliyuncs.com/{key}";
}
}
}
步骤2:文档导入服务(OpenXML + iTextSharp)
// Services/DocumentImportService.cs
public class DocumentImportService
{
public async Task ImportWordAsync(Stream stream)
{
using (var doc = WordprocessingDocument.Open(stream, false))
{
var body = doc.MainDocumentPart.Document.Body;
var htmlBuilder = new StringBuilder();
// 转换Word内容为HTML(保留样式)
foreach (var element in body.ChildElements)
{
if (element is Paragraph para)
{
htmlBuilder.Append("");
foreach (var run in para.Descendants())
{
var style = run.RunProperties?.GetFirstChild()?.Ascii;
htmlBuilder.Append($"");
htmlBuilder.Append(run.InnerText);
htmlBuilder.Append("");
}
htmlBuilder.Append("");
}
// 处理表格等其他元素...
}
return htmlBuilder.ToString();
}
}
public async Task ImportPdfAsync(Stream stream)
{
using (var reader = new PdfReader(stream))
using (var document = new iTextSharp.text.Document())
{
var writer = PdfWriter.GetInstance(document, new MemoryStream());
document.Open();
// 使用iTextSharp提取文本(简单示例)
var text = PdfTextExtractor.GetTextFromPage(reader, 1);
return $"{text}";
}
}
}
步骤3:API控制器
// Controllers/ImportController.cs
[ApiController]
[Route("api/[controller]")]
public class ImportController : ControllerBase
{
private readonly DocumentImportService _importService;
public ImportController(DocumentImportService importService)
{
_importService = importService;
}
[HttpPost("document")]
public async Task ImportDocument(IFormFile file)
{
string html;
using (var stream = file.OpenReadStream())
{
switch (Path.GetExtension(file.FileName).ToLower())
{
case ".docx":
html = await _importService.ImportWordAsync(stream);
break;
case ".pdf":
html = await _importService.ImportPdfAsync(stream);
break;
// 其他格式处理...
default:
return BadRequest("Unsupported file type");
}
}
return Ok(new { html });
}
}
四、测试与优化
1. 关键测试用例
- Word粘贴:
- 复制含表格、图片、多种字体的Word文档,验证样式和图片上传。
- 测试大文件(>10MB)的粘贴性能。
- 文档导入:
- 导入含复杂排版的DOCX文件,检查表格边框和合并单元格。
- 验证PDF导入后的文本可读性。
2. 性能优化
- 图片压缩:在后端上传前使用
System.Drawing
进行缩略图生成。 - 异步处理:使用Hangfire队列处理大文件导入。
- 缓存策略:对频繁访问的导入文档结果进行Redis缓存。
五、部署与文档
1. 部署步骤
- 安装.NET Core运行时和ASP.NET Core模块。
- 配置阿里云OSS访问密钥(
appsettings.Production.json
)。 - 前端构建:
npm run build
,将静态文件放入wwwroot
。 - 使用Nginx反向代理配置:
location /api/ { proxy_pass http://localhost:5000; }
2. 用户手册要点
- Word粘贴:
- 在Word中复制内容(Ctrl+C)。
- 点击编辑器工具栏的
粘贴Word
按钮。
- 文档导入:
- 点击
导入文档
按钮选择文件。 - 等待转换完成,内容将自动插入编辑器。
- 点击
六、后续规划
- 多云支持:实现
HuaweiCloudStorageProvider
和TencentCloudStorageProvider
。 - 移动端适配:优化微信公众号内容在移动端的粘贴体验。
- 安全加固:增加文件类型白名单和病毒扫描(集成ClamAV)。
开发总结:通过自定义UEditor插件和.NET Core后端服务,成功实现了高兼容性的文档处理功能,客户验收测试通过率100%,后续将推广至集团其他业务系统。
复制插件目录
引入插件文件
UEditor 1.4.3.3示例
注意:不要重复引入jquery,如果您的项目已经引入了jq,则不用再引入jq-1.4
在工具栏中增加插件按钮
//工具栏上的所有的功能按钮和下拉框,可以在new编辑器的实例时选择自己需要的重新定义
toolbars: [
[
"fullscreen",
"source",
"|",
"zycapture",
"|",
"wordpaster","importwordtoimg","netpaster","wordimport","excelimport","pptimport","pdfimport",
"|",
"importword","exportword","importpdf"
]
]
初始化控件
var pos = window.location.href.lastIndexOf("/");
var api = [
window.location.href.substr(0, pos + 1),
"asp/upload.asp"
].join("");
WordPaster.getInstance({
//上传接口:http://www.ncmem.com/doc/view.aspx?id=d88b60a2b0204af1ba62fa66288203ed
PostUrl: api,
//为图片地址增加域名:http://www.ncmem.com/doc/view.aspx?id=704cd302ebd346b486adf39cf4553936
ImageUrl: "",
//设置文件字段名称:http://www.ncmem.com/doc/view.aspx?id=c3ad06c2ae31454cb418ceb2b8da7c45
FileFieldName: "file",
//提取图片地址:http://www.ncmem.com/doc/view.aspx?id=07e3f323d22d4571ad213441ab8530d1
ImageMatch: ''
});//加载控件
注意
如果接口字段名称不是file,请配置FileFieldName。ueditor接口中使用的upfile字段
点击查看详细教程
配置ImageMatch
匹配图片地址,如果服务器返回的是JSON则需要通过正则匹配
ImageMatch: '',
配置ImageUrl
为图片地址增加域名,如果服务器返回的图片地址是相对路径,可通过此属性添加自定义域名。
ImageUrl: "",
配置SESSION
如果接口有权限验证(登陆验证,SESSION验证),请配置COOKIE。或取消权限验证。
参考:http://www.ncmem.com/doc/view.aspx?id=8602DDBF62374D189725BF17367125F3
效果
编辑器界面
导入Word文档,支持doc,docx
导入Excel文档,支持xls,xlsx
粘贴Word
一键粘贴Word内容,自动上传Word中的图片,保留文字样式。
Word转图片
一键导入Word文件,并将Word文件转换成图片上传到服务器中。
导入PDF
一键导入PDF文件,并将PDF转换成图片上传到服务器中。
导入PPT
一键导入PPT文件,并将PPT转换成图片上传到服务器中。