개발/코딩

[썸머노트] 썸머노트 에디터에 업로드한 이미지를 원하는 내부 경로에 저장하고 경로값을 DB에 저장하기

mabb 2022. 9. 18. 17:25
반응형

해당 게시물은 본인의 이해를 바탕으로 작성되었으므로 틀린 부분이 있을 수 있습니다.
댓글로 알려주신다면 감사하겠습니다!
----------------------------------------------------
Spring이든 summernote든 전혀 봄과 여름 같지 않았다. 이를 완벽하게 사용하기에는 아직 어려워서 Winter나 blizzardnote라고 해야하지 않을까(웃음). 하지만 이해하고 알아가면 알아갈수록 잘만 사용한다면 개발자에게 봄바람과 여름바다와 같은 훌륭한 도구가 될 것이라는 생각이 든다. 만든 사람들 대단하다.
이 글은 기본적인 썸머노트 연결법은 제외하며 <textarea>가 썸머노트 에디터로 작동하는 상황을 기준으로 한다.

🧀 썸대노트의 이미지 업로드 동작 원리 이해

<p>아아 이것이 썸머노트인가</p><p><img style="width: 25%;" src="/resources/image/summerImageFiles/20220918162246.png"></p><p><span style="background-color: rgb(255, 255, 0);">아름다운 사진</span></p><p><img style="width: 25%;" src="/resources/image/summerImageFiles/20220918162312.png"><br></p>

위는 썸머노트가 적용된 <textarea>의 value가 DB에 저장된 것이다. 썸머노트에디터 속에서 작성된 내용이 HTML통째로 DB에 저장되기 때문에 다시 화면에 출력할 때 작성하였던 형태 그대로 뽑아낼 수가 있다.
녹색 밑줄을 친 이미지 태그의 경로는 콜백함수의 ajax와 매핑된 컨트롤러에서 직접 설정하고 다시 json객체에 담아 서머노트 에디터에 'insertImage'의 값으로 전달한 값이다.

출처:썸머노트에디터, 에디터에 이미지 업로드 및 글 작성 화면

썸대노트를 이용하여 글 작성 시 이미지를 업로드하면,
썸머노트 에디터 속에 업로드한 이미지가 나타난다. (흔히 블로그를 작성할 때 사용하는 에디터와 같다)
이는 이미지를 업로드하는 순간어딘가에 이미지가 저장되었고 저장된 이미지의 경로를 다시 에디터 속으로 가져온 것이다. (ajax의 비동기 기능을 이용한 것)

🧀 썸머노트의 이미지 업로드 동작

1. 썸머노트의 에디터에서 이미지를 업로드하는 이벤트가 발생했을 때.
1-1. <script>태그의 .summernote({}); 에 callbacks 프로퍼티가 없다면 -> 썸머노트 자체 로직으로 이미지 업로드 작동.
1-2. callbacks프로퍼티가 있다면 -> 콜백함수 실행(onImageUpload, onPaste 등)
2. 어딘가에 저장되는 이미지 파일
2-1 썸머노트 자체적으로 어딘가에 이미지를 저장하고 불러온다.
2-2 개발자가 컨트롤러에서 직접 이미지가 저장되는 경로를 설정할 수 있다.

🧀 목적: 썸머노트로 업로드한 이미지를 썸네일 이미지로 사용하기

목적은 썸머노트로 업로드한 이미지를 썸네일로 사용하기 위하여 이미지를 원하는 경로에 저장하고, 그 경로와 파일명을 DB에 저장하는 것이다. 이를 위해 건드리는 부분은 다음과 같다.
1. 스크립트 부분

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<script>
        $(document).ready(function(){

            $('#summernote').summernote({
                height : 300,
                width : 700,
                lang : "ko-KR",
                callbacks:{
                    onImageUpload : function(files){
                       uploadSummernoteImageFile(files[0],this);
                   }
                }
            });
            
            function uploadSummernoteImageFile(file,editor){
                data = new FormData();
                data.append("file",file);
                $.ajax({
                    data:data,
                    type:"POST",
                    url:"/uploadSummernoteImageFile",
                    dataType:"JSON",
                    contentType:false,
                    processData:false,
                    success:function(data){
                        $(editor).summernote("insertImage",data.url);
                        $("#thumbnailPath").append("<option value="+data.url+">"+data.originName+"</option>");
                    }
                });
            }
        });
