springboot2大文件分片上传

springboot2大文件分片上传

1. 控制器
@RestController
@RequestMapping("/resource")
public class SysResourceController {
    
    
	// 上传的路径 将上传的路径分成了两部分,有一部分用于存储到数据库
    @Value("${upload.url}")
    private String UPLOAD_URL;
	// 上传的路径
    @Value("${upload.path}")
    private String UPLOAD_SUFFIX_URL;
    // 可接受的上传的文件的后缀
    @Value("${upload.fileTypes}")
    private String fileTypes;
    public String getUploadSuffixURL() {
    
    
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
        String dateString = sdf.format(new Date());
        return UPLOAD_SUFFIX_URL + dateString + "/";
    }
    public String getUPLOAD_URL() {
    
    
        return UPLOAD_URL + getUploadSuffixURL();
    }

    public String[] getFleTypesSuffix() {
    
    
        return fileTypes.split(",");
    }


    /**
     * 分片上传
     * @param multipartFile
     * @param fileName
     * @param chunkNumber
     * @param totalChunks
     * @return
     * @throws IOException
     */
    @PostMapping("/o_upload")
    public Result upload1(@RequestParam("file") MultipartFile multipartFile,
                          @RequestParam("fileName") String fileName,
                          @RequestParam("chunkNumber") int chunkNumber,
                          @ RequestParam("totalChunks") int totalChunks) throws IOException {
    
    
        UserDetail user = SecurityUser.getUser();
        String originalFileName = StringUtils.cleanPath(multipartFile.getOriginalFilename());
        String fileExtension = getFileExtension(originalFileName);
        if (org.apache.commons.lang3.StringUtils.isBlank(fileExtension)) {
    
    
            fileExtension = getFileExtension(fileName);
        }
        // 判断上传类型
        if (!Arrays.toString(getFleTypesSuffix()).contains(fileExtension.toLowerCase())) {
    
    
            return new Result().error("上传正确格式");
        }

        String uniqueFileName = fileName + "_" + chunkNumber + "." + fileExtension;
        Path uploadPath = Paths.get(this.getUPLOAD_URL());
        if (!Files.exists(uploadPath)) {
    
    
            Files.createDirectories(uploadPath);
        }
        Path filePath = Paths.get(this.getUPLOAD_URL() + uniqueFileName);
        Files.write(filePath, multipartFile.getBytes());
        if (chunkNumber == totalChunks - 1) {
    
    
            return mergeChunks(fileName, totalChunks, fileExtension, user.getId());
        } else {
    
    
            return null;
        }
    }

	/**
	* 获取文件后缀
	* @param fileName
	*/
    private static String getFileExtension(String fileName) {
    
    
        int dotIndex = fileName.lastIndexOf(".");
        if (dotIndex > 0) {
    
    
            return fileName.substring(dotIndex + 1);
        } else {
    
    
            return "";
        }
    }

    /**
     * 合并分片
     * @param fileName
     * @param totalChunks
     * @param fileExtension
     * @param userId
     * @return
     * @throws IOException
     */
    private Result mergeChunks(String fileName, int totalChunks, String fileExtension, Long userId) throws IOException {
    
    
        Path mergedFilePath = Paths.get(this.getUPLOAD_URL() + fileName + "." + fileExtension);
        if (!Files.exists(mergedFilePath)) {
    
    
            Files.createFile(mergedFilePath);
        }
        for (int i = 0; i < totalChunks; i++) {
    
    
            Path chunkFilePath = Paths.get(this.getUPLOAD_URL() + fileName + "_" + i + "." + fileExtension);
            Files.write(mergedFilePath, Files.readAllBytes(chunkFilePath), StandardOpenOption.APPEND);
            Files.delete(chunkFilePath);
        }

        Path filePath = Paths.get(this.getUPLOAD_URL()  + fileName + "." + fileExtension);
        File file = new File(filePath.toString());
        // 原文件名称
        String extension = file.getName().substring(0, file.getName().lastIndexOf("."));
        // 后缀
        String suffix = "." + file.getName().substring(file.getName().lastIndexOf(".") + 1);
        // 新的文件名称
        String newFileName = System.currentTimeMillis() + suffix;
        // 文件重命名
        File renamedFile = new File(file.getParent(), newFileName);
        file.renameTo(renamedFile);
        String resourceUrl = this.getUploadSuffixURL() + newFileName;
        SysResource sysResource = new SysResource();
        sysResource.setCreator(userId);
        sysResource.setResourceUrl(resourceUrl);
        sysResource.setSuffix(suffix);
        // -----------------保存到数据库
       // resourceService.save(sysResource);
        /*Map<String, Object> map = new HashMap<>();
        map.put("resourceId", sysResource.getId());
        map.put("url", resourceUrl);
        map.put("name", extension);*/
        return new Result().ok(sysResource);
    }
}
2. 配置类

