杰瑞科技汇

CKEditor Java配置有哪些关键步骤?

CKEditor 5 已经不再是过去的 jQuery 插件模式,它是一个基于现代 JavaScript 框架(主要是 TypeScript)构建的独立、模块化的富文本编辑器,配置方式与传统的 CKEditor 4 有很大不同。

CKEditor Java配置有哪些关键步骤?-图1
(图片来源网络,侵删)

本指南将涵盖以下内容:

  1. 核心概念:理解 CKEditor 5 的工作方式。
  2. 环境准备:搭建 Java Web 项目。
  3. 引入 CKEditor 5:将编辑器集成到 JSP 页面。
  4. 基础配置:配置工具栏、语言等。
  5. 高级配置:配置插件、自定义内容、上传图片等。
  6. 后端集成:如何在 Java 后端获取和保存编辑器内容。
  7. 推荐方案:使用官方的 Java 后端集成包。

核心概念

在开始配置前,你需要了解 CKEditor 5 的几个关键点:

  • 模块化:CKEditor 5 由许多独立的插件(如 Image, Link, Table)和核心模块组成,你可以按需引入,只打包你需要的功能,以减小最终文件体积。
  • 构建方式:官方提供了两种主要版本:
    • 预构建版本:已经编译打包好的版本,开箱即用,适合快速上手和大多数项目,我们主要使用这个。
    • 从源码构建:如果你需要深度定制,修改源码或引入非常新的插件,可以从源码构建,但这需要 Node.js 环境,过程更复杂。
  • 配置方式:通过一个 JavaScript 对象进行配置,非常灵活。
  • 数据格式:CKEditor 5 使用它自己的数据格式,称为 DataApi,它是一个标准化的、可序列化的 JSON 格式,可以很好地映射到 HTML。强烈建议在后端存储和传输这种格式,而不是 HTML,因为它能保留编辑器的所有状态和元数据。

环境准备

我们以一个标准的 Maven Java Web 项目 为例,你需要一个 Servlet 容器(如 Tomcat)来运行项目。

项目结构如下:

CKEditor Java配置有哪些关键步骤?-图2
(图片来源网络,侵删)
ckeditor-java-demo/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           └── servlet/
│   │   │               └── SaveContentServlet.java
│   │   ├── resources/
│   │   └   └── webapp/
│   │       ├── WEB-INF/
│   │       │   └── web.xml
│   │       ├── css/
│   │       │   └── style.css
│   │       ├── js/
│   │       │   └── custom-config.js
│   │       └── index.jsp
└── pom.xml

引入 CKEditor 5

步骤 1:下载 CKEditor 5

访问 CKEditor 5 下载页面,选择一个预构建版本,对于大多数用户,选择 StandardFull 版本即可,下载后,你会得到一个 ZIP 文件。

步骤 2:添加到项目

将下载的 ZIP 文件解压,你会看到 dist 目录,这个目录包含了编辑器所需的所有文件。

dist 目录下的内容复制到你的 Java Web 项目的 webapp 目录下,并重命名为 ckeditor,以便于引用。

你的 webapp 目录结构现在看起来像这样:

webapp/
├── ckeditor/  <-- 从官方下载解压后的文件
│   ├── ckeditor.js
│   ├── translations/  <-- 语言包
│   ├── samples/       <-- 示例和文档(可以删除)
│   └── ... (其他文件)
├── css/
├── js/
├── index.jsp
└── WEB-INF/

步骤 3:在 JSP 页面中引入

index.jsp 中,你需要引入 CKEditor 5 的核心 JavaScript 文件,推荐使用 异步加载 方式,这样可以避免阻塞页面渲染。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">CKEditor 5 in Java</title>
    <!-- 引入自定义样式 -->
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <h1>CKEditor 5 Demo</h1>
    <!-- 1. 定义一个可编辑的 div 容器 -->
    <div id="editor">
        <p>这里是一些初始内容。</p>
    </div>
    <!-- 2. 异步加载 CKEditor 5 -->
    <!-- 注意:我们使用 data-app-id 来避免在多个页面加载时冲突 -->
    <script src="ckeditor/ckeditor.js" data-app-id="my-app"></script>
    <!-- 3. 编写初始化脚本 -->
    <script>
        // 当 CKEditor 5 加载完成后执行
        CKEditor.create(document.querySelector('#editor'), {
            // 配置选项将在这里
        }).then(editor => {
            console.log('Editor was initialized', editor);
            // 可以在这里监听内容变化事件
            editor.model.document.on('change:data', () => {
                console.log('The editor content has changed.');
                // 可以在这里获取内容并实时保存到后端(不推荐,通常在提交表单时保存)
            });
        }).catch(error => {
            console.error(error);
        });
    </script>
