파일 업로드 2

폼 및 Ajax 파일

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<meta charset="UTF-8">
<title>Insert title here</title>


<style>
	.uploadResult {
		width: 100%;
		background-color: gray;
	}
	
	.uploadResult ul {
		display: flex;
		flex-flow: row;
		justify-content: center;
		align-items: center;
	}
	
	.uploadResult ul li {
		list-style: none;
		padding: 10px;
	}
	
	.uploadResult ul li img {
		width: 100px;
	}
</style>
<style>
	.bigPictureWrapper {
	  position: absolute;
	  display: none;
	  justify-content: center;
	  align-items: center;
	  top:0%;
	  width:100%;
	  height:100%;
	  background-color: gray; 
	  z-index: 100;
	}
	
	.bigPicture {
	  position: relative;
	  display:flex;
	  justify-content: center;
	  align-items: center;
	}
</style>

</head>
<body>

<h1>Upload with Ajax</h1>
<div class="bigPictureWrapper">
    <div class="bigPicture"></div>
</div>

<div class="uploadDiv">
    <input type="file" name="uploadfile" multiple>
</div>

<!-- 업로드된 파일정보를 출력 -->
<div class="uploadResult">
    <ul></ul>
</div>

<button id="uploadBtn">Upload</button>

<script>

	// 정규식-문자열을 대상으로 패턴문법을 이용하여, 패턴에 일치되는지 여부를 확인
    let regex = new RegExp("(.*?)\.(exe|sh|zip|alz)$");
    let maxSize = 5 * 1024 * 1024; //5mb

    // 업로드 파일크기, 확장자 체크
    function checkExtension(fileName, fileSize){

        if(fileName >= maxSize){
            alert("파일 크기용량 초과");
            return false;
        }

        if(regex.test(fileName)){
            alert("해당 종류의 파일은 업로드 불가");
            return false;
        }

        return true;
    }

    // cloneObj 안에 class가 uploadDiv인 div 태그 clone
    let cloneObj = $(".uploadDiv").clone();

    // 업로드 된 파일정보를 출력하는 태그를 참조
    let uploadResult = $(".uploadResult ul");

    // 파일정보를 출력하는 함수
    // uploadResultArr 파라미터 : 파일들에 대한 정보
    function showUploadedFile(uploadResultArr){
        let str = ""; // 파일정보를 html태그와 함께 구성

        $(uploadResultArr).each(function(i,obj){

    // private String uuid; // 중복되자 않는 파일명
	// private String uploadPath; // 날짜를 이용한 업로드 폴더명
	// private String fileName; // 클라이언트에서 보낸 파일명
	// private boolean image; // 이미지 파일구분. true -> 이미지, false -> 이미지가 아닌 파일
            

            if(!obj.image) { // 일반파일
                let fileCalPath = obj.uploadPath + "/" + obj.uuid + "_" + obj.fileName;
                
                // console.log("일반파일경로 : " + fileCalPath);
                // console.log("일반파일경로 : " + encodeURIComponent(fileCalPath));

                str += "<li><div><a href='/download?fileName=" + fileCalPath + "'><image src='/resources/img/attach.png'>" +
                    obj.fileName + "</a><span style='cursor:pointer;' data-file=\'" + fileCalPath + "\' data-type='file'></span></div></li>";



            } else { // 이미지파일
                let fileCalPath = obj.uploadPath + "/" + "s_" + obj.uuid + "_" + obj.fileName; // 섬네일 이미지 경로
                let originPath = obj.uploadPath + "\\" + obj.uuid + "_" + obj.fileName; // 원본이미지 경로

                console.log(fileCalPath);

                originPath - originPath.replace(new RegExp(/\\/g), "/");

                console.log(fileCalPath);

                str += "<li><a href=\"javascript:showImage('" + originPath + "')\"><img src='/display?fileName" + fileCalPath + "'></a>" +
                    "<span style ='cursor:pointer;' data-file=\'" + fileCalPath + "\' data-type='image'></span></li>";

            }
        });

        uploadResult.append(str);
    }

    $(document).ready(function(){
        $("#uploadBtn").on("click", function(){

            let formData = new FormData(); // form태그에 해당하는 의미. 데이터를 key:value 형태로 관리

            // <input type="file" name="uploadfile"> 아래 선택자가 복수개념
            let inputFile = $("input[name='uploadfile']");

            // 선택된 파일들의 정보를 참조
            let files = inputFile[0].files;

            console.log(files);

            // 파일크기와 확장자를 체크
            for(let i=0; i<files.length; i++){
                
                if(!checkExtension(files[i].name, files[i].size)) {
                    return false;
                }
				
                // uploadFile 는 컨트롤러 메서드의 변수와 같아야 한다
                formData.append("uploadFile", files[i]);
            }

            // ajax 작업
            $.ajax({
                url: 'uploadAjaxAction',
                // 기본값 true. false는 key:value값의 구조를 Query String으로 변환
                processData: false,
                // 기본값 true. false는 "application/x-www-form-urlencoded;charset=UTF-8" -> "multipart/form-data" 인코딩을 사용하여 전송.
                contentType: false,
                // 전송데이터. 파일정보
                data: formData,
                type: 'post',
                // 스프링에서 넘어오는 데이터 포맷
                dataType: 'json',
                success: function(result){

                    console.log("파일정보 : " + result[0].fileName);

                    //result 변수의 내용을 참조하여, 화면에 업로드된 파일정보를 출력
                    showUploadedFile(result);
                }
            });

        });
    });

