헤르메스 LIFE

[Spring Boot] Multi FileUpload 본문

Spring Boot Framework

[Spring Boot] Multi FileUpload

헤르메스의날개 2022. 2. 27. 00:43
728x90

springboot.zip
0.32MB

개발환경

1. STS 버전 : 4.13.1

2. JDK 버전 : OpenJDK 11.0.14_9_x64

3. Tomcat 버전 : 9.0.56

4. Maven 버전 : 3.8.4

5. Spring 버전 : Spring Boot 2.6.3

6. Database : Docker 에 DB 설치

- primary - PostgreSQL 13.3

8. lombok


프로젝트 목표

1. 파일업로드 경로를 다른 지정할 수 있음.

2. 업로드된 파일명을 변경해서 저장해야 함.

3. Mullti 파일 업로드 기능구현.

4. Ajax를 이용한 Form 전송


https://hermeslog.tistory.com/541?category=302344 

 

[SpringBoot] PostgreSQL 연결하기

IDE : IntelliJ JDK : OpenJDK 11 Framework : Spring Boot 2.5.2 Database : PostgreSQL 최신버전 ( 라이센스도 소스공개의무도 없음 ) 첨부파일이 MySqlRunner 로 되어있는데.. MySQL 접속테스트 중 소스만 바..

hermeslog.tistory.com


pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.study</groupId>
    <artifactId>springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>springboot</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>11</java.version>
    </properties>
    <dependencies>

        <!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency> 
            <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mustache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>


        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

application.yml

server:
  port: 9090
  servlet:
    context-path: /
    encoding:
      charset: UTF-8
      enabled: true
      force: true

  h2:
    console:
      enabled: true
      path: /h2-console

  datasource:
      url: jdbc:postgresql://localhost:5432/springboot
      username: hermeswing
      password: pass
      hikari:
        idle-timeout: 10000
        maximum-pool-size: 10
        minimum-idle: 5
        pool-name: BaseHikariPool
              
  jpa:
    generate-ddl: true
    hibernate:
      ddl-auto: update         # Hibernate ddl auto (create, create-drop, validate, update)
    show-sql: false
    properties:
      hibernatte:
        format_sql: true
  profiles:
    active: local


logging:
  level:
    org:
      hibernate:
        SQL: debug
        type:
          descriptor:
            SQL: trace

SyFileM.java

- 일단 테이블은 만들어 놓고...

package com.study.springboot.system.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Getter;
import lombok.NoArgsConstructor;

@Table(name = "SY_FILE_M")
@Entity
@NoArgsConstructor
@Getter
public class SyFileM {

    @Id
    @Column(name = "FILE_ID")
    private String fileId;

    @Column(name = "ORGN_FILE_NAME")
    private String orgnFileName;

    @Column(name = "PYSC_FILE_NAME")
    private String pyscFileName;

    @Column(name = "FILE_SIZE")
    private Long fileSize;

    /**
     * @param fileId
     * @param orgnFileName
     * @param pyscFileName
     * @param fileSize
     */
    public SyFileM(String fileId, String orgnFileName, String pyscFileName, long fileSize) {
        this.fileId       = fileId;
        this.orgnFileName = orgnFileName;
        this.pyscFileName = pyscFileName;
        this.fileSize     = fileSize;
    }
}

FileUploadController.java

package com.study.springboot.system.controller;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import com.study.springboot.system.entity.SyFileM;

@Controller
// @CrossOrigin(origins = "http://localhost:8082") open for specific port
// @CrossOrigin() // open for all ports
public class FileUploadController {

    private static final Logger logger     = LoggerFactory.getLogger(FileUploadController.class);
    private static final String folderPath = "c:/temp/upload/";

    @GetMapping("/upload.do")
    public String upload() {
        return "fileupload";
    }

