[Spring] 파일 업로드(Ajax) - 상세 처리 1

 단순히 파일을 업로드하는 것에 그치지 않고, 대상에 대한 검사나, 전처리 등이 요구된다.

- 업로드 되는 파일의 확장자 검사 : 특정 확장자에 대해서만 업로드 허용

- 파일 사이즈에 대한 검사 : 업로드 사이즈에 대한 한계 값 설정

- 중복 파일 처리 : 동일 이름의 파일 업로드 시의 처리

- 저장 파일에 대한 관리 : 저장 파일 수가 증가하는 경우, 로딩 속도가 증가함

- 썸네일에 대한 처리 : 이미지의 미리보기용 썸네일 생성

- 업로드 파일에 대한 정보 전달 : 이미지 전송과 동시에 해당 파일에 대한 정보 전달


썸네일 생성의 경우, 별도의 maven repository 에서의 설정이 요구됨

pom.xml 설정

- 썸네일 생성용

1
2
3
4
5
6
<dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.8</version>
</dependency>
 
cs


-ajax 설정용
1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.5</version>
</dependency>
 
 
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.5</version>
</dependency>
cs


실습 jsp(ajax 방식)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <div id='uploadDiv'>
        <input type='file' name='uploadFile' multiple>
    </div>
    <button id='uploadBtn'>upload</button>
</body>
 
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
        integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
        crossorigin="anonymous"></script>
<script type="text/javascript">
 
$(document).ready(function(){
    // 정규식을 이용하여 해당 파일 확장자 확인
    var regax = new RegExp("(.*?)\.(exe|sh|zip|alz)$");
    // 파일 최대 사이즈
    var maxSize = 5242880;
    
    // 파일 최대 사이즈 지정 및 확장자 검사
    function checkExtension(fileName, fileSize){
        if(fileSize >= maxSize){
            alert("파일 사이즈 초과")
            return false;
        }
        
        if(regax.test(fileName)){
            alert("해당 종류의 파일은 업로드할 수 없습니다.")
            return false;
        }
        return true;
    }
    
    
    $("#uploadBtn").on('click'function(e){
        var formData = new FormData();
        var inputFile=$("input[name='uploadFile']")
        var files = inputFile[0].files;
        console.log(files)
        
        for(var i =0; i<files.length; i++){
            if(!checkExtension(files[i].name, files[i].size)){
                return false;
            }
            
            formData.append("uploadFile", files[i]);
        }
        
        $.ajax({
            url : '/uploadAjaxAction',
            processData : false,
            contentType : false,
            data : formData,
            type : 'POST',
            dataType:'json',
            success : function(result){
                alert("uploaded");
            }
        })
        
    })
    
    
})
</script>
 
</html>
cs

- json 형식 전송 수행


사용 DTO(VO)

1
2
3
4
5
6
7
8
9
10
11
12
package org.zerock.domain;
 
import lombok.Data;
 
@Data
public class AttachFileDTO {
    private String filename;
    private String uploadPath;
    private String uuid;
    private boolean image;
}
 
cs

- 파일의 이름, 업로드 경로, 저장에 사용된 uuid, 이미지 여부 확인 저장


사용 controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package org.zerock.controller;
 
import java.io.File;
import java.io.FileOutputStream;
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 net.coobird.thumbnailator.Thumbnailator;
import javax.xml.crypto.Data;
 
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
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.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.zerock.domain.AttachFileDTO;
 
import lombok.extern.log4j.Log4j;
 
@Controller
@Log4j
public class UploadController {
    //날짜별 디렉토리 생성을 위한 문자열
    //ex) 2013-8-10 -> c:/upload/2013/8/10 형식
    private String getFolder() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        String str = sdf.format(date);
        return str.replace("-",File.separator);
    }
 
    //업로드 타입 이미지인지에 대한 판단
    //업로드 파일을 이미지로 한정
    private boolean checkImageType(File file) {
        try {
            String contentType = Files.probeContentType(file.toPath());
            
            return contentType.startsWith("image");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
    
    
    @GetMapping("/uploadAjax")
    public void uploadAjax() {
        
        log.info("upload Ajax");
    }
    
    @PostMapping(value = "/uploadAjaxAction", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public ResponseEntity<List<AttachFileDTO>> uploadAjaxPost(MultipartFile[] uploadFile) {
        log.info("uploadAjaxAction....");
        
        List<AttachFileDTO> list = new ArrayList<AttachFileDTO>();
    
        String uploadFolder = "c:\\upload";
        
        String uploadFolderPath = getFolder();
        
        //날짜 별 디렉토리 생성
        //ex) 2013-8-10 -> c:/upload/2013/8/10 형식
        //대상 디렉토리가 없을 때만 생성
        File uploadPath = new File(uploadFolder, getFolder());
        log.info("upload path : "+uploadPath);
        if(uploadPath.exists() == false) {
            uploadPath.mkdirs();
        }
        //----------------------------------------------------
        
        for (MultipartFile multipartFile : uploadFile) {
            AttachFileDTO attachDTO = new AttachFileDTO();
            
            String uploadFileName = multipartFile.getOriginalFilename();
            uploadFileName = uploadFileName.substring(uploadFileName.lastIndexOf("\\")+1);
            log.info("only file name : "+uploadFileName);
            attachDTO.setFilename(uploadFileName);
            
            //uuid를 이용한 파일 중복 처리
            //uuid는 중복없이 랜덤으로 
            UUID uuid = UUID.randomUUID();
            uploadFileName = uuid.toString()+"_"+uploadFileName;
            //-----
 
            //File saveFile = new File(uploadFolder, uploadFileName);
            try {
                File saveFile = new File(uploadPath, uploadFileName);
                multipartFile.transferTo(saveFile);
                
                attachDTO.setUuid(uuid.toString());
                attachDTO.setUploadPath(uploadFolderPath);
                
                if(checkImageType(saveFile)) {
                    attachDTO.setImage(true);
                    //썸네일 생성 및 업로드(s_로 시작한 썸네일 생성)
                    FileOutputStream thumbnail = new FileOutputStream(new File(uploadPath,"s_"+uploadFileName));
                    Thumbnailator.createThumbnail(multipartFile.getInputStream(), thumbnail, 100100);
                    thumbnail.close();
                }
            list.add(attachDTO);
            }catch (Exception e) {
                log.error(e.getMessage());
            }
            
        }
        return new ResponseEntity<List<AttachFileDTO>>(list, HttpStatus.OK);
    }
 
}
cs




댓글