目前有一个需求,需要在页面中获取QQ、微信等软件的截图上传到服务器,为了用户体验,不能让用户主动上传,提供给用户方法,在web页面使用粘贴快捷键,就可以粘贴到页面,然后点击发送进行上传。而且用户如果粘贴的是文字也需要能正常发送文字内容。
这个需求需要分为四个部分:
1、构造页面,存放获取的数据
2、获取粘贴板中的内容
3、在页面展示获取的内容
4、将获取的图片内容发送到服务器存储
首先看第一部分,构造页面,这里省去其他部分,主要介绍这个功能,因此只需要在body标签中存在两个div,一个存储展示的图片,一个用于输入文字。在默认情况下可以输入文字,因此这时展示图片的div是隐藏状态,具体代码如下:
<body>
<div id="jietuWrap" class="b1" style="display:none;">
<img id="jietuImg" src="">
<br />
<button class="sendBtn" onclick="send_msg()">发送</button>
</div>
<div class="b1">
<textarea id="dope" class="newtextarea"
style="width: 99%; border: none; outline: none; resize: none; font-size: 15px; color: black;" onkeydown="suball()"></textarea>
<br />
<button class="sendBtn" onclick="send_msg()">发送</button>
</div>
</body>
然后是第二、三部分,获取粘贴板的内容并展示,可以通过window对象的子对象clipboardData对象获取,其中保存了复制、剪切、粘贴的内容,这里只需要用到粘贴部分。ClipboardEvent对象中就包含了clipboardData对象,我们在监听到粘贴事件时,就可以获取到ClipboardEvent,然后获取到clipboardData对象,它是一个DataTransfer类型的对象,DataTransfer是拖动产生的一个对象,但实际上粘贴事件也是它:
从其中可以看到,data就是获取到的clipboardData对象对象,具体内容如下:
dropEffect: "none"
effectAllowed: "uninitialized"
files: FileList {length: 0}
items: DataTransferItemList
0: DataTransferItem
kind: "file"
type: "image/png"
__proto__: DataTransferItem
getAsFile: ƒ getAsFile()
getAsString: ƒ getAsString()
kind: (...)
type: (...)
webkitGetAsEntry: ƒ webkitGetAsEntry()
constructor: ƒ DataTransferItem()
Symbol(Symbol.toStringTag): "DataTransferItem"
get kind: ƒ ()
get type: ƒ ()
__proto__: Object
length: 1
__proto__: DataTransferItemList
types: ["Files"]
__proto__: DataTransfer
这是获取粘贴板的内容,所以最主要用到的是items对象,items是一个DataTransferItemList对象,里面是DataTransferItem类型的数据。items的DataTransferItem有两个属性kind和type:
kind | String或者file |
type | 具体的数据类型,比如字符串类型或者是文件的类型,即MIME-TYPE |
比如这里的例子中kind就是file,type是image/png。
还要用到一个方法来获取具体的文件或字符串的内容,即示例中的getAsFile()和getAsString()方法,从名字就可以看出来获取图片等文件就用getAsFile(),获取字符串就用getAsString()。
上面的例子就可以通过var blob=data.items[0].getAsFile();来获取图片内容。然后获取图片的base64流,通过ajax就可以上传到服务器。
下面列出第一部分,获取剪切板中的内容的代码:
//绑定粘贴事件 Ctrl+V
bindPaste();
//绑定粘贴事件
function bindPaste(){
//定义变量存储获取的图片内容
var blob;
//获取body对象
var body = document.getElementsByTagName("body");
//定义body标签绑定的粘贴事件处理函数
var fun=function(e){
//获取clipboardData对象
var data=e.clipboardData||window.clipboardData;
//获取图片内容
blob=data.items[0].getAsFile();
//判断是不是图片,最好通过文件类型判断
var isImg=(blob&&1)||-1;
var reader=new FileReader();
if(isImg>=0){
//将文件读取为 DataURL
reader.readAsDataURL(blob);
}
//文件读取完成时触发
reader.onload=function(event){
//获取base64流
var base64_str=event.target.result;
//div中的img标签src属性赋值,可以直接展示图片
$("#jietuImg").attr("src",base64_str);
//显示div
$("#jietuWrap").css("display","block");
//隐藏输入文字的div
$("#jietuWrap").next().css("display","none");
}
}
//通过body标签绑定粘贴事件,注意有些标签绑定粘贴事件可能出错
body[0].removeEventListener('paste',fun);
body[0].addEventListener('paste',fun);
}
最后就是将获取的图片的base64流通过ajax发送到服务器存储到资源服务器了,前端ajax大致如下:
// 上传的数据除了图片外,还可以包含自己需要传递的参数
var data = {
userId : $('#userId').val(),
base64 : savedPictureContent
};
$.ajax({
type : "POST",
url : "${ctx}/../jsp/fileInfo/sendPrintScreen.action",
dataType : "json",
data : data,
success : function(data) {
var res = data.result;
if (!res) {
alert("上传失败!");
} else {
alert("上传成功!");
}
},
error : function() {
alert("由于网络原因,上传失败。");
}
});
后端处理代码:
/**
* base64图片上传(截图)
*/
@RequestMapping("/sendPrintScreen")
public void sendPrintScreen(String userId,String base64){
if (StringUtils.isNotEmpty(base64))
{
if (base64.contains("base64,"))
{
base64=base64.substring(base64.indexOf("base64,")+7);
}
}
MultipartFile sendFile=BASE64DecodedMultipartFile.base64ToMultipartFile(base64);
//上传文件的工具类
this.sendFileUtil(sendFile userId);
}
注意后台获取base64流时必须要从字符串"base64, "后面开始截取,否则存储的图片会有问题。
最新测试发现,只可以获取到复制的QQ、微信、文件内的图片,如果是文件夹内保存的图片文件,复制之后是获取不到的。但是既然这种文件可以复制到比如Word中,应该也是通过剪切板获取的,这里却获取不到,没有想出原因是什么,不知道有没有人知道原因。。