参考文档: https://hc199421.gitee.io/vue-ueditor-wrap/#/home
1. 下载发布版本
上述版本前端没区别主要是后端对应不同版本, 随意下载一个版本即可,我这里下载的是ueditor1_4_3_3-utf8-jsp.zip
解压后如下图
将解压后的文件拷贝到vue项目中
在
vue-cli2
中我们放入的是static
文件夹,设置UEDITOR_HOME_URL
为/static/UEditor/
在vue-cli3
中放入的是public
文件夹,设置UEDITOR_HOME_URL
为/UEditor/
另外jsp文件夹下为后端内容,此处忽略未拷贝
2.安装vue-ueditor-wrap
npm install vue-ueditor-wrap --save
组件中引入,自定义组件
<template>
<vue-ueditor-wrap v-model="dataStr" mode="observer" :observer-options="observerOptions" :observer-debounce-time="50" :config="myConfig" ></vue-ueditor-wrap>
</template>
<script>
import VueUeditorWrap from 'vue-ueditor-wrap'
export default {
name: 'UEditor',
components: {
VueUeditorWrap,
},
data() {
return {
dataStr: '请输入内容',
observerOptions: {
attributes: true, // 是否监听 DOM 元素的属性变化
attributeFilter: ['src', 'style', 'type', 'name'], // 只有在该数组中的属性值的变化才会监听
characterData: true, // 是否监听文本节点
childList: true, // 是否监听子节点
subtree: true, // 是否监听后代元素
},
myConfig: {
toolbars: [[
'fullscreen', 'source', '|', 'undo', 'redo', '|',
'bold', 'italic', 'underline', 'fontborder', 'strikethrough', 'superscript', 'subscript', 'removeformat', 'formatmatch', 'autotypeset', 'blockquote', 'pasteplain', '|', 'forecolor', 'backcolor', 'insertorderedlist', 'insertunorderedlist', 'selectall', 'cleardoc', '|',
'rowspacingtop', 'rowspacingbottom', 'lineheight', '|',
'customstyle', 'paragraph', 'fontfamily', 'fontsize', '|',
'directionalityltr', 'directionalityrtl', 'indent', '|',
'justifyleft', 'justifycenter', 'justifyright', 'justifyjustify', '|', 'touppercase', 'tolowercase', '|',
'link', 'unlink', 'anchor', '|', 'imagenone', 'imageleft', 'imageright', 'imagecenter', '|',
'simpleupload', 'insertimage', 'emotion', 'scrawl', 'attachment', 'insertframe', 'insertcode', 'pagebreak', 'template', 'background', '|',
'horizontal', 'date', 'time', 'spechars', '|',
'inserttable', 'deletetable', 'insertparagraphbeforetable', 'insertrow', 'deleterow', 'insertcol', 'deletecol', 'mergecells', 'mergeright', 'mergedown', 'splittocells', 'splittorows', 'splittocols', 'charts', '|',
'print', 'preview', 'searchreplace', 'drafts', 'help'
]],
// 编辑器不自动被内容撑高
autoHeightEnabled: false,
// 初始容器高度
initialFrameHeight: 400,
// 初始容器宽度
initialFrameWidth: '100%',
// 上传文件接口(这个地址是我为了方便各位体验文件上传功能搭建的临时接口,请勿在生产环境使用!!!)
serverUrl: `${process.env.VUE_APP_BASE_API}/app-school/v1/public/index/api/admin/ueditor/`,
UEDITOR_HOME_URL:
process.env.NODE_ENV === 'development'
? '/static/ueditor/'
: `${process.env.VUE_APP_PUBLIC_PATH}static/ueditor/`,
},
}
},
watch: {
dataStr(val) {
console.log('watch dataStr',this.dataStr)
}
},
methods: {
handleUpdate(data) {
console.log('handleUpdate',data)
}
}
}
</script>
<style lang="less" scoped>
::v-deep .edui-default .edui-toolbar {
line-height: 20px;
.edui-combox .edui-combox-body,
.edui-button,
.edui-splitbutton,
.edui-menubutton {
line-height: 20px;
}
}
</style>
3.后端配置
/* 前后端通信相关的配置,注释只允许使用多行方式 */
{
/* 上传图片配置项 */
"imageActionName": "uploadimage", /* 执行上传图片的action名称 */
"imageFieldName": "upfile", /* 提交的图片表单名称 */
"imageMaxSize": 2048000, /* 上传大小限制,单位B */
"imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 上传图片格式显示 */
"imageCompressEnable": true, /* 是否压缩图片,默认是true */
"imageCompressBorder": 1600, /* 图片压缩最长边限制 */
"imageInsertAlign": "none", /* 插入的图片浮动方式 */
"imageUrlPrefix": "", /* 图片访问路径前缀 */
"imagePathFormat": "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
/* {filename} 会替换成原文件名,配置这项需要注意中文乱码问题 */
/* {rand:6} 会替换成随机数,后面的数字是随机数的位数 */
/* {time} 会替换成时间戳 */
/* {yyyy} 会替换成四位年份 */
/* {yy} 会替换成两位年份 */
/* {mm} 会替换成两位月份 */
/* {dd} 会替换成两位日期 */
/* {hh} 会替换成两位小时 */
/* {ii} 会替换成两位分钟 */
/* {ss} 会替换成两位秒 */
/* 非法字符 \ : * ? " < > | */
/* 具请体看线上文档: fex.baidu.com/ueditor/#use-format_upload_filename */
/* 涂鸦图片上传配置项 */
"scrawlActionName": "uploadscrawl", /* 执行上传涂鸦的action名称 */
"scrawlFieldName": "upfile", /* 提交的图片表单名称 */
"scrawlPathFormat": "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"scrawlMaxSize": 2048000, /* 上传大小限制,单位B */
"scrawlUrlPrefix": "", /* 图片访问路径前缀 */
"scrawlInsertAlign": "none",
/* 截图工具上传 */
"snapscreenActionName": "uploadimage", /* 执行上传截图的action名称 */
"snapscreenPathFormat": "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"snapscreenUrlPrefix": "", /* 图片访问路径前缀 */
"snapscreenInsertAlign": "none", /* 插入的图片浮动方式 */
/* 抓取远程图片配置 */
"catcherLocalDomain": ["127.0.0.1", "localhost", "img.baidu.com"],
"catcherActionName": "catchimage", /* 执行抓取远程图片的action名称 */
"catcherFieldName": "source", /* 提交的图片列表表单名称 */
"catcherPathFormat": "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"catcherUrlPrefix": "", /* 图片访问路径前缀 */
"catcherMaxSize": 2048000, /* 上传大小限制,单位B */
"catcherAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 抓取图片格式显示 */
/* 上传视频配置 */
"videoActionName": "uploadvideo", /* 执行上传视频的action名称 */
"videoFieldName": "upfile", /* 提交的视频表单名称 */
"videoPathFormat": "/ueditor/jsp/upload/video/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"videoUrlPrefix": "", /* 视频访问路径前缀 */
"videoMaxSize": 102400000, /* 上传大小限制,单位B,默认100MB */
"videoAllowFiles": [
".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid"], /* 上传视频格式显示 */
/* 上传文件配置 */
"fileActionName": "uploadfile", /* controller里,执行上传视频的action名称 */
"fileFieldName": "upfile", /* 提交的文件表单名称 */
"filePathFormat": "/ueditor/jsp/upload/file/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"fileUrlPrefix": "", /* 文件访问路径前缀 */
"fileMaxSize": 51200000, /* 上传大小限制,单位B,默认50MB */
"fileAllowFiles": [
".png", ".jpg", ".jpeg", ".gif", ".bmp",
".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
], /* 上传文件格式显示 */
/* 列出指定目录下的图片 */
"imageManagerActionName": "listimage", /* 执行图片管理的action名称 */
"imageManagerListPath": "/ueditor/jsp/upload/image/", /* 指定要列出图片的目录 */
"imageManagerListSize": 20, /* 每次列出文件数量 */
"imageManagerUrlPrefix": "", /* 图片访问路径前缀 */
"imageManagerInsertAlign": "none", /* 插入的图片浮动方式 */
"imageManagerAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 列出的文件类型 */
/* 列出指定目录下的文件 */
"fileManagerActionName": "listfile", /* 执行文件管理的action名称 */
"fileManagerListPath": "/ueditor/jsp/upload/file/", /* 指定要列出文件的目录 */
"fileManagerUrlPrefix": "", /* 文件访问路径前缀 */
"fileManagerListSize": 20, /* 每次列出文件数量 */
"fileManagerAllowFiles": [
".png", ".jpg", ".jpeg", ".gif", ".bmp",
".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
] /* 列出的文件类型 */
}
package com.huayun.bo.ioae.controller;
import com.alibaba.fastjson.JSONException;
import com.huayun.bo.ioae.controller.model.FileModel;
import com.huayun.bo.ioae.controller.model.FileVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
/**
* 百度Ueditor配置及文件上传支持
* @author liuyulei
* 2022/5/10 9:47
* @version 1.0
*/
@RestController()
@RequestMapping("/api/public/ueditor")
@Api(tags = "百度Ueditor配置及文件上传支持")
public class UeditorBaseController {
/**
* 配置内容常量,用于缓存配置信息,避免每次由硬盘读取
*/
private static String config;
@GetMapping(value = "/",produces = "application/javascript")
@ApiOperation(value = "获取ueditor配置")
@ApiImplicitParam(name = "callback", value = "jsonp的callback", required = true, dataType = "String")
public String config(String callback) throws JSONException {
return "/**/"+callback+"("+ getConfig() +");";
}
/**
* 文件上传<br>
* 接受POST请求<br>
* 同时支持多择文件上传和截图上传
* @param upfile 文件流
* @return
* @throws JSONException
* @throws IOException
*/
@PostMapping(value = "/")
@ApiOperation(value = "ueditor文件/图片上传")
public Map upload(MultipartFile upfile) throws JSONException, IOException {
Map result = new HashMap(16);
if (upfile != null && upfile.getOriginalFilename() != null) {
//文件类型
String contentType= upfile.getContentType();
//获取文件名称后缀
String ext = contentType.substring(contentType.lastIndexOf("/") + 1, contentType.length());
//if(!FileUtil.isAllowUpImg(ext)){
//
// result.put("state","不允许上传的文件格式,请上传gif,jpg,png,jpeg,mp4格式文件。");
// return result;
//
//}
FileModel input = new FileModel();
input.setName(upfile.getOriginalFilename());
input.setStream(upfile.getInputStream());
input.setExt(ext);
FileVO file = null;//this.fileManager.upload(input, "ueditor");
String url = file.getUrl();
String title = file.getName();
String original = file.getName();
result.put("state","SUCCESS");
result.put("url", url);
result.put("title", title);
result.put("name", title);
result.put("original", original);
result.put("type","."+file.getExt());
return result;
}else{
result.put("state","没有读取要上传的文件");
return result;
}
}
/**
* 获取配置<br>
* 如果config中已经存在,则直接返回,否则由硬盘读取<br>
* 读取文件为/resource/ueditor_config.json<br><br>
* @return
*/
private String getConfig() {
if (config == null || config.isEmpty()) {
config = readFile("/config/ueditor_config.json");
}
return config;
}
private String readFile(String resource) {
String stripped = resource.startsWith("/") ? resource.substring(1)
: resource;
InputStream stream = null;
ClassLoader classLoader = Thread.currentThread()
.getContextClassLoader();
if (classLoader != null) {
stream = classLoader.getResourceAsStream(stripped);
}
return readStreamToString(stream);
}
private String readStreamToString(InputStream stream) {
StringBuilder fileContentsb = new StringBuilder();
String fileContent = "";
try {
InputStreamReader read = new InputStreamReader(stream, "utf-8");
BufferedReader reader = new BufferedReader(read);
String line;
while ((line = reader.readLine()) != null) {
fileContentsb.append(line + "\n");
}
read.close();
reader.close();
fileContent = fileContentsb.toString();
} catch (Exception ex) {
fileContent = "";
}
return fileContent;
}
}
package com.huayun.bo.ioae.controller.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotEmpty;
import java.io.InputStream;
/**
* 文件上传入参
* @author liuyulei
* 2022/5/10 9:42
* @version 1.0
*/
@ApiModel
public class FileModel {
/**
* 文件流
*/
@ApiModelProperty(name = "stream", value = "文件流", required = true)
private InputStream stream;
/**
* 文件名称
*/
@NotEmpty(message = "文件名称不能为空")
@ApiModelProperty(name = "name", value = "文件名称", required = true)
private String name;
/**
* 文件后缀
*/
private String ext;
public InputStream getStream() {
return stream;
}
public void setStream(InputStream stream) {
this.stream = stream;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getExt() {
return ext;
}
public void setExt(String ext) {
this.ext = ext;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
FileModel fileDTO = (FileModel) o;
if (stream != null ? !stream.equals(fileDTO.stream) : fileDTO.stream != null) {
return false;
}
if (name != null ? !name.equals(fileDTO.name) : fileDTO.name != null) {
return false;
}
return ext != null ? ext.equals(fileDTO.ext) : fileDTO.ext == null;
}
@Override
public int hashCode() {
int result = stream != null ? stream.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (ext != null ? ext.hashCode() : 0);
return result;
}
}
package com.huayun.bo.ioae.controller.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* 文件上传返回值封装
* @author liuyulei
* 2022/5/10 9:47
* @version 1.0
*/
@ApiModel
public class FileVO {
/** 文件名称 */
@ApiModelProperty(name="name",value="文件名称",required=true)
private String name;
/** 文件后缀 */
@ApiModelProperty(name="ext",value="文件后缀",required=true)
private String ext;
/** url */
@ApiModelProperty(name="url",value="图片地址",required=true)
private String url;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "FileVO{" +
"name='" + name + '\'' +
", ext='" + ext + '\'' +
", url='" + url + '\'' +
'}';
}
public String getExt() {
return ext;
}
public void setExt(String ext) {
this.ext = ext;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
后端接口自行实现文件上传服务器,在
UeditorBaseController.java
中进行适配即可