</body>
</html>

基础配置

为了保持 JSP 页面的整洁,我们推荐将配置代码放在一个单独的 JavaScript 文件中(如 webapp/js/custom-config.js)。

修改 index.jsp,加载这个配置文件:

<!-- index.jsp -->
...
    <script src="ckeditor/ckeditor.js" data-app-id="my-app"></script>
    <!-- 加载你的自定义配置文件 -->
    <script src="js/custom-config.js"></script>
...

custom-config.js 中进行配置:

// js/custom-config.js
// 确保在 CKEditor 全局对象加载完成后执行
window.CKEditorConfig = (function() {
    return {
        toolbar: {
            items: [
                'heading', '|',
                'bold', 'italic', 'link', 'bulletedList', 'numberedList', '|',
                'outdent', 'indent', '|',
                'blockQuote', 'insertTable', 'undo', 'redo'
            ]
        },
        language: 'zh-cn' // 设置语言为中文
    };
})();

然后在 index.jsp 的初始化代码中使用这个配置对象:

<!-- index.jsp -->
...
    <script>
        CKEditor.create(document.querySelector('#editor'), window.CKEditorConfig)
        .then(editor => { ... })
        .catch(error => { ... });
    </script>
...

常用配置项:

  • toolbar: 定义工具栏上显示哪些按钮。
  • language: 设置编辑器语言,CKEditor 5 内置了多种语言,包括简体中文 (zh-cn),文件在 ckeditor/translations/ 目录下。
  • placeholder: 设置编辑器占位符文本。
  • image: 配置图片插入功能。

高级配置

a) 自定义内容

通过 initialData 属性可以在初始化时为编辑器设置内容,这个内容可以是 HTML 字符串。

// custom-config.js
window.CKEditorConfig = {
    // ... 其他配置
    initialData: '<p>这是通过 <strong>initialData</strong> 设置的初始内容。</p>'
};

b) 配置图片上传(关键步骤)

图片上传是富文本编辑器最重要的功能之一,CKEditor 5 本身不处理文件上传,它提供了一个上传适配器接口,让你可以连接到任何后端。

这里我们以最简单的 SimpleUploadAdapter 为例,它是一个可以直接发送 POST 请求到指定 URL 的适配器。

修改配置,启用上传适配器:

// custom-config.js
window.CKEditorConfig = {
    // ... 其他配置
    // 1. 配置上传 URL
    uploadUrl: 'http://localhost:8080/ckeditor-java-demo/upload', // 你的 Java Servlet 上传地址
    // 2. 配置图片插件,启用上传
    image: {
        toolbar: [
            'imageStyle:full',
            'imageStyle:side',
            '|',
            'imageTextAlternative'
        ],
        // 启用上传适配器
        upload: {
            // 上传适配器的类型
            types: [ 'insertImage', 'autoUpload' ],
            // 自定义上传适配器
            adapter: (loader) => {
                // 创建一个新的上传适配器实例
                return new SimpleFileUploadAdapter(loader);
            }
        }
    }
};
// 需要引入 SimpleUploadAdapter 的插件
// 你需要从 ckeditor-5 包中引入它,或者在页面中单独引入其构建文件
// 如果你使用的是 Standard 或 Full 版本,它通常已经包含在内

注意SimpleFileUploadAdapter 需要被定义,你可以从 ckeditor.com 的文档中找到它的源码,或者直接在你的初始化脚本中定义它,为了简化,这里假设它已经包含在你的 ckeditor.js 中(Standard 版本会包含)。

创建 Java 后端上传 Servlet (SaveContentServlet.javaUploadServlet.java)

