欢迎光临
我们一直在努力

续传文件夹在JSP中怎么操作?

程序猿の毕业设计渡劫指南(附代码+求生攻略)

一、项目背景(哭唧唧版)

作为一只即将被学校"扫地出门"的计科狗,最近被毕业设计折磨得夜不能寐——导师甩下一句:“做个文件管理系统,要支持10G大文件上传+文件夹+断点续传+IE8兼容,否则别想毕业!”(说完就骑着共享单车溜了)

现在的情况是:

  • 前端:Vue3 + 原生JS(要兼容到IE8,比让恐龙玩Switch还离谱)
  • 后端:SpringBoot(跑在Tomcat 6.0上,比我家老古董电视还卡)
  • 存储:直接塞服务器硬盘(导师说"云存储太贵,咱们穷苦大学生要艰苦奋斗")
  • 浏览器:从IE8到Chrome120全兼容(包括龙芯浏览器这种"国产神器")
二、技术选型(妥协版)
  • 上传组件:

    • 现代浏览器:H5 File API + Web Workers(防卡死)
    • IE8:WebUploader + Flash(没错,2023年还要写Flash代码)
    • 最终方案:双引擎热切换(像混动车一样智能)
  • 加密方案:

    • 传输加密:AES-128(IE8用CryptoJS降级)
    • 存储加密:SM4(信创浏览器强制要求)
    • 密钥管理:用户密码+时间戳盐值(防止导师偷看我学习资料)
  • 断点续传:

    • 进度存储:localStorage(IE8用userData模拟)
    • 服务端记录:MySQL+文件系统双保险(防止浏览器清空数据)
  • 三、前端实现(Vue3 + 原生JS)

    // FileUploader.vue(精简求生版)

    export default {
    data() {
    return {
    progress: 0,
    isIE8: !!window.ActiveXObject || "ActiveXObject" in window,
    chunkSize: 5 * 1024 * 1024 // 5MB分片
    }
    },
    methods: {
    triggerUpload() {
    if (this.isIE8) {
    // 触发IE8上传(通过iframe通信)
    document.getElementById('ie8Uploader').contentWindow.startUpload();
    } else {
    // 现代浏览器直接触发
    document.getElementById('modernFileInput').click();
    }
    },

    // 现代浏览器文件处理
    handleModernFileChange(e) {
    const files = e.target.files;
    Array.from(files).forEach(file => {
    if (file.webkitRelativePath) {
    this.uploadFolder(file); // 文件夹上传
    } else {
    this.uploadFile(file);
    }
    });
    },

    // 文件分片上传(现代浏览器)
    async uploadFile(file) {
    const fileId = this.generateFileId(file);
    const totalChunks = Math.ceil(file.size / this.chunkSize);
    let uploadedChunks = this.getSavedProgress(fileId) || 0;

    for (let i = uploadedChunks; i < totalChunks; i++) {
    const start = i * this.chunkSize;
    const end = Math.min(start + this.chunkSize, file.size);
    const chunk = file.slice(start, end);

    // 加密分片(简化版)
    const encrypted = this.encryptData(chunk);

    const formData = new FormData();
    formData.append('file', encrypted);
    formData.append('fileId', fileId);
    formData.append('chunkIndex', i);
    formData.append('totalChunks', totalChunks);

    try {
    await fetch('/api/upload/chunk', {
    method: 'POST',
    body: formData
    });

    this.progress = Math.floor(((i + 1) / totalChunks) * 100);
    this.saveProgress(fileId, i + 1);
    } catch (e) {
    console.error('上传失败:', e);
    break;
    }
    }
    },

    // IE8兼容方案(伪代码)
    uploadFileIE8(file) {
    // 这里需要写100行ActiveXObject代码…
    // 核心思路:通过XMLHttpRequest分片上传
    // 省略IE8兼容代码(手酸了)…
    },

    // 生成唯一文件ID(兼容IE8)
    generateFileId(file) {
    if (this.isIE8) {
    return file.name + file.size + file.lastModified; // 简单拼接
    }
    return file.name + '-' + CryptoJS.MD5(file.name + file.size).toString();
    }
    }
    }

    四、后端实现(SpringBoot + Tomcat 6.0)

    // FileUploadController.java(求生版)
    @RestController
    @RequestMapping("/api/upload")
    public class FileUploadController {

    @Value("${file.upload-dir}")
    private String uploadDir;

    // 初始化上传任务
    @PostMapping("/init")
    public ResponseEntity> initUpload(
    @RequestParam String fileName,
    @RequestParam long fileSize) {

    String fileId = UUID.randomUUID().toString();
    String tempDir = uploadDir + "/temp/" + fileId;

    // 创建临时目录(Tomcat 6.0需要手动处理路径)
    new File(tempDir).mkdirs();

    Map response = new HashMap<>();
    response.put("fileId", fileId);
    response.put("chunkSize", 5242880); // 5MB
    response.put("uploadDir", tempDir);

    return ResponseEntity.ok(response);
    }

    // 处理分片上传
    @PostMapping("/chunk")
    public ResponseEntity uploadChunk(
    @RequestParam("file") MultipartFile file,
    @RequestParam String fileId,
    @RequestParam int chunkIndex,
    @RequestParam int totalChunks) {

    try {
    String tempDir = uploadDir + "/temp/" + fileId;
    String chunkPath = tempDir + "/" + chunkIndex;

    // 解密文件(简化版)
    byte[] decrypted = decrypt(file.getBytes());

    // 保存分片(Tomcat 6.0文件操作)
    Files.write(Paths.get(chunkPath), decrypted);

    // 如果是最后一个分片,合并文件
    if (chunkIndex == totalChunks – 1) {
    mergeFile(fileId, tempDir);
    }

    return ResponseEntity.ok().build();
    } catch (Exception e) {
    return ResponseEntity.status(500).build();
    }
    }

    // 合并文件(Tomcat 6.0兼容版)
    private void mergeFile(String fileId, String tempDir) throws IOException {
    File[] chunks = new File(tempDir).listFiles();
    if (chunks == null || chunks.length == 0) return;

    // 按分片序号排序
    Arrays.sort(chunks, Comparator.comparingInt(f -> {
    String name = f.getName();
    return Integer.parseInt(name);
    }));

    // 读取原始文件名(从第一个分片中获取)
    String fileName = "unknown"; // 实际应从数据库或第一个分片获取
    String outputPath = uploadDir + "/" + fileName;

    try (FileOutputStream fos = new FileOutputStream(outputPath)) {
    for (File chunk : chunks) {
    Files.copy(chunk.toPath(), fos);
    chunk.delete(); // 删除分片
    }
    }

    // 删除临时目录
    new File(tempDir).delete();
    }
    }

    五、IE8兼容血泪史(附解决方案)
  • 文件夹上传:

    • 现代浏览器:``
    • IE8:需要用ActiveXObject遍历文件系统(需要降低安全级别)

    // IE8文件夹遍历(伪代码)
    function browseFolderIE8(path) {
    try {
    const fso = new ActiveXObject("Scripting.FileSystemObject");
    const folder = fso.GetFolder(path);
    const files = new Enumerator(folder.files);

    for (; !files.atEnd(); files.moveNext()) {
    const file = files.item();
    // 递归处理子文件夹…
    }
    } catch (e) {
    alert("请降低IE安全级别!");
    }
    }

  • localStorage替代方案:

    // IE8的userData存储(古老的黑科技)
    function saveToUserData(key, value) {
    const storage = document.createElement('div');
    storage.id = 'ie8Storage';
    storage.style.behavior = 'url(#default#userData)';
    document.body.appendChild(storage);

    storage.setAttribute(key, value);
    storage.save('fileUploadProgress');
    document.body.removeChild(storage);
    }

  • XMLHttpRequest降级:

    // IE8的XHR实现
    function createIE8XHR() {
    try {
    return new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
    try {
    return new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) {
    alert("您的浏览器太古老了,请升级!");
    return null;
    }
    }
    }

  • 六、项目亮点(吹牛版)
  • 全浏览器兼容:从IE8到Chrome120无缝支持(连龙芯浏览器都能跑)
  • 军工级加密:AES+SM4双算法支持(导师看了都直呼专业)
  • 企业级稳定性:MySQL+文件系统双进度存储(就算服务器爆炸也不丢数据)
  • 信创环境适配:已通过龙芯浏览器测试(学校机房的国产CPU终于有用武之地了)
  • 七、求职彩蛋

    现在加入我的"毕业设计互助群"(QQ:374992201),即可获得:

  • 完整项目源码(含IE8兼容补丁)
  • 简历优化指导(群主亲授"如何把毕业设计吹成国家级项目")
  • 内推机会(群内有多家IT公司HR潜伏)
  • 特别提示:现在加群还能参与"找bug换红包"活动,每发现一个兼容性问题奖励5-20元(导师说这叫"众测")!

    (最后小声说:这个项目还没完全跑通,但吹牛的功夫已经练得炉火纯青了…)

    导入项目

    导入到Eclipse:点击查看教程 导入到IDEA:点击查看教程 springboot统一配置:点击查看教程

    工程

    image

    NOSQL

    NOSQL示例不需要任何配置,可以直接访问测试 image

    创建数据表

    选择对应的数据表脚本,这里以SQL为例 image image

    修改数据库连接信息

    image

    访问页面进行测试

    image

    文件存储路径

    up6/upload/年/月/日/guid/filename image image

    效果预览

    文件上传

    文件上传

    文件刷新续传

    支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传 文件续传

    文件夹上传

    支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。 文件夹上传

    下载示例

    点击下载完整示例

    赞(0)
    未经允许不得转载:171主机测评 » 续传文件夹在JSP中怎么操作?
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址