作为广西某集团公司的项目负责人,近期需对现有企业网站后台管理系统中的文章发布模块进行功能升级。主要目标是提升内容编辑效率,支持多种格式文档的快速导入与粘贴,并确保在复杂环境下稳定运行。
[前端]
Vue2 CLI → TinyMCE编辑器 → 自定义插件(Word/公众号处理)
↓
[后端API]
SpringBoot → 文件处理服务 → 华为云OBS存储
↑
[数据库]
MySQL(存储元数据)
通过对当前市场上主流富文本处理方案进行调研,初步确定以下几类候选方案:
| 功能特性 | TinyMCE PowerPaste | KindEditor商业版 | WangEditor企业版 | UEditor | 自定义开发 | WordPaster源码版 |
|---|---|---|---|---|---|---|
| Word粘贴 | ||||||
| 文件导入 | 仅Word | Word, Excel, PPT, PDF | ||||
| 公众号粘贴 | ||||||
| 公式支持 | LaTeX, MathType | |||||
| 信创兼容 | 部分 | |||||
| IE8兼容 | ||||||
| 买断授权 | 不适用 | |||||
| 预算内 |
综合评估后,决定采用WordPaster源码版作为核心技术基础,原因如下:
整体系统采用前后端分离架构,前端通过Vue2集成TinyMCE编辑器,后端基于SpringBoot提供RESTful接口,图片资源统一上传至华为云OBS存储。安全传输通过HTTPS保障,跨域请求由Nginx代理配置完成。
[前端]
Vue2 CLI → TinyMCE编辑器 → 自定义插件(Word/公众号处理)
↓
[后端API]
SpringBoot → 文件处理服务 → 华为云OBS存储
↑
[数据库]
MySQL(存储元数据)
在 main.js 中完成TinyMCE初始化配置:
import tinymce from 'tinymce/tinymce'
import 'tinymce/themes/silver'
import 'tinymce/plugins/powerpaste'
import 'tinymce/plugins/wechatpaste' // 自定义公众号粘贴插件
Vue.prototype.$tinymce = tinymce
const initTinyMCE = {
language: 'zh_CN',
plugins: 'powerpaste wechatpaste image table code',
toolbar: 'paste wechatpaste | image table',
powerpaste_word_import: 'clean',
powerpaste_html_import: 'clean',
powerpaste_allow_local_images: true,
paste_data_images: true,
images_upload_handler: function (blobInfo, success, failure) {
// 调用后端图片上传接口
uploadImage(blobInfo.blob()).then(url => {
success(url)
}).catch(err => {
failure('上传失败: ' + err)
})
}
}
图片上传接口由UploadController处理:
@RestController
@RequestMapping("/api/upload")
public class UploadController {
@Autowired
private HuaweiObsService obsService;
@PostMapping("/image")
public ResponseEntity<String> uploadImage(@RequestParam("file") MultipartFile file) {
try {
String url = obsService.upload(file);
return ResponseEntity.ok(url);
} catch (Exception e) {
return ResponseEntity.status(500).body("上传失败:" + e.getMessage());
}
}
}
该接口接收前端传递的图片二进制流,调用华为云OBS服务完成存储,并返回访问URL,供编辑器插入到内容中。
public ResponseEntity uploadImage(@RequestParam("file") MultipartFile file) {
try {
// 生成唯一文件名
String filename = UUID.randomUUID() + getFileExtension(file.getOriginalFilename());
// 上传至华为云OBS存储
String url = obsService.uploadFile("images/" + filename, file.getInputStream());
// 返回JSON格式的响应结果
return ResponseEntity.ok(Collections.singletonMap("url", url));
} catch (Exception e) {
return ResponseEntity.status(500).body("上传失败: " + e.getMessage());
}
}
private String getFileExtension(String filename) {
return filename.substring(filename.lastIndexOf("."));
}
实现类 HuaweiObsServiceImpl 提供了对华为云对象存储(OBS)的基础操作封装,支持文件上传功能。
@Service
public class HuaweiObsServiceImpl implements HuaweiObsService {
@Value("${huawei.obs.endpoint}")
private String endpoint;
@Value("${huawei.obs.bucket}")
private String bucketName;
private ObsClient obsClient;
@PostConstruct
public void init() {
// 使用永久AK/SK初始化客户端
obsClient = new ObsClient(
"your-access-key",
"your-secret-key",
endpoint
);
}
@Override
public String uploadFile(String objectKey, InputStream inputStream) throws Exception {
PutObjectRequest request = new PutObjectRequest(bucketName, objectKey, inputStream);
obsClient.putObject(request);
return String.format("https://%s.%s/%s", bucketName, endpoint, objectKey);
}
@PreDestroy
public void destroy() {
if (obsClient != null) {
try {
obsClient.close();
} catch (Exception e) {
// 记录关闭异常日志
}
}
}
}
针对信息技术应用创新环境下的系统适配需求,从字体、浏览器及硬件架构三个层面进行兼容性优化。
在全局样式中设置符合中文GB2312标准的字体回退机制,确保在缺失默认字体时仍能正常显示文本内容:
/* 全局CSS设置GB2312字体回退 */
body {
font-family: "SimSun", "STSong", "NSimSun", "FangSong", "KaiTi", sans-serif;
}
为保障老旧浏览器(如IE8)的功能可用性,在项目入口文件中引入必要的JavaScript兼容层:
// 在入口文件添加IE8兼容代码
if (window.attachEvent && !window.addEventListener) {
import('es5-shim').then(() => {
import('console-polyfill');
import('eventlistener-polyfill');
});
}
采用多阶段Docker构建策略,针对不同国产处理器平台(如龙芯、飞腾、兆芯等)实现镜像的交叉编译与打包部署。
# 多架构Dockerfile示例
FROM --platform=$TARGETPLATFORM openjdk:8-jdk-alpine
COPY target/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
覆盖主流及国产浏览器,验证前端功能一致性:
在以下国产化操作系统版本中完成部署与运行测试:
应对措施:提前联系设备厂商协调测试资源,获取真实信创终端用于验证。
备选方案:对于存在严重兼容问题的场景,提供简化版用户界面以保证基础功能可访问。
应对措施:通过代码分割和按需加载(懒加载)降低初始加载压力。
监控手段:上线后持续跟踪页面运行时的CPU与内存占用情况,及时发现潜在卡顿。
优化上传流程容错机制,增加重试逻辑与断点续传支持,提升大文件在弱网络环境下的成功率。
| 需求项 | 实现状态 | 备注 |
|---|---|---|
| Word粘贴 | ?? | 支持至Office 2019格式 |
| 文件导入 | ?? | 兼容Word、Excel、PPT、PDF等多种文档类型 |
| 公众号内容粘贴 | ?? | 适配主流公众号排版样式 |
| 样式保留 | ?? | 包括表格、公式、字体等元素的完整还原 |
| 信创兼容 | ?? | 已在麒麟、UOS等国产系统中通过测试 |
| IE8兼容 | ?? | 经性能优化后满足运行标准 |
本项目在既定预算内如期交付,所有关键指标均达到或超越预期目标。尤其在信创生态兼容性方面表现突出,为后续参与政府类项目投标奠定了坚实的技术基础。采用买断式授权模式,集团未来相关项目无需重复采购,预计可节约授权费用约200万元。
为保障大文件传输的稳定性和用户体验,系统实现了断点续传与分片上传机制,有效应对网络波动和中断问题。
上传失败时自动触发最多3次重试尝试,并在多次失败后提示人工介入处理,确保数据完整性与操作可恢复性。
npm install jquery
// 引入tinymce-vue
import Editor from '@tinymce/tinymce-vue'
import {WordPaster} from '../../static/WordPaster/js/w'
import {zyOffice} from '../../static/zyOffice/js/o'
import {zyCapture} from '../../static/zyCapture/z'
添加“导入Excel”按钮功能:
(function () {
'use strict';
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
function selectLocalImages(editor) {
WordPaster.getInstance().SetEditor(editor).importExcel()
}
var register$1 = function (editor) {
editor.ui.registry.addButton('excelimport', {
text: '',
tooltip: '导入Excel文档',
onAction: function () {
selectLocalImages(editor)
}
});
editor.ui.registry.addMenuItem('excelimport', {
text: '',
tooltip: '导入Excel文档',
onAction: function () {
selectLocalImages(editor)
}
});
};
var Buttons = { register: register$1 };
function Plugin () {
global.add('excelimport', function (editor) {
Buttons.register(editor);
});
}
Plugin();
}());
添加“Word转图片”按钮功能:
(function () {
'use strict';
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
function selectLocalImages(editor) {
WordPaster.getInstance().SetEditor(editor);
WordPaster.getInstance().importWordToImg()
}
var register$1 = function (editor) {
editor.ui.registry.addButton('importwordtoimg', {
text: '',
tooltip: 'Word转图片',
onAction: function () {
selectLocalImages(editor)
}
});
editor.ui.registry.addMenuItem('importwordtoimg', {
text: '',
tooltip: 'Word转图片',
onAction: function () {
selectLocalImages(editor)
}
});
};
var Buttons = { register: register$1 };
function Plugin () {
global.add('importwordtoimg', function (editor) {
Buttons.register(editor);
});
}
Plugin();
}());
(function () {
'use strict';
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
function selectLocalImages(editor) {
WordPaster.getInstance().SetEditor(editor);
WordPaster.getInstance().UploadNetImg();
}
var register$1 = function (editor) {
editor.ui.registry.addButton('netpaster', {
text: '',
tooltip: '网络图片一键上传',
onAction: function () {
selectLocalImages(editor);
}
});
editor.ui.registry.addMenuItem('netpaster', {
text: '',
tooltip: '网络图片一键上传',
onAction: function () {
selectLocalImages(editor);
}
});
};
var Buttons = { register: register$1 };
function Plugin() {
global.add('netpaster', function (editor) {
Buttons.register(editor);
});
}
Plugin();
}());
// 添加导入PDF功能模块
(function () {
'use strict';
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
function selectLocalImages(editor) {
WordPaster.getInstance().SetEditor(editor);
WordPaster.getInstance().ImportPDF();
}
var register$1 = function (editor) {
editor.ui.registry.addButton('pdfimport', {
text: '',
tooltip: '导入pdf文档',
onAction: function () {
selectLocalImages(editor);
}
});
editor.ui.registry.addMenuItem('pdfimport', {
text: '',
tooltip: '导入pdf文档',
onAction: function () {
selectLocalImages(editor);
}
});
};
var Buttons = { register: register$1 };
function Plugin() {
global.add('pdfimport', function (editor) {
Buttons.register(editor);
});
}
Plugin();
}());
// 插入PPT文档导入功能
(function () {
'use strict';
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
function selectLocalImages(editor) {
WordPaster.getInstance().SetEditor(editor);
WordPaster.getInstance().importPPT();
}
var register$1 = function (editor) {
editor.ui.registry.addButton('pptimport', {
text: '',
tooltip: '导入PowerPoint文档',
onAction: function () {
selectLocalImages(editor);
}
});
editor.ui.registry.addMenuItem('pptimport', {
text: '',
tooltip: '导入PowerPoint文档',
onAction: function () {
selectLocalImages(editor);
}
});
};
var Buttons = { register: register$1 };
function Plugin() {
global.add('pptimport', function (editor) {
Buttons.register(editor);
});
}
Plugin();
}());
// 添加导入Word文档功能按钮
(function () {
'use strict';
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
function selectLocalImages(editor) {
WordPaster.getInstance().SetEditor(editor).importWord();
}
var register$1 = function (editor) {
editor.ui.registry.addButton('wordimport', {
text: '',
tooltip: '导入Word文档',
onAction: function () {
selectLocalImages(editor);
}
});
editor.ui.registry.addMenuItem('wordimport', {
text: '',
tooltip: '导入Word文档',
onAction: function () {
selectLocalImages(editor);
}
});
};
var Buttons = { register: register$1 };
function Plugin() {
global.add('wordimport', function (editor) {
Buttons.register(editor);
});
}
Plugin();
}());
// 注入Word一键粘贴功能按钮
(function () {
'use strict';
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
var ico = "http://localhost:8080/static/WordPaster/plugin/word.png";
function pasteFromWord(editor) {
WordPaster.getInstance().SetEditor(editor).PasteManual();
}
var register$1 = function (editor) {
editor.ui.registry.addButton('wordpaster', {
text: '',
tooltip: 'Word一键粘贴',
onAction: function () {
pasteFromWord(editor);
}
});
editor.ui.registry.addMenuItem('wordpaster', {
text: '',
tooltip: 'Word一键粘贴',
onAction: function () {
pasteFromWord(editor);
}
});
};
var Buttons = { register: register$1 };
function Plugin() {
global.add('wordpaster', function (editor) {
Buttons.register(editor);
});
}
Plugin();
}());
在线代码示例:
配置插件列表
plugins: {
type: [String, Array],
// 默认值包含多项功能,如:advlist anchor autolink autosave code 等
default: 'autoresize code autolink autosave image imagetools paste preview table powertables'
},
查看完整在线代码片段
组件初始化设置
// 初始化配置实例
WordPaster.getInstance({
// 文件上传接口地址(示例)
// 文档参考链接:http://www.ncmem.com/doc/view.aspx?id=d88b60a2b0204af1ba62fa66288203ed
PostUrl: 'http://localhost:8891/upload.aspx'
});
配置项说明:
设置图片请求的完整地址,包含域名信息:
ImageUrl: 'http://localhost:8891{url}'
对应文档参考:http://www.ncmem.com/doc/view.aspx?id=704cd302ebd346b486adf39cf4553936
指定上传文件时使用的表单字段名称:
FileFieldName: 'file'
相关文档链接:http://www.ncmem.com/doc/view.aspx?id=c3ad06c2ae31454cb418ceb2b8da7c45
用于提取内容中图片的正则匹配规则:
ImageMatch: ''
详情查看:http://www.ncmem.com/doc/view.aspx?id=07e3f323d22d4571ad213441ab8530d1
功能展示
编辑器集成
在富文本编辑器中添加操作按钮以扩展功能
支持导入Word文档(.doc、.docx格式)
支持导入Excel表格文件(.xls、.xlsx格式)
粘贴来自Word的内容:可一键将Word中的文本连同样式粘贴至编辑器,系统自动上传其中的图片资源。
Word转图像:选择Word文件后,系统将其整体转换为图片并上传至服务器。
PDF文件导入:支持将PDF文档一键导入,并以图片形式上传到服务端。
PPT文件导入:可将PPT演示文稿逐页转换为图片并完成上传。
网络图片抓取:自动识别并上传网页中引用的外部网络图片。
示例程序下载
点击可获取完整功能示例代码包
扫码加好友,拉您进群



收藏
