DBILITY

pure javascript file upload 테스트 본문

front-end & ui/javascript

pure javascript file upload 테스트

DBILITY 2021. 5. 12. 12:12
반응형

기능을 테스트하며 기록을 남긴다.

 

back-end는 spring 4.3.9.RELEASE를 사용했다.

commons-fileupload를 사용하기 위해 pom에 dependency 추가

<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.2.2</version>
</dependency>
<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.6</version>
</dependency>

spring dispatcer설정(xml방식)에 CommonsMultipartResolver를 추가

<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
	<property name="defaultEncoding" value="UTF-8" />
	<property name="maxUploadSize" value="262144000" />
	<property name="maxUploadSizePerFile" value="262144000" />
	<property name="maxInMemorySize" value="0" />
</bean>

테스트용 Controller를 추가하고 RequestMapping 처리

@RequestMapping(value = "/upload", method = RequestMethod.POST)
@ResponseBody
public String upload(@RequestParam("mediaFile") List<MultipartFile> files, @RequestParam("user") String user, HttpServletRequest request, HttpServletResponse response) throws Exception {
	Gson gson = new Gson();
	JsonObject obj = new JsonObject();
	String uploadDir = request.getSession().getServletContext().getRealPath("/")+"resources";
	logger.info("------------------> {} , {}", user, uploadDir);
	if(files.size()>0){
		try{
			for (MultipartFile file : files){
				if(!file.getOriginalFilename().isEmpty()){
					logger.info("{}",file.getName());
					logger.info("{}",file.getOriginalFilename());
					byte[] bytes = file.getBytes();
					File dir = new File(uploadDir);
					if(!dir.exists()){
						dir.mkdirs();
					}
					File uploadFile = new File(dir.getAbsolutePath() + File.separator + file.getOriginalFilename());
					BufferedOutputStream uploadStream = new BufferedOutputStream(new FileOutputStream(uploadFile));
					uploadStream.write(bytes);
					uploadStream.close();
				}
			}
		obj.addProperty("error",-1);
		} catch (Exception e) {
			obj.addProperty("error",1);
			throw e;
		}
	}
	return gson.toJson(obj);
}    

html view

fetch는 아직 progress를 지원하지 않는다.XMLHttpRequest는 upload.onprogress로 지원.

이미지와 동영상파일을 선택했을때 base64로 연결하였다.

업로드할때 file로 변환 후 FormData에 추가

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Image & Video Base64 Upload Test</title>
    <style>
        button {
            margin: 2px;
        }

        ul {
            list-style-type: none;
        }

        progress {
            margin-left: 10px;
        }
    </style>
</head>
<body>
<div>
    <ul>
        <li>
            <button id="btnSelectImageFile">이미지선택</button>
            <button id="btnUploadImage">이미지업로드</button>
        </li>
        <li>
            <button id="btnSelectVideoFile">동영상선택</button>
            <button id="btnUploadVideo">동영상업로드</button>
        </li>
        <li><label for="uploadProgress">Uploading progress:</label><progress id="uploadProgress" value="0" max="100"></progress></li>
    </ul>
</div>

