본문 바로가기
Web/기타

[JAVA, SPRING, SUMMERNOTE] 서머노트 사용법 ③ (다중 이미지 업로드)

by tyrannojung 2020. 12. 3.
반응형

서머노트 툴바설정 : tyrannocoding.tistory.com/14

 

[JAVA, SPRING, SUMMERNOTE] 서머노트 사용법 ② (Toolbar 수정)

서머노트 연동 : tyrannocoding.tistory.com/13 [JAVA, SPRING, SUMMERNOTE] 서머노트 사용법 ①  기존에 서머노트 외에 많이 쓰는 CKEditor 같은 경우는 file에 대해서는 부분 유료라는 단점으로 괜찮은 에디터..

tyrannocoding.tistory.com

서머노트 툴바 설정 이후 게시글입니다.

 

 

이미지업로드

 툴바에 있는 이미지로 사진을 첨부할 수도 있지만 마우스를 이용한 드래그 앤 드롭으로 아래처럼 이미지를 첨부할 수 있습니다. 문제는 섬머노트는 <textarea id="summernote" name="content"></textarea>로 이루어져 있어 서버로 데이터를 넘겨줄 때 파일을 넘겨주는 것이 아닌 content 내용을 string 그 자체로 가져갑니다. 그러므로 이미지는 '경로 값을 읽어 보여주는 것'입니다. 

 

드래그 해서 파일을 가져갔을때 나오는 모습

 

 그러므로 이미지를 드래그 앤 드롭하고 해당 이미지를 크롬의 '개발자 도구'로 경로를 확인했을 때 내가 저장한 외부 경로, 혹은 스프링 내부 경로를 위와 같이 나타나개 해주어야 합니다.

 

동작 순서

 

 

  1.  파일을 드래그 앤 드롭
  2. 콜백 함수
  3. AJAX로 파일 업로드 (외부 혹은 내부 경로)
  4. 원하는 위치에 업로드 후 경로 값 RETURN

 

콜백함수

Javascript

<script>
	// 툴바생략
	var setting = {
            height : 300,
            minHeight : null,
            maxHeight : null,
            focus : true,
            lang : 'ko-KR',
            toolbar : toolbar,
            //콜백 함수
            callbacks : { 
            	onImageUpload : function(files, editor, welEditable) {
            // 파일 업로드(다중업로드를 위해 반복문 사용)
            for (var i = files.length - 1; i >= 0; i--) {
            uploadSummernoteImageFile(files[i],
            this);
            		}
            	}
            }
         };
        $('#summernote').summernote(setting);
        });
        
        function uploadSummernoteImageFile(file, el) {
			data = new FormData();
			data.append("file", file);
			$.ajax({
				data : data,
				type : "POST",
				url : "uploadSummernoteImageFile",
				contentType : false,
				enctype : 'multipart/form-data',
				processData : false,
				success : function(data) {
					$(el).summernote('editor.insertImage', data.url);
				}
			});
		}
</script>

 

 섬머노트는 여러 가지의 callbacks함수를 지원하는데 그중 'onImageUpload'함수는 '이미지를 업로드했을 때' 동작하는 함수입니다. 여러 개의 파일을 Drag And Drop 하거나, 파일 첨부에서 다중 선택 후 업로드할 때를 위해 for문으로 처리해 줍니다.

 

 그 후 새로 만든 uploadSummernoteImageFile 자바스크립트 함수를 통해 ajax로 서버에서 파일 업로드를 진행합니다. 서버에서 기대하는 값은 파일업로드 성공 후 파일 경로를 return 받는 것입니다.

 

 

서버 구현(spring legacy)

 pom.xml

          <!-- 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 -->
          <!-- json 변환 -->
          <dependency>
              <groupId>com.google.code.gson</groupId>
              <artifactId>gson</artifactId>
              <version>2.8.6</version>
          </dependency>

          <!-- commons-fileupload -->
          <!-- multipart등을 사용할수 있음 -->
          <dependency>
              <groupId>commons-fileupload</groupId>
              <artifactId>commons-fileupload</artifactId>
              <version>1.3.1</version>
          </dependency>	

 

 

servlet-context.xml

<!-- 스프링에서 기본으로 제공하는 multipartResolver는 CommonsMultipartResolver 이므로, 순수한 multipartResolver를 사용하기 위해 빈 이름으로 "multipartResolver"를 등록해야함 + 프로퍼티를 이용 최대 가능한 업로드 사이즈 지정함 -->
    
<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<beans:property name="maxUploadSize" value="100000000"></beans:property>
</beans:bean>

 

 

java

@RequestMapping(value="/uploadSummernoteImageFile", produces = "application/json; charset=utf8")
	@ResponseBody
	public String uploadSummernoteImageFile(@RequestParam("file") MultipartFile multipartFile, HttpServletRequest request )  {
		JsonObject jsonObject = new JsonObject();
		
        /*
		 * String fileRoot = "C:\\summernote_image\\"; // 외부경로로 저장을 희망할때.
		 */
		
		// 내부경로로 저장
		String contextRoot = new HttpServletRequestWrapper(request).getRealPath("/");
		String fileRoot = contextRoot+"resources/fileupload/";
		
		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", "/summernote/resources/fileupload/"+savedFileName); // contextroot + resources + 저장할 내부 폴더명
			jsonObject.addProperty("responseCode", "success");
				
		} catch (IOException e) {
			FileUtils.deleteQuietly(targetFile);	//저장된 파일 삭제
			jsonObject.addProperty("responseCode", "error");
			e.printStackTrace();
		}
		String a = jsonObject.toString();
		return a;
	}

 

 

1. 오리지널 파일명과 확장자를 분리합니다.

2. UUID.randomUUID() 함수를 통해 고유의 이름으로 바꾸어 저장합니다.(추후 중복 이름 때문에 파일이 덮어 써지거나 저장이 안 되는 걸 방지하기 위해서)

3. inputstream으로 파일을 저장합니다.

4. 저장한 이미지를 보여줘야 하므로 json형태로 url : 파일 이름으로 jsonobject에 저장합니다.

5. 파일 저장을 시도하는데 애러가 나면 파일을 삭제합니다.

6. Responsebody를 통해 json 형태의 string이 성공적으로 return 되면 ajax의 success부분이 실행되고, editor.insertimage를 통해 서머 노트에 저장된 이미지가 불러와집니다.

 

 

마치며

 해당 코드를 사용하면 다중 업로드까지 손쉽게 구현되는 것을 확인할 수 있습니다. 이 정도 예제로 잘 가공해서 사용하면 DB에 CRUD는 문제없이 사용할 수 있을 겁니다. 혹시라도 구현 진행 중에 안 되는 부분이 있으시면 댓글 남겨주시면 소스 보내드릴께요~

반응형

댓글