포스트 목록

2016년 6월 28일 화요일

Spring MVC 파일 업로드

파일 업로드

이 게시물은 참조하지 않는 것을 권장합니다.

목차

  1. 데이터베이스 테이블 생성
  2. pom.xml 에 dependency 추가
  3. servlet-context.xml 추가
  4. Domain 작성
  5. Dao 작성
  6. Query 작성 
  7. View Layer 작성
  8. Service 작성


1. 데이터베이스 테이블 생성

  데이터베이스 테이블은 HeidiSQL로 생성했다.





CREATE TABLE `ARTICLE_FILE` (
 `article_file_no` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '게시물 파일 번호',
 `article_no` INT(10) UNSIGNED NOT NULL,
 `original_file_name` VARCHAR(260) NOT NULL COMMENT '파일 이름',
 `hash_file_name` VARCHAR(80) NOT NULL COMMENT '해쉬 파일 이름',
 `file_size` INT(11) NOT NULL COMMENT '파일 크기',
 `insert_datetime` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '첨부 시간',
 PRIMARY KEY (`article_file_no`),
 INDEX `article_file_article_no` (`article_no`),
 CONSTRAINT `article_file_article_no` FOREIGN KEY (`article_no`) REFERENCES `ARTICLE` (`article_no`)
)
COMMENT='게시물에 첨부하는 파일'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;


2. pom.xml 에 dependency 추가

  pom.xml 에 다음 두개의 dependency 를 추가한다.


<dependency>
  <groupid>commons-io</groupid>
  <artifactid>commons-io</artifactid>
  <version>2.4</version>
</dependency>

<dependency>
  <groupid>commons-fileupload</groupid>
  <artifactid>commons-fileupload</artifactid>
  <version>1.3.1</version>
</dependency>

3. servlet-context.xml 추가

id는 multipartResolver 여야 한다.


<beans:bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
  <beans:property name="maxUploadSize" value="1070599167"></beans:property>
</beans:bean>

4. Domain 작성


/*
 * ArticleFile 테이블의 Domain
 *
 */
public class ArticleFile {

  private Integer articleFileNo;
  private Integer articleNo;
  private String originalFileName;
  private String hashFileName;
  private Integer fileSize;
  private String insertDatetime;

  public Integer getArticleFileNo() {
    return articleFileNo;
  }
  public void setArticleFileNo(Integer articleFileNo) {
    this.articleFileNo = articleFileNo;
  }
  public Integer getArticleNo() {
    return articleNo;
  }
  public void setArticleNo(Integer articleNo) {
    this.articleNo = articleNo;
  }
  public String getOriginalFileName() {
    return originalFileName;
  }
  public void setOriginalFileName(String originalFileName) {
    this.originalFileName = originalFileName;
  }
  public String getHashFileName() {
    return hashFileName;
  }
  public void setHashFileName(String hashFileName) {
    this.hashFileName = hashFileName;
  }
  public Integer getFileSize() {
    return fileSize;
  }
  public void setFileSize(Integer fileSize) {
    this.fileSize = fileSize;
  }
  public String getInsertDatetime() {
    return insertDatetime;
  }
  public void setInsertDatetime(String insertDatetime) {
    this.insertDatetime = insertDatetime;
  }

  @Override
  public String toString() {
    return "ArticleFile [articleFileNo=" + articleFileNo + ", articleNo=" + articleNo
        + ", originalFileName=" + originalFileName + ", hashFileName=" + hashFileName
        + ", fileSize=" + fileSize + ", insertDatetime=" + insertDatetime + "]";
  }
}
5. Dao 작성

(interface) ArticleFileDao

import java.util.List;

import suwon.spring.study.article.domain.ArticleFile;

public interface ArticleFileDao {

  public void insertArticleFile(ArticleFile articleFile) throws Exception;

  public List selectArticleFileListByArticleNo(ArticleFile articleFile) throws Exception;

