CKEditor4
当前版本为CKEditor4.13.0
下载CKEditor4
选择基础组件(Basic
)
我们这里只用到了图片的上传,因此选择基础组件
2.选择图片上传插件
注意⚠️:选择File Browser
3.下载
将下载好的文件,解压后放入对应的目录中
引入并使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>A Simple Page with CKEditor</title> <!-- 确保引入的CKEditor文件路径正确 --> <script src="../ckeditor.js"></script> </head> <body> <form> <textarea name="editor1" id="editor1" rows="10" cols="80"> This is my textarea to be replaced with CKEditor. </textarea> <script> // 使用CKEditor替换 <textarea id="editor1"> // 实例化,使用默认配置 CKEDITOR.replace( 'editor1' ); </script> </form> </body> </html>
相关配置
配置插件
1.展开ckeditor
目录找到samples
目录下的index.html
文件,用浏览器打开
2.点击右上角的TOOLBAR CONFIGURATOR
3.勾选或者取消你想要的插件,然后点击Get toolbar config
按钮,得到你想要的配置文件
4.复制该配置
5.找到ckeditor
目录下的config.js
文件
6.将刚复制的配置,粘贴到config.js
文件中
添加上传tag
此时点击图片按钮我们发现,仍然不能上传图片
需要在刚刚的config.js
中添加两个配置
config.extraPlugins = 'uploadimage' config.filebrowserImageUploadUrl = 'https://192.168.0.1/api/ECategoryDetail/UploadImg' //filebrowserImageUploadUrl 替换成你需要上传的服务器地址
我们再次点击图片按钮时候,便发现弹窗中多了上传的tag
隐藏浏览服务器按钮
我们可能无法浏览服务器上的图片,当我们点击浏览服务器按钮时,可能会出现空白页面
因此,为了实际体验,我们可能需要隐藏浏览服务器按钮
我们根据ckeditor/plugins/image2/dialogs
路径找到image2.js
文件
搜索关键字browseServer
找到下行
label:f.lang.common.browseServer,hidden:!0
在其中添加style:"display:none"
,如下:
label:f.lang.common.browseServer,style:"display:none",hidden:!0
效果如下:
上传图片时,如何修改上传地址
在上面的配置里,我们添加了一条配置用来上传文件config.filebrowserImageUploadUrl
如果不做任何修改,当我们点击上传到服务器时,他会默认使用该地址上传图片。
但这样很不灵活,通过查看文档,我们发现可以通过监听事件fileUploadRequest
来做上传前的操作。
editor.on( 'fileUploadRequest', function( evt ) { var fileLoader = evt.data.fileLoader, formData = new FormData(), xhr = fileLoader.xhr; xhr.open( 'PUT', fileLoader.uploadUrl, true ); formData.append( 'upload', fileLoader.file, fileLoader.fileName ); fileLoader.xhr.send( formData ); // Prevented the default behavior. evt.stop(); } );
修改fileLoader.uploadUrl
即可,当然你也可以做其他操作,例如增加或修改消息头。
如何修改服务器的返回结果
服务器返回的结构有时候不是我们想要的,因此,可能需要对之进行修改。通过对事件fileUploadResponse
进行监听即可。
editor.on( 'fileUploadResponse', function( evt ) { // Prevent the default response handler. evt.stop(); // Get XHR and response. var data = evt.data, xhr = data.fileLoader.xhr, response = xhr.responseText.split( '|' ); if ( response[ 1 ] ) { // An error occurred during upload. data.message = response[ 1 ]; evt.cancel(); } else { data.url = response[ 0 ]; } } );
注意⚠️:
对其事件的监听一般放在CKeditor
实例完成后instanceReady
,因此如下使用:
CKEDITOR.on('instanceReady', function(e) { console.log('CKEDITOR初始化', e.editor) e.editor.widgets.on('instanceCreated', function(params) { console.log('editor创建', params) }) var upload = e.editor.uploadRepository upload.on('instanceCreated', function(eve) { alert('112233') }) e.editor.on('change', function(change) { console.log('change', change) }) e.editor.on( 'fileUploadRequest', function( evt ) { console.log(evt) } e.editor.on( 'fileUploadResponse', function( evt ) { console.log(evt) } }
参考:
2022年最新完全版CKeditor v4.18.0,修改成可上传图片
1、修改配置文件config.js
,增加如下选项:
config.extraPlugins = 'uploadimage'; config.filebrowserImageUploadUrl = '/widget/ckeditor/uploadImage';
2、Java服务端接收上传文件(图片)资源
(1) UploadConfig.java
package com.wanma.framework_web.config; /** * 上传文件配置 */ public interface UploadConfig { // 允许上传的文件类型 String[] imgTypes = new String[]{ "image/jpeg", "image/gif", "image/png" }; }
(2) CkeditorForm.java
编辑器默认会传2个参数到后端:ckCsrfToken 和 upload
package com.wanma.framework_web.widget.ckeditor; import lombok.Data; import org.springframework.web.multipart.MultipartFile; @Data public class CkeditorForm { private String ckCsrfToken; private MultipartFile upload; }
(3) CkeditorUploadController.java
package com.wanma.framework_web.widget.ckeditor; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.crypto.SecureUtil; import com.wanma.framework_web.config.UploadConfig; import com.wanma.framework_web.constant.UrlConst; import com.wanma.framework_web.controller.BaseController; import com.wanma.framework_web.entity.SysFile; import com.wanma.framework_web.entity.SysUserFile; import com.wanma.framework_web.service.ISysFileService; import com.wanma.framework_web.service.ISysUserFileService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; @Slf4j @Controller public class CkeditorUploadController extends BaseController { @Resource private ISysFileService iBaseFileService; @Resource private ISysUserFileService iUserFileService; /** * 上传 图片 */ @ResponseBody @RequestMapping(UrlConst.widget_ckeditor_uploadImage) public String uploadImage( Model model, @Value("${setting.uploadRootPath}") String uploadRootPath, // 上传文件保存路径 CkeditorForm ckeditorForm ) { try { // 创建根目录 if (!FileUtil.exist(uploadRootPath)) { FileUtil.mkdir(uploadRootPath); } // 检测文件类型,只能上传常用图片类型 String contentType = ckeditorForm.getUpload().getContentType(); if (!ArrayUtil.contains(UploadConfig.imgTypes, contentType)) { return """ { "uploaded": 0, "error": { "message": "只能上传常用类型的图片" } } """; } // 文件对象 MultipartFile file = ckeditorForm.getUpload(); // 扩展名 String fileName = file.getOriginalFilename(); String fileExt = FileUtil.extName(fileName); // 是否已存在 String md5 = SecureUtil.md5(file.getInputStream()); SysFile oldFile = this.iBaseFileService.getByMd5(md5); String fileUrl; int fileId; if (ObjectUtil.isEmpty(oldFile)) { // 保存文件 String saveName = md5 + "." + fileExt; String savePath = DateUtil.date().toString("yyyy/MM/dd"); String uploadDir = uploadRootPath + FileUtil.FILE_SEPARATOR + savePath; FileUtil.mkdir(uploadDir); String targeFilePath = uploadDir + FileUtil.FILE_SEPARATOR + saveName; FileUtil.writeBytes(file.getBytes(), targeFilePath); // 保存到数据库 SysFile baseFile = new SysFile(); baseFile.setName(file.getOriginalFilename()); baseFile.setType(file.getContentType()); baseFile.setExt(FileUtil.extName(file.getOriginalFilename())); baseFile.setSize(file.getSize()); baseFile.setMd5(md5); baseFile.setSavePath(savePath); baseFile.setSaveName(saveName); this.iBaseFileService.save(baseFile); fileUrl = "/" + savePath + "/" + saveName; fileId = baseFile.getId(); } else { fileId = oldFile.getId(); fileUrl = "/" + oldFile.getSavePath() + "/" + oldFile.getSaveName(); } // 插入 用户文件表 SysUserFile userFile = new SysUserFile(); userFile.setUserId(this.getLoginUserId(model)); userFile.setFileId(fileId); userFile.setFileName(file.getOriginalFilename()); userFile.setFileUrl(fileUrl); this.iUserFileService.save(userFile); return """ { "uploaded": 1, "fileName": "#fileName#", "url": "#fileUrl#" } """.replace("#fileName#", fileName) .replace("#fileUrl#", fileUrl); } catch (Exception e) { log.error("上传图片发生错误:" + e.getMessage()); return """ { "uploaded": 0, "error": { "message": "上传图片发生错误" } } """; } } }
【注意】
4.10版本之后,官方文档要求图片上传成功后,返回json格式,示例如下:
(1) 上传成功返回:
{ "uploaded": 1, "fileName": "demo.jpg", "url": "/files/demo.jpg" }
{ "uploaded": 1, "fileName": "test.jpg", "url": "/files/test.jpg", "error": { "message": "A file with the same name already exists. The uploaded file was renamed to \"test.jpg\"." } }
(2) 上传失败返回:
{ "uploaded": 0, "error": { "message": "The file is too big." } }