> Hello World !!!

     

@syaku

#6 스프링 파일업로드 - 스프링 프레임워크 게시판 : Spring Framework FileUpload

written by Seok Kyun. Choi. 최석균


스프링 프레임워크 연재 포스팅

2014/07/21 - [개발노트/Spring] - 스프링 프레임워크 게시판 #1 STS 설치 및 스프링 프로젝트 만들기 : Spring Framework Hello, World!!!
2014/07/21 - [개발노트/Spring] - 스프링 프레임워크 게시판 #2 스프링 프로젝트 만들기 : Spring Framework Create Project
2014/07/21 - [개발노트/Spring] - 스프링 프레임워크 게시판 #3 스프링 MyBatis 설정하기 및 로그출력 : Spring Framework MyBatis Log4jdbc
2014/07/21 - [개발노트/Spring] - 스프링 프레임워크 게시판 #4 스프링 XML , 스프링 유효성검사 : Spring Framework Hibernate Validator XML Marshaller
2014/07/21 - [개발노트/Spring] - 스프링 프레임워크 게시판 #5 스프링 트랜잭션 : Spring Framework Transaction
2014/07/21 - [개발노트/Spring] - 스프링 프레임워크 게시판 #6 스프링 파일업로드 : Spring Framework FileUpload
2014/07/28 - [개발노트/Spring] - 스프링 프레임워크 게시판 #부록 스프링 검색 및 조회수 올리기 , 스프링 한글깨짐: Spring Framework Cookie


개발 환경

Mac OS X 10.9.4
JAVA 1.6
Apache Tomcat 7.x
MySQL 5.x
Spring 3.1.1
Spring Tool Suite 3.5.1
Maven 2.5.1
myBatis 3.2.7
jQuery 1.11.0

2014.07.19 Written by 최석균 (Syaku)

  

소스파일 : source-6.zip


6. 파일업로드

게시판 글쓰기에 파일업로드를 추가한다. 스프링에서 파일업로드는 매우 간결하게 개발할 수 있다.
일반적인 파일업로드가 아닌 에디터를 이용하여 파일업로드를 개발할 것이다.
에디터는 CKEditor 4.4.3 을 사용하고, CKEditor 에서 제공하는 파일업로드 UI를 사용한다.

CKEditor 공식사이트 : http://ckeditor.com

CKEditor 사이트 다운로드에서 Full Package를 선택하고, 4.4.3 다운로드를 선택한다. 받은 파일을 압축을 풀고 src/main/webapp/resources STS 경로에 복사한다.

업로드한 파일을 저장할 폴더를 생성한다. src/main/webapp/resources/files/attach resources 폴더 아래 files/attach 폴더를 생성한다.

resources 폴더가 아닌 다른 폴더를 사용하고 싶다면, 폴더를 추가하고 servlet-context.xml 에 폴더를 추가하면 된다. 만약 css 폴더를 추가한다면 아래와 같이 한다.
<resources mapping="/css/**" location="/css/" />

CKEditor 을 추가하면 STS 에서 js 파일에 오류가 발생한다. minify 사용한 스크립트에 발생하는 오류로 보여진다. 프로젝트에는 지장이 없으나 해결하려면 아래와 같이 한다.

프로젝트 메뉴 > Build Path > Configure Build Path… 선택한다.

