JavaScript 활용팁
2021.01.18 / 01:27

summernote 이미지 업로드 구현 방법 - 썸머노트 이미지 업로드

하얀소
추천 수 102

- summernote 이미지 업로드 구현 방법 -

 

summernote는 base64로 인코딩 후 저장하는 방식이여서 이미지 파일 관리가 어렵다.

그래서 callback을 이용하여 이미지를 특정 경로에 업로드 후 고유한 url를 리턴하는 방식으로 구현한다.

이 과정에서 url을 통한 외부 리소스 접근을 위한 톰캣 설정도 해줘야 한다.

 

spring boot 를 기준으로 설명된 글입니다.

 

1. summernote 세팅 및 이미지 파일 업로드 callback 함수 구현

 

써머노트에서는 몇개의 callback 함수를 지원한다.

그 중 이미지를 업로드할 때 사용할  callback 함수는 onImageUpload 란 함수이다.

 

onPaste 함수(복붙에 대한 콜백) 는 - 기본값을 사용하면 복붙시 base64로 인코딩된 src 이미지 파일과 onImageUpload에서 구현한 url 기반의 이미지 파일이 두개가 들어가는 버그가 생긴다, 따라서 아래와 같이 재 설정을 해준다.

 

	$('#summernote').summernote({
				height: 300,                 // 에디터 높이
				minHeight: null,             // 최소 높이
				maxHeight: null,             // 최대 높이
				focus: true,                  // 에디터 로딩후 포커스를 맞출지 여부
				lang: "ko-KR",					// 한글 설정
				placeholder: '최대 2048자까지 쓸 수 있습니다',	//placeholder 설정
				callbacks: {	//여기 부분이 이미지를 첨부하는 부분
					onImageUpload : function(files) {
						uploadSummernoteImageFile(files[0],this);
					},
					onPaste: function (e) {
						var clipboardData = e.originalEvent.clipboardData;
						if (clipboardData && clipboardData.items && clipboardData.items.length) {
							var item = clipboardData.items[0];
							if (item.kind === 'file' && item.type.indexOf('image/') !== -1) {
								e.preventDefault();
							}
						}
					}
				}
	});
        
        

	/**
	* 이미지 파일 업로드
	*/
	function uploadSummernoteImageFile(file, editor) {
		data = new FormData();
		data.append("file", file);
		$.ajax({
			data : data,
			type : "POST",
			url : "/uploadSummernoteImageFile",
			contentType : false,
			processData : false,
			success : function(data) {
            	//항상 업로드된 파일의 url이 있어야 한다.
				$(editor).summernote('insertImage', data.url);
			}
		});
	}

l

 

2. pom.xml에 gson , commons-io maven 추가 (필수 아님) 

파일 업로드 로직과 JSON을 리턴하기 위한 gson 사용

		<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
		<dependency>
		    <groupId>commons-io</groupId>
		    <artifactId>commons-io</artifactId>
		    <version>2.6</version>
		</dependency>
		
		
		<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
		<dependency>
		    <groupId>com.google.code.gson</groupId>
		    <artifactId>gson</artifactId>
		    <version>2.8.6</version>
		</dependency>

 

2-1. application.properties에 json 컨버터를 gson으로 세팅 (2 생략시 생략 가능)

이거 설정 안하고 JsonObject 리턴하면 오류난다.

#spring json 기본 컨버터가 jackson 이므로 gson 으로 컨버터시 오류가 발생해서 기본을 gson으로 변경
spring.http.converters.preferred-json-mapper=gson

 

 

3. 컨트롤러에서 파일 업로드 로직 구현

서머노트로 업로드한 이미지를 웹루트에 업로드해버리면 하면 빌드하고 재배포시 이미지가 다 사라지니 외부 경로에 잡아준다.

	@PostMapping(value="/uploadSummernoteImageFile", produces = "application/json")
	@ResponseBody
	public JsonObject uploadSummernoteImageFile(@RequestParam("file") MultipartFile multipartFile) {
		
		JsonObject jsonObject = new JsonObject();
		
		String fileRoot = "C:\\summernote_image\\";	//저장될 외부 파일 경로
		String originalFileName = multipartFile.getOriginalFilename();	//오리지날 파일명
		String extension = originalFileName.substring(originalFileName.lastIndexOf("."));	//파일 확장자
				
		String savedFileName = UUID.randomUUID() + extension;	//저장될 파일 명
		
		File targetFile = new File(fileRoot + savedFileName);	
		
		try {
			InputStream fileStream = multipartFile.getInputStream();
			FileUtils.copyInputStreamToFile(fileStream, targetFile);	//파일 저장
			jsonObject.addProperty("url", "/summernoteImage/"+savedFileName);
			jsonObject.addProperty("responseCode", "success");
				
		} catch (IOException e) {
			FileUtils.deleteQuietly(targetFile);	//저장된 파일 삭제
			jsonObject.addProperty("responseCode", "error");
			e.printStackTrace();
		}
		
		return jsonObject;
	}

 

4. 외부 리소스 경로 톰캣에 매핑

 

이미지 업로드에서 가장 삽질했던 부분이다. 외부 리소스를 톰캣에서 접근을 해야하는데 계속 경로 오류가나서 몇시간동안 찾았는데 file://  ->  file:/// 로 /을 3번을 써야하는데 2번을 써서 그랬다.

잘 확인하자. 

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

	//web root가 아닌 외부 경로에 있는 리소스를 url로 불러올 수 있도록 설정
    //현재 localhost:8090/summernoteImage/1234.jpg
    //로 접속하면 C:/summernote_image/1234.jpg 파일을 불러온다.
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/summernoteImage/**")
                .addResourceLocations("file:///C:/summernote_image/");
    }
}

 

업로드 된 화면

이미지 업로드가 완료되면 다음과 같이 url로 접근을 하게된다.

업로드 된 화면
url로 호출된 이미지

 

 

 

 

하다보니까 드래그 앤 드랍이 안되는 경우가 있다. 그러면 하단의 코드를 추가한다. ( summernote 생성한 다음 코드)

드래그 앤 드랍으로 이미지 첨부가 안 된다면 밑의 코드를 추가한다.

$("div.note-editable").on('drop',function(e){
         for(i=0; i< e.originalEvent.dataTransfer.files.length; i++){
         	uploadSummernoteImageFile(e.originalEvent.dataTransfer.files[i],$("#summernote")[0]);
         }
        e.preventDefault();
   })