(2020最新版)SpringBoot+Ueditor+themleaf+fastDFS问题记录及处理

前言:之前做了很多富文本编辑器的工作,不过都是以前了,最近项目突然要加富文本编辑器。心想那就加嘛,没想到springboot整合ueditor这么多坑,一个一个淌过来足足用了整整一天时间。趁着记忆力还算充足赶紧记录一下。

一、ueditor引入SpringBoot
首先请准备进入这个浑水的请务必注意,百度富文本编辑器已经4年没有更新过了。如果不是项目必须要用,你完全可以选择市面上仍在维护的编辑器。
那么开始正常的引入流程:
(1)官网下载适合的版本,这里我选择的是JSP版本(2020最新版)SpringBoot+Ueditor+themleaf+fastDFS问题记录及处理_第1张图片
下载后解压缩,是一个如此结构的目录
(2020最新版)SpringBoot+Ueditor+themleaf+fastDFS问题记录及处理_第2张图片

我们将这部分代码直接复制到项目中的静态文件目录下,我这里的目录是这样的
(2020最新版)SpringBoot+Ueditor+themleaf+fastDFS问题记录及处理_第3张图片

导入maven依赖及相关的文件引入
ueditor的jar包存放在jsp/lib目录下,自己maven进去即可
(2020最新版)SpringBoot+Ueditor+themleaf+fastDFS问题记录及处理_第4张图片
相关的maven依赖:(这里ueditor和json包我没在中央仓库下载,而是手动cmd mvn引入的,所以实际依赖可能会和我的不一样,请自行选择,效果是一样的)

        <!-- 引入富文本编辑器依赖 -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.10</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
         <dependency>
            <groupId>com.baidu</groupId>
            <artifactId>ueditor</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>1.0</version>
        </dependency>

在相关页面用themleaf引入对应的JS

    <script th:src="@{/ueditor/ueditor.config.js}"></script>
    <script th:src="@{/ueditor/ueditor.all.min.js}"></script>
    <script th:src="@{/ueditor/lang/zh-cn/zh-cn.js}"></script>

这里请务必注意引入顺序,config.js必须在all.min.js上面,让ueditor先加载相关配置项,不然会JS报错,富文本编辑器初始化失败。
(3)在页面初始化富文本编辑器
html:
在这里插入图片描述
JS:

//初始化富文本编辑器
var ue = UE.getEditor("editor");

至此,项目引入富文本编辑器第一步就完成了。
打开对应的页面,出现如图
(2020最新版)SpringBoot+Ueditor+themleaf+fastDFS问题记录及处理_第5张图片
二、ueditor的图片、附件、视频等相关的配置与结合fastDFS
完成了上面步骤后,富文本编辑器自己已经可以运转了,但附件上传功能还是坏的。
会提示后端配置不正确,上传插件不能使用。
这里ueditor会读取ueditor.config.js中的配置
在这里插入图片描述
而JSP中只是个跳转,最终找到的是config.json,这里面是全部富文本编辑器上传所需要的配置项
(2020最新版)SpringBoot+Ueditor+themleaf+fastDFS问题记录及处理_第6张图片
但是这里有两个问题,
一个是config.json在这个目录下是读取不到的,为此我们需要把它移动到statics目录下,
第二个是config.json读取加载完毕后会走ueditor内置的BinaryUploader文件上传。
这里由于springboot默认配置原因,springboot与BinaryUploader内置的方法冲突,所以用它自带的上传方法是拿不到文件流的,会不停的报未找到上传数据的错误。

三、ueditor重写,并整合进fastDFS

于是为了拿到上传数据,以及整合fastDFS,我们需要重写这部分代码。
首先干掉controller.jsp和config.json,这里我们完全不需要ueditor内置的上传方法了,
新建一个ueditor的controller



import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;




/**
 * @author deer_boom
 * @version 1.0
 * @date 2020年7月27日
 */
@RequestMapping("ueditor")
@RestController
public class UEditorController {