我们需要两个 Servlet:

  • 一个用于处理编辑器内容的保存(提交整个表单)。
  • 一个专门用于处理图片上传(AJAX 请求)。

UploadServlet.java (处理图片上传)

// src/main/java/com/example/servlet/UploadServlet.java
package com.example.servlet;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.UUID;
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private static final String UPLOAD_DIRECTORY = "uploads"; // 上传文件存放目录
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 检查是否为 multipart/form-data 请求
        if (!ServletFileUpload.isMultipartContent(request)) {
            PrintWriter writer = response.getWriter();
            writer.println("Error: 表单必须包含 enctype=multipart/form-data");
            writer.flush();
            return;
        }
        // 配置上传参数
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        try {
            List<FileItem> formItems = upload.parseRequest(request);
            if (formItems != null && formItems.size() > 0) {
                for (FileItem item : formItems) {
                    if (!item.isFormField()) {
                        // 获取文件名
                        String fileName = new File(item.getName()).getName();
                        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
                        // 生成唯一文件名
                        String uniqueFileName = UUID.randomUUID().toString() + fileExtension;
                        // 构建上传文件的完整路径
                        String uploadPath = getServletContext().getRealPath("") + File.separator + UPLOAD_DIRECTORY;
                        File uploadDir = new File(uploadPath);
                        if (!uploadDir.exists()) {
                            uploadDir.mkdir();
                        }
                        String filePath = uploadPath + File.separator + uniqueFileName;
                        File storeFile = new File(filePath);
                        // 在控制台输出上传文件路径
                        System.out.println("文件上传到: " + filePath);
                        // 保存文件到硬盘
                        item.write(storeFile);
                        // 返回 CKEditor 5 期望的 JSON 格式响应
                        response.setContentType("application/json");
                        response.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
                        // CKEditor 5 期望的响应格式
                        out.println("{\"url\": \"" + request.getContextPath() + "/uploads/" + uniqueFileName + "\"}");
                        out.flush();
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

注意:你需要添加 commons-fileupload 依赖到你的 pom.xml

<!-- pom.xml -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>

后端集成:获取和保存内容

当用户提交表单时,你需要从编辑器中获取内容并保存到数据库。

步骤 1:修改 JSP,添加提交表单

<!-- index.jsp -->
...
<body>
    <h1>CKEditor 5 Demo</h1>
    <form action="save-content" method="post">
        <div id="editor">
            <p>这里是一些初始内容。</p>
        </div>
        <button type="submit">保存内容</button>
    </form>
    <script src="ckeditor/ckeditor.js" data-app-id="my-app"></script>
    <script src="js/custom-config.js"></script>
    <script>
        let editorInstance; // 保存 editor 实例,以便在表单提交时使用
        CKEditor.create(document.querySelector('#editor'), window.CKEditorConfig)
        .then(editor => {
            editorInstance = editor; // 将实例保存到全局变量
            console.log('Editor was initialized', editor);
        })
        .catch(error => {
            console.error(error);
        });
    </script>
</body>
...

步骤 2:创建保存内容的 Servlet

// src/main/java/com/example/servlet/SaveContentServlet.java
package com.example.servlet;
import org.json.JSONObject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/save-content")
public class SaveContentServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 获取编辑器内容
        // 注意:CKEditor 5 推荐存储 DataApi 格式,因为它更丰富
        String editorData = request.getParameter("editorData");
        // 2. 在实际应用中,这里应该将内容保存到数据库
        //  contentService.saveContent(editorData);
        System.out.println("从编辑器获取到的内容 (DataApi):");
        System.out.println(editorData);
        // 3. 可选:将 DataApi 转换为 HTML 以便在非富文本编辑器中显示
        // 注意:这需要引入 CKEditor 5 的 DataApi 模块
        // String htmlContent = editorInstance.getData(); // 直接获取 HTML
        // 4. 返回成功响应
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write("{\"status\":\"success\", \"message\":\"内容已保存!\"}");
    }
}

步骤 3:修改前端,在提交时获取内容

我们需要在表单提交前,从 CKEditor 实例中获取内容,并放入一个隐藏的 input 字段中。

// 在 custom-config.js 或 index.jsp 的 script 标签内
document.querySelector('form').addEventListener('submit', function(event) {
    // 阻止表单的默认提交行为
    event.preventDefault();
    // 从 editorInstance 获取 DataApi 格式的数据
    const data = editorInstance.getData();
    // 创建一个隐藏的 input 元素
    const input = document.createElement('input');
    input.type = 'hidden';
    input.name = 'editorData'; // Servlet 中通过 request.getParameter("editorData") 获取
    input.value = data;
    // 将隐藏的 input 添加到表单中
    this.appendChild(input);
    // 再次提交表单
    this.submit();
});

推荐方案:使用官方 Java 后端集成包

CKEditor 官方提供了一个 Java 后端集成包,它极大地简化了与 CKEditor 5 的交互,特别是内容转换和上传适配器的实现。

这个包包含:

  • 一个 XHRCrossDomain 兼容的文件上传 Servlet。
  • 一个用于将 CKEditor 5 的 DataApi 格式转换为 HTML 的工具。

使用步骤:

  1. 添加依赖

    <!-- pom.xml -->
    <dependency>
        <groupId>orgckeditor</groupId>
        <artifactId>ckeditor-java-integration</artifactId>
        <version>1.0.0</version> <!-- 请使用最新版本 -->
    </dependency>
  2. 配置编辑器:在 custom-config.js 中,使用官方提供的 CKEditorUploadAdapter

    // custom-config.js
    window.CKEditorConfig = {
        // ... 其他配置
        uploadUrl: 'http://localhost:8080/ckeditor-java-demo/upload', // 指向官方提供的 UploadServlet
        image: {
            toolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ],
            // 使用官方的上传适配器
            upload: {
                adapter: (loader) => {
                    // CKEditorUploadAdapter 是官方包提供的类
                    return new CKEditorUploadAdapter(loader);
                }
            }
        }
    };
    // 你需要从官方包中引入 CKEditorUploadAdapter
    // 通常你需要将这个 JS 文件放在你的项目中
    // <script src="js/CKEditorUploadAdapter.js"></script>
    // 这个文件可以从官方的 Java 包中找到,或者自己根据文档实现。
  3. 使用官方的 UploadServlet:直接使用官方提供的 org.ckeditor.java integration.upload.CKEditorUploadServlet,无需自己编写。

    <!-- web.xml -->
    <servlet>
        <servlet-name>CKEditorUploadServlet</servlet-name>
        <servlet-class>org.ckeditor.java.integration.upload.CKEditorUploadServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CKEditorUploadServlet</servlet-name>
        <url-pattern>/upload</url-pattern>
    </servlet-mapping>
  4. 使用工具类转换数据:在 SaveContentServlet 中,使用官方的工具类进行转换。

    // SaveContentServlet.java
    import org.ckeditor.java.utils.CKEditorDataUtils;
    import org.json.JSONObject;
    // ...
    String editorData = request.getParameter("editorData");
    // 将 DataApi 转换为 HTML
    String htmlContent = CKEditorDataUtils.dataToHtml(editorData);
    System.out.println("转换后的 HTML:");
    System.out.println(htmlContent);
    // ... 保存 htmlContent 到数据库

为什么推荐使用官方包?

  • 标准化:遵循 CKEditor 5 的官方规范,兼容性更好。
  • 功能完整:处理了各种边界情况和安全考虑。
  • 省时省力:你不需要自己实现复杂的上传逻辑和数据转换。

配置 CKEditor 5 在 Java 项目中,核心流程是:

  1. 引入前端文件:下载预构建版,放入 webapp
  2. 页面初始化:在 JSP 中通过 JavaScript 异步加载并创建编辑器实例。
  3. 前端配置:通过 JavaScript 对象配置工具栏、语言、上传URL等。
  4. 后端实现
    • 创建 Servlet 处理图片上传,并返回 CKEditor 5 期望的 JSON 格式。
    • 创建 Servlet 处理表单提交,获取编辑器内容(最好是 DataApi 格式)并保存。
  5. (推荐)使用官方集成包:简化上传和数据处理逻辑,提高项目稳定性和可维护性。

希望这份详细的指南能帮助你成功地在 Java 项目中集成 CKEditor 5!

分享:
扫描分享到社交APP
上一篇
下一篇