다음 블로그를 참고하여 작성하였습니다!
https://truecode-95.tistory.com/208
게시글을 작성하는 서비스를 제공할 때, 이전 토이 프로젝트에서는 html form 태그의 textarea를 사용했다.
하지만 이번 프로젝트에서는 사진과 게시글을 같이 저장하고, 또한 다양한 텍스트 편집 기능을 제공하기 위해 무료로 사용 가능한 summernote 텍스트 에디터를 사용해보기로 결정하였다.
텍스트 에디터를 적용

다음과 같이 사진과 글을 동시에 작성하고 저장할 수 있다.

게시글 화면

서비스를 구현하면서 핵심 사항은 어떻게 이미지 파일을 저장할 것인가였다.
부트캠프 최종 프로젝트에서 임시방편으로 이미지 파일은 DB에 Blob 형식으로 저장해본적이 있고, 개인적으로 공부하며 이미지 파일을 프로젝트 외부 디렉토리에 저장하는 경험을 해본 적이 있다.
하지만 이 서비스의 핵심은 사진과 글을 동시에 저장하는 것이었다.
즉, 본문 사이사이에 이미지 파일이 존재해야 되고, 본문이 DB에 저장될 때 그 형식 그대로 저장되어야 했다.
아래와 같이 사진이 글 중간에 포함되게 할려면 어떻게 DB에 저장되어야 할까?

summernote는 기본적으로 이미지 파일을 텍스트 형식으로 관리한다. 따라서 이미지 파일 그 자체를 텍스트 형식으로 다른 텍스트들과 함께 DB에 텍스트 형식으로 저장할 수 있다.
하지만 이미지 파일을 텍스트 형식으로 저장한다는 것은 정말 비효율적라는 것을 프로젝트를 진행하면 직접 경험해볼 수 있다. summernote가 제공하는 기본 기능을 사용하면, 텍스트 중간 중간에 이미지 파일을 삽입하고 그 순서를 유지하여 DB에 저장할 수는 있다. 하지만 그 길이가 워낙 방대하기 때문에 DB에 텍스트 형식으로 이미지 파일을 저장한다는 것은 불가능한 일이었다.
실제로 위에서 업로드한 이미지 파일의 텍스트 형식의 길이는 85320자였다. 하나의 이미지 파일의 길이가 이 정도인데, 여러장의 사진들과 글을 한 번에 저장하는 것은 정말 비효율적이라는 생각이 들었다.
따라서 이미지 파일을 외부 디렉토리에 저장하되, 그 이미지 파일의 위치를 표시해두는 작업이 필요하다.
실제 DB에 저장되는 텍스트는 다음과 같다
<p>
<img style="width: 458px;" src="/images/886ec755-1a5f-4ee4-ac5a-c12e1fa45bd7.jpg">
</p>
<p>
<span style="background-color: rgb(255, 255, 255);">
오늘의 책을 추천합니다!!!!! 김정운 작가님의
</span>
<span style="background-color: rgb(255, 255, 255); font-weight: bolder;">
'창조의 시선'
</span>
<span style="background-color: rgb(255, 255, 255);">
이라는 책입니다
</span>
<br>
</p>
이렇게 DB에 게시글의 내용을 저장하면 해당 내용을 DB에서 다시 꺼내왔을 때, 이미지와 글이 동시에 화면에서 나타날 수 있고 또한 원래 순서를 유지할 수 있게 된다.
중요한 것은 이미지 파일 그 자체가 DB에 저장되는 것이 아니라, 이미지 파일의 경로가 DB에 저장된다.

이미지 파일은 다음과 같은 방식대로 저장된다.
먼저 사용자가 summernote 텍스트 에디터에 이미지를 업로드하는 순간, summernote의 onImageUpload 콜백 함수가 발동된다. 따라서 개발자가 해야 하는 일은 summernote에 어떠한 콜백 함수를 넘겨주어야 하는지 결정하는 것이다.
다음과 같이 summernote에게 콜백 함수를 넘겨줄 수 있다.
$(document).ready(function() {
// summernote 초기화
$('#summernote').summernote({
tabsize: 2,
height: 500,
lang: "ko-KR",
callbacks: {
//사진 업로드 시 작동하는 콜백 함수
onImageUpload : function(files, editor, welEditable){
for (var i = files.length - 1; i >= 0; i--) {
uploadSummernoteImageFile(files[i], this);
}
},
//사진 제거 시 작동하는 콜백 함수
onMediaDelete : function(target) {
if(postSaveViewDto.id == null){ // 포스트를 새로 작성하는 경우!
deleteFile(target[0].src);
}else{
deleteFileTemp(target[0].src);
}
}
}
});
//summernote에게 넘겨준 콜백 함수
function uploadSummernoteImageFile(file, summernote) {
var data = new FormData();
data.append("file",file);
$.ajax({
url: '/api/temp/upload',
type: "POST",
enctype: 'multipart/form-data',
data: data,
cache: false,
contentType : false,
processData : false,
success : function(json) {
$(summernote).summernote('editor.insertImage', json.data);
jsonArray.push(json.data);
},
error : function(e) {
}
});
};
};
실제 동작 순서
1. 이미지를 업로드 하는 동시에 onImageUpload 콜백 함수가 동작
2. 이 함수는 이미지 파일을 서버에 전송한다
3. 서버는 이 이미지 파일을 그 즉시 AWS S3와 같은 외부 디렉터리에 저장한다
4. 그리고 그 저장한 주소를 다시 프론트엔드로 전송한다.
5. 프론트엔드에서 이 이미지 경로에 접근해 다시 이미지 파일을 불러오고 그렇게 불러온 이미지 파일이 화면에 보이게 된다.
따라서 이미지를 summnernote 텍스트 에디터에 업로드했을 때 실제로 보이는 이미지는 S3에 저장된 이미지이다!

콜백 함수를 제공하지 않는다면 summernote 텍스트 에디터는 다음과 같이 텍스트 형식으로 이미지 파일을 저장할 것이다. 이러한 텍스트 전체를 DB에 저장하여 관리한다는 것은 비효율적일 수밖에 없을 것 같다
