summernote 이미지 업로드 구현 및 이미지 경로 설정 - 삽질중인 개발자
- 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로 접근을 하게된다.
하다보니까 드래그 앤 드랍이 안되는 경우가 있다. 그러면 하단의 코드를 추가한다. ( 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();
})
summernote 사용법