<script>

    function log(){
        for (let x of arguments) {
            console.log(x);
        }
    }

    function removeItem() {
        ["imageLayer","sImage","videoLayer","sVideo"].forEach((item,index)=>{
            if(document.getElementById(item)) {
                document.getElementById(item).remove();
            }
        });
        document.getElementById("uploadProgress").setAttribute("value", "0");
    }

    function fnImageSelector() {

        removeItem();
        let divEle = document.createElement("div");
        divEle.id = "imageLayer";
        divEle.innerHTML = "<img id='img' />";

        let fileEle = document.createElement("input");
        fileEle.type = "file";
        fileEle.id = "sImage";
        fileEle.name = "sImage";
        fileEle.style.display = "none";
        fileEle.accept = "image/jpeg, image/png";

        document.body.append(fileEle);

        document.getElementById("sImage").addEventListener("change", function (e) {
            let reader = new FileReader();
            let file = null;
            let fileName = null;
            let fileType = null;

            if (e.target.files.length > 0) {
                document.body.append(divEle);
                file = e.target.files[0];
                fileName = file.name;
                fileType = file.type;
                reader.readAsDataURL(file);
                reader.onload = function (e) {
                    let image = reader.result;
                    let imgObj = document.getElementById("img");
                    imgObj.setAttribute("src", image);
                    imgObj.setAttribute("data-fileName", fileName);
                    imgObj.setAttribute("data-fileType", fileType);
                    document.getElementById("sImage").remove();
                };
            } else {
                document.getElementById("sImage").remove();
            }
        });
        document.getElementById("sImage").click();
    }

    function fnUploadImageByXMLHttpRequest() {
        let formData = new FormData();
        let fileRes = document.getElementById("img").getAttribute("src");
        let fileName = document.getElementById("img").getAttribute("data-filename");
        let fileType = document.getElementById("img").getAttribute("data-filetype");
        let file;
        fetch(fileRes)
            .then(result => result.blob())
            .then(blob => {
                file = new File([blob], fileName, {type: fileType});
                file.type = fileType;
                formData.append("mediaFile", file);
                /*formData.append("mediaFile", file);
                formData.append("mediaFile", file);
                formData.append("mediaFile", file);
                formData.append("mediaFile", file);*/
                /* 동일이름으로 다른 파일을 추가하면 멀티업로드가 됨 */
                /*formData.enctype='multipart/form-data';
                formData.method='post';*/
                return formData;
            }).then(formData => {
            formData.append("user", "hyperrookie@gmail.com");
            let xhttp = new XMLHttpRequest();
            xhttp.onreadystatechange = function (e) {
                console.log(this.readyState + ":" + this.status + ":" + this.statusText);
                /*1. UNSENT (숫자 0) : XMLHttpRequest 객체가 생성됨.
                2. OPENED (숫자 1) : open() 메소드가 성공적으로 실행됨.
                3. HEADERS_RECEIVED (숫자 2) : 모든 요청에 대한 응답이 도착함.
                4. LOADING (숫자 3) : 요청한 데이터를 처리 중임.
                5. DONE (숫자 4) : 요청한 데이터의 처리가 완료되어 응답할 준비가 완료됨.
                 - 200 : 서버에 문서가 존재함.
                 - 404 : 서버에 문서가 존재하지 않음.
                */
                if (this.readyState == XMLHttpRequest.DONE) {
                    if (this.status == 200) {
                        log(this.response, this.responseText);
                    } else {
                        log(this.response, this.statusText);
                    }
                }
            };
            xhttp.upload.onprogress = function(e){
                if(e.lengthComputable) {
                    log(e.total, e.loaded);
                    document.getElementById("uploadProgress").setAttribute("value", String(Number(e.loaded / e.total) * 100));
                } else {
                    log(e.loaded);
                    document.getElementById("uploadProgress").setAttribute("value", "0");
                }
            };
            xhttp.onerror = function (e) {
                log(e);
            };
            xhttp.open("POST", "/upload", true);
            xhttp.send(formData);
        }).catch(error => {
            log(error);
        });
    }

    function fnUploadImageByFetch() {
        let formData = new FormData();
        let fileRes = document.getElementById("img").getAttribute("src");
        let fileName = document.getElementById("img").getAttribute("data-filename");
        let fileType = document.getElementById("img").getAttribute("data-filetype");
        let file;
        fetch(fileRes)
            .then(result => result.blob())
            .then(blob => {
                file = new File([blob], fileName, {type: fileType});
                file.type = fileType;
                formData.append("mediaFile", file);
                return formData;
            }).then(formData => {
            formData.append("user", "hyperrookie@gmail.com");
            fetch("/upload", {
                method: "POST",
                headers: {},
                body: formData
            }).then(response => {
                log(response.status);
            }).catch(error => {
                log(error);
            });
        }).catch(error => {
            log(error);
        });
    }

    function fnVideoSelector() {

        removeItem();
        let divEle = document.createElement("div");
        divEle.id = "videoLayer";
        divEle.innerHTML = "<video id='movie' />";

        let fileEle = document.createElement("input");
        fileEle.type = "file";
        fileEle.id = "sVideo";
        fileEle.name = "sVideo";
        fileEle.style.display = "none";
        fileEle.accept = "video/mp4, video/webm";

        document.body.append(fileEle);
        document.getElementById("sVideo").addEventListener("change", function(e){
            let reader = new FileReader();
            let file = null;
            let fileName = null;
            let fileType = null;
            if( e.target.files.length > 0) {
                file = e.target.files[0];
                fileName = file.name;
                fileType = file.type;
                if(Number(file.size/1024/1024) > 220){
                    window.alert("용량초과");
                    this.remove();
                    return;
                };
                document.body.append(divEle);
                reader.readAsDataURL(file);
                reader.onload = function(e) {
                    let video = reader.result+"#t=10";
                    let videoObj = document.getElementById("movie");
                    videoObj.childNodes.forEach((node,index)=>{
                        node.remove();
                    });
                    //videoObj.innerHTML = "<source src='"+video+"' type='"+fileType+"'/>";
                    videoObj.setAttribute("src", video);
                    videoObj.setAttribute("data-fileName", fileName);
                    videoObj.setAttribute("data-fileType", fileType);
                    videoObj.setAttribute("autoplay", false);
                    videoObj.setAttribute("loop", true);
                    videoObj.setAttribute("controls", true);
                    videoObj.play();
                    document.getElementById("sVideo").remove();
                };
            } else {
                document.getElementById("sVideo").remove();
            }
        });
        document.getElementById("sVideo").click();
    }

    function fnUploadVideoByXMLHttpRequest() {
        let formData = new FormData();
        let fileRes = document.getElementById("movie").getAttribute("src");
        let fileName = document.getElementById("movie").getAttribute("data-filename");
        let fileType = document.getElementById("movie").getAttribute("data-filetype");
        let file;
        fetch(fileRes)
            .then(result => result.blob())
            .then(blob => {
                file = new File([blob], fileName, {type: fileType});
                file.type = fileType;
                formData.append("mediaFile", file);
                return formData;
            }).then(formData => {
                formData.append("user", "hyperrookie@gmail.com");
                let xhttp = new XMLHttpRequest();
                xhttp.onreadystatechange = function (e) {
                    console.log(this.readyState + ":" + this.status + ":" + this.statusText);
                    /*1. UNSENT (숫자 0) : XMLHttpRequest 객체가 생성됨.
                    2. OPENED (숫자 1) : open() 메소드가 성공적으로 실행됨.
                    3. HEADERS_RECEIVED (숫자 2) : 모든 요청에 대한 응답이 도착함.
                    4. LOADING (숫자 3) : 요청한 데이터를 처리 중임.
                    5. DONE (숫자 4) : 요청한 데이터의 처리가 완료되어 응답할 준비가 완료됨.
                     - 200 : 서버에 문서가 존재함.
                     - 404 : 서버에 문서가 존재하지 않음.
                    */
                    if (this.readyState == XMLHttpRequest.DONE) {
                        if (this.status == 200) {
                            log(this.response, this.responseText);
                        } else {
                            log(this.response, this.statusText);
                        }
                    }
                };
                xhttp.upload.onprogress = function(e){
                    if(e.lengthComputable) {
                        log(e.total, e.loaded);
                        document.getElementById("uploadProgress").setAttribute("value", String(Number(e.loaded / e.total) * 100));
                    } else {
                        log(e.loaded);
                        document.getElementById("uploadProgress").setAttribute("value", "0");
                    }
                };
                xhttp.onerror = function (e) {
                    log(e);
                };
                xhttp.open("POST", "/upload", true);
                xhttp.send(formData);
        }).catch(error => {
            log(error);
        });
    }

    function fnUploadVideoByFetch() {
        let formData = new FormData();
        let fileRes = document.getElementById("movie").getAttribute("src");
        let fileName = document.getElementById("movie").getAttribute("data-filename");
        let fileType = document.getElementById("movie").getAttribute("data-filetype");
        let file;
        fetch(fileRes)
            .then(result => result.blob())
            .then(blob => {
                file = new File([blob], fileName, {type: fileType});
                file.type = fileType;
                formData.append("mediaFile", file);
                return formData;
            }).then(formData => {
            formData.append("user", "hyperrookie@gmail.com");
            fetch("/upload", {
                method: "POST",
                headers: {},
                body: formData
            }).then(response => {
                log(response.status);
            }).catch(error => {
                log(error);
            });
        }).catch(error => {
            log(error);
        });
    }

    window.addEventListener("load", e => {
        let btnList = document.querySelectorAll("button");
        btnList.forEach((node, index) => {
            node.addEventListener("click",e => {
                e.preventDefault();
                let btnId = e.currentTarget.id;
                if (btnId == "btnSelectImageFile") {
                    fnImageSelector();
                } else if (btnId == "btnUploadImage") {
                    fnUploadImageByFetch();
                    //fnUploadImageByXMLHttpRequest();
                } else if (btnId == "btnSelectVideoFile") {
                    fnVideoSelector();
                } else if (btnId == "btnUploadVideo") {
                    fnUploadVideoByFetch();
                    //fnUploadVideoByXMLHttpRequest();
                }
            });
        });
    });

</script>
</body>
</html>
반응형

'front-end & ui > javascript' 카테고리의 다른 글

div move + rotate + resize test  (0) 2021.05.20
div rotate test  (0) 2021.05.18
div drag test  (0) 2021.05.14
EventSource + Spring Server Sent Event  (0) 2021.05.12
ajax download  (0) 2019.06.03
Comments