记一次在Vue2+SpringBoot项目里给UEditor加Word导入功能的奇妙冒险
第一章:需求突降,老板的夺命连环call
"小王啊,咱们后台发布文章那个编辑器得升级了!用户反馈说每次从Word复制内容到编辑器,图片全丢了,格式也乱成一锅粥,你得想办法解决!"电话那头传来老板急促的声音。
我盯着屏幕上那个熟悉的UEditor界面,心里咯噔一下——这不就是传说中的"Word内容搬家"难题吗?作为前端开发,我深知这个需求的坑有多深:Word生成的HTML代码比蜘蛛网还复杂,图片处理更是让人头大。但老板的命令就是圣旨,我立刻开启了我的技术探索之旅。
第二章:开源江湖寻宝记
第一站:CSDN博客的神秘线索
我在CSDN上疯狂搜索,突然被一篇标题为《UEDITOR富文本实现导入WORD功能》的文章吸引。文章里提到一个叫zyOffice的开源组件,号称能完美解决Word导入问题,还支持Vue2!
我火速下载了示例项目,发现这个组件的集成方式相当友好:
- 上传zyoffice文件夹到项目
- 在工具栏添加插件按钮
- 初始化组件时配置转换接口
// 在Vue组件中初始化zyOfficezyOffice.getInstance({word:"http://localhost:8080/api/word/convert",wordExport:"http://localhost:8080/api/word/export",ui:{render:"wdpst"}});最让我惊喜的是,这个组件居然支持信创国产化系统,比如中标麒麟、银河麒麟等,这对我们服务政府客户来说简直是福音!
第二站:GitHub的意外收获
在GitHub上闲逛时,我发现了另一个宝藏项目——WordPaster。这个项目专门解决富文本编辑器粘贴Word内容时的图片上传问题,而且完美支持UEditor!
项目文档里详细介绍了在Vue2中的集成步骤:
- 复制WordPaster插件目录到项目
- 引入必要的JS文件(注意不要重复引入jQuery)
- 在工具栏添加自定义按钮
- 初始化WordPaster组件
// 初始化WordPaster组件constapi=window.location.href.substr(0,window.location.href.lastIndexOf("/")+1)+"api/upload";WordPaster.getInstance({PostUrl:api,// 上传接口地址FileFilter:".doc;.docx",// 支持的文件类型MaxSize:10*1024*1024// 最大文件大小10MB});第三章:后端SpringBoot的攻坚战
有了前端组件还不够,后端处理才是重头戏。我参考了多个SpringBoot集成UEditor的方案,最终决定采用以下架构:
1. 文件转换服务
使用Apache POI处理Word文档,但发现直接解析复杂格式还是不够完美。于是转向使用Aspose.Words(虽然不是完全开源,但有免费试用版),它对Word格式的保留效果更好。
@RestController@RequestMapping("/api/word")publicclassWordController{@PostMapping("/convert")publicResponseEntityconvertWordToHtml(@RequestParam("file")MultipartFilefile){try{// 使用Aspose.Words转换Word为HTMLDocumentdoc=newDocument(file.getInputStream());HtmlSaveOptionsoptions=newHtmlSaveOptions();options.setExportImagesAsBase64(false);// 不使用Base64嵌入图片options.setResourcesFolder("uploads/images/"+UUID.randomUUID());// 图片保存路径// 保存HTML和图片StringhtmlPath="uploads/html/"+UUID.randomUUID()+".html";doc.save(htmlPath,options);// 返回处理后的HTML(需要提取图片URL)StringhtmlContent=Files.readString(Paths.get(htmlPath));// 这里需要进一步处理htmlContent,替换图片路径为可访问的URLreturnResponseEntity.ok(htmlContent);}catch(Exceptione){returnResponseEntity.badRequest().body("转换失败: "+e.getMessage());}}}2. 图片上传处理
配置UEditor的上传接口,使用SpringBoot的MultipartFile接收上传的文件:
@RestController@RequestMapping("/ueditor")publicclassUEditorController{@Value("${file.upload-dir}")privateStringuploadDir;@PostMapping("/upload")publicMapuploadImage(@RequestParam("upfile")MultipartFilefile){Mapresult=newHashMap<>();try{// 确保上传目录存在FileuploadPath=newFile(uploadDir);if(!uploadPath.exists()){uploadPath.mkdirs();}// 保存文件StringfileName=UUID.randomUUID().toString()+file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));Filedest=newFile(uploadPath,fileName);file.transferTo(dest);// 返回UEditor需要的JSON格式result.put("state","SUCCESS");result.put("url","/uploads/"+fileName);// 前端可访问的URLresult.put("title",fileName);result.put("original",file.getOriginalFilename());}catch(IOExceptione){result.put("state","ERROR");result.put("message","上传失败: "+e.getMessage());}returnresult;}}第四章:数据库设计的智慧
关于富文本内容的存储,我参考了MySQL富文本存储方案对比,最终选择了以下方案:
- 内容表设计:
CREATETABLEarticle(idBIGINTPRIMARYKEYAUTO_INCREMENT,titleVARCHAR(200)NOTNULL,contentTEXTNOTNULL,-- 存储HTML内容content_html_pathVARCHAR(500),-- 如果内容很大,可以存储HTML文件路径create_timeDATETIMEDEFAULTCURRENT_TIMESTAMP,update_timeDATETIMEDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP);- 图片资源表(可选):
CREATETABLEarticle_image(idBIGINTPRIMARYKEYAUTO_INCREMENT,article_idBIGINTNOTNULL,image_urlVARCHAR(500)NOTNULL,alt_textVARCHAR(200),sort_orderINTDEFAULT0,FOREIGNKEY(article_id)REFERENCESarticle(id));对于大多数情况,直接将HTML存储在content字段就足够了。只有当内容特别大时,才考虑将HTML保存为文件,并在数据库中存储文件路径。
第五章:集成测试的酸甜苦辣
成功时刻
经过一周的奋战,终于迎来了第一次完整测试:
- 在Word中编写了一篇包含多种格式(标题、加粗、斜体、表格、图片)的文档
- 点击UEditor的"导入Word"按钮
- 见证奇迹的时刻——所有格式完美保留,图片自动上传并显示!
踩过的坑
- 图片路径问题:最初转换后的HTML中图片使用相对路径,导致前端无法显示。解决方案是在后端转换时统一替换为绝对URL。
- 跨域问题:前端和后端分离部署时,需要配置CORS。
- 样式冲突:Word生成的HTML带有大量内联样式,与UEditor的默认样式冲突。通过自定义CSS重置解决了这个问题。
第六章:最终胜利与经验总结
经过这次冒险,我总结出以下关键点:
- 选择合适的工具:zyOffice和WordPaster这两个组件大大简化了开发工作,避免了重复造轮子。
- 前后端协作:前端负责展示和交互,后端专注文件处理和存储,分工明确。
- 测试的重要性:不同版本的Word、不同浏览器都需要充分测试,确保兼容性。
- 性能优化:对于大文件,考虑分块上传和异步处理。
现在,我们的后台编辑器已经能够完美支持Word导入,用户反馈良好。这次经历也让我深刻认识到:在技术世界里,没有解决不了的问题,只有还没找到的解决方案!
最后,附上项目关键依赖版本信息:
- UEditor: 1.4.3.3
- zyOffice: 1.5.x
- WordPaster: 最新版
- SpringBoot: 2.7.x
- Aspose.Words: 23.10 (试用版)
希望我的经历能给同样面临这个问题的开发者一些启发和帮助!
复制插件目录
引入插件文件
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"]]初始化控件
varpos=window.location.href.lastIndexOf("/");varapi=[window.location.href.substr(0,pos+1),"asp/upload.asp"].join("");WordPaster.getInstance({//上传接口:http://www.ncmem.com/doc/view.aspx?id=d88b60a2b0204af1ba62fa66288203edPostUrl:api,//为图片地址增加域名:http://www.ncmem.com/doc/view.aspx?id=704cd302ebd346b486adf39cf4553936ImageUrl:"",//设置文件字段名称:http://www.ncmem.com/doc/view.aspx?id=c3ad06c2ae31454cb418ceb2b8da7c45FileFieldName:"file",//提取图片地址:http://www.ncmem.com/doc/view.aspx?id=07e3f323d22d4571ad213441ab8530d1ImageMatch:''});//加载控件注意
如果接口字段名称不是file,请配置FileFieldName。ueditor接口中使用的upfile字段
点击查看详细教程
配置ImageMatch
匹配图片地址,如果服务器返回的是JSON则需要通过正则匹配
ImageMatch:'',点击参考链接
配置ImageUrl
为图片地址增加域名,如果服务器返回的图片地址是相对路径,可通过此属性添加自定义域名。
ImageUrl:"",点击查看详细教程
配置SESSION
如果接口有权限验证(登陆验证,SESSION验证),请配置COOKIE。或取消权限验证。
参考:http://www.ncmem.com/doc/view.aspx?id=8602DDBF62374D189725BF17367125F3
导入效果
下载示例
点击下载完整示例