반응형

- 보통 서버에서는 request size 1MB이 걸려있는 경우가 많음 

new File([imgFile.slice(chunkIndex * chunkSize, (chunkIndex + 1) * chunkSize)], imgFile.name)

- 위와 같이 하면 파일을 잘라서 분리가능

- 보낼때는 async await써서 순차적으로 보내지도록 해야함 

[js 소스]

const resultUrl = await uploadChunk(other.imgFile);
  const uploadChunk = async (imgFile) => {
    one.activeDimLayer(true);
    const chunkSize = 1024 * 1023
    const totalChunk = imgFile.size % chunkSize == 0 ? imgFile.size / chunkSize : Math.floor(imgFile.size / chunkSize) + 1;
    const path = window.location.search.split('=')[1] + '_' + window.location.pathname.split('/').pop() + '/' + (new Date()).getFullYear() + '/' + ((new Date()).getMonth() + 1).toString().padStart(2, '0') + '/'
    let chunkIndex = -1;
    let resultUrl;

    while (chunkIndex < totalChunk - 1) {
      chunkIndex += 1;
      let chunk = new File([imgFile.slice(chunkIndex * chunkSize, (chunkIndex + 1) * chunkSize)], imgFile.name);
      //console.log('chunk', chunk);
      const body = new FormData();
      body.append('DetailPath', '/' + path);
      body.append('totalChunk', totalChunk);
      body.append("chunkIndex", chunkIndex);
      body.append('UploadFiles', chunk);

      await fetch('api/farmos/files/manual/upload/' + path,
        { method: "post", headers: { Authorization: 'Bearer ' + localStorage.getItem('token') }, body })
        .then((res => {//console.log('res', res);
          if (res.status === 200) return res.json()
          else if (res.status === 206);
          else chunkIndex = totalChunk
        }))
        .then(res => { if (res?.filepath && res?.filename) resultUrl = window.origin + '/api/farmos/files/manual/download' + res.filepath + res.filename })
        .catch(err => {
          console.log('imgUploadError', err);
          chunkIndex = totalChunk
        });
    }
    one.activeDimLayer(true);
    return resultUrl;
  }

 

[java 소스]

    @ResponseBody
    @PostMapping(value = "/files/manual/upload/{menu}/{year}/{month}/")    
    public ResponseEntity<?> chunkUpload(@RequestParam("UploadFiles") MultipartFile file,
                                              @RequestParam(value = "chunkIndex", required = false, defaultValue = "0") int chunkIndex,
                                              @RequestParam(value = "totalChunk", required = false, defaultValue = "1") int totalChunk,
                                              @PathVariable String menu, 
                                              @PathVariable String year, 
                                              @PathVariable String month, 
                                              HttpServletRequest request 
     ) throws IOException {
     String screenDetailPath =  '/' + filterInjectedString(menu) + '/' + filterInjectedString(year) + '/' + filterInjectedString(month) + '/';
     Map<String, Object> resultFileStatus = mdmManualRule.chunkUpload(file, screenDetailPath, chunkIndex, totalChunk);
        boolean isDone = (boolean) resultFileStatus.get("status"); 
        if (isDone) {
//         String filename = resultFileStatus.get("filename").toString();
         return ResponseEntity.ok().body(resultFileStatus);
        } else {
         return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT).build();
        } 
    }

@SuppressWarnings("unchecked")
    public Map<String, Object> chunkUpload(MultipartFile file, String screenDetailPath, int chunkIndex, int totalChunk) throws IOException {
     // 파일 업로드 위치
        String uploadDir;
        String os = System.getProperty("os.name").toLowerCase();
        if (os.contains("win")) {
            // System.out.println("Windows");
         uploadDir = "C:";
        } else {
     // System.out.println("ubuntu");
     uploadDir = "";
    }
        
        if (uploadPath == null) {
         uploadPath = "/app/WAS/FARMOS/uploadfile";
        }

        uploadDir = uploadDir + uploadPath + screenDetailPath;

        File dir = new File(uploadDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        if (os.contains("win")) {
         uploadDir = uploadDir.replaceAll("/", "\\\\");
        }
        String seperator;
        if (os.contains("win")) {
         seperator = "/";
        } else {
         seperator = "\\";
        }

// 임시 저장 파일 이름
        String filename = file.getOriginalFilename() + ".part" + chunkIndex;

        Path filePath = Paths.get(uploadDir, filename);
        // 임시 저장
        Files.write(filePath, file.getBytes());
        Map<String, Object> result = new HashMap<String, Object>();
// 마지막 조각이 전송 됐을 경우
        if (chunkIndex == totalChunk-1) {
            String[] split = file.getOriginalFilename().split("\\.");
            String outputFilename = UUID.randomUUID() + "." + split[split.length-1];
            // need file duplication check in while ?
            
            Path outputFile = Paths.get(uploadDir, outputFilename);
            Files.createFile(outputFile);
            
            // merge temp file
            for (int i = 0; i < totalChunk; i++) {
                Path chunkFile = Paths.get(uploadDir, file.getOriginalFilename() + ".part" + i);
                Files.write(outputFile, Files.readAllBytes(chunkFile), StandardOpenOption.APPEND);
                // delete temp file
                Files.delete(chunkFile);
            }
            log.info("File uploaded successfully");
            result.put("filename", outputFilename);
            result.put("filelabel", file.getOriginalFilename());
            result.put("filepath", screenDetailPath);
            result.put("status", true);
            return result;
        } else {
         result.put("status", false);
            return result;
        }
    }

 

반응형

+ Recent posts