본문 바로가기
Projects/NodeBoard

Summernote 에디터 적용, imgbb 서버로 게시글 이미지 업로드

by DawIT 2021. 4. 29.
320x100

글 에디터는 기존에 그냥 텍스트만 쓸 수 있는 에디터였다. 이는 게시판이라면 너무나 부실한 것이고 전혀 실용적이지 않다.

 

그래서 에디터를 적용해야 하는데, 에디터를 javascript로 직접 만들기에는 너무 배보다 배꼽이 커질 것 같고 해서 공개되어있는 에디터를 적용하기로 했다.

 

그중에서도 심플하면서 유명한 Summernote를 적용하기로 했다.

 

summernote.org/

 

Summernote - Super Simple WYSIWYG editor

Super Simple WYSIWYG Editor on Bootstrap Summernote is a JavaScript library that helps you create WYSIWYG editors online.

summernote.org

view.ejs

그 전에, 사전작업으로 글 조회 페이지에서 글 본문에 html코드가 적용될 수 있도록 바꿨다. 이전에는 <br>을 본문에 입력해도 <pre>태그 때문에 그대로 출력됐는데, 이제 html코드가 적용된다.

 

ejs에서 <%= %> 와 <%- %>의 차이는, 전자는 html코드상에서 문자열로 들어가고, 후자는 코드로 인식된다.

 

<!-- 서머노트 css -->
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.css" rel="stylesheet">
<!-- popper.js -->
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<!-- 서머노트 js -->
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.js"></script>

 

먼저 write.ejs 상,하단에 해당 코드를 삽입해줘야 한다. 제이쿼리와 부트스트랩은 기본으로 삽입되어 있어야 한다. 나는 부트스트랩4를 사용중이었기에 부트스트랩4 전용 버전을 삽입했다. popper.js를 넣지 않으면 툴바가 제대로 보이지 않는다.

 

<textarea id="summernote" name="content"></textarea>

 

에디터의 경우 딱 html코드에는 한줄만 추가하면 된다. form내부 textarea 형태와 div 형태로 사용할 수 있는데, 나는 textarea형태로 사용했다. 이때 id값을 summernote로 지정해주고,

 

$(document).ready(function() {
	$('#summernote').summernote();
});

 

자바스크립트에서 summernote함수를 호출해주기만 하면 된다. 근데 이러면 기본 에디터가 나와서 조금 밋밋하고 기능이 부실하다. 따라서 입맛에 맞게 커스터마이징 해준다.

 

$(document).ready(function() {
	//여기 아래 부분
	$('#summernote').summernote({
		  height: 788,                 // 에디터 높이
		  focus: true,                  // 에디터 로딩후 포커스를 맞출지 여부
		  lang: "ko-KR",					// 한글 설정
		  placeholder: '내용',
          disableResizeEditor: true,	// 크기 조절 기능 삭제
          toolbar: [
            ['fontname', ['fontname']],
            ['fontsize', ['fontsize']],
            ['style', ['bold', 'italic', 'underline','strikethrough', 'clear']],
            ['color', ['forecolor','color']],
            ['table', ['table']],
            ['para', ['ul', 'ol', 'paragraph']],
            ['height', ['height']],
            ['insert',['picture','link','video']],
            ['view', ['fullscreen', 'help']]
          ],
        fontNames: ['Arial', 'Arial Black', 'Comic Sans MS', 'Courier New','맑은 고딕','궁서','굴림체','굴림','돋움체','바탕체'],
        fontSizes: ['8','9','10','11','12','14','16','18','20','22','24','28','30','36','50','72']
        }
	});
});

 

이렇게 하면 꽤 쓸만해진다. 웬만하면 disableResizeEditor 옵션은 꼭 켜주는게 좋을 것 같다.

 

 

여기까지 적용한 상태이다. 솔직히 이정도만 해도 아주 좋다. 그런데 여기서 하나의 문제점이 있다.

 

이미지를 업로드하면,

 

 

이렇게 업로드는 잘 된다 그러나 DB를 살펴보면

 

<p><img style="width: 50%;" src="data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAB8IAAAizCAYAAADBS5ixAAAACXBIWX
MAAAsTAAALEwEAmpwYAAAgAElEQVR4nOzZwQkAIBDAMHX/nc8lBKEk
E/TfPTOz4VYsfEdQoAAAAASUVORK5CYII=....."
data-filename="noname-crop.png">이미지 업로드 테스트<br></p>

 

