Spring

[SUMMERNOTE] ์ธ๋จธ๋…ธํŠธ ์ด๋ฏธ์ง€ ๋‹ค์ค‘ ์—…๋กœ๋“œ ์ฒ˜๋ฆฌ (๊ธ€ ์ €์žฅ ํด๋ฆญ ์‹œ ์ž„์‹œํด๋”์— ์žˆ๋˜ ํŒŒ์ผ ๋ณต์‚ฌํ•˜์—ฌ ์™ธ๋ถ€ ํด๋”์—..)

natrue 2022. 2. 24. 14:27
728x90
 

[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>