接到这个需求的时候有点诧异和迷茫,后面经过自己的一步一步摸索终于实现了这个让人头疼的需求。客户需求:从第三方(秀米编辑器)复制粘贴图文保留图文样式,并且图片批量上传至本地文件夹,并在小程序端显示。前端是vue,后端是java语言。
这个功能是实现我试了3个富文本,分别是quillEditor,tinymce,vue-html5-editor。
最后用vue-html5-editor这个富文本实现了,vue-html5-editor富文本从第三方复制过来时可以保留第三方的所有样式,包括文字样式,图片样式。思路:复制过来图片批量上传是在后台(JAVA)进行处理的,后台可以直接用正则表达式截取网络图片或者Base64图片上传至本地文件夹然后显示在小程序端。
先介绍一下quillEditor这个富文本,quillEditor该富文本只能实现单个图片上传,从第三方复制黏贴过来上传无效,亲测。
tinymce可以使用powerpaste(收费)插件进行图片批量上传,但是我公司做的是一个小项目,老板也拒绝付费去购买该插件。网上其实也可以找到powerpaste插件,可以去网盘直接下载,但是又遇到问题从网盘下载的powerpaste(不收费插件)配Tinymce4.x就会很多地方不适应的地方,该版本的兼容性肯定不行,会导致图片复制过来是空白的问题,然后又放弃了这个富文本。
vue-html5-editor富文本虽然是个html5的富文本,但是从第三方复制过来的图文是可以保留样式的,然后百度搜索该富文本是否有批量上传图片的属性,根本没有找到,然后自己转换了想法,决定在前端点保存时把图片全部都都转成base64格式,转完之后存进数据库里发现数据量太大(5M,10M),在小程序端渲染速率太慢了。这个想法也放弃了。
最后灵机一动发现可以把网络图片或者bsae64的图片直接在后台进行上传。不多说了,上代码。
步骤一: 前端(vue):
在页面引入
<vue-html5-editor class="coursesuggest" :content="activityForm.activityContent" @change="updateData"></vue-html5-editor>
步骤二:在main.js引入
let opt = {
// 全局组件名称,使用new VueHtml5Editor(options)时该选项无效
name:"vue-html5-editor",
// 是否显示模块名称,开启的话会在工具栏的图标后台直接显示名称
showModuleName:true,
// 自定义各个图标的class,默认使用的是font-awesome提供的图标
icons: {
text:"fa fa-pencil",
color:"fa fa-paint-brush",
font:"fa fa-font",
align:"fa fa-align-justify",
list:"fa fa-list",
link:"fa fa-chain",
unlink:"fa fa-chain-broken",
tabulation:"fa fa-table",
image:"fa fa-file-image-o",
hr:"fa fa-minus",
eraser:"fa fa-eraser",
undo:"fa-undo fa",
"full-screen":"fa fa-arrows-alt",
info:"fa fa-info",
},
// 配置图片模块
image: {
// 文件最大体积,单位字节
sizeLimit:512 *1024 *10,
// 上传参数,默认把图片转为base64而不上传
// upload config,default null and convert image to base64
upload: {
// url: 'https://test.xiujianshen.com/media/upload',
url:null,
headers: {
},
params: {
},
fieldName:'file'
},
// 压缩参数,默认使用localResizeIMG进行压缩,设置为null禁止压缩
// width和height是文件的最大宽高
compress: {
width:300,
height:null,
quality:80
},
// 响应数据处理,最终返回图片链接
uploadHandler(responseText){
console.log(JSON.parse(responseText));
// default accept json data like {ok:false,msg:"unexpected"} or {ok:true,data:"image url"}
var json =JSON.parse(responseText);
if(json.code ==0){
return json.data;
}else{
alert(json.message)
}
}
},
// 语言,内建的有英文(en-us)和中文(zh-cn)
language:"zh-cn",
// 自定义语言
i18n: {
"zh-cn": {
"align":"对齐方式",
"image":"图片",
"list":"列表",
"link":"链接",
"unlink":"去除链接",
"table":"表格",
"font":"文字",
"full screen":"全屏",
"text":"排版",
"eraser":"格式清除",
"info":"关于",
"color":"颜色",
"please enter a url":"请输入地址",
"create link":"创建链接",
"bold":"加粗",
"italic":"倾斜",
"underline":"下划线",
"strike through":"删除线",
"subscript":"上标",
"superscript":"下标",
"heading":"标题",
"font name":"字体",
"font size":"文字大小",
"left justify":"左对齐",
"center justify":"居中",
"right justify":"右对齐",
"ordered list":"有序列表",
"unordered list":"无序列表",
"fore color":"前景色",
"background color":"背景色",
"row count":"行数",
"column count":"列数",
"save":"确定",
"upload":"上传",
"progress":"进度",
"unknown":"未知",
"please wait":"请稍等",
"error":"错误",
"abort":"中断",
"reset":"重置"
}
},
// 隐藏不想要显示出来的模块
hiddenModules: [],
// 自定义要显示的模块,并控制顺序
visibleModules: [
"text",
"color",
"font",
"align",
"list",
"link",
"unlink",
"tabulation",
"image",
"hr",
"eraser",
"undo",
"full-screen",
"info",
],
// 扩展模块,具体可以参考examples或查看源码
// extended modules
modules: {
//omit,reference to source code of build-in modules
}
};
Vue.use(VueHtml5Editor,opt);
步骤三:前台页面点提交后把富文本的全部数据都传到后台,后台代码如下
String regex ="src=['\"](.*?)['\"]";//正则表达式来匹配src属性
Pattern pattern = Pattern.compile(regex);//使用正则获取富文本里的所有图片
Matcher m = pattern.matcher(activity.getActivityContent());//传入富文本内容进行格式化
StringBuffer sb =new StringBuffer();//new一个StringBuffer
while( m.find())
{
String newUrl="";
String url = m.group(1);// 外链URL
//单个图片上传时是base64
if(url.indexOf("data") != -1){
//去掉base64字符串的开头部分
String base64Url = url.substring(url.indexOf(",")+1);
newUrl=GenerateImage(base64Url);
}
//复制上传是网络图片
else {
newUrl = richImage(url);// 本地化
}
String newSrc = String.format(" src='%s' ", newUrl);// 新的src属性
m.appendReplacement(sb, newSrc);// 替换回去
}
m.appendTail(sb);
String ActivityContent = sb.toString();//获取替换后的富文本
上面分别把base64的图片和网络图片上传到了本地,
base64上传代码如下
/**
* base64转图片上传至本地文件夹
* @param base64str base64码
* @return
*/
public String GenerateImage(String base64str)throws Exception{
BASE64Decoder decoder =new BASE64Decoder();
//Base64解码
byte[] b = decoder.decodeBuffer(base64str);
for (int i =0; i < b.length; ++i) {
//调整异常数据
if (b[i] <0) {
b[i] +=256;
}
}
int x = (int) (Math.random() *1000);
String filedata = dates();
SimpleDateFormat df =new SimpleDateFormat("yyyy-MM-dd");//设置日期格式
String date=df.format(new Date());
//new一个文件对象用来保存图片,默认保存当前工程根目录
String realPath = SpringConfig.fileRootPath + SpringConfig.activityEditorImage+date;
File imageFile =new File(realPath);
if (imageFile.exists()) {
}else {
imageFile.mkdir();
}
String realPath1 = SpringConfig.fileRootPath + SpringConfig.activityEditorImage + date+"/" + x + filedata +".jpeg";
//生成jpeg图片
OutputStream out =new FileOutputStream(realPath1);
out.write(b);
out.flush();
out.close();
//返回本地化后的图片路径 SpringConfig.fileRootWeb+
String outFielPath ="/static"+SpringConfig.activityEditorImage +"/"+ date+"/" + x + filedata +".jpeg";
return outFielPath;
}
网络图片上传代码如下:
/**
* 秀米图片转图片上传至本地文件夹
* @param imgOldUrl
* @return
*/
public String richImage(String imgOldUrl)throws Exception{
//new一个URL对象
URL url =new URL(imgOldUrl);
//打开链接
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
//设置请求方式为"GET"
conn.setRequestMethod("GET");
//超时响应时间为5秒
conn.setConnectTimeout(5 *1000);
//通过输入流获取图片数据
InputStream inStream = conn.getInputStream();
//得到图片的二进制数据,以二进制封装得到数据,具有通用性
byte[] data =this.readInputStream(inStream);
int x = (int) (Math.random() *1000);
String filedata = dates();
SimpleDateFormat df =new SimpleDateFormat("yyyy-MM-dd");//设置日期格式
String date=df.format(new Date());
//new一个文件对象用来保存图片,默认保存当前工程根目录
String realPath = SpringConfig.fileRootPath + SpringConfig.activityEditorImage+date;
File imageFile =new File(realPath);
if (imageFile.exists()) {
}else {
imageFile.mkdir();
}
String realPath1 = SpringConfig.fileRootPath + SpringConfig.activityEditorImage + date+"/" + x + filedata +".jpeg";
File imageFile1 =new File(realPath1);
//创建输出流
FileOutputStream outStream =new FileOutputStream(imageFile1);
//写入数据
outStream.write(data);
//关闭输出流
outStream.close();
//返回本地化后的图片路径 SpringConfig.fileRootWeb+
String outFielPath ="/static"+SpringConfig.activityEditorImage +"/"+ date+"/" + x + filedata +".jpeg";
return outFielPath;
}
public byte[] readInputStream(InputStream inStream)throws Exception{
ByteArrayOutputStream outStream =new ByteArrayOutputStream();
//创建一个Buffer字符串
byte[] buffer =new byte[1024];
//每次读取的字符串长度,如果为-1,代表全部读取完毕
int len =0;
//使用一个输入流从buffer里把数据读取出来
while( (len=inStream.read(buffer)) != -1 ){
//用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
outStream.write(buffer,0, len);
}
//关闭输入流
inStream.close();
//把outStream里的数据写入内存
return outStream.toByteArray();
}
以上步骤就分别把富文本的普通批量上传了,可以看到文件夹里有复制过来上传的大量图片
富文本批量上传的功能也就实现了,其实其他2个富文本也可以用后台上传图片的方式处理,只是这2个富文本实现不了保留第三方复制过来的图文的格式。所以我最终选择了vue-html5-editor。欢迎大家投稿,第一次写简书文档,菜鸟程序员飞真顺献上。V:yqf822547775