项目需求分析与技术选型实施记录
(广东某集团公司项目负责人,2023年X月X日)
一、需求深化解析与核心约束
客户新增需求聚焦于富文本编辑器功能扩展,需满足以下严苛条件:
- 功能完整性:
- Word粘贴:保留复杂样式(表格嵌套、字体渐变、文本框),图片二进制存储至华为云OBS。
- 文档导入:支持Word/Excel/PPT/PDF全格式解析,图片自动上传且样式零丢失。
- 公众号抓取:解析HTML时自动替换图片URL为OBS地址,规避防盗链。
- 信创刚性要求:
- 操作系统:兼容中标麒麟/银河麒麟V10(桌面版+服务器版)、统信UOS(龙芯版)。
- CPU架构:需通过龙芯3A5000(LoongArch指令集)和鲲鹏920(ARMv8)兼容性测试。
- 中间件:必须使用国产JDK(如麒麟JDK 11)和国产数据库(达梦DM8)。
- 授权成本控制:
- 预算≤58万元,需覆盖1000+客户项目的长期授权。
- 拒绝SaaS订阅模式,强制要求本地化部署授权。
二、技术选型与产品评估
1. 富文本编辑器方案对比
方案 | UEditor(百度开源) | CKEditor 5(商业版) | TinyMCE Enterprise | WordPaster信创版 |
---|---|---|---|---|
信创兼容性 | 需深度适配(依赖jQuery,国产浏览器支持弱) | 需二次开发(React/Vue集成复杂) | 官方支持麒麟/统信UOS | 官方支持信创环境 |
文档解析能力 | 依赖第三方插件(如ueditor-word ,功能残缺) | 原生支持Word粘贴但样式丢失严重 | PowerPaste插件功能完整 | 功能完整 |
授权成本 | MIT协议(免费) | $1200/年(不可买断) | $4800/买断(5年) | 完全开源(下载源码) |
国产化适配 | 需替换字体库(解决Linux下中文字体缺失) | 需重写图片处理模块(规避Base64) | 提供麒麟JDK专用版本 | 提供国产化版本 |
决策结果:
选择**WordPaster(源码版)**作为基础框架,原因如下:
- 零授权成本,符合预算约束。
- 完全开源,符合集团自主可控需求。
- 信创适配,符合政府信息安全需求。
- 可通过扩展插件实现核心需求(如自定义图片处理器)。
- 社区存在信创适配案例(如某政务平台改造方案)。
2. 文档解析技术栈
- Word/Excel/PPT:
采用Apache POI 5.2.3(信创版需替换为华为开源的LibreOffice Online
Java API)。 - PDF解析:
使用PDFBox 2.0.27(解决中文乱码问题需配置FontBox
字体包)。 - 公众号内容抓取:
集成Jsoup 1.15.3 + OkHttp 4.9.3(需处理反爬机制,如User-Agent轮换)。
3. 信创环境验证清单
组件 | 验证项 |
---|---|
操作系统 | 统信UOS 1050(龙芯版)下UEditor渲染异常(需回退至Chrome 89内核) |
JDK | 麒麟JDK 11.0.15需添加JVM参数-Djava.awt.fonts=/usr/share/fonts/windows/ |
MySQL | 达梦DM8需修改连接池配置(useSSL=false&serverTimezone=Asia/Shanghai ) |
浏览器 | 360安全浏览器(信创版)需强制启用IE11兼容模式 |
三、核心功能开发实现
1. 前端实现(Vue2 + UEditor定制)
(1)Word粘贴插件开发
重写UEditor的pasteutils.js
,拦截剪贴板数据并提取图片:
// src/plugins/ue-word-paste/word-paste.js
UE.plugins['wordpaste'] = function() {
const me = this;
me.addListener('ready', function() {
document.addEventListener('paste', async (e) => {
const html = e.clipboardData.getData('text/html');
if (!html) return;
// 提取Base64图片并上传
const images = html.match(/]+src="([^"]+)"/g) || [];
for (const imgTag of images) {
const src = imgTag.match(/src="([^"]+)"/)[1];
if (src.startsWith('data:image')) {
const base64 = src.split(',')[1];
const res = await axios.post('/api/upload', { file: base64 });
const newImgTag = imgTag.replace(src, res.data.url);
html.replace(imgTag, newImgTag);
}
}
// 插入处理后的HTML
me.execCommand('insertHtml', html);
e.preventDefault();
});
});
};
(2)工具栏集成
在UEditor初始化配置中添加自定义按钮:
// src/components/UEditor.vue
export default {
mounted() {
window.UE.registerUI('wordpaste-btn', function(editor, uiName) {
const btn = document.createElement('button');
btn.innerHTML = 'Word粘贴';
btn.onclick = () => {
editor.execCommand('pasteFromWord'); // 触发自定义粘贴逻辑
};
return btn;
}, 10);
this.editor = window.UE.getEditor('editor', {
toolbars: [['wordpaste-btn', 'source']] // 添加自定义按钮
});
}
}
2. 后端实现(SpringBoot + OBS SDK)
(1)图片上传接口
处理前端传来的Base64图片并存储至OBS:
// src/main/java/com/example/controller/UploadController.java
@RestController
@RequestMapping("/api/upload")
public class UploadController {
@Value("${obs.endpoint}")
private String endpoint;
@PostMapping
public ResponseEntity upload(@RequestParam("file") String base64) {
String fileName = "images/" + UUID.randomUUID() + ".jpg";
byte[] bytes = Base64.decodeBase64(base64.split(",")[1]);
// 使用华为云OBS SDK上传
OBSClient client = new OBSClient(ak, sk, endpoint);
client.putObject(bucketName, fileName, new ByteArrayInputStream(bytes));
client.close();
return ResponseEntity.ok(new UploadResult("https://obs.example.com/" + fileName));
}
}
(2)文档解析服务
使用Apache POI解析Word表格样式:
// src/main/java/com/example/service/DocParserService.java
@Service
public class DocParserService {
public String parseWord(MultipartFile file) throws IOException {
XWPFDocument doc = new XWPFDocument(file.getInputStream());
StringBuilder html = new StringBuilder("");
doc.getTables().forEach(table -> {
table.getRows().forEach(row -> {
html.append("");
row.getTableCells().forEach(cell -> {
// 获取单元格背景色(需处理RGB转HEX)
String bgColor = cell.getCTTc().getTcPr().getShd() != null ?
cell.getCTTc().getTcPr().getShd().getFill() : "transparent";
html.append(String.format("", bgColor, cell.getText()));
});
html.append("");
});
});
html.append("%s");
return html.toString();
}
}
3. 信创适配关键修改
(1)中文字体处理
在UEditor配置中指定国产字体路径:
// src/config/ueditor.config.js
window.UEDITOR_CONFIG = {
fontFamily: [
{ name: '宋体', val: 'SimSun' },
{ name: '黑体', val: 'SimHei' },
{ name: '微软雅黑', val: 'Microsoft YaHei' }
],
// 强制使用系统字体(解决Linux下字体缺失)
initialFont: 'SimSun'
};
(2)龙芯架构优化
修改SpringBoot启动参数以适配LoongArch:
# src/main/resources/application.properties
java.library.path=/opt/loongnix/lib
server.tomcat.max-threads=50 # 龙芯CPU核心数较少,需限制线程数
四、成本与风险评估
项目 | 方案 | 成本(万元) | 风险点 |
---|---|---|---|
商业插件授权 | TinyMCE买断(5年) | 48 | 信创兼容性不达标,需额外适配成本 |
自定义开发 | 人力成本(4人×3月×2.5万/月) | 30 | 文档解析复杂度高,可能延期 |
信创测试 | 麒麟/统信UOS官方认证 | 5 | 部分国产浏览器存在渲染偏差 |
总计 | 58 | 需预留10%预算缓冲(约5.8万) |
最终决策:
采用自定义开发+UEditor深度定制方案,原因如下:
- 完全满足信创兼容性要求,可通过麒麟/统信官方认证。
- 一次性买断成本控制在预算范围内,且代码所有权归属公司。
- 文档解析功能通过组合Apache POI+PDFBox实现,技术可控性强。
五、后续计划
- 性能测试:
模拟1000并发用户上传10MB Word文档,监控OBS上传带宽占用率。 - 安全加固:
增加图片上传文件类型白名单(仅允许jpg/png/gif),防止恶意文件上传。 - 多云迁移:
抽象OBS SDK为StorageService
接口,未来可无缝切换至阿里云OSS或AWS S3。
(记录人:XXX,广东某集团公司项目部)
复制插件目录
引入插件文件
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转换成图片上传到服务器中。