[JAVA, SPRING, SUMMERNOTE] 서머노트 사용법 ③ (다중 이미지 업로드)
서머노트 툴바설정 : tyrannocoding.tistory.com/14 [JAVA, SPRING, SUMMERNOTE] 서머노트 사용법 ② (Toolbar 수정) 서머노트 연동 : tyrannocoding.tistory.com/13 [JAVA, SPRING, SUMMERNOTE] 서머노트 사용법..
tyrannocoding.tistory.com
Summernote - Super Simple WYSIWYG editor
Super Simple WYSIWYG Editor on Bootstrap Summernote is a JavaScript library that helps you create WYSIWYG editors online.
summernote.org
1. summernote 에디터 파일 모양 클릭

2. 콜백 함수 호출
섬머 노트는 callbacks함수를 지원하는데 'onImageUpload'함수는 '이미지를 업로드했을 때' 동작하는 함수이다.
파일 첨부에서 다중 선택 후 업로드할 때를 위해 for문으로 처리한다.
uploadSummernoteImageFile 자바스크립트 함수를 통해 ajax로 서버에서 파일 업로드를 진행한다.
// summernote 부분
function textEdit(){
jsonArray = [];
$('#summernote').summernote({
height: 500, // 에디터 높이
minHeight: null, // 최소 높이
maxHeight: null, // 최대 높이
focus: true, // 에디터 로딩후 포커스를 맞출지 여부
lang: "ko-KR", // 한글 설정
toolbar: [
// [groupName, [list of button]]
['fontname', ['fontname']],
['fontsize', ['fontsize']],
['style', ['bold', 'italic', 'underline','strikethrough', 'clear']],
['color', ['forecolor','color']],
['table', ['table']],
['para', ['ul', 'ol', 'paragraph']],
['height', ['height']],
['insert',['picture','link','video']],
['view', ['fullscreen', 'help']]
],
fontNames: ['Arial', 'Arial Black', 'Comic Sans MS', 'Courier New','맑은 고딕','궁서','굴림체','굴림','돋움체','바탕체'],
fontSizes: ['8','9','10','11','12','14','16','18','20','22','24','28','30','36','50','72'],
callbacks: {
onImageUpload : function(files, editor, welEditable){
// 파일 업로드(다중업로드를 위해 반복문 사용)
for (var i = files.length - 1; i >= 0; i--) {
uploadSummernoteImageFile(files[i],
this);
}
}
}
});
$('#summernote').summernote('fontSize', '24');
function uploadSummernoteImageFile(file, el) {
var data = new FormData();
data.append("file",file);
$.ajax({
url: '/../summer_image.do',
type: "POST",
enctype: 'multipart/form-data',
data: data,
cache: false,
contentType : false,
processData : false,
success : function(data) {
var json = JSON.parse(data);
$(el).summernote('editor.insertImage',json["url"]);
jsonArray.push(json["url"]);
jsonFn(jsonArray);
},
error : function(e) {
console.log(e);
}
});
}
},
function jsonFn(jsonArray){
console.log(jsonArray);
},
3.pom.xml추가 // globals.properties 생성
<!-- 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>
// 임시로 만드는 폴더
Globals.tempDir = C:/temp/
// 임시폴더에서 copy해서 넣는 폴더
Globals.copyDir = C:/summer/copy/
4. ajax url호출
summer_image.do (파일 업로드-외부 경로)
@RequestMapping(value="/summer_image.do", produces = "application/json; charset=utf8")
@ResponseBody
public String uploadSummernoteImageFile(@RequestParam("file") MultipartFile multipartFile, HttpServletRequest request ) throws IOException {
JsonObject json = new JsonObject();
String fileRoot = EgovProperties.getProperty("Globals.tempDir");
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);
// 파일을 열기위하여 common/getImg.do 호출 / 파라미터로 savedFileName 보냄.
json.addProperty("url", "common/getImg.do?savedFileName="+savedFileName);
json.addProperty("responseCode", "success");
} catch (IOException e) {
FileUtils.deleteQuietly(targetFile);
json.addProperty("responseCode", "error");
e.printStackTrace();
}
String jsonvalue = json.toString();
return jsonvalue;
}
5. 외부 이미지 불러오는 자세한 방법은 아래 참고
[File] 프로젝트 외부에 이미지 불러오기
프로젝트 내부에 있는 폴더로 접근하여 이미지 파일을 가져올 경우 주의할 점 여러 이미지(파일)를 프로젝트 내부에 추가 후 프로젝트를 빌드하게 되면 용량이 커 빌드 시간이 느려지고, Git이나
truecode-95.tistory.com
6. temp파일에 업로드 url 리턴 (이미지 미리보기 느낌)
(summer_image.do -> json.addProperty("url",....);
json.addProperty("url", "common/getImg.do?savedFileName="+savedFileName);
@RequestMapping(value="/common/getImg.do" , method=RequestMethod.GET)
public void getImg(@RequestParam(value="savedFileName") String savedFileName, HttpServletResponse response) throws Exception{
String filePath;
String DIR = EgovProperties.getProperty("Globals.tempDir");
filePath = DIR +savedFileName;
fileutils.getImage(filePath, response);
}
@RequestMapping(value="/common/getImgCopy.do" , method=RequestMethod.GET)
public void getImgCopy(@RequestParam(value="savedFileName") String savedFileName, HttpServletResponse response) throws Exception{
String filePath;
String DIR = EgovProperties.getProperty("Globals.copyDir");
filePath = DIR +savedFileName;
fileutils.getImage(filePath, response);
}
7. url리턴이 성공
=> summernote화면에 추가한 이미지가 에디터에 보여진다. = temp 폴더엔 이미 저장 되었다는 의미.
개발자 모드 키고 추가된 이미지를 클릭하면 src에
<img src="common/getImg.do?savedFileName=bc395afe-2324-438d-ae68-1a0a75d0a431.png" style="width: 1920px;">
이런식으로 삽입.
이제 제목과 + summernote에디터에 사진까지,내용까지 추가 할 경우 temp폴더가 아닌 copy폴더에 저장을 해야한다. (복사개념)
8. 저장 버튼 클릭 시 controller호출
1) 에디터에 이미지를 추가만 해도 외부에 저장이 된다.. temp에 계속 쌓이는것..
2) 에디터에 이미지를 추가할 때 가져온 파일 리스트에서 common/getImg.do?savedFileName= 는 제거하고
파일 이름값만 가져온다.
3) 저장 버튼 이벤트에 formData를 선언하고 append 시킨다.
for(var i = 0; i<jsonArray.length; i++){
var str = jsonArray[i];
// str의 값 : common/getImg.do?savedFileName=bc395afe-2324-438d-ae68-1a0a75d0a431.png
// '='를 기준으로 자른다.
var result = str.toString().split('=');
formData.append('file[]',result[1]);
// result[1] : bc395afe-2324-438d-ae68-1a0a75d0a431.png
}
9. boardWriteSummerCopy 메서드 호출 (temp폴더에 있는 파일을 copy 폴더로 복사)
1) @RequestParam(value="file[]") List<String> summerfile로 받아오고
2) DB에는 html태그로 들어가기 때문에 .replaceAll("getImg","getImgCopy");을 통해 치환
@RequestMapping(value = "/등록.do")
public Map<String, Object> 등록(MultipartHttpServletRequest multipartRequest, HttpServletResponse response,
@RequestParam Map<String,String> boardVO, @SessionAttribute("LoginResultVO") LoginVO loginVO,
@RequestParam(value="file[]") List<String> summerfile) throws Exception {
summerCopy(summerfile);
// db에 들어가있는 editordata 값
//<p><span style="font-size: 24px;">d</span><img src="common/getImg.do?savedFileName=bc395afe-2324-438d-ae68-1a0a75d0a431.png" style="width: 1903px;"><br></p>
String editordata = boardVO.get("editordata").replaceAll("getImg","getImgCopy");
//replaceAll을 통해 getImg를 -> getImgCopy로 다 변경한다.
// 결과
//<p><span style="font-size: 24px;">d</span><img src="common/getImgCopy.do?savedFileName=bc395afe-2324-438d-ae68-1a0a75d0a431.png" style="width: 1903px;"><br></p>
summerCopy
public Map<String, Object> summerCopy(
@RequestParam(value="file[]") List<String> fileList) throws Exception {
Map<String, Object> result = new HashMap<String, Object>();
//원본 파일경로
for(int i=0;i<fileList.size();i++){
String oriFilePath = EgovProperties.getProperty("Globals.tempDir")+fileList.get(i);
logger.debug("oriFilePath: {}", oriFilePath);
//복사될 파일경로
String copyFilePath = EgovProperties.getProperty("Globals.copyDir")+fileList.get(i);
logger.debug("copyFilePath: {}", copyFilePath);
try {
FileInputStream fis = new FileInputStream(oriFilePath); //읽을파일
FileOutputStream fos = new FileOutputStream(copyFilePath); //복사할파일
int data = 0;
while((data=fis.read())!=-1) {
fos.write(data);
}
fis.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
result.put("SUCCESS", true);
logger.debug("result: {}", result);
return result;
}

4) DB 열어서 치환한 이름으로 잘 들어가는지 확인
<p><span style="font-size: 24px;">d</span><img src="common/getImgCopy.do?savedFileName=bc395afe-2324-438d-ae68-1a0a75d0a431.png" style="width: 1903px;"><br></p>
'Spring' 카테고리의 다른 글
| POI monitorjbl xlsx-streamer 메모리 이슈 해결 (2) | 2024.06.07 |
|---|---|
| POI SAX XSSFReader 대용량 엑셀 파일 읽기 OOME(Out of Memory Error) 방지 (0) | 2024.05.23 |
| @RequestParam 값이 Null / 예외 처리 (required=false) (0) | 2022.02.16 |
| [Spring] WebSocket sockJS 실시간 알림 구현하기 (3) (1) | 2022.01.10 |
| [Spring] 파일 다운로드 구현 (0) | 2021.12.15 |