이런 식으로 엄~청나게 긴 base64 코드로 이미지가 인코딩되어 들어간다. 이는 사진이 늘어나면 늘어날수로 DB가 터져나간다는 뜻이다. 그리고 mysql 의 mediumtext는 최대 16MB 의 길이만 저장할 수 있는데, 자칫 크기가 큰 사진이 들어오면 이 용량을 초과해서 문제가 생길 수 있다.

 

그래서 어떻게 해야 할지 고민하다가, 무료 이미지 호스팅 서비스를 이용하기로 했다.

 

무료 이미지 호스팅을 지원하는 사이트는 postimage, imgbb 등등 여러가지가 있는데, 나는 이중 imgbb를 사용하기로 했다. API가 가장 심플하게 설명이 되어 있었기 때문이다.

 

ko.imgbb.com/

 

무료 이미지 호스팅 / 이미지 업로드

이미지를 업로드 하고공유해보세요. 원하는 곳 어디든 끌어놓기로 이미지를 바로 업로드해보세요.(이미지당 32 MB 가능) 다이렉트 링크, BBCode 및 HTML 미리보기등을 제공해드립니다.

ko.imgbb.com

 

 

imgbb의 API 문서를 보면 예시가 나와 있다. 간단하게 POST 요청으로 지정된 URL에다가 clientkey와 base64로 인코딩된 값을 보내기만 하면 된다. client key는 로그인하면 상단에서 얻을 수 있다.

 

 

응답은 이런 식으로 json 형태로 온다. 이미지 링크와 다이렉트 링크, 파일명, 다양한 정보들이 온다.

 

 

아까 js에서 summernote를 호출하는 부분의 callback에 onImageUpload 함수를 사용한다. 이미지를 업로드하면 sendFile 함수로 이미지와 에디터를 참조할 수 있도록 넘겨준다.

 

function sendFile(file,editor,welEditable) {
    data = new FormData();
    data.append("file", file);
    $.ajax({
        data: data,
        type: "POST",
        url: "/write/imageUpload",
        enctype: 'multipart/form-data',
        cache: false,
        contentType: false,
        processData: false,
        success: function(response) {
            if (response.error){
                alert('에러가 발생했습니다. ' + response.error);
            } else {
                $('#summernote').summernote('insertImage', response.url);
            }
        }
    });
}

 

sendFile 함수에서는 POST요청으로 먼저 서버에 이미지를 전송한다. processData 옵션은 true로 해두면 jquery에서 내부적으로 쿼리로 바꿔서 전달하기 때문에 파일전송시에는 false 로 둔다.

 

router.post('/imageUpload',multipartMiddleware,function(req,res){
    f = fs.readFileSync(req.files.file.path);
    base64 = Buffer.from(f).toString('base64');
    
    var imgbbAPI = require('../imgbbAPIkey.json'); // API KEY
    const options = {
        uri:'https://api.imgbb.com/1/upload?expiration=600&key='+imgbbAPI.key, 
        method: 'POST',
        form: {
          image:base64, // 이미지 첨부
        },
        json: true // json 형식으로 응답
    }
    request.post(options, function(error,httpResponse,body){
        if(error){
            res.send({error: error});
        } else{
            res.send({url: body.data.display_url});
        }
    });
});

 

imgUpload에서는 먼저 file system 모듈로 파일을 읽어들여서 base64 코드로 인코딩한다. 그 뒤 서버에서 imgbb 서버로 url을 만들어서 요청을 보내주면 된다. (이를 위해 request 모듈이 필요하다)

 

 

API KEY의 경우 따로 json 파일을 만들어서 저장해놓은 뒤, 버전관리에서 빼 놓는다.

 

이렇게 적용하고 나서 이미지를 업로드하면,

 

 

이렇게 잘 보인다. 이제 DB를 확인해보면,

 

<p><img style="width: 340px;" src="https://i.ibb.co/y00zW95/c1d01001fc20.png">
</p><p><br></p><p>이미지 업로드가 base64로 DB에 직접 저장되는것이 아닌 imgbb 서버에 업로드하여 링크만 거는 형식으로 잘 적용되었는지 확인해보아야 한다.</p>

 

이런식으로 base64 코드가 통째로 들어있는게 아닌 사진링크만 가져온 것을 확인할 수 있다.

 

-------------------------------------------------------------------------------------------------------------------------------------------

그런데 다음날 확인해보니..

 

 

이렇게 이미지가 날아가 버려서.. 현재는 imgur 로 서버를 옮겼다.

댓글