    @RequestMapping("/Config")
    public String uploadConfig() {
        String s = "/* 前后端通信相关的配置,注释只允许使用多行方式 */\n" +
                "{\n" +
                "    /* 上传图片配置项 */\n" +
                "    \"imageActionName\": \"uploadimage\", /* 执行上传图片的action名称 */\n" +
                "    \"imageFieldName\": \"upfile\", /* 提交的图片表单名称 */\n" +
                "    \"imageMaxSize\": 2048000, /* 上传大小限制,单位B */\n" +
                "    \"imageAllowFiles\": [\".png\", \".jpg\", \".jpeg\", \".gif\", \".bmp\"], /* 上传图片格式显示 */\n" +
                "    \"imageCompressEnable\": true, /* 是否压缩图片,默认是true */\n" +
                "    \"imageCompressBorder\": 1600, /* 图片压缩最长边限制 */\n" +
                "    \"imageInsertAlign\": \"none\", /* 插入的图片浮动方式 */\n" +
                "    \"imageUrlPrefix\": \"\", /* 图片访问路径前缀 */\n" +
                "    \"imagePathFormat\": \"/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}\", /* 上传保存路径,可以自定义保存路径和文件名格式 */\n" +
                "                                /* {filename} 会替换成原文件名,配置这项需要注意中文乱码问题 */\n" +
                "                                /* {rand:6} 会替换成随机数,后面的数字是随机数的位数 */\n" +
                "                                /* {time} 会替换成时间戳 */\n" +
                "                                /* {yyyy} 会替换成四位年份 */\n" +
                "                                /* {yy} 会替换成两位年份 */\n" +
                "                                /* {mm} 会替换成两位月份 */\n" +
                "                                /* {dd} 会替换成两位日期 */\n" +
                "                                /* {hh} 会替换成两位小时 */\n" +
                "                                /* {ii} 会替换成两位分钟 */\n" +
                "                                /* {ss} 会替换成两位秒 */\n" +
                "                                /* 非法字符 \\ : * ? \" < > | */\n" +
                "                                /* 具请体看线上文档: fex.baidu.com/ueditor/#use-format_upload_filename */\n" +
                "\n" +
                "    /* 涂鸦图片上传配置项 */\n" +
                "    \"scrawlActionName\": \"uploadscrawl\", /* 执行上传涂鸦的action名称 */\n" +
                "    \"scrawlFieldName\": \"upfile\", /* 提交的图片表单名称 */\n" +
                "    \"scrawlPathFormat\": \"/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}\", /* 上传保存路径,可以自定义保存路径和文件名格式 */\n" +
                "    \"scrawlMaxSize\": 2048000, /* 上传大小限制,单位B */\n" +
                "    \"scrawlUrlPrefix\": \"\", /* 图片访问路径前缀 */\n" +
                "    \"scrawlInsertAlign\": \"none\",\n" +
                "\n" +
                "    /* 截图工具上传 */\n" +
                "    \"snapscreenActionName\": \"uploadimage\", /* 执行上传截图的action名称 */\n" +
                "    \"snapscreenPathFormat\": \"/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}\", /* 上传保存路径,可以自定义保存路径和文件名格式 */\n" +
                "    \"snapscreenUrlPrefix\": \"\", /* 图片访问路径前缀 */\n" +
                "    \"snapscreenInsertAlign\": \"none\", /* 插入的图片浮动方式 */\n" +
                "\n" +
                "    /* 抓取远程图片配置 */\n" +
                "    \"catcherLocalDomain\": [\"127.0.0.1\", \"localhost\", \"img.baidu.com\"],\n" +
                "    \"catcherActionName\": \"catchimage\", /* 执行抓取远程图片的action名称 */\n" +
                "    \"catcherFieldName\": \"source\", /* 提交的图片列表表单名称 */\n" +
                "    \"catcherPathFormat\": \"/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}\", /* 上传保存路径,可以自定义保存路径和文件名格式 */\n" +
                "    \"catcherUrlPrefix\": \"\", /* 图片访问路径前缀 */\n" +
                "    \"catcherMaxSize\": 2048000, /* 上传大小限制,单位B */\n" +
                "    \"catcherAllowFiles\": [\".png\", \".jpg\", \".jpeg\", \".gif\", \".bmp\"], /* 抓取图片格式显示 */\n" +
                "\n" +
                "    /* 上传视频配置 */\n" +
                "    \"videoActionName\": \"uploadvideo\", /* 执行上传视频的action名称 */\n" +
                "    \"videoFieldName\": \"upfile\", /* 提交的视频表单名称 */\n" +
                "    \"videoPathFormat\": \"/ueditor/jsp/upload/video/{yyyy}{mm}{dd}/{time}{rand:6}\", /* 上传保存路径,可以自定义保存路径和文件名格式 */\n" +
                "    \"videoUrlPrefix\": \"\", /* 视频访问路径前缀 */\n" +
                "    \"videoMaxSize\": 102400000, /* 上传大小限制,单位B,默认100MB */\n" +
                "    \"videoAllowFiles\": [\n" +
                "        \".flv\", \".swf\", \".mkv\", \".avi\", \".rm\", \".rmvb\", \".mpeg\", \".mpg\",\n" +
                "        \".ogg\", \".ogv\", \".mov\", \".wmv\", \".mp4\", \".webm\", \".mp3\", \".wav\", \".mid\"], /* 上传视频格式显示 */\n" +
                "\n" +
                "    /* 上传文件配置 */\n" +
                "    \"fileActionName\": \"uploadfile\", /* controller里,执行上传视频的action名称 */\n" +
                "    \"fileFieldName\": \"upfile\", /* 提交的文件表单名称 */\n" +
                "    \"filePathFormat\": \"/ueditor/jsp/upload/file/{yyyy}{mm}{dd}/{time}{rand:6}\", /* 上传保存路径,可以自定义保存路径和文件名格式 */\n" +
                "    \"fileUrlPrefix\": \"\", /* 文件访问路径前缀 */\n" +
                "    \"fileMaxSize\": 51200000, /* 上传大小限制,单位B,默认50MB */\n" +
                "    \"fileAllowFiles\": [\n" +
                "        \".png\", \".jpg\", \".jpeg\", \".gif\", \".bmp\",\n" +
                "        \".flv\", \".swf\", \".mkv\", \".avi\", \".rm\", \".rmvb\", \".mpeg\", \".mpg\",\n" +
                "        \".ogg\", \".ogv\", \".mov\", \".wmv\", \".mp4\", \".webm\", \".mp3\", \".wav\", \".mid\",\n" +
                "        \".rar\", \".zip\", \".tar\", \".gz\", \".7z\", \".bz2\", \".cab\", \".iso\",\n" +
                "        \".doc\", \".docx\", \".xls\", \".xlsx\", \".ppt\", \".pptx\", \".pdf\", \".txt\", \".md\", \".xml\"\n" +
                "    ], /* 上传文件格式显示 */\n" +
                "\n" +
                "    /* 列出指定目录下的图片 */\n" +
                "    \"imageManagerActionName\": \"listimage\", /* 执行图片管理的action名称 */\n" +
                "    \"imageManagerListPath\": \"/ueditor/jsp/upload/image/\", /* 指定要列出图片的目录 */\n" +
                "    \"imageManagerListSize\": 20, /* 每次列出文件数量 */\n" +
                "    \"imageManagerUrlPrefix\": \"\", /* 图片访问路径前缀 */\n" +
                "    \"imageManagerInsertAlign\": \"none\", /* 插入的图片浮动方式 */\n" +
                "    \"imageManagerAllowFiles\": [\".png\", \".jpg\", \".jpeg\", \".gif\", \".bmp\"], /* 列出的文件类型 */\n" +
                "\n" +
                "    /* 列出指定目录下的文件 */\n" +
                "    \"fileManagerActionName\": \"listfile\", /* 执行文件管理的action名称 */\n" +
                "    \"fileManagerListPath\": \"/ueditor/jsp/upload/file/\", /* 指定要列出文件的目录 */\n" +
                "    \"fileManagerUrlPrefix\": \"\", /* 文件访问路径前缀 */\n" +
                "    \"fileManagerListSize\": 20, /* 每次列出文件数量 */\n" +
                "    \"fileManagerAllowFiles\": [\n" +
                "        \".png\", \".jpg\", \".jpeg\", \".gif\", \".bmp\",\n" +
                "        \".flv\", \".swf\", \".mkv\", \".avi\", \".rm\", \".rmvb\", \".mpeg\", \".mpg\",\n" +
                "        \".ogg\", \".ogv\", \".mov\", \".wmv\", \".mp4\", \".webm\", \".mp3\", \".wav\", \".mid\",\n" +
                "        \".rar\", \".zip\", \".tar\", \".gz\", \".7z\", \".bz2\", \".cab\", \".iso\",\n" +
                "        \".doc\", \".docx\", \".xls\", \".xlsx\", \".ppt\", \".pptx\", \".pdf\", \".txt\", \".md\", \".xml\"\n" +
                "    ] /* 列出的文件类型 */\n" +
                "\n" +
                "}";
        return s;
    }

}

