前言
最近应上级要求,添加一个富文本编辑器,百度的Ueditor(主角来了);划重点2016年就停更了!
废话不多说,直接开始操作吧。
!!!建议看的时候仔细一点,因为很可能遗漏了某个地方就很抓狂!!!
相信你看完肯定会有收获的
1、先去GitHub
官网上下载Ueditor(点这里)
下载完成之后解压出来,一会要复制文件的
注意
:我这里直接开始导入操作,默认你会maven
,vue
,并且会使用IDEA工具
2、再下载一个jsp版本(我是用java写得)
此处也可以不下载,但是怕有童鞋整不明白,所以还是多下一个吧
第一个zip是整个源码,第二个是分离出来的,后面会涉及到修改源码
3、复制文件
1、将ueditor1_4_3_3-utf8-jsp
中的文件全部复制到 vue 项目的static
目录或者public
目录的 ueditor 文件夹下(自行创建),效果如图:
注:我的jsp文件夹已经删了,后面都移走了
2、将这个路径下ueditor-1.4.3.3\jsp\src\com\baidu\ueditor
中的文件全部复制到 springboot 工程当中
如图:
3、引入maven
将下面这4个jar包引入工程中
注:因为我们上面引入了源码,所以第5个jar包就不需要引入
<!--Ueditor-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>1.0.0</version>
</dependency>
这里上面 3 个可以直接通过 maven 引入,第 4 个可能会有问题
(没问题的略过~)
笔者这里是通过 mvn 命令引入的,如下:
mvn install:install-file -Dfile=D:\DEV\work\erp_server_v4\src\web\WEB-INF\lib\proxool-0.9.1.jar -DgroupId=proxool -DartifactId=proxool -Dversion=0.9.1 -Dpackaging=jar
4、编写 Ueditor 组件
创建组件引入下面的 css
和 js
文件
注:注意红色的框,引入的是
ueditor.all.js
,别问为什么,血泪史~~
压缩之后会有莫名其妙的问题,还是别用的好
还需要注意文件引用的路径,根据自己的项目结构而定
功能和参数都是因地制宜的,难度不大。下面直接附上源码:
<template>
<div>
<script :id="editorId" type="text/plain"></script>
</div>
</template>
<script>
import '../../../public/ueditor/ueditor.config.js'
import '../../../public/ueditor/ueditor.all.js'
import '../../../public/ueditor/ueditor.parse.js'
import '../../../public/ueditor/lang/zh-cn/zh-cn.js'
import '../../../public/ueditor/themes/default/css/ueditor.css'
export default {
name: 'UEditor',
props: {
/* 编辑器Id */
editorId: {
type: String,
default: '',
},
/* 编辑器的内容 */
value: {
type: String,
default: "",
},
/* 高度 */
height: {
type: Number,
default: 300,
}
},
data () {
return {
editor: null,
config: {
autoHeightEnabled: false,
initialFrameHeight: this.height,
initialFrameWidth: '100%',
UEDITOR_HOME_URL: '/ueditor/',
toolbars: [
[
'source', //源代码
'undo', //撤销
'redo', //重做
'bold', //加粗
'italic', //斜体
'underline', //下划线
'strikethrough', //删除线
'subscript', //下标
'superscript', //上标
'fontborder', //字符边框
'blockquote', //引用
'pasteplain', //纯文本粘贴模式
'preview', //预览
'horizontal', //分隔线
'removeformat', //清除格式
'time', //时间
'date', //日期
'cleardoc', //清空文档
'insertcode', //代码语言
'fontfamily', //字体
'fontsize', //字号
'paragraph', //段落格式
'insertimage', //多图上传
'edittd', //单元格属性
'inserttable', //插入表格
'deletetable', //删除表格
'link', //超链接
'emotion', //表情
'spechars', //特殊字符
'searchreplace', //查询替换
'justifyleft', //居左对齐
'justifyright', //居右对齐
'justifycenter', //居中对齐
'justifyjustify', //两端对齐
'forecolor', //字体颜色
'backcolor', //背景色
'insertorderedlist', //有序列表
'insertunorderedlist', //无序列表
'fullscreen', //全屏
'imagenone', //默认
'imageleft', //左浮动
'imageright', //右浮动
'attachment', //附件
'imagecenter', //居中
'wordimage', //图片转存
'lineheight', //行间距
'autotypeset', //自动排版
'touppercase', //字母大写
'tolowercase', //字母小写
]
]
}
}
},
mounted () {
/**
* 初始化编辑器,并设置值
*/
this.editor = UE.getEditor(this.editorId, this.config);
this.editor.addListener('ready', () => {
this.editor.setContent(this.value)
})
/**
* 监听编辑器,当编辑器中输入内容时与父组件进行同步
*/
this.editor.addListener("contentChange", () => {
this.$emit('input',this.editor.getContent())
})
},
methods: {
getUEContent () {
return this.editor.getContent()
},
setUEContent (value) {
return this.editor.setContent(value)
}
},
destroyed () {
this.editor.destroy()
}
}
</script>
这里提一嘴,创建每一个ueditor实例时一定要有不同的id,不然在同一个组件无法多次使用(害,该踩的坑让我来,一个都不少~)
5、写好另一个父组件引用我们刚刚完成的Ueditor
组件
这里不具体实现,朋友们自己动手啦~
此时成功的显示出来即可,注意还不能上传图像
6、(重点)开始配置图像上传功能
1、将 ueditor1_4_3_3-utf8-jsp/jsp 文件夹下的 config.json
文件复制到 springboot 项目下的 resources
文件夹下
2、在后台编写 UEditorController
来代替 controller.jsp
文件
@RestController
public class UEditorController {
@RequestMapping("/config")
public String exec(HttpServletRequest request,
HttpServletResponse response,
@RequestParam(value = "action") String action) throws Exception {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html");
String rootPath = request.getSession().getServletContext().getRealPath("/");
return new ActionEnter(request, rootPath).exec();
}
}
解释
:
controller.jsp 这个文件主要是用来获取
config.json
中的内容,并返回过去,因为富文本编辑器在初始化时会调接口来访问这个文件中的内容
所以你在baidu的时候会发现有很多不一样的版本,没关系,目的都一样
这里我们获取的路径还会有问题,因此我们还有修改源码
修改一:修改 ConfigManager.java
文件中的 getConfigPath()
方法
private String getConfigPath () {
// return this.parentPath + File.separator + ConfigManager.configFileName;
// 修改源码
try{
return this.getClass().getClassLoader().getResource("config.json").toURI().getPath();
} catch (URISyntaxException e) {
e.printStackTrace();
return null;
}
}
修改二:修改 BinaryUploader.java
文件中的 save()
方法(删除或注释掉)
public static final State save(HttpServletRequest request,
Map<String, Object> conf) {
if (!ServletFileUpload.isMultipartContent(request)) {
return new BaseState(false, AppInfo.NOT_MULTIPART_CONTENT);
}
try {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
MultipartFile multipartFile = multipartRequest.getFile(conf.get("fieldName").toString());
if (multipartFile == null) {
return new BaseState(false, AppInfo.NOTFOUND_UPLOAD_DATA);
}
String savePath = (String) conf.get("savePath");
String originFileName = multipartFile.getOriginalFilename();
String suffix = FileType.getSuffixByFilename(originFileName);
originFileName = originFileName.substring(0,
originFileName.length() - suffix.length());
savePath = savePath + suffix;
long maxSize = ((Long) conf.get("maxSize")).longValue();
if (!validType(suffix, (String[]) conf.get("allowFiles"))) {
return new BaseState(false, AppInfo.NOT_ALLOW_FILE_TYPE);
}
savePath = PathFormat.parse(savePath, originFileName);
String physicalPath = (String) conf.get("rootPath") + savePath;
InputStream is = multipartFile.getInputStream();
State storageState = StorageManager.saveFileByInputStream(is,
physicalPath, maxSize);
is.close();
if (storageState.isSuccess()) {
storageState.putInfo("url", PathFormat.format(savePath));
storageState.putInfo("type", suffix);
storageState.putInfo("original", originFileName + suffix);
}
return storageState;
} catch (IOException e) {
}
return new BaseState(false, AppInfo.IO_ERROR);
}
到这里启动工程访问http://localhost:8080/config?action=config应该能正常返回 config.json
中的内容了
如果访问不能正常返回的话,注意路径问题,
或者未知原因也有,其实里面bug挺多的,界面也过时了,但是耐不住人家功能强大…
修改三:修改 ueditor.all.js
文件
var configUrl = me.getActionUrl('config'),
// isJsonp = utils.isCrossDomainUrl(configUrl);
isJsonp = false;
ctrl+f 找到并注释掉它,再补上
isJsonp = false;
注意:
使用了security
的童鞋要放开链接访问权限
和相关的文件(资源)访问权限
(如png,jpg等等)
这一点对后面的测试也很重要,能少走很多弯路!!!
7、修改配置文件
1、修改 config.json
文件
也就是说再上传成功后,会调用 http://localhost:8081/image/upload/ueditor/{time}/{filename}
来显示在文本框里面
没理解也不要紧,接着往下看,后面实践了就恍然大悟了
2、修改 ueditor.config.js
文件
再把controller放过来对照
@RestController
public class UEditorController {
@RequestMapping("/config") //看这里!!!
public String exec(HttpServletRequest request,
HttpServletResponse response,
@RequestParam(value = "action") String action) throws Exception {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html");
String rootPath = request.getSession().getServletContext().getRealPath("/");
return new ActionEnter(request, rootPath).exec();
}
}
这里就是编辑器初始化时,向服务器发送请求读取
config.json
文件的配置
3、编写上传文件的controller
放在这里方便你拷贝~
@Autowired
private UEditorUpload uEditorUpload;
@RequestMapping("/config")
public String exec(HttpServletRequest request,
HttpServletResponse response,
@RequestParam(value = "action") String action,
@RequestParam(value = "upfile", required = false) MultipartFile upfile) throws Exception {
if (action.equals("config")) {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html");
String rootPath = request.getSession().getServletContext().getRealPath("/");
return new ActionEnter(request, rootPath).exec();
} else if (action.equals("uploadimage")) {
UEditorFile uEditorFile = uEditorUpload.uploadImage(upfile);
JSONObject jsonObject = new JSONObject(uEditorFile);
return jsonObject.toString();
}
return "无效Action";
}
4、补充注入方法和返回结果封装类(没错,不返回指定参数是用不了的!!)具体情况请看官网要求。
新建 UEditorUpload.java
源码如下:
(相信看到这里的朋友,有能力自己分析方法实现了上面,我偷懒去了)
private Logger log = LoggerFactory.getLogger(UEditorUpload.class);
private String path = ClassUtils.getDefaultClassLoader().getResource("").getPath();
public UEditorFile uploadImage(MultipartFile file) throws IOException {
log.info("UEditor开始上传文件");
String fileName = file.getOriginalFilename(); //获取文件名
//Ueditor的config.json规定的返回路径格式
String returnPath = "/image/upload/ueditor/"+new Date().getTime()+"/"+fileName;
File saveFile = new File(path+"static"+returnPath);
if (!saveFile.exists()){
saveFile.mkdirs();
}
file.transferTo(saveFile); //将临时文件移动到保存路径
log.info("UEditor上传文件成功,保存路径:"+saveFile.getAbsolutePath());
UEditorFile uEditorFile = new UEditorFile();
uEditorFile.setState("SUCCESS");
uEditorFile.setUrl(returnPath); //访问URL
uEditorFile.setTitle(fileName);
uEditorFile.setOriginal(fileName);
return uEditorFile;
}
String path = ClassUtils.getDefaultClassLoader().getResource("").getPath();
这是引用spring中的工具类来获取地址,有兴趣的话可以试试
getClass().getClassLoader().getResource(“文件”).toURI().getPath();
新建 UEditorFile.java
这个文件主要是按照上传文件返回格式而创建的,源码如下:
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class UEditorFile {
private static final long serialVersionUID=1L;
private String state;
private String url;
private String title;
private String original;
@Override
public String toString() {
return "{" +
"state='" + state + '\'' +
", url='" + url + '\'' +
", title='" + title + '\'' +
", original='" + original + '\'' +
'}';
}
}
整理到这里就可以去启动整个工程项目了
7、启动测试
ok的话就很nice,说明你成功了!
下面我总结一下我遇到的及其解决办法,由于已经写完了,错误截图就没有,后面找时间补上(求放过~)
1、读取不到 config.json 文件
1、检查读取路径是否正确,这个得自己一步步debug了
2、直接访问时记得带上参数action。。。(虽然时笨笨的问题,但是我发生了)
3、放开地址访问权限
4、检查文件是否被过滤
2、跨域问题可自行百度,方案挺多的
3、控制台显示http请求错误
1、认真检查配置文件路径
2、测试后端接口带上参数看看有没有问题
3、2
中可以的话,看看vue组件是不是用的ueditor.all.min.js
,改成ueditor.all.js
,(我就是这里离谱的问题!!!,估计时压缩后的问题)
4、能选择图片,(多图上传按钮下)点击上传后,后端能拿到数据,也存下来图片,但是编辑器显示http错误
或者 服务器端错误
1、检查路径…(没错,还是检查路径)
2、返回的数据类型要是string
类型的,或者说要json
的字符串
3、返回的字符串没按照官网要求,具体可以翻上面,我将了
5、上传成功了,但是编辑器不能正常显示
我这里报的是跨域的错,
但是其实不是的
,这种情况还有很多,前面也出现了!!!
我把静态文件访问路径放开
就能正常回显了,(我是需要认证的项目,不是demo~)
终于写完了,后续我在抽空写一个 demo
放到 gitee
上,可以参考自己理解后去写,更好一点
demo来了!!!点击这里
最后
感谢这位博主的分享@kshon,他的文章链接