  public ArticleFile selectArticleFile(ArticleFile articleFile) throws Exception;

}

(class) ArticleFileDaoImpl

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import suwon.spring.study.article.domain.ArticleFile;

@Repository
public class ArticleFileDaoImpl implements ArticleFileDao {

  @Autowired
  private SqlSession sqlSession;

  @Override
  public void insertArticleFile(ArticleFile articleFile) throws Exception {

    sqlSession.insert("articleFile.insertArticleFile", articleFile);
  }

  @Override
  public List selectArticleFileListByArticleNo(ArticleFile articleFile) throws Exception {

    return sqlSession.selectList("articleFile.selectArticleFileListByArticleNo", articleFile);
  }

  @Override
  public ArticleFile selectArticleFile(ArticleFile articleFile) throws Exception {

    return sqlSession.selectOne("articleFile.selectArticleFile", articleFile);
  }
}
6. Query 작성 


<mapper namespace="articleFile">

  <insert id="insertArticleFile" parametertype="articleFile">

    INSERT INTO ARTICLE_FILE
      (article_no, original_file_name, hash_file_name, file_size, insert_datetime)
    VALUES
      (#{articleNo}, #{originalFileName}, #{hashFileName}, #{fileSize}, now())

  </insert>

  <select id="selectArticleFileListByArticleNo" parametertype="articleFile" resulttype="articleFile">

    SELECT
      article_file_no
      , article_no
      , original_file_name
      , hash_file_name
      , file_size
      , insert_datetime
    FROM
      ARTICLE_FILE
    WHERE
      article_no = #{articleNo}

  </select>

  <select id="selectArticleFile" parametertype="articleFile" resulttype="articleFile">

    SELECT
      article_file_no
      , article_no
      , original_file_name
      , hash_file_name
      , file_size
      , insert_datetime
    FROM
      ARTICLE_FILE
    WHERE
      article_file_no = #{articleFileNo}

  </select>

</mapper>



7. View 작성

View 는 특별히 다른건 필요 없고, form 에서 method 는 post 로, enctype="multipart/form-data" 를 추가한다.


8. Service 작성


Service를 작성하기 이전에 Controller에서 Parameter에 MultipartFile 을 받아야한다.

서비스에서는 그대로 MultipartFile 의 기능을 사용하면 된다.

public static void upload(String[] hashFileNames, MultipartFile[] files) throws Exception {

    // 디렉토리 생성
    File dir = new File(CommonUtils.convertFileSeparator(Const.UPLOAD_FILE_PATH));
    if(dir.exists() == false) {
      dir.mkdirs();
    }

    int hashFileNamesIndex = 0;
    for(int i = 0; i < files.length; i++) {

      if(files[i].isEmpty() == false) {

        MultipartFile multipartFile = files[i];

        // FileOutputStream 취득
        File file = new File(dir.getAbsolutePath() + File.separator + hashFileNames[hashFileNamesIndex]);
        FileOutputStream fos = new FileOutputStream(file, false);

        InputStream is = multipartFile.getInputStream();

        byte [] bytes = new byte[Const.FILE_UPLOAD_BUFFER_SIZE];
        while(is.read(bytes) != -1) {
          fos.write(bytes);
        }

        hashFileNamesIndex++;

        fos.flush();
        fos.close();
      }
    }

  }

9. Controller 작성


지금의 경우에는 여러개의 파일을 업로드 가능하게 하였으므로, MultipartFile 를 배열의 형태로 받는다.


  @RequestMapping(value="/articleWrite")
  public String articleWrite(HttpServletRequest request, Article article, @RequestParam("file") MultipartFile [] files) throws Exception {

    HttpSession session = request.getSession();
    User user = (User) session.getAttribute(Const.LOGIN);

    article.setUserNo(user.getUserNo());
    articleService.articleWrite(article, files);

    return "redirect:/article/articleList";
  }

댓글 없음:

댓글 쓰기