这里我们在controller中,直接把ueditor需要的配置项拼接字符串直接返回。
这样可以瞒过ueditor,上传方法就可以用了。
然后在页面上传的JS中,重写文件上传的路径
这个在网络上到处都是,可以直接复制

    UE.Editor.prototype.getActionUrl = function(action) {
        if (action == 'uploadimage' || action == 'uploadfile') {
            return parent.parent.webPath + 'notice/upload';
        } else {
            return this._bkGetActionUrl.call(this, action);
        }
    }

注意此处,uploadimage代表的是图片上传,uploadfile代表的是文件上传,如果你的业务需要视频,也可以在条件里自己加上。
此时来到上传方法

    /**
     * 富文本附件上传的方法(包括图片、附件)
     * @date 2020年7月27日
     * @author deer_boom
     * @param file
     * @return java.util.Map
     */
    @ResponseBody
    @RequestMapping("/upload")
    public Map upload(@RequestParam(value = "upfile") MultipartFile file) {
        RetBean retBean = new RetBean();
        try {
            String fileFullName = file.getOriginalFilename();
            String extName = fileFullName.split("\\.")[1];
            byte[] bytes = null;
            bytes = file.getBytes();
            String filePath = FastDFSClientUtils.upload(bytes, extName);
            String id = StringUtils.getUUID();
            String time = StringUtils.getDateTime();
            long fileSize = file.getSize();
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileName(fileFullName);
            fileInfo.setFilePath(filePath);
            fileInfo.setId(id);
            fileInfo.setFileTime(time);
            fileInfo.setFileSuffix(extName);
            int code = archiveNoticeService.savaFile(fileInfo);
            if (code > 0) {
                retBean.setFileInfo(fileInfo);
                retBean.setMessage("SUCCESS");
                retBean.setCode("0");
                //给ueditor的回调参数
                Map<String ,Object> result = Maps.newHashMap();
                result.put("state","SUCCESS");
                result.put("original",extName);
                result.put("size",fileSize);
                result.put("title",fileFullName);
                result.put("type",bytes);
                result.put("url", "downLoad?id=" + id);
                return result;
            } else {
                retBean.setMessage("ERROR");
                retBean.setCode("1");
            }
        } catch (IOException e) {
            retBean.setMessage("UPLOAD FILE ERROR");
            retBean.setCode("1");
        }
        return null;
    }