</script>
cs


2.컨트롤러 부분 (gson, io 라이브러리 pom.xml추가 후)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    @ResponseBody
    @RequestMapping(value="/uploadSummernoteImageFile",method=RequestMethod.POST)
    public JsonObject uploadSummernoteImageFile(@RequestParam("file") MultipartFile multipartFile,
            HttpServletRequest request) {
        JsonObject jsonObject = new JsonObject();
//파일저장 외부 경로, 파일명, 저장할 파일명        
        try {
            String originalFileName = multipartFile.getOriginalFilename();
            String root = request.getSession().getServletContext().getRealPath("resources");
            String savePath = root + "\\image\\review\\summerImageFiles";
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            String extension = originalFileName.substring(originalFileName.lastIndexOf(".")+1);
            String boardFileRename = sdf.format(new Date(System.currentTimeMillis())) + "." + extension; 
            File targetFile = new File(savePath);
            if(!targetFile.exists()) {
                targetFile.mkdir();
            }
           multipartFile.transferTo(new File(savePath+"\\"+boardFileRename));
            
            System.out.println(savePath);
            jsonObject.addProperty("url","/resources/image/review/summerImageFiles/"+boardFileRename);
            jsonObject.addProperty("originName",originalFileName);
            jsonObject.addProperty("reponseCode","success");
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        return jsonObject;
    }
cs


files
썸머노트에 업로드한 이미지 파일은 Formdata에 추가되어 컨트롤러로 전해지고
컨트롤러에서는 @RequestParam으로 이를 받아서 사용한다. 한 번에 한 장 씩 업로드를 하기 때문에 files[0]으로 이미지 파일을 가져왔다. 가지고 온 파일을 원하는 경로에 저장하고 저장한 경로+파일명을 썸머노트로 보내준다.
"/uploadSummernoteImageFile"
ajax에서 서버로 보내는 json의 url로 컨트롤러에 매핑된다.
jsonObject
컨트롤러에서 다시 화면으로 보내는 json객체이다. @ResponseBody 어노테이션이 붙은 컨트롤러의 메소드는
뷰리졸버가 아닌 화면으로 리턴한다. 이 json객체의 url프로퍼티에 저장한 이미지의 경로와 파일명을 담아 보낸다.
컨트롤러에서 반환하는 이 json객체는 화면단 ajax의 sucess함수의 data 매개값으로 들어간다.

data.url
컨트롤러에서 json에 담아서 보낸 파일의 경로는 화면단 ajax의 sucess함수에서 꺼내 사용할 수 있다.

이렇게하여 썸머노트로 업로드하는 이미지의 경로를 DB에 저장할 수 있게 되었다.


썸네일은 다음과 같이 셀렉트태그를 이용하여 에디터에 올린 사진 중에서 선택할 수 있도록 하였다.
$(
"#thumbnailPath").append("<option value="+data.url+">"+data.originName+"</option>");

ajax의 success 함수가 실행될 때마다 <select>태그의 하위에 <option>태그가 생기도록 한 것이고
최종적으로 작성한 글을 저장할 때 선택한 옵션값의 value(이미지파일의 경로)가 DB에 저장되도록 하였다.

🧀 해결해야할 문제

1. 게시물을 최종 저장하지 않고 에디터에 올려보는 것만으로 서버에 이미지가 저장되고 있다...
최종 저장하지 않은 경우에는 이렇게 저장된 임시 이미지파일들을 삭제하여야 한다.

2. DB는 한 게시물에 썸네일 컬럼을 한 개만 만들었고, 업로드한 다른 이미지파일의 경로는 DB에 저장하지 않았다.
(업로드할 이미지가 몇 개가 될 지 모르기 때문에 하나의 컬럼에 컴마 ',' 등으로 구분하여 경로들을 저장하고 이를 배열로 다루는 방법을 생각해보고 있다.)
게시물을 수정할 때 선택하였던 다른 이미지로 썸네일을 수정할 수 있도록 변경하여야 한다.
3.에디터에 올렸던 이미지파일을 에디터에서 지웠을 때 썸네일 선택용 <option>태그가 지워지도록 해야한다.

반응형