CKEditor, pasteBase64ToServer 플러그인 제작
CKEditor에 이미지를 복사 붙여넣기 할 경우
다음과 같이 이미지 태그에 주소가입력되어 삽입됩니다.
<img alt="Google" src="https://www.google.co.kr/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"/>
<br/>
<br/>
이렇게 타 서버의 이미지 주소를 삽입하게되면
추후 타 서버에서 이미지파일을 삭제할 경우 엑스박스를 보게 될 것입니다....?
<br/>
아마 이런 문제점을 다른 개발자들도 인지를 하고 있었고 <a href="https://ckeditor.com/cke4/addon/pastebase64" target="_blank">pasteBase64</a>라는 플러그인을 확인하였습니다.
해당 플러그인을 설치하면 이미지 태그에 서버 주소가 들어가는 것이 아니라, 이미지를 다음과 같이 base64로 인코딩되어 삽입됩니다.
<img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />
<br/>
<br/>
<br/>
하지만 여기서 작은 문제가 하나 발생합니다.
고용량의 이미지를 base64 형태로 인코딩하여 database에 삽입되는것은 상당히 무거운 작업입니다
SELECT할때도 무거운데이터를, UPDATE할때도 무거운데이터를 컨트롤하게 됩니다.
<br/>
방법을 찾아야겠습니다.
인코딩된 base64를 Ajax를 태워 바로 서버에 보내고, 본 서버의 URL을 받아 이미지 태그에 삽입하는 방법을 생각했습니다.
이렇게 구현하면 위의 두가지 문제점을 해결 할 수 있을 것입니다.! ?
<br/>
우선 기존에 있던 pasteBase64 플러그인의 소스크도를 확인하면, 클립보드에 있는 이미지파일을 걸러 base64로 인코딩하는 로직이 있습니다.
로직을 더하여 인코딩된 base64를 Ajax로 서버단으로 날려, 이미지파일로 저장하게 할 것입니다.
저장 후 이미지 URL을 받아, 이미지 태그에 주소를 담아 삽입하면 작업이 완료됩니다!
<br/>
코드의 일부를 보면 다음과 같습니다.
/*** -- ***/
/**************/
function onPaste(event) {
var editor = event.listenerData && event.listenerData.editor;
var $event = event.data.$;
var clipboardData = $event.clipboardData;
var found = false;
var imageType = /^image/;
if (!clipboardData) {
return;
}
return Array.prototype.forEach.call(clipboardData.types, function (type, i) {
if (found) {
return;
}
if (type.match(imageType) || clipboardData.items[i].type.match(imageType)) {
return readImageAsBase64(clipboardData.items[i], editor, clipboardData.items.length > 1);
}
});
}
function readImageAsBase64(item, editor, useWorkAround) {
if (!item || typeof item.getAsFile !== 'function') {
return;
}
if(editor.config.pasteImageUrl){
var c = confirm("이미지를 서버에 저장하시겠습니까?");
if(c){
var file = item.getAsFile();
var reader = new FileReader();
reader.onload = function (evt) {
var base64 = evt.target.result;
$.ajax({
type : "post",
url : editor.config.pasteImageUrl,
dataType: "JSON",
async : false,
data : {
"base64" : base64
},
success : function(result) {
var element = editor.document.createElement('img', {attributes: { src : result.path }});
setTimeout(function () {
if (useWorkAround) {
var img = editor.getSelection().getRanges()[0].getBoundaryNodes().endNode;
if (img.$.tagName !== "IMG") {
img = img.getPrevious();
}
if (img && img.$.tagName === "IMG") {
img.remove()
}
}
editor.insertElement(element);
}, 10);
return true;
}
});
}
reader.readAsDataURL(file);
} else{
return;
}
}
}
/*** -- ***/
/**************/
-
4 : 붙여넣기시 발생하는 콜백함수를 말합니다.
-
20 : 콜백함수가 호출되고 클립보드의 이미지파일을 확인하는 로직입니다.
-
21 : 이미지 파일을 base64로 인코딩하는 함수를 호출합니다.
-
32 : 이미지 파일을 서버에 저장할 것인지 확인받습니다. 아니라면 타서버 이미지 URL로 이미지태그를 생성 후 내용에 삽입됩니다.
-
37 : base64로 인코딩된 이미지파일입니다.
-
39 : Ajax를 이용하여 서버에 base64로 인코딩한 이미지파일을 저장합니다.
-
48 : Ajax로 받은 이미지URL로 이미지태그를 생성후 내용에 삽입합니다.
<br/>
<br/>
그럼 이제 Ajax를 받은 백엔드는 다음과 같습니다.
@ResponseBody
@RequestMapping(value = "/mgnt/imgBase64Upload.do")
public String blogDoImgUpload(HttpServletRequest request, String base64) throws IllegalStateException, IOException {
String path = commonService.saveContentImage(base64);
JSONObject result = new JSONObject();
result.put("path", path);
return result.toString();
}
-
3 : 파라미터로 base64 데이터를 받습니다.
-
4 : base64파일을 이미지 파일로 저장합니다.
-
8 : 저장한 경로를 반환합니다.
<br/>
<br/>
<hr/>
그럼 이제 결과를 확인해볼까요?
<br/>
<img src="https://static.podo-dev.com/blogs/images/2019/07/10/origin/YGFYGF181224235514.PNG" style="border-style:solid; border-width:1px"/>
클립보드의 이미지를 붙여넣기 하면 다음과 같이 서버에 저장할 것인지 확인받습니다.
<br/>
*** 확인을 누른경우**
<img src="/uploaded/temp/content_180713_160706_pasteImage.png"/>
<br/>
Ajax를 통해 본 서버에 업로드되었고 리턴받은 이미지 URL로 태그가 삽입됩니다.
<br/>
*** 취소를 누른경우**
<img alt="Google" src="https://www.google.co.kr/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"/>
<br/>
타 서버 URL로 이미지태그가 삽입됩니다.
<br/>
<br/>
추가작업
- Ckeditor, Ajax경로 설정
var editor = CKEDITOR.replace("study-contents", {
height : '400px',
filebrowserUploadUrl : getContextPath() + "/mgnt/imgUpload.do",
pasteImageUrl : getContextPath() + "/mgnt/imgBase64Upload.do",
on : {
instanceReady : function( ev ){
// Output paragraphs as Text
.
this.dataProcessor.writer.setRules( 'p', {
indent : false,
breakBeforeOpen : true,
breakAfterOpen : false,
breakBeforeClose : false,
breakAfterClose : true
});
}
},
toolbar : 'Full'
});
- 4 : 업로드 페이지에서 CKeditor 초기화 시, 해당 라인과 같이 Ajax 주소를 지정하도록 하였습니다.
<br/>
<br/>
- Server.xml의 maxPostSize 설정.
<Connector connectionTimeout="20000" maxPostSize="-1" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
- 1 : post 사이즈는 무제한이라고 알려져있는데 실제로 디폴트 값은 그렇지않습니다. 적절한 maxPostSize를 설정해줍니다.
<br/>
<br/>
- Ckeditor, config.js에 플러그인 추가.
config.extraPlugins = 'pastebase64toserver';
- 1 : 추가된 플러그인을 설정해줍니다.
<br/>
<br/>
<hr/>
다만 몇가지 한계점이 존재합니다.
-
해당 기능은 GIF 이미지 파일은 작동하지 않습니다.
-
클립보드에 텍스트 + 이미지파일을 복사하여 붙여넣기 하는 경우 작동하지 않습니다.
<br/>
<br/>
<br/>