这里需要注意的是需要手动用map给ueditor返回它需要的格式

				//给ueditor的回调参数
                Map<String ,Object> result = Maps.newHashMap();
                result.put("state","SUCCESS");
                result.put("original",extName);
                result.put("size",fileSize);
                result.put("title",fileFullName);
                result.put("type",bytes);
                result.put("url", "downLoad?id=" + id);

URL为fastDFS获取图片的方法
这里需要注意的问题有:
1、Springboot获取不到文件流,MultipartFile一直是null
这个原因有俩,一个是springboot自带的org.springframework.web.multipart.MultipartFile和Multipart冲突。
为此需要自己添加配置到启动项

@Configuration
public class UploadConfig {
    @Bean(name = "multipartResolver")
    public MultipartResolver multipartResolver() {
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setDefaultEncoding("UTF-8");
        //resolveLazily属性启用是为了推迟文件解析,以在在UploadAction中捕获文件大小异常
        resolver.setResolveLazily(true);
        resolver.setMaxInMemorySize(40960);
        //上传文件大小 5M 5*1024*1024
        resolver.setMaxUploadSize(5 * 1024 * 1024);
        return resolver;
    }
}

2、请重新回头查看刚才拼接的ueditorController,里面写了上传表单名
在这里插入图片描述
这里请务必与后台接收名对应好,在这里插入图片描述
(2020最新版)SpringBoot+Ueditor+themleaf+fastDFS问题记录及处理_第7张图片