上传图片,附件地址

# 上传图片,附件地址
upload:
  url: F:\20230719
  path: /u/cms/www/
  fileTypes: pdf,txt,zip,rar,7z,doc,docx,xls,xlsx,ppt,pptx,mp3,mp4,jpg,png,jpeg,gif
3. 工具类

响应数据结构

import java.io.Serializable;

/**
 * 响应数据
 *
 */
public class Result<T> implements Serializable {
    
    
    private static final long serialVersionUID = 1L;
    /**
     * 编码:200表示成功,其他值表示失败
     */
    private int code = 200;
    /**
     * 消息内容
     */
    private String msg = "success";
    /**
     * 响应数据
     */
    private T data;

    public Result<T> ok(T data) {
    
    
        this.setData(data);
        return this;
    }

    public boolean success(){
    
    
        return code == 0;
    }

    public Result<T> error() {
    
    
        this.code = ErrorCode.INTERNAL_SERVER_ERROR;
        this.msg = MessageUtils.getMessage(this.code);
        return this;
    }

    public Result<T> error(int code) {
    
    
        this.code = code;
        this.msg = MessageUtils.getMessage(this.code);
        return this;
    }

    public Result<T> error(int code, String msg) {
    
    
        this.code = code;
        this.msg = msg;
        return this;
    }

    public Result<T> error(String msg) {
    
    
        this.code = ErrorCode.INTERNAL_SERVER_ERROR;
        this.msg = msg;
        return this;
    }

    public int getCode() {
    
    
        return code;
    }

    public void setCode(int code) {
    
    
        this.code = code;
    }

    public String getMsg() {
    
    
        return msg;
    }

    public void setMsg(String msg) {
    
    
        this.msg = msg;
    }

    public T getData() {
    
    
        return data;
    }

    public void setData(T data) {
    
    
        this.data = data;
    }
}
4. 前端代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>File Upload Test</title>
</head>
<body>
    <input type="file" id="fileInput">
    <button onclick="uploadFile()">Upload</button>
    <script>
        function uploadFile() {
      
      
            const file = document.getElementById("fileInput").files[0];
            const url = "/upload/o_upload";
            const chunkSize = 1024 * 1024 * 10; // 每个块的大小(字节),10M
            const fileSize = file.size; // 文件的总大小
            const totalChunks = Math.ceil(fileSize / chunkSize); // 文件被分成的总块数

            let chunkNumber = 0; // 当前上传的块的编号
            let startByte = 0; // 当前上传块的起始字节位置
            let endByte = chunkSize; // 当前上传块的结束字节位置(不包括)
            uploadChunk();
            function uploadChunk() {
      
      
                const chunk = file.slice(startByte, endByte); // 获取当前上传块的内容
                //const attribute = 1;
                const formData = new FormData(); // 创建FormData对象

                // 将参数添加到FormData对象中
                formData.append("file", chunk);
                formData.append("chunkNumber", chunkNumber);
                formData.append("totalChunks", totalChunks);
                formData.append("fileName", file.name);
                //formData.append("fileSize", fileSize);
                //formData.append("attribute", attribute);

                // 创建XMLHttpRequest对象
                const xhr = new XMLHttpRequest();
                xhr.open("POST", url, true);
                // 监听XMLHttpRequest对象的事件
                xhr.onload = function() {
      
      
                    if (xhr.status === 200) {
      
      
                        // 上传成功,继续上传下一块
                        chunkNumber++;
                        startByte = endByte;
                        endByte = Math.min(startByte + chunkSize, fileSize);
                        if (startByte < fileSize) {
      
      
                            uploadChunk();
                        } else {
      
      
                            // 所有块上传成功
                            console.log("Upload completed");
                        }
                    } else {
      
      
                        // 上传失败,尝试重传当前块
                        console.error(xhr.statusText);
                        setTimeout(uploadChunk, 1000);
                    }
                };

                xhr.onerror = function() {
      
      
                    // 网络错误,尝试重传当前块
                    console.error(xhr.statusText);
                    setTimeout(uploadChunk, 1000);
                };

                // 发送POST请求
                xhr.send(formData);
            }
        }
    </script>
</body>
</html>
5. nginx静态文件配置
server {
    
    
    listen  8525;
    server_name _;

    location  ~ .*\.(gif|jpg|jpeg|png|pdf|txt|zip|rar|7z|doc|docx|xls|xlsx|ppt|pptx|mp3|mp4)$ {
    
    
        root    F:/20230719;
    }
    location / {
    
    
        proxy_pass  http://localhost:8082;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_44021888/article/details/131823056