项目需求分析与技术选型实施记录
(广东某集团公司项目负责人,2023年X月X日)

一、需求深化解析与核心约束

客户新增需求聚焦于富文本编辑器功能扩展,需满足以下严苛条件:

  1. 功能完整性
    • Word粘贴:保留复杂样式(表格嵌套、字体渐变、文本框),图片二进制存储至华为云OBS。
    • 文档导入:支持Word/Excel/PPT/PDF全格式解析,图片自动上传且样式零丢失。
    • 公众号抓取:解析HTML时自动替换图片URL为OBS地址,规避防盗链。
  2. 信创刚性要求
    • 操作系统:兼容中标麒麟/银河麒麟V10(桌面版+服务器版)、统信UOS(龙芯版)。
    • CPU架构:需通过龙芯3A5000(LoongArch指令集)和鲲鹏920(ARMv8)兼容性测试。
    • 中间件:必须使用国产JDK(如麒麟JDK 11)和国产数据库(达梦DM8)。
  3. 授权成本控制
    • 预算≤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深度定制方案,原因如下:

  1. 完全满足信创兼容性要求,可通过麒麟/统信官方认证。
  2. 一次性买断成本控制在预算范围内,且代码所有权归属公司。
  3. 文档解析功能通过组合Apache POI+PDFBox实现,技术可控性强。

五、后续计划

  1. 性能测试
    模拟1000并发用户上传10MB Word文档,监控OBS上传带宽占用率。
  2. 安全加固
    增加图片上传文件类型白名单(仅允许jpg/png/gif),防止恶意文件上传。
  3. 多云迁移
    抽象OBS SDK为StorageService接口,未来可无缝切换至阿里云OSS或AWS S3。

(记录人:XXX,广东某集团公司项目部)

复制插件目录

WordPaster插件目录

引入插件文件


	
	UEditor 1.4.3.3示例
	
    
	
	
    
    
    
    
    
    
	
    

注意:不要重复引入jquery,如果您的项目已经引入了jq,则不用再引入jq-1.4
image

在工具栏中增加插件按钮

//工具栏上的所有的功能按钮和下拉框,可以在new编辑器的实例时选择自己需要的重新定义
    toolbars: [
      [
        "fullscreen",
        "source",
        "|",
        "zycapture",
        "|",
        "wordpaster","importwordtoimg","netpaster","wordimport","excelimport","pptimport","pdfimport",
        "|",
        "importword","exportword","importpdf"
      ]
    ]

初始化控件

image

        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字段
image
点击查看详细教程

配置ImageMatch

匹配图片地址,如果服务器返回的是JSON则需要通过正则匹配

ImageMatch: '',

点击参考链接

配置ImageUrl

为图片地址增加域名,如果服务器返回的图片地址是相对路径,可通过此属性添加自定义域名。

ImageUrl: "",

点击查看详细教程

配置SESSION

如果接口有权限验证(登陆验证,SESSION验证),请配置COOKIE。或取消权限验证。
参考:http://www.ncmem.com/doc/view.aspx?id=8602DDBF62374D189725BF17367125F3

效果

编辑器界面

image

导入Word文档,支持doc,docx

粘贴Word和图片

导入Excel文档,支持xls,xlsx

粘贴Word和图片

粘贴Word

一键粘贴Word内容,自动上传Word中的图片,保留文字样式。
粘贴Word和图片

Word转图片

一键导入Word文件,并将Word文件转换成图片上传到服务器中。
导入Word转图片

导入PDF

一键导入PDF文件,并将PDF转换成图片上传到服务器中。
导入PDF转图片

导入PPT

一键导入PPT文件,并将PPT转换成图片上传到服务器中。
导入PPT转图片

上传网络图片

自动上传网络图片

下载示例

点击下载完整示例

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