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

本指南将涵盖以下内容:
- 核心概念:理解 CKEditor 5 的工作方式。
- 环境准备:搭建 Java Web 项目。
- 引入 CKEditor 5:将编辑器集成到 JSP 页面。
- 基础配置:配置工具栏、语言等。
- 高级配置:配置插件、自定义内容、上传图片等。
- 后端集成:如何在 Java 后端获取和保存编辑器内容。
- 推荐方案:使用官方的 Java 后端集成包。
核心概念
在开始配置前,你需要了解 CKEditor 5 的几个关键点:
- 模块化:CKEditor 5 由许多独立的插件(如
Image,Link,Table)和核心模块组成,你可以按需引入,只打包你需要的功能,以减小最终文件体积。 - 构建方式:官方提供了两种主要版本:
- 预构建版本:已经编译打包好的版本,开箱即用,适合快速上手和大多数项目,我们主要使用这个。
- 从源码构建:如果你需要深度定制,修改源码或引入非常新的插件,可以从源码构建,但这需要 Node.js 环境,过程更复杂。
- 配置方式:通过一个 JavaScript 对象进行配置,非常灵活。
- 数据格式:CKEditor 5 使用它自己的数据格式,称为
DataApi,它是一个标准化的、可序列化的 JSON 格式,可以很好地映射到 HTML。强烈建议在后端存储和传输这种格式,而不是 HTML,因为它能保留编辑器的所有状态和元数据。
环境准备
我们以一个标准的 Maven Java Web 项目 为例,你需要一个 Servlet 容器(如 Tomcat)来运行项目。
项目结构如下:

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 下载页面,选择一个预构建版本,对于大多数用户,选择 Standard 或 Full 版本即可,下载后,你会得到一个 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.java 和 UploadServlet.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 的工具。
使用步骤:
-
添加依赖:
<!-- pom.xml --> <dependency> <groupId>orgckeditor</groupId> <artifactId>ckeditor-java-integration</artifactId> <version>1.0.0</version> <!-- 请使用最新版本 --> </dependency> -
配置编辑器:在
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 包中找到,或者自己根据文档实现。 -
使用官方的 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> -
使用工具类转换数据:在
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 项目中,核心流程是:
- 引入前端文件:下载预构建版,放入
webapp。 - 页面初始化:在 JSP 中通过 JavaScript 异步加载并创建编辑器实例。
- 前端配置:通过 JavaScript 对象配置工具栏、语言、上传URL等。
- 后端实现:
- 创建 Servlet 处理图片上传,并返回 CKEditor 5 期望的 JSON 格式。
- 创建 Servlet 处理表单提交,获取编辑器内容(最好是
DataApi格式)并保存。
- (推荐)使用官方集成包:简化上传和数据处理逻辑,提高项目稳定性和可维护性。
希望这份详细的指南能帮助你成功地在 Java 项目中集成 CKEditor 5!
