从第三方(秀米编辑器)复制粘贴图文,图片上传至本地文件夹,并在小程序端显示

        接到这个需求的时候有点诧异和迷茫,后面经过自己的一步一步摸索终于实现了这个让人头疼的需求。客户需求:从第三方(秀米编辑器)复制粘贴图文保留图文样式,并且图片批量上传至本地文件夹,并在小程序端显示。前端是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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342