    /**
     * Multi 파일 업로드
     *
     * @param  file[]
     * @return
     */
    @PostMapping(value = "/upload", produces = "application/json; charset=utf8")
    public ResponseEntity<?> uploadFile(@RequestParam("files") MultipartFile[] multiFiles, Model model) {
        Map<String, Object> result = new HashMap<>();

        try {
            createDirIfNotExist();

            SyFileM syFileM = null;
            String  uuId, fileId, orgnFileName, pyscFileName, physicalPath;

            List<SyFileM> fileList = new ArrayList<>();
            for (int i = 0; i < multiFiles.length; i++) {
                if (!multiFiles[i].isEmpty()) {
                    // byte[] bytes = multiFiles[i].getBytes();

                    logger.debug("folderPath :: {}", folderPath);
                    logger.debug("file.getOriginalFilename() :: {}", multiFiles[i].getOriginalFilename());
                    logger.debug("file size :: {}", multiFiles[i].getSize());

                    uuId         = UUID.randomUUID().toString();
                    fileId       = getToDate() + "_" + uuId;
                    orgnFileName = multiFiles[i].getOriginalFilename();
                    pyscFileName = uuId;
                    physicalPath = folderPath + getToDate() + "/";

                    syFileM = new SyFileM(fileId, orgnFileName, pyscFileName, multiFiles[i].getSize());
                    fileList.add(syFileM);

                    // 파일에 저장하기
                    logger.debug("dest :: {}", physicalPath + pyscFileName);
                    File dest = new File(physicalPath + pyscFileName);
                    multiFiles[i].transferTo(dest);
                }
            }

            result.put("success", true);
            result.put("fileList", fileList);

        } catch (Exception e) {
            result.put("success", false);
            result.put("message", e.getMessage());
        }

        logger.debug("result :: {}", result);

        return ResponseEntity.ok().body(result);
    }

    /**
     * Create directory to save files, if not exist
     */
    private void createDirIfNotExist() {
        // create directory to save the files
        File directory = new File(folderPath + "/" + getToDate());
        if (!directory.exists()) {
            directory.mkdir();
        }
    }

    /**
     * Method to get the list of files from the file storage folder.
     *
     * @return file
     */
    @GetMapping("/files")
    public ResponseEntity<String[]> getListFiles() {
        return ResponseEntity.status(HttpStatus.OK).body(new java.io.File(folderPath).list());
    }

    private String getToDate() {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
        Date             date      = new Date(System.currentTimeMillis());

        return formatter.format(date);
    }
}

fileupload.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파일업로드</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
    crossorigin="anonymous"></script>
</head>
<body>
    <form id="form" name="form" method="post" enctype="multipart/form-data">
        <input type="text"   id="content"   name="content"   value="Content" />
        <input type="file"   id="files"     name="files"     multiple="multiple" /> 
        <input type="button" id="btnSubmit" name="btnSubmit" value="업로드" />
    </form>
</body>
<script>
$(document).ready(function () {
	$('#btnSubmit').click(function (event) {
        event.preventDefault();
        
        var form = $('#form')[0];
        var formData = new FormData(form);
        $('#btnSubmit').prop('disabled', true);

        $.ajax({
            type: 'POST',
            enctype: 'multipart/form-data',
            url: '/upload',
            data: formData,
            processData: false,
            contentType: false,
            cache: false,
            timeout: 600000,
            success: function (data) {
                //$('#result').text(data);
                console.log('SUCCESS : ', data);
                $('#btnSubmit').prop('disabled', false);
                $('#files').val("");
            },
            error: function (e) {
                //$('#result').text(e.responseText);
                console.log('ERROR : ', e);
                $('#btnSubmit').prop('disabled', false);
            }
        });
        
    });
});
</script>
</html>

전체 프로젝트 구조는 대략 이렇습니다.


실행

1. 오픈된 화면입니다.

2. 파일3개를 선택한 화면입니다.

3. 업로드 완료된 화면입니다.

4. 실제 업로드된 파일 목록 입니다.


너무 많은 분들의 소스를 참고했는지 정리가 안됩니다.

소스를 오픈 해주신 분들께 감사드립니다.

복 받으실 겁니다. ^^;;

728x90