1.问题描述:
- quill自带的图片上传是base64,直接存入数据库的话,在多图片时可能会有溢出风险。所以改用ajax发送formData自定义图片上传
2.原理流程
通过自定义一个input上传图片,在onchagne时发送ajax请求,后台写入之后返回url到前端,插入显示
3.自定义图片上传具体代码
要注意quill的版本,有些人就是版本不对然后效果出不来,可以去quill官网找最新的cdn链接https://quilljs.com/
前端代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>Quill</title>
<link href="https://cdn.bootcss.com/quill/2.0.0-dev.3/quill.snow.css" rel="stylesheet">
<link href="https://cdn.bootcss.com/quill/2.0.0-dev.3/quill.bubble.css" rel="stylesheet">
<style>
body {
padding: 10px 30px;
}
#editor {
min-height: 180px;
}
</style>
</head>
<body>
<div>jjsjsj</div>
<!--存放富文本div-->
<div id="editor" class="showContent">
<!--回显的内容-->
<!--可以直接在指定元素内加入文本或者html标签-->
</div>
<!-- 单图片上传:this.files[0] 图片列表的第0项,也就是当前选择的图片 -->
<input type="file" onchange="updateImg(this.files[0])" id="imgData" style="display: none;">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<script src="//cdn.quilljs.com/1.3.6/quill.js"></script>
<script src="https://cdn.bootcss.com/quill/2.0.0-dev.3/quill.js"></script>
<script>
var quill;
$(function() {
/* 编辑器操作条选项 */
var toolbarOptions = [
['bold', 'italic', 'underline', 'strike'], //加粗、倾斜、下划线、删除线
[{'align': []}], //内容对齐方式:左对齐、右对齐、居中、平行
[{'color': []}, {'background': []}], //字体颜色、文本的背景色
['image'], //图片上传
['clean'], //清除格式
[{'header': 1}, {'header': 2}], //标题H1 H2
[{'list': 'ordered'}, {'list': 'bullet'}], //数据列表
[{'script': 'sub'}, {'script': 'super'}], // 上标、下标
[{'indent': '-1'}, {'indent': '+1'}], // 缩进、减少缩进
[{'size': ['small', false, 'large', 'huge']}], // 自定义下拉:字体的样式....跟加粗差不多
[{'header': [1, 2, 3, 4, 5, 6, false]}], //标题 H1 H2 H3......
[{'direction': 'rtl'}], // 文本方向
[{'font': []}],
['blockquote', 'code-block']
// ['video'], //视频上传
// ['formula'] //需要加载cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/katex.min.js
];
/**
* 初始化富文本,绑定一个div: div id为editor
*/
quill = new Quill('#editor', {
modules: {
toolbar: toolbarOptions //指定编辑器操作条
},
theme: 'snow', //主题,有两种,snow和bubble,一般都是使用snow
placeholder: '请输入内容....',
readOnly: false
});
//修改样式
var Align = Quill.import('attributors/style/align');
Align.whitelist = ['right', 'center', 'justify'];
Quill.register(Align, true);
/* 传入布尔值,控制编辑器是否可用 */
quill.enable();
//quill.blur(); //失去焦点
//quill.focus(); //获得焦点
/**
* 自定义上传图片第二步
*
* 通过addHander监听点击控件事件:image事件
*/
var toolbar = quill.getModule('toolbar');
toolbar.addHandler('image',function () {
$('#imgData').click();
});
});
/**
* 自定义上传图片第三步
*
* 图片上传接口
*/
function updateImg(file) {
var formData = new FormData();
formData.append('file', file);
$.ajax({
url: '/uploadPhoto', //url
type: 'post', //以post发送
data: formData, //要发送的数据。后端接收$_POST['user']
dataType: 'json', //返回的数据类型
cache: false,
traditional: true,
contentType: false,
processData: false,
success: function (res) {
/*console.log(res);*/
//图片上传成功之后的回调
const range = quill.getSelection();
if (range) {
//将上传好的图片,插入到富文本的range.index(当前光标处)
quill.insertEmbed(range.index, 'image', "" + res.src);
}
},
error: function (e) {
console.log(e);
}
});
}
/**
* 获取富文本内容方法(提交)
*/
function submitData() {
res = quill.container.firstChild.innerHTML; //获取当前富文本编辑器实例的内容(带html标签)
console.log(res); //获取当前富文本编辑器实例的内容(带html标签)
};
</script>
</body>
</html>
后端代码,使用java,下面展示上传图片的controller
@RequestMapping("/uploadPhoto")
@ResponseBody
public Map<String,String> testQuestion(@RequestParam MultipartFile file){
Map<String,String> data = new HashMap<>();
OutputStream os = null;
InputStream inputStream = null;
String fileName = System.currentTimeMillis() + ".jpg";
String userUrl = savePath+fileName;
try {
inputStream = photo.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
try {
byte[] bs = new byte[1024];
int len;
// 输出的文件流保存到本地文件
File tempFile = new File(writePath);
if (!tempFile.exists()) {
tempFile.mkdirs();
}
os = new FileOutputStream(tempFile.getPath() + File.separator + fileName);
// 开始读取
while ((len = inputStream.read(bs)) != -1) {
os.write(bs, 0, len);
}
os.flush();
data.put("src", userUrl);
return data;
}
4.自定义视频上传
其实自定义上传视频和上传图片是一个样的,原理都是写入文件后,回传url
前端
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>Quill</title>
<link href="https://cdn.bootcss.com/quill/2.0.0-dev.3/quill.snow.css" rel="stylesheet">
<link href="https://cdn.bootcss.com/quill/2.0.0-dev.3/quill.bubble.css" rel="stylesheet">
<style>
body {
padding: 10px 30px;
}
#editor {
min-height: 180px;
}
</style>
</head>
<body>
<div>jjsjsj</div>
<!--存放富文本div-->
<div id="editor" class="showContent">
<!--回显的内容-->
<!--可以直接在指定元素内加入文本或者html标签-->
</div>
<!-- 单图片上传:this.files[0] 图片列表的第0项,也就是当前选择的图片 -->
<input type="file" onchange="updateImg(this.files[0])" id="imgData" style="display: none;">
<!--用来上传图片的input-->
<input type="file" onchange="uploadVideo(this.files[0])" id="uploadVideo" style="display:none" >
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<script src="//cdn.quilljs.com/1.3.6/quill.js"></script>
<script src="https://cdn.bootcss.com/quill/2.0.0-dev.3/quill.js"></script>
<script>
var quill;
$(function() {
/* 编辑器操作条选项 */
var toolbarOptions = [
['bold', 'italic', 'underline', 'strike'], //加粗、倾斜、下划线、删除线
[{'align': []}], //内容对齐方式:左对齐、右对齐、居中、平行
[{'color': []}, {'background': []}], //字体颜色、文本的背景色
['image'], //图片上传
['clean'], //清除格式
[{'header': 1}, {'header': 2}], //标题H1 H2
[{'list': 'ordered'}, {'list': 'bullet'}], //数据列表
[{'script': 'sub'}, {'script': 'super'}], // 上标、下标
[{'indent': '-1'}, {'indent': '+1'}], // 缩进、减少缩进
[{'size': ['small', false, 'large', 'huge']}], // 自定义下拉:字体的样式....跟加粗差不多
[{'header': [1, 2, 3, 4, 5, 6, false]}], //标题 H1 H2 H3......
[{'direction': 'rtl'}], // 文本方向
[{'font': []}],
['blockquote', 'code-block']
['video'], //视频上传
// ['formula'] //需要加载cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/katex.min.js
];
/**
* 初始化富文本,绑定一个div: div id为editor
*/
quill = new Quill('#editor', {
modules: {
toolbar: toolbarOptions //指定编辑器操作条
},
theme: 'snow', //主题,有两种,snow和bubble,一般都是使用snow
placeholder: '请输入内容....',
readOnly: false
});
//修改样式
var Align = Quill.import('attributors/style/align');
Align.whitelist = ['right', 'center', 'justify'];
Quill.register(Align, true);
/* 传入布尔值,控制编辑器是否可用 */
quill.enable();
//quill.blur(); //失去焦点
//quill.focus(); //获得焦点
/**
* 自定义上传图片第二步
*
* 通过addHander监听点击控件事件:image事件
*/
var toolbar = quill.getModule('toolbar');
toolbar.addHandler('image',function () {
$('#imgData').click();
});
});
/**
* 自定义上传图片第三步
*
* 图片上传接口
*/
function updateImg(file) {
var formData = new FormData();
formData.append('file', file);
$.ajax({
url: '/uploadPhoto', //url
type: 'post', //以post发送
data: formData, //要发送的数据。后端接收$_POST['user']
dataType: 'json', //返回的数据类型
cache: false,
traditional: true,
contentType: false,
processData: false,
success: function (res) {
/*console.log(res);*/
//图片上传成功之后的回调
const range = quill.getSelection();
if (range) {
//将上传好的图片,插入到富文本的range.index(当前光标处)
quill.insertEmbed(range.index, 'image', "" + res.src);
}
},
error: function (e) {
console.log(e);
}
});
}
/**
* 获取富文本内容方法(提交)
*/
function submitData() {
res = quill.container.firstChild.innerHTML; //获取当前富文本编辑器实例的内容(带html标签)
console.log(res); //获取当前富文本编辑器实例的内容(带html标签)
};
/**
* 自定义上传视频,仅mp4格式
*
* 视频上传接口
*/
function uploadVideo(file) {
var formData = new FormData();
formData.append('file', file);
$.ajax({
url: '/uploadVideo', //url
type: 'post', //以post发送
data: formData, //要发送的数据。后端接收$_POST['user']
dataType: 'json', //返回的数据类型
cache: false,
traditional: true,
contentType: false,
processData: false,
success: function (res) {
/*console.log(res);*/
//图片上传成功之后的回调
const range = quill.getSelection();
if (range) {
//将上传好的图片,插入到富文本的range.index(当前光标处)
quill.insertEmbed(range.index, 'video', "" + res.src);
}
},
error: function (e) {
$.alert({
title: 'Error',
content: data.msg,
});
}
});
}
</script>
</body>
</html>
上传视频后端,这里笔者主要是通过文件的后缀名判断文件格式,因为这个视频需要有关联关系,要将其路径写入数据库,
所以会有数据库写入操作,如果大家没有这个需求的话可以把对应的代码删掉。
@RequestMapping("/uploadVideo")
@ResponseBody
public Map<String,String> upload(@RequestParam MultipartFile file, HttpServletRequest request){
Integer user = (Integer) request.getSession().getAttribute("userId");
Long userId = user.longValue();
Map<String,String> data = new HashMap<>();
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
if ( suffix.equalsIgnoreCase("mp4") ){
OutputStream os = null;
InputStream inputStream = null;
Long articleId = publishArticleService.whetherCreateArticle(userId);
String fileName = ("video" + articleId) + System.currentTimeMillis() + "." + suffix;
String videoUrl = articleSavePath + fileName; //articleSavePath 代表/article/,写入数据库中的相对路径
try {
inputStream = file.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
try {
byte[] bs = new byte[1024];
int len;
// 输出的文件流保存到本地文件
File tempFile = new File(articleWritePath); //articleWritePath代表"F:\\images\\article"
if (!tempFile.exists()) {
tempFile.mkdirs();
}
os = new FileOutputStream(tempFile.getPath() + File.separator + fileName);
// 开始读取
while ((len = inputStream.read(bs)) != -1) {
os.write(bs, 0, len);
}
os.flush();
articlePhotoService.insertVideo(videoUrl, articleId);
data.put("src", videoUrl);
return data;
} catch (IOException e) {
e.printStackTrace();
data.put("msg","上传视频失败,请稍后重试!");
return data;
} catch (Exception e) {
e.printStackTrace();
data.put("msg","上传视频失败,请稍后重试!");
return data;
} finally {
// 完毕,关闭所有链接
try {
os.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}else {
data.put("msg","上传视频格式仅支持mp4!"); //可以上传什么格式,可以自定义判断
return data;
}
}
最终效果: