개발자의 오르막

Tinymce & SpringBoot 웹 및 모바일 게시판 에디터 파일업로드 본문

Trouble Shouting

Tinymce & SpringBoot 웹 및 모바일 게시판 에디터 파일업로드

계단 2020. 2. 24. 18:42

 

 

* 프레임워크 : SpringBoot + Thymeleaf

 

이번 프로젝트를 하면서 가장 애먹었던 부분중 하나이다. 웹용 에디터는 무리없이 잘 적용시켰지만

모바일용 에디터에서는 Custom 버튼이 적용이 되지 않아 애를 많이 먹었다.

 

 

TinyMCE 는 Base64를 기반으로 이미지를 지원해준다. 대부분 에디터가 파일 이미지를

Base64로 인코딩하는 방식을 채택하는데, 이는 사용자의 파일 업로드 로직에 의존하지 않고

오직 에디터 라이브러리만으로 이미지를 올리기 위함이다.

 

 

그러나 단점은 화질이 높은 이미지일수록 이미지 src 태그에 엄청나게 많은 인코딩이 써지게 된다.

이런 경우 화면 로드자체가 느려져 게시물의 수정 화면 및 기능 자체가 작동이 안되게 된다.

 

 

- Base64로 저장할 때의 이미지 태그

<img src="blob:http://localhost:8088/99fcbaf2-5a33-4a8e-a96b-64c5016f5b52">

 

- 에디터에 이미지를 불러올 때 src 주소

 

따라서 이 문제를 해결하기 위해 우리는 TinyMCE 에 내장된 Base64 기준의 파일업로드가 아닌

우리 자체적인 파일 업로드 로직을 연동시켜야 한다.

 

이 연동은 TinyMCE.js 에서 진행 할 수 있다.

 

 


 

# 웹 파일업로드 ( custom Button )

var tinyEditor = tinymce.init({
        selector: "."+option.target,
        min_height: 500,
        max_height: 1000,
        menubar: false,
        paste_as_text: true,
        fullpage_default_font_size: "14px",
        branding: false,
        plugins: "autolink code link autoresize paste contextmenu image preview",
        toolbar: "undo redo | fontsizeselect | forecolor | bold italic strikethrough underline | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link custom_image | code preview",
        fontsize_formats: '10px 12px 14px 16px 18px 20px 22px 24px 28px 32px 36px 48px',
        setup: function(editor) {
            editor.ui.registry.addButton('custom_image', {
                icon: 'image',
                tooltip: 'insert Image',
                onAction: function () {
                    documentUpload({
                        multiple: false,
                        accept: '.jpg, .png',
                        callback: function (data) {
                            if (data.rs_st === 0) {
                                var fileInfo = data.rs_data;
                                tinymce.execCommand('mceInsertContent', false,
                                    /**
                                     "<img src='" + fileInfo.fullPath + "' data-mce-src='" + fileInfo.fullPath + "' data-originalFileName='" + fileInfo.orgFilename + "' >");
                                     **/
                                    "<img src='" + fileInfo.thumbnailPath + "' data-mce-src='" + fileInfo.thumbnailPath + "' data-originalFileName='" + fileInfo.orgFilename + "' >");
                            }
                        }
                    });
                }
            });
        }
    });
};

 

파일 업로드는 바로 setup 이란 옵션에서 진행할 수 있다.

이 옵션은 게시판에디터가 있는 화면에 들어올 때 바로 실행되는 이벤트인데,  custom Button 을 등록하면

해당 버튼을 등록할 때 발생하는 이벤트를 우리가 정할 수 있다.

 

onAction : function 아래 있는 documentUpload 이벤트 함수가 프로젝트 자체 파일업로드 함수이며,

tinymce.execCommand('mceInsertContent', false, <img>) 를 통해 게시판 에디터에 들어갈 이미지의

주소와 data-mce-src 를 바꿀 수 있다.

 

* data-mce-src 는 게시판 에디터를 수정할 때 게시판 에디터가 이미지를 불러오는 경로이다. 

 

 


# 모바일 파일 업로드 ( images_upload_handler )

 

var tinimceInit = function (options) {

    var option = {
        target: 'tiny-editor'
    };

    $.extend(options, option);

    var tinyEditor = tinymce.init({
        selector: "."+option.target,
        min_height: 500,
        max_height: 1000,
        menubar: false,
        paste_as_text: true,
        fullpage_default_font_size: "14px",
        branding: false,
        plugins: "autolink code link autoresize paste contextmenu image preview",
        toolbar: "undo redo | fontsizeselect | forecolor | bold italic strikethrough underline | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link custom_image | code preview",
        fontsize_formats: '10px 12px 14px 16px 18px 20px 22px 24px 28px 32px 36px 48px',
        mobile: {
            theme: 'mobile',
            menubar: true,
            plugins: 'autosave | lists | autolink | image code',
            toolbar: 'undo | redo | bold | italic | underline | link | unlink | image | fontsizeselect | forecolor',
            relative_urls: false,
            remove_script_host: false,
            images_upload_handler: function (blobInfo, success, failure) {
                // console.log(blobInfo.blob());

                // 파일데이터를 가져와서, 업로드 시키고, 변경된 url 로 바꾸면 된다.

                mobileUpload(blobInfo.blob(), {
                    callback: function(data) {
                        if (data.rs_st === 0) {
                            var fileInfo = data.rs_data;
                            success(fileInfo.thumbnailPath);
                        }
                    }
                });
            }
        }
    });
};

 

 모바일 테마에서 파일 업로드가 가장 힘들었다.

 웹에서 적용되는 customButton 과 file_picker 등 이벤트를 지원하지 않는다.

 따라서 우리는 기존의 tinymce 이미지 업로드 이벤트를 컨트롤 해야 한다.

 

 이때 images_upload_handler 의 옵션 중 blobInfo, success 파라미터 값이 가장 중요했다.

 blobInfo.blob() 은 바로 이미지를 업로드한 파일 정보이다.

 success 는 파일 업로드를 성공했을 때 이미지 src를 변경할 수 있는 값이다.

 remove_script_host, relative_urls 를 false 로 옵션을 설정해주어야 data-mce-src 가 이미지의 src와 동일하게

 설정된다.

 

 

 - blobInfo.blob() 파일 정보를 컨트롤러에 보내는 자바스크립트 이벤트