至此,附件上传成功,但是回显还是有问题
(2020最新版)SpringBoot+Ueditor+themleaf+fastDFS问题记录及处理_第8张图片
来简单看一下现在图片的src:
在这里插入图片描述

为此需要我们在手动拼的url对应中,写从fastDFS中获取图片的方法

    @ResponseBody
    @RequestMapping("/downLoad")
    public void downLoad(@RequestParam(value = "id") String id, HttpServletResponse response) throws IOException {
        PrintWriter writer = response.getWriter();
        FileInfo fileInfo = archiveNoticeService.fileInfoById(id);
        String fileName = fileInfo.getFileName();
        String filePath = fileInfo.getFilePath();
        try {
            String group = filePath.split("/")[0];
            InputStream inStream = FastDFSClientUtils.download(group, fileInfo.getFilePath());
            // 设置输出的格式
            response.reset();

            response.setContentType("application/octet-stream");//设置文件类型

            response.addHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName, "UTF-8") + "\"");
            // 循环取出流中的数据
            byte[] b = IOUtils.toByteArray(inStream);
            response.getOutputStream().write(b);
            response.flushBuffer();
            inStream.close();
            response.getOutputStream().close();
        } catch (Exception e) {
            writer.println("Download failure!");
            e.printStackTrace();
        }
    }

重新尝试:回显成功!(2020最新版)SpringBoot+Ueditor+themleaf+fastDFS问题记录及处理_第9张图片

但是此时保存后还是有问题的,因为ueditor和springboot相关配置的XSS注入拦截,会在新增时传参的时候,把img标签里的src过滤掉,导致回显src缺失没图没文件,为此我们需要做两手解决:
1、ueditor的解决:在ueditor中直接将XSS拦截关闭,统一改成false
(2020最新版)SpringBoot+Ueditor+themleaf+fastDFS问题记录及处理_第10张图片
担心这样会出现注入问题的话,可以在ueditor.all.js和ueditor.all.min.js中干掉img的判断

(2020最新版)SpringBoot+Ueditor+themleaf+fastDFS问题记录及处理_第11张图片

					case 'img':
                        //todo base64暂时去掉,后边做远程图片上传后,干掉这个
                        /*if (val = node.getAttr('src')) {
                            if (/^data:/.test(val)) {
                                node.parentNode.removeChild(node);
                                break;
                            }
                        }
                        node.setAttr('_src', node.getAttr('src'));*/
                        break;

第二步,如果你的Springboot项目也配置了XSS拦截,那么需要将对应的字符串转义即可,这个根据你自己实际业务随时引入,我把有用的JS都放上了,noticeContent就是你后台传过来的富文本内容

noticeContent = html2Escape(noticeContent);
//特殊字符转义
function html2Escape(sHtml) {
    return sHtml.replace(/[<>&"]/g,function(c){
        return {'<':'<','>':'>','&':'&','"':'"'}[c];
    });
}

由于涉及到了转义,所以请记得回显的时候反转义回来,

	noticeContent = escape2Html(noticeContent);
	console.log("转义前::"+noticeContent);
	ue.setContent(noticeContent);

//特殊字符反转义
function escape2Html(str) {
    var arrEntities={'lt':'<','gt':'>','nbsp':' ','amp':'&','quot':'"'};
    return str.replace(/&(lt|gt|nbsp|amp|quot);/ig,function(all,t){
        return arrEntities[t];
    });
}

这样,富文本内回显也没有问题了。

此时新增、修改的上传与回显都是正常的。但是作为一个富文本管理功能,必然有一个专门的展示页,所以回显富文本也是有问题的,不过很简单,稍做记录:
themleaf使用th:text回显会导致页面不渲染,所以这里请使用th:utext回显,就可以正常加载了

<div id="noticeContent" th:utext="${noticeMap.NOTICE_CONTENT}"></div>

至此,SpringBoot+Ueditor+themleaf+fastDFS都全都弄好了,功能正常可以使用。

结尾:我自己水平不高,因为这个东西着实头疼了我一天,而且网上很多方法又碎又不好用,一个问题可能需要三篇博客结合看才能解决问题,所以分享出来权当帮大家伙踩坑,有什么问题可以留言。

你可能感兴趣的:(java踩过的坑,java,html)