</script>

</body>
</html>

AttachFileDTO 파일

package com.demo.domain;

import lombok.Data;

// 업로드 된 파일정보를 저장목적

@Data
public class AttachFileDTO {

	private String uuid; // 중복되자 않는 파일명
	private String uploadPath; // 날짜를 이용한 업로드 폴더명
	private String fileName; // 클라이언트에서 보낸 파일명
	private boolean image; // 이미지 파일구분. true -> 이미지, false -> 이미지가 아닌 파일
	
}

컨트롤러 파일

package com.demo.controller;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.demo.domain.AttachFileDTO;

import lombok.extern.log4j.Log4j;
import net.coobird.thumbnailator.Thumbnailator;

@Log4j
@Controller
@RequestMapping("/upload/*")
public class UploadController {

	@GetMapping("/uploadForm")
	public void uploadForm() {
		
	}
	
//	@PostMapping("/uploadFormAction")
//	public void uploadFormPost(MultipartFile[] uploadFile) {
//		
//		for(MultipartFile multipartFile: uploadFile) {
//			log.info("-------------------------------");
//			log.info("파일이름 : " + multipartFile.getOriginalFilename());
//			log.info("파일크기 : " + multipartFile.getSize());
//		}
//		
//	}
	
	@PostMapping("/uploadFormAction")
	public void uploadFormPost(MultipartFile[] uploadFile) {
		
		String uploadFolder = "C:\\Dev\\upload";
		for(MultipartFile multipartFile: uploadFile) {
			log.info("-------------------------------");
			log.info("파일이름 : " + multipartFile.getOriginalFilename());
			log.info("파일크기 : " + multipartFile.getSize());
			
			File saveFile = new File(uploadFolder, multipartFile.getOriginalFilename());
			
			try {
				multipartFile.transferTo(saveFile); // 파일복사(업로드)
			} catch (IllegalStateException | IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	
	// Ajax작업
	@GetMapping("/uploadAjax")
	public void uploadAjax() {
		
	}
	
	@ResponseBody // 이 메서드만 리턴값을 json으로 변환
	@PostMapping(value = "/uploadAjaxAction", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
	public ResponseEntity<List<AttachFileDTO>> uploadAjaxAction(MultipartFile[] uploadFile){
		ResponseEntity<List<AttachFileDTO>> entity = null;
		
		List<AttachFileDTO> list = new ArrayList<AttachFileDTO>();
		
		String uploadFolder = "C:\\Dev\\upload";
		
		String uploadFolderPath = getFolder(); // "2022\06\29"
		
		File uploadPath = new File(uploadFolder, uploadFolderPath); // C:\\Dev\\upload\\2022\\06\\29
		
		// 위의 2가지 데이터가 존재하느냐
		if(uploadPath.exists() == false) {
			uploadPath.mkdirs();
		}
		
		log.info("경로 + 날짜 : " + uploadPath);
		
		// 향상된 for문
		for(MultipartFile multipartFile: uploadFile) {
			
			// 업로드하고자 하는 파일정보를 저장목적
			// 필드값 가져오기
			AttachFileDTO attachFileDTO = new AttachFileDTO();
			
			// 1)파일정보 : 클라이언트 파일이름
			// 넣은 변수에 새로운변수를 만들어 이름을 넣고, 필드에 set시킨다
			String uploadFileName = multipartFile.getOriginalFilename();
			attachFileDTO.setFileName(uploadFileName);
			
			// 중복되지 않는 문자열 생성
			UUID uuid = UUID.randomUUID();
			
			// 업로드시 중복되지 않는 파일이름을 생성
			uploadFileName = uuid.toString() + "_" + uploadFileName;
			
			try {
				// 유일한 파일이름으로 객체생성
				File saveFile = new File(uploadPath, uploadFileName);
				multipartFile.transferTo(saveFile);
				
				// 2)파일정보 : 중복되지 않은 고유의 문자열.
				attachFileDTO.setUuid(uuid.toString());
				
				// 3)파일정보 : 업로드 날짜폴더경로
				attachFileDTO.setUploadPath(uploadFolderPath);
				
				// 4)파일정보 : 이미지 또는 일반파일 여부
				if(checkImageType(saveFile)) {
					attachFileDTO.setImage(true);
					
					// 섬네일 작업 : 원본이미지를 대상으로 사본이미지를 해상도의 손실을 줄이고, 크기를 작게 작업한다
					FileOutputStream thumbnail = new FileOutputStream(new File(uploadPath, "s_" + uploadFileName));
					
					Thumbnailator.createThumbnail(multipartFile.getInputStream(), thumbnail, 100, 100);
					
					thumbnail.close();
					
				}
				
				list.add(attachFileDTO);
				
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		
		entity = new ResponseEntity<List<AttachFileDTO>>(list, HttpStatus.OK);
		
		log.info("entity : " + entity);
		
		return entity; // list -> json으로 변환되어 리턴
	}
	
	// 날짜를 이용한 업로드 폴더생성 및 폴더이름 반환
	private String getFolder() {
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		
		Date date = new Date();
		
		String str = sdf.format(date); // str = "2022-06-29"
		
		log.info("파일 경로 호환 : " + str.replace("-", File.separator));
		
		// File.separator : 운영체제에 따라서 파일경로 구분자를 반환. 예> 윈도우 c:\temp\... 리눅스 /home/etc/...
		return str.replace("-", File.separator);
	}
	
	// 이미지 파일여부를 체크
	private boolean checkImageType(File saveFile) {
		
		boolean isImage = false;
		
		try {
		
		String contentType = Files.probeContentType(saveFile.toPath()); // text/html, text/plain, image/jpeg
		
		isImage = contentType.startsWith("image");
		
		} catch(Exception e) {
			e.printStackTrace();
		}
		
		return isImage;
	}
	
}

MVN Thumbnailator 검색

pom.xml에 추가

<!-- https://mvnrepository.com/artifact/net.coobird/thumbnailator -->
<!-- 썸네일 이미지 -->
<dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.8</version>
</dependency>

댓글남기기