function mobileUpload(formData, options) {

    var $form = $("form[name='multipartFileUpload']");
    var $formMobile = $form[0];

    var mobileData = new FormData($formMobile);
    mobileData.append("mobileData", formData);

    $.ajax({
        type: "POST",
        enctype: 'multipart/form-data',
        url: "/file/upload/mobile",
        data: mobileData,
        processData: false,
        contentType: false,
        cache: false,
        timeout: 600000,
        success: function (data) {
            // console.log("SUCCESS : ", data);
            if (typeof(options.callback) === 'function') options.callback(data, options);
        },
        error: function (e) {
            // console.log("ERROR : ", e);
        }
    });
}

 

 - 데이터를 받아주는 컨트롤러

@PostMapping("upload/mobile")
@ResponseBody
public void upload(HttpServletResponse response,
		@RequestParam(value = "identity", required = false) String identity,
		@RequestParam(value = "mobileData", required = false) MultipartFile[] mobileData,
		@RequestParam(value = "position", required = false, defaultValue="0") int position) throws Exception {
}

 위 컨트롤러처럼 mobileData 를 MultipartFile[] 형식으로 받으면 파일 업로드를 진행할 수 있다.

 

 컨트롤러에서 받은 정보를 자바스크립트에서 콜백으로 돌려준 다음 successs 를 통해 이미지의 src를 바꿔주면 된다.

 

 


 

Tinymce 는 무료 오픈소스 라이브러리이다. 그리고 웹버전과 모바일버전을 따로 구분하여 지원해준다.

웹 버전에서는 Custom Button 기능을 지원하여 우리가 원하는 버튼을 만들고 이벤트를 걸 수 있다.

전세계적으로 많이 쓰는 추세이다.

 

 

# Tinymce 설치하기

- TinyMCE 설치하기 포스팅은 이후 자세하게 진행하도록 하겠다.

- https://www.tiny.cloud/get-tiny/

 

Download WYSIWYG HTML Editor | TinyMCE

Download TinyMCE for free, the most advanced WYSIWYG HTML editor designed to simplify website content creation.

www.tiny.cloud

 먼저 TinyMCE 홈페이지에 들어가서 설치 및 사용방법을 본다.

 tinyMCE 내장 라이브러리는 프로젝트의 lib 폴더에 위치시키고, tinyMCE.js 를 공통 js에 위치시킨다.

 

 그리고 TinyMCE 에디터를 적용시킬 화면에서 아래와 같은 스크립트들을 연결시켜준다.

<script src="/static/js/lib/tinymce/tinymce.min.js" th:src="@{/js/lib/tinymce/tinymce.min.js}"></script>
<script src="/static/js/tinyMCE.js" th:src="@{/js/tinyMCE.js}"></script>

화면에서 적용시킬 Textarea 태그에 tiny-editor 클래스를 입력해준다. 이는 js에서 명시할 이름과

동일하게 맞춰야 한다.

<textarea name="description" class="tiny-editor"></textarea>

 

그리고 해당 화면의 스크립트 부분에서, 로딩할 때 target 을 선언해주면 tinyMCE 가 적용된다.

var onReady = function() {
    tinimceInit({target: 'tiny-editor'});
};

# TinyMCE Web 에디터 적용하기

 

- TinyMCE.JS 

var tinimceInit = function (options) {

    var option = {
        target: 'tiny-editor'
    };

    $.extend(options, option);

    var tinyEditor = tinymce.init({
        selector: "."+option.target,
        min_height: 500,
        max_height: 1000,
        menubar: false,
        paste_as_text: true,
        fullpage_default_font_size: "14px",
        branding: false,
        plugins: "autolink code link autoresize paste contextmenu image preview",
        toolbar: "undo redo | fontsizeselect | forecolor | bold italic strikethrough underline | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link custom_image | code preview",
        fontsize_formats: '10px 12px 14px 16px 18px 20px 22px 24px 28px 32px 36px 48px',
        mobile: {
            theme: 'mobile',
            menubar: true,
            plugins: 'autosave | lists | autolink | image code',
            toolbar: 'undo | redo | bold | italic | underline | link | unlink | image | fontsizeselect | forecolor',
        }
    });
};

 먼저 options 에서 해당 target 의 이름을 적용시키자 했던 화면의 textarea class와 일치시켜줘야 한다.

 그리고 selector 를 통해 연결시켜준다. 쓰고자 하는 플러그인과 메뉴는 옵션을 통해 설정한다.

 

https://www.tiny.cloud/docs/demo/basic-example/

 

TinyMCE | Basic example

This example contains the plugins needed for the most common use cases.

www.tiny.cloud

 기본적인 옵션 설정은 위의 링크에서 친절하게 안내되어 있음으로 참고하길 바란다.

 

 

 

 

 

Comments