Clipboard的使用和CKEditor在编辑框粘贴截图并上传(Java版)

近来需要完成一个在文本编辑框中直接粘贴截图的功能。但是发现现有的CKEditor并不能做到。但是发现知乎,还有CSDN本身,都能直接在编辑框中直接Ctrl+V将图片粘贴上。所以,有实现的地方,就有相应的技术。后面再回去看新浪微博,支持得刚好,Ctrl+V还会弹个框出来。这次结合了好多网友的回答和文章,结合之后完成了自己想要的功能。


粘贴图片到文本框雏形。

首先是在知乎上受到Clipboard的启发。知乎回答问题编辑框用 Ctrl+V 粘贴图片是如何实现的?

发现了大体的思路。参照其中的一个回答,修改之后再写一个demo。是简单的textarea实现粘贴截图还有html的功能。



	test chrome paste image




	

test image paste in browser

copy the following img, then paste it into the area below


getAsString方法可以参照 Clipboard object, is there a way to capture pasted text?


用Java后台接收参数并保存图片到本地

这边的原理好多东西自己查找大量资料,发现主要是webapi这块很薄弱。

1、如何将文件发送请求处理。

这里通过ajax请求。不过首先,我们要先了解一下。FormData是什么?

现在blog为getAsFile方法返回,为File对象。


FormData介绍:

https://developer.mozilla.org/zh-CN/docs/Web/API/FormData


普通的Ajax请求代码,这是一篇博客里面写的,具体出处忘了开了太多东西了:

var createStandardXHR = function () {
    try {
        return new window.XMLHttpRequest();
    } catch (e) {
        return false;
    }
};
var createActiveXHR = function () {
    try {
        return new window.ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) {
        return false;
    }
};

var xhr;

function createXHR() {
    var temp = createStandardXHR() || createActiveXHR();
    if (window.XDomainRequest === undefined) {
        return temp;
    } else {
        return new XDomainRequest();
    }
}

function uploadImg(obj) {
    xhr = createXHR();
    var fd = new FormData();
    fd.append("image", obj, "test.png");
    xhr.open('POST', 'xx.action', true);
    xhr.send(fd);
}

上面的例子页面,加上uploadImg(blob);即可。


再来看看FormData的方法介绍:

append()  给当前FormData对象添加一个键/值对.
void append(DOMString name, Blob value, optional DOMString filename);
void append(DOMString name, DOMString value);
参数值
name 字段名称.
value 字段值.可以是,或者一个字符串,如果全都不是,则该值会被自动转换成字符串.
filename
(可选) 指定文件的文件名,当value参数被指定为一个Blob对象或者一个File对象时,该文件名会被发送到服务器上,对于Blob对象来说,这个值默认为"blob"。


上述普通的ajax方法比较复杂,引入jQuery的js文件,使用封装方法就简单很多了。

 var fd = new FormData();
 fd.append("image", blob,"a.png");
 $.ajax({
  type: 'POST',
  url: 'xx.action',
  data: fd,
    processData: false,
    contentType: false
 })


最后两个参数一定要设: https://developer.mozilla.org/zh-CN/docs/Web/Guide/Using_FormData_Objects
不让jquery处理数据和修改请求头。不然直接普通的ajax请求,会报Uncaught TypeError: Illegal invocation 错误。


2、后台接收,通过Struts2来获取请求的参数。

public String upload() throws Exception {
	ActionContext context=ActionContext.getContext();    
    Map parameterMap=context.getParameters(); 
    Set s = parameterMap.keySet();
    for (Object object : s) {
		System.out.println(object);
		System.out.println(parameterMap.get(object));
	}
    
    String filename =((String[])parameterMap.get("imageFileName"))[0] ;
    System.out.println(((String[]) parameterMap.get("imageContentType"))[0]);
    System.out.println(filename);
    File f = ((File[]) parameterMap.get("image"))[0];
    BufferedImage image = ImageIO.read(f);
    ImageIO.write(image, "png", new File("e:\\test.png"));
    return "ok";
}


输出
image
[Ljava.io.File;@3b382278
imageContentType
[Ljava.lang.String;@625f12a7
imageFileName
[Ljava.lang.String;@4fc1c465
image/png
a.png

这里文件都获取到了,具体想保存在服务器还是本地,接下来就好办多了。之前是卡在了这步上面。

这里有东西是需要注意的,如果File f = ((File) parameterMap.get("image")); 这样的强制转换是异常的。

原因是类型为Ljava.io.File,而不是java.io.File。


区别是什么呢?

[Ljava.io.File;是 File[].class的名字,java.io.File表示的File.class。所以需要类型转换是将其转换File数组对象。


CKEditor添加该功能

到CKEditor添加该功能的时候,我就被卡死了一次。

CKEditor相当于一个内嵌iframe,然后上面的document.getElementById('editable').innerHTML这种方式获取修改内容就做不到了。


多亏看了这位仁兄的做法:Ckeditor and ckfinder 配置实现截图上传图片到远程服务器

然后成功地让CKEditor能够顺利的粘贴到截图,后续发现同事用的CKEditor,只要配置一下东西就有这个功能了。囧。


不过刚开始整个原理没有弄清楚。现在终于把这些FileReader等对象的方法给理顺了。


//instances是保存editor实例的引用
var editor = CKEDITOR.instances["Editor"];
//如果存在,则销毁。
if (editor2) {editor2.destroy(true)};
//用 CKEditor实例替换