트리메뉴에서 JavaScript > Include Path > Source 선택하고, Excluded 를 선택하고 Edit… 선택한다. 그리고 Exclusion patterns 영역에 Add… 버튼을 눌러 **/*.js 를 추가하고 적용하면 된다.

게시판에 등록하면 에디터를 추가한다. bbs.write.jsp 에 아래의 소수를 추가한다.

@소스 bbs.write.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html lang="en">
  <head>

       생략...

    <!-- ckediter -->
    <script src="/bbs/resources/ckeditor/ckeditor.js"></script>
  </head>
  <body>

  <script>
       // ckeditor setting
       var ckeditor_config = {
            resize_enabled : false, // 에디터 크기를 조절하지 않음
            enterMode : CKEDITOR.ENTER_BR , // 엔터키를 <br> 로 적용함.
            shiftEnterMode : CKEDITOR.ENTER_P ,  // 쉬프트 +  엔터를 <p> 로 적용함.
            toolbarCanCollapse : true , 
            removePlugins : "elementspath", // DOM 출력하지 않음
            filebrowserUploadUrl: '/bbs/file_upload', // 파일 업로드를 처리 할 경로 설정.

            // 에디터에 사용할 기능들 정의
            toolbar : [
              [ 'Source', '-' , 'NewPage', 'Preview' ],
              [ 'Cut', 'Copy', 'Paste', 'PasteText', '-', 'Undo', 'Redo' ],
              [ 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript'],
              [ 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock' ],
              '/',
              [ 'Styles', 'Format', 'Font', 'FontSize' ],
              [ 'TextColor', 'BGColor' ],
              [ 'Image', 'Flash', 'Table' , 'SpecialChar' , 'Link', 'Unlink']

            ]

          };

       var editor = null;
       jQuery(function() {
            // ckeditor 적용
            editor = CKEDITOR.replace( "content" , ckeditor_config );
       });

       생략 ...    

       // 전송을 위한 체크 함수
       function form_save(form) {
            editor.updateElement();

            생략 ...
       }

       생략 ...

  </script>

  생략 ...

  </body>
</html>
  • <script src="/bbs/resources/ckeditor/ckeditor.js"></script> CKEditor 스크립트를 추가
  • ckeditor_config CKEditor 설정 추가. 설명은 소스 주석을 참고한다.
  • CKEDITOR.replace( "content" , ckeditor_config ); CKEditor 를 적용할 엘리먼트 설정
  • editor.updateElement(); 게시물이 저장되기 전에 에디터에 입력된 값을 가져옴.

게시판 글쓰기에서 CKEditor 출력되는 지 확인한다.

파일 업로드를 처리할 때 사용하는 라이브러리 Apache Commons FileUpload 를 pom.xml에 추가한다.

<!-- file upload -->
<dependency>
     <groupId>commons-fileupload</groupId>
     <artifactId>commons-fileupload</artifactId>
     <version>1.3.1</version>
</dependency>
<dependency>
     <groupId>commons-io</groupId>
     <artifactId>commons-io</artifactId>
     <version>2.4</version>
</dependency>

그리고 servlet-context.xml에 multiport 빈을 추가한다.

@소스 servlet-context.xml

<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

Request 파라메터로 넘겨받아 파일정보를 담을 파일 빈을 생성한다. com.syaku.bbs.dao 패킷에 빈 파일을 생성한다.

@소스 FileBean.java

package com.syaku.bbs.dao;

import org.springframework.web.multipart.MultipartFile;

public class FileBean {
     private String attach_path;
     private MultipartFile upload;
     private String filename;
     private String CKEditorFuncNum;

     public String getAttach_path() {
          return this.attach_path;
     }

     public void setAttach_path(String attach_path) {
          this.attach_path = attach_path;
     }

     public MultipartFile getUpload() {
         return upload;
     }

     public void setUpload(MultipartFile upload) {
         this.upload = upload;
     }

     public String getFilename() {
          return this.filename;
     }
     public void setFilename(String filename) {
          this.filename = filename;
     }

     public String getCKEditorFuncNum() {
          return this.CKEditorFuncNum;
     }
     public void setCKEditorFuncNum(String CKEditorFuncNum) {
          this.CKEditorFuncNum = CKEditorFuncNum;
     }
}

CKEditorFuncNum은 CKEditor 대상을 기억하기 위한 값을 저장한다.
컨트롤러에 파일업로드를 처리하기 위한 작업을 추가한다.

@소스 ViewController.java

@RequestMapping(value = "/file_upload", method = RequestMethod.POST)
public String procFileUpload(FileBean fileBean,HttpServletRequest request, Model model) {

     HttpSession session = request.getSession();
     String root_path = session.getServletContext().getRealPath("/"); // 웹서비스 root 경로
     String attach_path = "resources/files/attach/";

    MultipartFile upload = fileBean.getUpload();
    String filename = "";
    String CKEditorFuncNum = "";
    if (upload != null) {
        filename = upload.getOriginalFilename();
        fileBean.setFilename(filename);
        CKEditorFuncNum = fileBean.getCKEditorFuncNum();
        try {
            File file = new File(root_path + attach_path + filename);
            logger.info(root_path + attach_path + filename);
            upload.transferTo(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    String file_path = "/bbs/" + attach_path + filename;
    model.addAttribute("file_path", file_path);
    model.addAttribute("CKEditorFuncNum", CKEditorFuncNum);

     return "bbs.fileupload";
}

컨트롤러에 procFileUpload 메서드를 추가한다. 그리고 컨트롤러 처리 후 결과를 출력할 페이지를 추가한다.

@소스 bbs.fileupload.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<script type='text/javascript'>
window.parent.CKEDITOR.tools.callFunction('${CKEditorFuncNum}', '${file_path}', '파일 전송 완료.');
</script>

파일업로드 후 CKEditor 에 이미지를 삽입하기 위해 window.parent.CKEDITOR.tools.callFunction(CKEditorFuncNum, 첨부파일경로, 완료메세지); CKEditor 콜백 함수를 추가한다.

이제 CKEditor UI 를 사용하여 파일 첨부한다. 위 그림처럼 이미지 버튼을 눌러 활성화된 창에서 이미지탭으로 이동하고 파일을 첨부한다. 한글명을 가진 파일은 제대로 불러오지 못할 경우가 있으니 참고한다.

그리고 그외 세부적인 필터 기능들은 직접 구현해보도록 한다.

파일명이 중복으로 업로드 되지 않게하기.
파일 제한 용량을 넘지 않게하기
정해진 확장자 파일만 업로드하기



posted syaku blog

Syaku Blog by Seok Kyun. Choi. 최석균.

http://syaku.tistory.com