精华内容
下载资源
问答
  • 文章目录前言一、环境准备及依赖库二、项目结构三、 ...在另一篇文章JavaScript高级 - nodejs+koa2实现文件上传文件切片上传断点续传(服务器端)中已经介绍了文件上传的服务器端实现,并实现了几个不同上传形式的服务


    前言

    一、环境准备及依赖库

    • axios v0.21.1: 用于调用服务端接口发送服务端请求
    • spark-md5 v3.0.1: 用于根据文件内容生成hash码
    • qs v6.9.6:用于将application/x-www-form-urlencoded格式从参数解析为a=x&b=y的格式

    二、项目结构

    web 项目根目录

    • scripts 存放js脚本目录
      • axios.min.js axios库(第三方)
      • qs.js qs库(第三方)
      • spark-md5.min.js spark-md5库(第三方)
      • axios2.js axios二次封装库(自定义)、
      • upload.js 上传文件功能代码(自定义)
    • css 样式文件目录
      • upload.css 页面样式
    • index.html 文件上传html页面

    三、 功能实现

    • 结合上面的截图,将分为5个模块进行讲解,所有模块用到的上传控件都是html原生的类型为file的input控件。
    • 为了页面的美观,我们将input隐藏起来,并用普通按钮替代,当点击按钮时触发input的click事件。
    • 另外可以再额外加一些进度显示,图片缩略图显示,文件名称显示等。
    • 关于HTML和css部分不再过多说明,下面将分模块进行js部分重点讲解,每个模块都用闭包函数包裹,避免变量冲突

    1、axios二次封装

    在每个功能模块中,我们都将通过使用axios向服务端发送请求,这时我们就需要对axios做一些特殊处理,也就是二次封装

    • 创建axios对象,避免不同场景配置冲突
    • 设置baseURL
    • 设置默认Content-Type 为 multipart/form-data
    • 在transformRequest中判断Content-Type,如果是application/x-www-form-urlencoded 则利用qs库对参数进行格式化
    //axios.js axios二次封装
    let request = axios.create();
    request.defaults.baseURL = 'http://127.0.0.1:3000';
    request.defaults.headers['Content-Type'] = 'mutipart/form-data';
    request.defaults.transformRequest = (data, headers) => {
        let contentType = headers['Content-Type'];
        if (contentType === 'application/x-www-form-urlencoded') return Qs.stringify(data);
        return data;
    }
    
    request.interceptors.response.use(response => {
        return response.data;
    });
    

    2、 单文件上传FROM-DATA,先选文件再上传

    在这里插入图片描述

    • 简单步骤分析:
    • 首先应该先获取到需要用到的页面元素:上传控件input,选择按钮,上传按钮,缩略图展示,文件展示,进度条展示
    • 绑定选择按钮的click事件并在click事件中触发上传控件input的click事件
    • 绑定上传控件input的change事件,在该事件中获取已选择的文件
    • 绑定上传按钮的click事件,在该事件中组合参数并发送post请求调用服务端API实现文件上传
    • 文件上传的关键代码就是发送请求前的参数拼接部分
      • 这里我们利用js内置的FromData类将文件作为参数传输
      • new FormData().append(“file”, file);
    • 代码实现
    //upload.js 单文件上传form-data
    (function () {
        let upload1 = document.querySelector("#upload1"),
            upload_inp = upload1.querySelector('.upload-inp'),
            upload_select = upload1.querySelector('.upload-btn.select'),
            upload_upload = upload1.querySelector('.upload-btn.upload'),
            sel_files = upload1.querySelector('.files'),
            file1 = upload1.querySelector('.abbr'),
            cur_pro = upload1.querySelector('.cur-pro'),
            pro_val = upload1.querySelector('.pro-val'),
            progress = upload1.querySelector('.progress'),
            _file;
    
        upload_select.addEventListener('click', () => {
            upload_inp.click();
        });
        upload_inp.addEventListener('change', function () {
            let file = this.files[0];
            _file = file;
            sel_files.innerHTML = file.name;
            progress.style.display = 'inline-block';
            pro_val.innerHTML = '';
        })
    
        upload_upload.addEventListener('click', function () {
            let formData = new FormData();
            formData.append('file', _file);
            formData.append('filename', _file.name);
            request.post('/upload_single_file', formData, {
                onUploadProgress: function (ev) {
                    let pro = ((ev.loaded / ev.total) * 100).toFixed(0) + '%';
                    cur_pro.style.width = pro;
                    pro_val.innerHTML = pro;
                }
            }).then(res => {
                console.log(res);
                file1.src = `http://${res.serverPath}`;
                file1.style.display = 'block';
            }).catch(err => {
                console.log(err);
            });
        });
    })();
    

    3、 单文件上传BASE64,只能上传小于100K的png或jpg图片文件

    在这里插入图片描述

    • 简单步骤分析:
    • 首先应该先获取到需要用到的页面元素:上传控件input,选择上传按钮,缩略图展示,文件名展示,进度条展示
    • 绑定选择并上传按钮的click事件并在click事件中触发上传控件input的click事件
    • 这里由于选择和上传按钮合并为一个,所以向服务端发送请求的步骤我们将放在input的change事件中
    • 绑定input的change事件,在该事件中组合参数并发送post请求调用服务端API实现文件上传
    • 在文件域的change事件中,我们需要
      • 根据获得的文件信息校验文件的大小不能超过100k(base64格式上传文件不能太大) file.size属性
      • 校验文件格式只能是png或jpg格式,file.type属性
      • 利用js内置的FileReader类将文件转换为BASE64格式
      • 并在filereader的onload函数中拿到转换为BASE64格式的内容并发送post请求实现文件上传
      • 另外在因为BASE64格式内容涉及到的字符比较多,为了避免一些特殊字符问题,在参数传递前需要用encodeURIComponent进行编码
    • 代码实现
    //upload.js 单文件base64上传
    (function () {
        let upload2 = document.querySelector("#upload2"),
            upload_inp = upload2.querySelector('.upload-inp'),
            upload_upload = upload2.querySelector('.upload-btn.upload'),
            sel_files = upload2.querySelector('.files'),
            file2 = upload2.querySelector('.abbr'),
            progress = upload2.querySelector('.progress'),
            cur_pro = upload2.querySelector('.cur-pro'),
            pro_val = upload2.querySelector('.pro-val'),
            _file;
    
        upload_upload.addEventListener('click', () => {
            upload_inp.click();
        });
        upload_inp.addEventListener('change', function () {
            progress.style.display = 'inline-block';
            pro_val.innerHTML = '';
            let file = this.files[0];
            _file = file;
            if (file.size > 100 * 1024) {
                alert('图片必须小于100k');
                return;
            }
    
            if (!/(jpg|jpeg|png)/.test(file.type)) {
                alert('只能上传png或jpg或jpeg格式的图片');
                return;
            }
            sel_files.innerHTML = file.name;
            let fr = new FileReader();
            fr.readAsDataURL(file);
            fr.onload = ev => {
                file2.src = ev.target.result;
                file2.style.display = 'block';
                console.log(file.name);
                request.post('/upload_base64', {
                    file: encodeURIComponent(ev.target.result),
                    filename: file.name
                }, {
                    headers: {
                        "Content-Type": "application/x-www-form-urlencoded"
                    },
                    onUploadProgress: function (ev) {
                        let pro = ((ev.loaded / ev.total) * 100) + '%';
                        pro_val.innerHTML = pro;
                        cur_pro.style.width = pro;
                    }
                }).then(res => {
                    console.log(res);
                    alert('上传成功了');
                    return;
                }).catch(err => {
                    console.log(err);
                    alert('失败了?')
                });
            };
    
        })
    })();
    

    4、多文件上传FORM-DATA

    在这里插入图片描述

    • 简单步骤分析:
    • 多文件上传的步骤跟单文件FORM-DATA的步骤类似
    • 首先也是先获取到需要用到的页面元素:上传控件input,选择上传按钮
    • 绑定选择按钮的click事件并在click事件中触发上传控件input的click事件
    • 绑定上传控件input的change事件,在该事件中获取已选择的文件,并遍历所选的文件组合参数发送post请求调用服务端API实现文件上传
    • 与单文件FORM-DATA上传不同的是,我们获取到的是一个文件列表
      • 在change事件中需要遍历所有所选的文件,组合参数然后循环发送请求调用服务器API接口实现多文件上传
      • 因为是不固定个数文件上传,所以在遍历所选文件后需要动态将文件名和上传进度拼接为HTML元素展示在页面上
    • 代码实现
    // upload.js 多文件上传form-data
    (function () {
        let upload3 = document.querySelector("#upload3"),
            upload_inp = upload3.querySelector('.upload-inp'),
            upload_upload = upload3.querySelector('.upload-btn.upload'),
            sel_files = upload3.querySelector('.list');
    
    
        upload_upload.addEventListener('click', () => {
            upload_inp.click();
        });
        upload_inp.addEventListener('change', function () {
            let files = this.files;
            sel_files.innerHTML = '';
            [].forEach.call(files, (file, index) => {
                sel_files.innerHTML += `<div><span class="files" style="margin-right:8px;font-size:12px">${file.name}</span><span class="pro-val" id="myfile${index}"></span></div>`
                let formData = new FormData();
                formData.append('file', file);
                formData.append('filename', file.name);
                request.post('/upload_single_file', formData, {
                    onUploadProgress: function (ev) {
                        let pro = ((ev.loaded / ev.total) * 100).toFixed(0) + '%';
                        document.querySelector(`#myfile${index}`).innerHTML = pro;
                        // sel_files.innerHTML += `<span class="files">${file.name}</span> <span class="pro-val" >${pro}</span>`
                    }
                }).then(res => {
                    console.log(res);
                    // alert('上传成功了');
                }).catch(err => {
                    console.log(err);
                });
            });
        });
    })();
    

    5、多文件拖拽上传FORM-DATA

    在这里插入图片描述

    • 简单步骤分析:
    • 在该模块中,实现拖拽上传的重点就是在**拖拽**上,而其它上传步骤跟上面的多文件上传是一样的。
    • 除了要实现拖拽上传,原来的点击上传我们也需要保留
    • 所以首先我们还是要获取到上传控件input,div块作为拖拽区域和触发点击事件的区域
    • 然后把主要的上传逻辑封装为一个单独的方法uploadFiles,接收一个数组或类数组类型的参数,以方便点击或拖拽时调用
    • 点击上传:
      • 这里我们需要给拖拽域(div)绑定一个click事件,并在该事件中触发input的click事件
      • 绑定input的change事件,在该事件中调用获取到选择的文件列表,并调用上传方法uploadFiles实现文件上传
    • 拖拽上传:
      • 要实现拖拽上传需要借助两个事件,分别是dragover和drop,就是将文件拖拽到拖拽域(div)上或是落在拖拽域(div)上时要触发的事件
      • 需要注意的是:如果将一个文件拖拽到网页上时,有些格式的文件(如:txt,jpg,png等)会被默认打开直接显示在网页上,所以我们需要在这两个事件中阻止浏览器的默认行为:ev.preventDefault()
      • 然后在drop事件中也就是当我们将文件拖拽到div上并松开鼠标时,调用uploadFiles将文件上传
      • 在drop事件中有个dataTransfer属性的files属性可以获取到拖拽进来的文件列表,这样就可以通过ev.dataTransfer.files获取到所有的多文件了
    • 代码实现
    //upload.js 拖拽上传form-data
    (function () {
        let upload5 = document.querySelector("#upload5"),
            upload_inp = upload5.querySelector('.upload-inp'),
            upload_upload = upload5.querySelector('.upload-btn'),
            sel_files = upload5.querySelector('.list');
    
        const uploadFiles = function uploadFiles(files) {
            sel_files.innerHTML = '';
            [].forEach.call(files, (file, index) => {
                sel_files.innerHTML += `<div><span class="files" style="margin-right:8px;font-size:12px">${file.name}</span><span class="pro-val" id="myfile${index}"></span></div>`
                let formData = new FormData();
                formData.append('file', file);
                formData.append('filename', file.name);
                request.post('/upload_single_file', formData, {
                    onUploadProgress: function (ev) {
                        let pro = ((ev.loaded / ev.total) * 100).toFixed(0) + '%';
                        document.querySelector(`#myfile${index}`).innerHTML = pro;
                    }
                }).then(res => {
                    console.log(res);
                    // alert('上传成功了');
                }).catch(err => {
                    console.log(err);
                });
            });
        }
        upload5.addEventListener('dragover', function (ev) {
            ev.preventDefault();
        });
        upload5.addEventListener('drop', (ev) => {
            ev.preventDefault();
            uploadFiles(ev.dataTransfer.files);
        });
    
        upload_inp.addEventListener('change', function () {
            uploadFiles(this.files);
        });
        upload5.addEventListener('click', (ev) => {
            upload_inp.click();
        });
    })();
    

    6、大文件切片上传,断点续传FORM-DATA

    接下来就是本文的最后一个模块,也是最复杂和最重点的模块:大文件切片上传和断点续传,要实现切片上传和断点续传逻辑较前面几个模块都稍有些复杂,下面我们依然来一步步分析一下:

    • 简单逻辑分析
    • 切片上传顾名思义就是将一个大文件分割成多个小文件进行分别上传,待所有切片上传完成后再将它们合并成一个文件,这样就实现了一个大文件的切片上传,同时如果上传过程出现问题,下次继续上传时还能实现断点续传
    • 切片上传的关键在于上传后要将所有切片文件合并,那么合并时就需要考虑一下问题了:
      • 需要将哪些文件进行合并?
      • 找到需要合并后的文件,要按怎么样的顺序进行合并?
        =>首先第一问题,为了能够快速方便的找到哪些文件是需要合并的,在将切片文件上传到服务器时,我们需要在服务器端建立一个单独的临时文件夹用于保存所有的切片
        =>第二个问题,为了保证合并后的文件与原文件保持一致,在切片时需要给每个切片添加一个索引,这样就能在合并时按照索引进行按顺序合并了。
    • 如果切片在上传过程中出现了问题,导致上传中断,那么下次上传时为了实现不重复上传,也就是所说的断点续传,就需要进行判断,如果文件存在则直接跳过,那么如何去判断一个文件(或切片)是否存在了呢?
      • 这时就需要用到我们前面提到的spark-md5库了,该库可根据文件内容生成一串hash值,只要文件内容不变那么生成出来的hash值也永远都是一样的,所以我们可以利用hash值加索引的形式进行文件切片的命名
    • 切片思路分析:
      • 要将一个文件进行切片,需要借助文件的**size属性和slice**方法
      • 方法一(固定个数):将一个文件切成固定个数,比如20个,然后用size/20计算出每个切片文件的大小,再利用slice进行截取
      • 方法二(固定大小):固定每个切片文件的大小,比如100k,然后用size/100计算需要分成几个切片,同样也是再用slice截取
      • 在本案例中,我们将采取方法一和方法二合并的方式进行切片:我们先根据方法二固定每个切片的大小,计算出切片的个数,然后再规定一个最大个数,如果计算出的个数超过了最大个数,就需要根据方法一进行重新切片。如果没有超出个数,则按固定大小切片。
    • 简单步骤分析

    在梳理出切片逻辑后,下面就是要一步步实现了:

    • 首先我们先来封装一个返回promise实例的方法retrieveHash,该方法主要用于根据文件内容生成一个hash值,需要借助spark-md5和FileReader
    • 封装一个所有切片上传完成后发送合并请求方法uploadComplete
      • 在该方法外面需要定义一个计数器,每上传完成一个切片需要调用一次该方法,每调用一次该方法,计数器就需要累加1
      • 当计数器的值等于切片的个数时,则说明所有切片已经上传完成,这时就可以发送合并请求进行切片合并了
      • 这里有一点需要注意:就是在发送合并请求前,最好是延迟几秒再发送,以避免一些不必要的错误
    • 在文件域的change事件中得到要上传的文件
    • 调用上面封装好的获取hash值的方法retrieveHash,然后根据hash值向服务端发送一个请求来获取已经上传过的切片列表filelist(用于断点续传判断)
    • 根据上面分析的切片逻辑进行切片,并将切片文件信息保存在数组中
    • 遍历切片数组,首先判断该切片是否已经上传,也就是看该切片文件是否已经存在于上面所获取到的文件列表filelist中
      • 如果存在则调用uploadComplete,让计数器累加
      • 如果不存在,则调用服务端切片上传接口进行文件上传,同时在上传完成后,仍需调用uploadComplete方法进行计数器累加,一旦计数器的值跟切片个数相等,则会自动调用合并接口进行文件合并
    • 至此大文件的切片上传和断点续传就实现了。
    • 代码实现
    //upload.js 大文件切片上传,断点续传
    (function () {
        let upload4 = document.querySelector("#upload4"),
            upload_inp = upload4.querySelector('.upload-inp'),
            upload_upload = upload4.querySelector('.upload-btn'),
            sel_files = upload4.querySelector('.files'),
            cur_pro = upload4.querySelector('.cur-pro'),
            pro_val = upload4.querySelector('.pro-val'),
            progress = upload4.querySelector('.progress');
    
        const retriveHash = function retriveHash(file) {
            return new Promise((resolve, reject) => {
                let spark = new SparkMD5.ArrayBuffer();
                let fr = new FileReader();
                fr.readAsArrayBuffer(file);
                fr.onload = (ev) => {
                    spark.append(ev.target.result);
                    let hash = spark.end();
                    let suffix = /\.([0-9a-zA-Z]+)$/.exec(file.name)[1];
                    resolve({
                        hash,
                        suffix
                    });
                };
            });
    
    
        }
    
        let complete = 0;
        const uploadComplete = function uploadComplete(hash, count) {
            complete++;
            let progerss = (complete / count * 100).toFixed(2) + '%';
            cur_pro.style.width = progerss;
            pro_val.innerHTML = progerss;
            if (complete < count) return;
            cur_pro.style.width = '100%';
            pro_val.innerHTML = '100%';
            setTimeout(() => {
                request.post('/upload_merge', {
                    hash,
                    count
                }, {
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded'
                    }
                }).then(res => {
                    console.log(res);
                    // alert('上传成功了');
                }).catch(err => {
                    console.log(err);
                });
            }, 3000);
        }
        upload_upload.addEventListener('click', function () {
            upload_inp.click();
        });
    
        upload_inp.addEventListener('change', async function () {
            let file = this.files[0];
            progress.style.display = 'inline-block';
            cur_pro.style.width = '0%';
            pro_val.innerHTML = '0%';
            let chunks = [];
            let {
                hash,
                suffix
            } = await retriveHash(file);
            sel_files.innerHTML = `${hash}.${suffix}`;
            let {
                filelist
            } = await request.get('/uploaded', {
                params: {
                    hash
                }
            });
    
            let maxSize = 100 * 1024; //100k
            let count = Math.ceil(file.size / maxSize);
            //限制切片的数量不能超过20个,并重新计算每个切片的大小
            if (count > 20) {
                maxSize = file.size / 20;
                count = 20;
            }
    
            let index = 0;
            while (index < count) {
                chunks.push({
                    file: file.slice(index * maxSize, (index + 1) * maxSize),
                    filename: `${hash}_${index+1}.${suffix}`
                });
                index++;
            }
    
            chunks.forEach((item, index) => {
                //如果已经上传过就不再上传了
                if (filelist && filelist.length > 0 && filelist.includes(item.filename)) {
                    uploadComplete(hash, count);
                    return;
                }
                let formData = new FormData();
                formData.append('file', item.file);
                formData.append('filename', item.filename);
                request.post('/upload_chunk', formData).then(res => {
                    uploadComplete(hash, count);
                    // console.log(res);
                    // alert('上传成功了');
                }).catch(err => {
                    console.log(err);
                });
            });
        });
    
    
    })()
    

    总结

    本文中我们进行了分模块分场景实现了关于端文件上传的几个功能点,并重点分析了大文件切片上传和断点续传的功能点。每个模块对应的功能代码都已经提供。
    在下一篇文章JavaScript高级 - 实现文件上传大文件切片上传断点续传前后端完整代码中我们将会把服务端和客户端的全部完整代码展示出来

    展开全文
  • 主要为大家详细介绍了js实现上传文件添加删除文件选择框 ,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • * 用一个JavaScript文件实现局域网文件的上传下载 * Core code only, To upload and download any file by NodeJS; * # -*-coding:utf-8 -*- * # @Created on : "Tuesday July 27 2021 11:00:37 GMT+0800 ...
  • js 上传图片 校验 文件类型 大小js 上传图片 校验 文件类型 大小js 上传图片 校验 文件类型 大小 js 上传文件校验 js 上传文件校验 js 上传文件校验
  • JS上传文件

    2018-08-31 12:26:24
    通过JS实现文件上传的组件,Uploadify。如有需要请下载
  • JS文件上传

    2016-09-30 18:11:30
    JS上传文件
  • 下载文件 方法一 1.跟后端童鞋确认交付的接口的response header设置了 2.修改axios请求的responseType为blob,以post请求为例: 3.请求成功,拿到response后,调用download函数(创建a标签,设置download属性,...

     

    目录

    下载文件

    方法一

    1.跟后端童鞋确认交付的接口的response header设置了

    2.修改axios请求的responseType为blob,以post请求为例:

    3.请求成功,拿到response后,调用download函数(创建a标签,设置download属性,插入到文档中并click)

     方法二

    1.下载图片效果图如下:

    2. 下载例如docx文档效果图如下:

    方法三

    1.代码

    判断上传文件类型

    1.代码

    获取上传文件大小

    1.代码


     

    下载文件

     

    所用的浏览器:Google Chrome

     

    方法一

     

    功能:点击导出按钮,提交请求,下载excel文件;

     

    1.跟后端童鞋确认交付的接口的response header设置了

    以及返回了文件流。

     

    2.修改axios请求的responseType为blob,以post请求为例:

     

    axios({
        method: 'post',
        url: 'api/user/',
        data: {
            firstName: 'Fred',
            lastName: 'Flintstone'
        },
        responseType: 'blob'
    }).then(response => {
        this.download(response)
    }).catch((error) => {
    
    })

     

    3.请求成功,拿到response后,调用download函数(创建a标签,设置download属性,插入到文档中并click)

     

    methods: {
        // 下载文件
        download (data) {
            if (!data) {
                return
            }
            let url = window.URL.createObjectURL(new Blob([data]))
            let link = document.createElement('a')
            link.style.display = 'none'
            link.href = url
            link.setAttribute('download', 'excel.xlsx')
            
            document.body.appendChild(link)
            link.click()
        }
    }

     

    上面代码来源与:https://www.cnblogs.com/yulj/p/8494465.html

     

     方法二

     

    window.open(url)

     

    1.下载图片效果图如下:

     

    open

     

    2. 下载例如docx文档效果图如下:

     

    docx

     

    Window open() 方法请查看:http://www.runoob.com/jsref/met-win-open.html

     

    方法三

     

    1.代码

     

    window.location.href = url;

     

     

    判断上传文件类型

     

    1.代码

     //判断上传文件类型
                        var filextension = that.formItem.de_enclosure.substring(that.formItem.de_enclosure.lastIndexOf("."), that.formItem.de_enclosure.length);
                        filextension = filextension.toLowerCase();
    
                        if ((filextension != '.jpg') && (filextension != '.gif') && (filextension != '.jpeg')
                            && (filextension != '.png') && (filextension != '.bmp') && (filextension != '.txt')
                            && (filextension != '.docx') && (filextension != '.zip')) {
                            alert("对不起,系统仅支持jpg,gif,jpeg,png,bmp,docx,txt,zip格式的文件。");
                            return
                        }

     

    上面代码中的that.formItem.de_enclosure是一个图片全部路径,例如:http://artmofang.oss-cn-beijing.aliyuncs.com/2018/1533281483000-hdiFCC.png

     

    获取上传文件大小

     

    1.代码

     

    
                    var size = 0;
                    size =files.target.files[0].size;//byte
                    size = size / 1024;//kb
                    size = (size / 1024).toFixed(3);//mb
                    alert('上传文件大小为' + size + 'M');

     

    上面代码files.target.files[0]是我们获取到的文件。toFixed是保留小数,例如如下代码:

     

    var num =2.446242342;
    num = num.toFixed(2);  // 输出结果为 2.45

     

    JavaScript 保留小数具体请看:https://www.runoob.com/w3cnote/javascript-two-decimal.html

    展开全文
  • HTML实现文件上传的3种实现方法 1用flash上传文件 2用js插件上传文件 3用表单上传文件
  • js异步上传文件

    2016-03-17 17:32:03
    JavaScript js Ajax 异步 上传文件 包含servlet action 以及JSP 代码
  • JS实现本地文件上传至阿里云服务器 前言 在前面的博客《AngularJS进阶(二十五)JS实现图片预览并导入服务器功能》(点击查看详情)中,实现了JS将本地图片文件预览并上传至阿里云服务器的操作。这次需要实现将本地打包...

    JS实现本地文件上传至阿里云服务器

    前言

          在前面的博客《 JavaScript进阶(八)JS实现图片预览并导入服务器功能》(点击查看详情)中,实现了JS将本地图片文件预览并上传至阿里云服务器的操作。这次需要实现将本地打包好的文件上传至阿里云服务器。使用前面的图片文件上传方法无法完成此操作。操作界面如下:

     

    思路

          本地与服务端传输文件的格式应该是熟悉的Base64格式。首先需要将本地文件转换为Base64格式,传输至服务端后,在服务端再将Base64格式的文件转换为原始文件。

    源码解析

    控制器

     

    /*--------------移动APP版本管理G030 G031-------------------------*/
    medModule.controller('VersionController',function($scope, $http){
    $scope.queryFun = function() {
    try{
    appCallServer($http,"G030",{"mangid":localStorage.mangid
    },
    //success function
    function(data){
    $scope.currentVersion = data.version;
    },
    //fail function
    function(data){
    //alert("未找到记录:"+data.errtext);
    });
    }catch(error){
    alert("G030:"+error.message);
    }
    };
    $scope.queryFun();
    // 上传文件
    $scope.doTx = function() {
    var appBase64 = document.getElementById("appBase64").innerHTML;	// 获取文件Base64编码内容
    var sunny = document.getElementById("appName").innerHTML;	// 获取文件名称(PS:瞬间感觉自己好聪明啊~~)
    var appName = sunny.substr(0, sunny.length-4); // 获取子字符串。
    /*alert(appBase64);
    alert(appName);*/
    if(appBase64.length == 0){
    alert("请选择有效文件[该文件为空]");
    }
    try {
    appCallServer($http, "G031", {
    "mangid"   : localStorage.mangid,
    "appBase64": appBase64,
    "appVersion"  : appName
    },
    // success function
    function(data) {
    alert("上传文件成功");
    },
    // fail function
    function(data) {
    alert("上传文件失败:" + data.errtext);
    });
    } catch (error) {
    alert("G031:" + error.message);
    }
    };
    });

     

    Html脚本

     

    <script type="text/javascript">  
    function loadAppFile(source) {
    var file = source.files[0];
    if (window.FileReader) {
    var fr = new FileReader();
    // onloadend读取完成触发,无论成功或失败.如果读取失败,则 result的值为 null,否则即是读取的结果
    fr.onloadend = function(e) {
    var content = e.target.result;
    if(content != null){
    var arr = content.toString().split(",");
    // 将文件Base64编码内容传至页面
    document.getElementById("appBase64").innerHTML = arr[1];
    // 获取图片名称(PS:瞬间感觉自己好聪明啊~~) 
    document.getElementById("appName").innerHTML = document.getElementById("appInput").files[0].name;
    /* alert(document.getElementById("appInput").files[0].name);
    alert(document.getElementById("appName").innerHTML);
    alert(document.getElementById("appBase64").innerHTML); */
    }
    };
    fr.readAsDataURL(file);
    }
    }
    </script>

     

    服务端接收代码

     

    /************************* 更新移动APP版本信息 *************************/
    public static boolean do_G031(RequestMessage request,ResponseMessage response){
    logger.info("\n\n------------Update_APP_G031 debug info-------------\n请求数据包信息:" + request.json.toString());
    if(!Pubf.checkMangSession(request,response)){
    return(false);
    }
    try{
    String app,version;
    app	= request.getString("appBase64").trim();
    version	= request.getString("appVersion").trim();
    /*--------------------------- 将应用存进服务端 ---------------------------*/
    if(!app.equals("")){
    logger.info("开始写文件.....");
    FileUtil.GenerateApp(app, MyConst.APP_FILE_PATH + version + ".wgt");
    logger.info("写文件完成.....");
    /*-------------------------将应用版本号写进版本文件--------------------------*/
    logger.info("开始写入版本号.....");
    FileUtil.writeFile(MyConst.APP_VERSION_FILE_PATH, version);
    logger.info("写版本号完成.....");
    return(true);
    }else{
    return(false);
    }
    }catch(Exception e){
    e.printStackTrace();
    response.errtext = "移动APP更新失败";
    response.result  = MyConst.ERR_FORMAT;
    return(false);
    }
    }

     

    工具类

     

    <pre name="code" class="java">/**
     * 
     * @param appStr 应用内容
     * @param appFilePath 应用存放路径
     * @return
     */
    public static boolean GenerateApp(String appStr, String appFilePath) { // 对字节数组字符串进行Base64解码并生成wgt更新包
    if (appStr == null) // 文件数据为空
    return false;
    BASE64Decoder decoder = new BASE64Decoder();
    try {
    // Base64解码
    byte[] b = decoder.decodeBuffer(appStr);
    for (int i = 0; i < b.length; ++i) {
    if (b[i] < 0) {// 调整异常数据
    b[i] += 256;
    }
    }
    // 生成wgt应用
    OutputStream out = new FileOutputStream(appFilePath);
    out.write(b);
    out.flush();
    out.close();
    return true;
    } catch (Exception e) {
    return false;
    }
    }

     

     

     

    读取到的文件内容如下:

     

          由上图可见,其编码方式正是我们之前所说的Base64编码方式。那么接下来的工作就很好做了。按照之前图片处理的思路即可。

          期间自己也遇到了一部分问题。例如

    <i id="appBase64" hidden="hidden"></i>

    <i id="appName" hidden="hidden"></i>

          隐藏元素的位置,尽量将其置于靠近提交Buton的附近,否则在控制器中获取不到其内容。

          经过以上步骤,就可以实现将更新包上传至服务端相应更新文件夹中,同时将更新包版本号信息写入相应的version.txt文件内。

    代码领悟

           将以上代码与之前做过的图片上传做对比,发现两者在数据获取时的方式是不同的,本文使用了HTML5之FileReader方法(点击查看详情)。之前做图片上传时应用此方法亦可以解决问题。两者写入服务端的方法是相同的,均是将Base64编码内容写入文件中。思路清晰了,问题自然会很容易得到解决。

    进一步优化

          幸福永不满足,在以上文件上传过程中会遇到较大文件的上传,为此可能需要等待1min,甚至若干分钟,这是让人无法忍受的事情。为了增强用户的使用体验。特为文件上传增加进度条美化效果。详情见下篇博客。

    参考文献

    1.http://blog.csdn.net/sunhuaqiang1/article/details/50475429

    2.http://www.ibm.com/developerworks/cn/web/1101_hanbf_fileupload/

    3.http://blog.csdn.net/jackfrued/article/details/8967667

    4.http://www.cnblogs.com/hema/archive/2009/10/21/1587560.html

    5.http://www.108js.com/article/article7/70001.html?id=26

    鸣谢

    HTML5之FileReader的使用

    美文美图

     

    展开全文
  • JS上传文件的方法,上传单个文件的大小可以任意自己定.
  • 文件上传和下载

    千次阅读 2017-03-27 19:34:53
    什么是文件上传?文件上传就是把用户的信息保存起来。为什么需要文件上传?...那么这张照片就应该要进行保存。...上传文件数据是经过MIME协议进行分割的,表单进行了二进制封装。也就是说:getParameter()无法获取得到

    什么是文件上传?

    文件上传就是把用户的信息保存起来。

    为什么需要文件上传?

    在用户注册的时候,可能需要用户提交照片。那么这张照片就应该要进行保存。

    上传组件(工具)

    为什么我们要使用上传工具?

    为啥我们需要上传组件呢?当我们要获取客户端的数据,我们一般是通过getParameter()方法来获取的。

    上传文件数据是经过MIME协议进行分割的,表单进行了二进制封装。也就是说:getParameter()无法获取得到上传文件的数据。

    我们首先来看看文件上传http是怎么把数据带过去的

    • jsp页面,表单一定要指定enctype:multipart/form-data
    
        <form action="${pageContext.request.contextPath }/servlet/UploadServlet1" enctype="multipart/form-data" method="post">
            上传用户:<input type="text" name="username"><br/>
            上传文件1:<input type="file" name="file1"><br/>
            上传文件2:<input type="file" name="file2"><br/>
            <input type="submit" value="提交">
        </form>
    
    
    • http抓包

    这里写图片描述

    • 尝试在Servlet上使用getParameter()获取数据
    
    
            String ss = request.getParameter("username");
            System.out.println(ss);
    • 直接使用getParameter是获取不到数据的。

    这里写图片描述

    那么我们要怎么办呢????request对象提供了ServletInputStream流给我们读取数据

    • 我们试着读取下文件
    
            ServletInputStream inputStream = request.getInputStream();
    
            byte[] bytes = new byte[1024];
            int len = 0;
    
            while ((len = inputStream.read(bytes)) > 0) {
                System.out.println(new String(bytes, 0, len));
            }
    
    • 在jsp页面多增添一个input控件
    
    <input type="text" name="password">
    
    • 我上传的文本文件内容就是111111,读取效果如下:

    这里写图片描述

    现在我们能够读取上传文件的数据了,但是现在问题又来了:怎么把文件上传个数据和普通传送给服务器的数据分割开来呢???上面在图上我们已经看到了,他们是混合在一起的。

    按我们平常的做法是很难分割开来的,所以我们需要上传组件


    上传组件有两种

    • FileUpload【操作比较复杂】
    • SamrtUpload【操作比较简单】

    FileUpload

    要使用FileUpload组件,就需要导入两个jar包

    • commons-io
    • Commons-fileupload

    开发步骤

    • 创建解析器工厂对象【DiskFileItemFactory】
    • 通过解析器工厂创建解析器【ServletFileUpload】
    • 调用解析器方法解析request对象,得到所有上传的内容【list】
    • 遍历list,判断每个对象是否是上传文件
      • 如果是普通表单字段,得到字段名和字段值
      • 如果是上传文件,调用InputSteam方法得到输入流,读取上传的数据

    快速入门

    
    
            try{
    
                //1.得到解析器工厂
                DiskFileItemFactory factory = new DiskFileItemFactory();
    
                //2.得到解析器
                ServletFileUpload upload = new ServletFileUpload(factory);
    
                //3.判断上传表单的类型
                if(!upload.isMultipartContent(request)){
                    //上传表单为普通表单,则按照传统方式获取数据即可
                    return;
                }
    
                //为上传表单,则调用解析器解析上传数据
                List<FileItem> list = upload.parseRequest(request);  //FileItem
    
                //遍历list,得到用于封装第一个上传输入项数据fileItem对象
                for(FileItem item : list){
    
                    if(item.isFormField()){
                        //得到的是普通输入项
                        String name = item.getFieldName();  //得到输入项的名称
                        String value = item.getString();
                        System.out.println(name + "=" + value);
                    }else{
                        //得到上传输入项
                        String filename = item.getName();  //得到上传文件名  C:\Documents and Settings\ThinkPad\桌面\1.txt
                        filename = filename.substring(filename.lastIndexOf("\\")+1);
                        InputStream in = item.getInputStream();   //得到上传数据
                        int len = 0;
                        byte buffer[]= new byte[1024];
    
    
                        String savepath = this.getServletContext().getRealPath("/upload");
                        FileOutputStream out = new FileOutputStream(savepath + "\\" + filename);  //向upload目录中写入文件
                        while((len=in.read(buffer))>0){
                            out.write(buffer, 0, len);
                        }
    
                        in.close();
                        out.close();
                    }
                }
    
            }catch (Exception e) {
                e.printStackTrace();
            }

    测试

    • 普通的字段和上传的文件都能读取得到了!

    这里写图片描述


    SmartUpload

    要使用SmartUpload组件,就需要导入smartupload.jar开发包

    快速入门

    
    
            //实例化组件
            SmartUpload smartUpload = new SmartUpload();
    
            //初始化上传操作
            smartUpload.initialize(this.getServletConfig(), request, response);
    
    
            try {
    
                //上传准备
                smartUpload.upload();
    
                //对于普通数据,单纯到request对象是无法获取得到提交参数的。也是需要依赖smartUpload
                String password = smartUpload.getRequest().getParameter("password");
                System.out.println(password);
    
                //上传到uploadFile文件夹中
                smartUpload.save("uploadFile");
    
    
            } catch (SmartUploadException e) {
                e.printStackTrace();
            }
    

    测试

    同样地,我们可以上传文件到uploadFile文件夹中。代码量也的确减少很多!

    也能够获取普通字段的参数

    这里写图片描述


    上传文件名的中文乱码和上传数据的中文乱码

    • 我把文件名改成中文,就乱码了

    这里写图片描述

    • 表单提交过来的中文数据也乱码了

    这里写图片描述

    上面已经说了,上传文件的数据的表单进行了二进制封装,所以使用request对数据编码编码,对于表单提交过来的数据是不奏效的!

    FileUpload解决乱码

    使用FileUpload解决乱码问题是十分简单的

    • 解决中文文件名乱码,得到解析器以后,就直接设置解析器的编码为UTF-8就行了!
    
    
            //设置upload的编码
            fileUpload.setHeaderEncoding("UTF-8");
    
    • 解决表单数据乱码,在获取表单值的时候,按照UTF-8编码来获取
    
       String value = fileItem.getString("UTF-8");

    效果:

    这里写图片描述


    SmartUpload解决乱码

    这个组件解决乱码问题有点麻烦,在网上找了各种办法也没找到简单的……

    所以,如果数据不涉及到中文就使用SmartUpload组件,涉及到中文数据就使用FileUpload组件吧!


    多个文件上传,动态添加上传控件

    假设我现在有多个文件要上传,而且要上传的个数是不确定的。那么我们要怎么办呢???

    我们不可能列出很多很多个上传文件的控件在页面上,这样不美观。如果用户用不到那么多个控件,也浪费呀。

    所以,我们想要动态地增添上传文件的控件,如果用户还想要上传文件,只需要动态地生成控件出来即可!

    分析

    要想在页面上动态地生成控件,无非就是使用JavaScript代码。

    那么我们要怎么做呢??

    这样子吧:当用户想要上传文件的时候,就点击按钮,按钮绑定事件,生成文件上传的控件

    为了做得更加完善,每当生成了文件上传的控件,也提供一个删除按钮,删除该控件!

    我们应该使用div装载着我们要生成的控件和删除按钮,而用户点击删除的时候,应该是要把删除按钮和文件上传控件都一起隐藏起来的。所以,最好就是使用嵌套div

    代码

    • 页面代码:
    
    
    <table border="1px">
    
        <tr>
            <td>上传用户:</td>
            <td><input type="text" name="username"></td>
        </tr>
    
        <tr>
            <td>添加上传文件</td>
            <td><input type="button" value="添加上传文件" onclick="addUploadFile()"> </td>
        </tr>
    
        <tr>
    
            <td>
                <div id="file">
                </div>
            </td>
        </tr>
    
    </table>
    
    • javaScript代码
    
        <script type="text/javascript">
    
            function addUploadFile() {
    
                //生成文件上传控件
                var input = document.createElement("input");
                input.type = 'file';
                input.name = 'fileName';
    
    
                //生成删除按钮
                var del = document.createElement("input");
                del.type = 'button';
                del.value = '删除';
    
                //生成内部的div
                var innerDiv = document.createElement("div");
    
                //将两个控件绑定到内部div上
                innerDiv.appendChild(input);
                innerDiv.appendChild(del);
    
                //得到外部div控件,并将内部div绑定到外部div上
                var outterDiv = document.getElementById("file");
                outterDiv.appendChild(innerDiv);
    
                //为删除按钮绑定事件
                del.onclick = function dele() {
    
                    //调用外界div的remove方法把内部的div干掉
                    this.parentNode.parentNode.removeChild(this.parentNode);
                }
    
            }
    
        </script>
    

    文件上传细节

    • 如果上传文件的大小大于我们设定文件的大小,那么文件在上传的时候会使用临时文件保存上传数据。在上传完毕后,我们应该删除临时文件
    • 上传文件的位置是不能在WEB服务器管理之下的,否则可能造成安全问题【其他人有可能通过手段来修改上传文件】
    • 如果上传文件名相同,那么就会把原本的上传文件覆盖掉。我们要生成一个独一无二的文件名。
    • 如果用户量很大,上传文件非常多。那么我们不应该在一个目录保存所有的上传文件,这样很可能造成磁盘奔溃了。所以我们要把上传的文件打散到不同的目录下

    分析

    删除临时文件问题是非常简单的,只需要在所有的操作完毕之后,调用FileItem的delete()方法即可

    让上传文件的位置不能在WEB服务器管理之下,我们把上传文件的位置放到WEB-INF/目录下即可!

    文件名相同的问题,我们可以使用UUID+用户上传的文件名来作为我们保存上传文件名。这样的文件名就是独一无二的了。

    要将上传的文件进行打散,那么我们需要使用HashCode算法来进行打散

    • 低四位生成一级目录
    • 5-8位生成二级目录

    代码

    下面我们写一个比较完善的上传文件代码

    • 使用hashCode算法来打散保存的目录
    
        private String makeDirPath(String fileName, String path) {
    
            //通过文件名来算出一级目录和二级目录
            int hashCode = fileName.hashCode();
            int dir1 = hashCode & 0xf;
            int dir2 = (hashCode & 0xf0) >> 4;
    
            String dir = path + "\\" + dir1 + "\\" + dir2;
    
            //如果该目录不存在,就创建目录
            File file = new File(dir);
            if (!file.exists()) {
    
                file.mkdirs();
            }
            //返回全路径
            return dir;
    
        }
    
    
    • 生成独一无二的文件名
    
    
        private String makeFileName(String fileName) {
    
            //使用下划线把UUID和文件名分割开来,后面可能会解析文件名的。
            return UUID.randomUUID().toString() + "_"+ fileName;
    
        }
    • 上传的代码
    
    
            //创建工厂
            DiskFileItemFactory factory = new DiskFileItemFactory();
    
            //通过工厂创建解析器
            ServletFileUpload fileUpload = new ServletFileUpload(factory);
    
            //设置upload的编码
            fileUpload.setHeaderEncoding("UTF-8");
    
            //判断上传表单的类型
            if(!fileUpload.isMultipartContent(request)){
                //上传表单为普通表单,则按照传统方式获取数据即可
                return;
            }
    
            try {
    
                //解析request对象,得到List【装载着上传的全部内容】
                List<FileItem> list = fileUpload.parseRequest(request);
    
                //遍历List,判断装载的内容是普通字段还是上传文件
                for (FileItem fileItem : list) {
    
                    //如果是普通输入项
                    if (fileItem.isFormField()) {
    
                        //得到输入项的名称和值
                        String name = fileItem.getFieldName();
                        String value = fileItem.getString("UTF-8");
    
                        System.out.println(name + " = " + value);
                    } else {
    
                        //如果是上传文件
    
                        //得到上传名称【包括路径名】
                        String fileName = fileItem.getName();
    
                        //截取文件名
                        fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
    
                        //生成独一无二的文件名
                        fileName = makeFileName(fileName);
    
                        InputStream inputStream = fileItem.getInputStream();
    
                        //得到项目的路径,把上传文件写到项目中
                        String path = this.getServletContext().getRealPath("/WEB-INF/uploadFile");
    
                        //得到分散后的目录路径
                        String realPath = makeDirPath(fileName, path);
    
                        FileOutputStream outputStream = new FileOutputStream(realPath + "\\" + fileName);
    
                        byte[] bytes = new byte[1024];
                        int len = 0;
                        while ((len = inputStream.read(bytes)) > 0) {
                            outputStream.write(bytes, 0, len);
                        }
    
                        inputStream.close();
                        outputStream.close();
    
                        //删除临时文件的数据
                        fileItem.delete();
    
                    }
                }
    
            } catch (FileUploadException e) {
                e.printStackTrace();
            }
    

    效果:

    • 成功把目录打散,文件名也是独一无二的了。

    这里写图片描述


    列出上传目录下的文件,提供下载

    在讲解respose对象的时候已经讲解过文件下载了。这次我们就直接写一个小案例来巩固文件下载把。

    • 上传目录下的文件有3个

    这里写图片描述

    分析

    首先,要把目录下的文件都列出来。由于后面要根据文件名对文件进行下载,所以我们用一个Map集合来保存所有的文件

    下载文件部分也很简单,根据文件名和上传文件位置找到对应的文件,对其进行读写,然后修改消息头实现下载就好了。

    代码

    • 将存放在WEB-INF/目录下的文件全部放在Map集合中
    
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
            //得到上传文件的目录
            String filePath = this.getServletContext().getRealPath("/WEB-INF/uploadFile");
    
            Map map = new HashMap();
    
            //使用递归来得到所有的文件,并添加到Map集合中
            getAllFiles(new File(filePath), map);
    
            request.setAttribute("map", map);
            request.getRequestDispatcher("/listFile.jsp").forward(request, response);
    
    
    
        }
    
        private void getAllFiles(File filePath, Map map) {
    
            //如果不是文件,那么它就是文件夹
            if (!filePath.isFile()) {
    
                //列出文件夹下所有的文件(可能是文件,可能是文件夹)
                File[] files = filePath.listFiles();
                for (File file : files) {
    
                    //得到的文件(或者是文件夹)再对其进行判断
                    getAllFiles(file, map);
                }
            } else {
                //进入到else语句了,肯定是文件了
    
                //得到文件名
                String fileName = filePath.getName().substring(filePath.getName().lastIndexOf("_") + 1);
    
                //我们将文件全名作为key,文件名作为value保存在map集合中
                map.put(filePath.getName(), fileName);
    
            }
    
        }
    
    • 在JSP页面中显示可以下载的文件
    
    
    
    <c:forEach items="${map}" var="me">
    
        <c:url var="url" value="/DownFileServlet">
            <c:param name="fileName" value="${me.key}"></c:param>
        </c:url>
        ${me.value}<a href="${url}">下载!</a><br>
    
    </c:forEach>
    • 实现下载的Servlet
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            //得到文件的全名
            String fileName = request.getParameter("fileName");
    
            //如果是中文数据,需要转码。
            fileName = new String(fileName.getBytes("ISO8859-1"), "utf-8");
    
            //得到保存文件的位置
            String path = this.getServletContext().getRealPath("/WEB-INF/uploadFile");
    
            //文件是通过文件名进行hashCode打散保存的,通过文件名拿到文件绝对路径
            String fileRealPath = makeFilePath(fileName, path);
            System.out.println(fileRealPath);
    
            //判断文件是否存在
            File file = new File(fileRealPath);
            if (!file.exists()) {
                request.setAttribute("message", "您要下载的资源不存在了!");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
                return ;
            }
    
            //存在
    
            //读取该文件并把数据写给浏览器
            FileInputStream inputStream = new FileInputStream(fileRealPath);
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = inputStream.read(bytes)) > 0) {
                response.getOutputStream().write(bytes, 0, len);
            }
    
            inputStream.close();
    
    
            //设置消息头,告诉浏览器,这是下载的文件
            String name = fileName.substring(fileName.lastIndexOf("_") + 1);
            response.setHeader("content-disposition","attachment;filename=" + URLEncoder.encode(name, "UTF-8"));
    
        }
    
        private String makeFilePath(String fileName, String path) {
    
            int hashCode = fileName.hashCode();
    
            int dir1 = hashCode & 0xf;
            int dir2 = (hashCode & 0xf0) >> 4;
    
            String dir = path + "\\" + dir1 + "\\" + dir2 +"\\"+ fileName;
            return dir;
        }
    

    效果

    这里写图片描述

    展开全文
  • 一个包含多文件上传下载,以及相关js和代码类。
  • 主要介绍了node.js express框架实现文件上传下载功能,结合具体实例形式详细分析了node.js express框架针对文件上传下载的前后台相关实现技巧,需要的朋友可以参考下
  • Element UI 和js实现文件上传和下载

    千次阅读 2019-07-15 14:29:37
    文件上传 before-upload参数是在文件上传之前对文件进行一些验证 action参数是文件上传的服务器地址 this.uploadHref = this.baseUrl + '/tourismManagement/uploadTourismMesExcel'; baseUrl: process.env....
  • JSJS 实现文件上传下载和删除

    千次阅读 2018-06-06 14:14:33
    本篇运用html的input type=”file”属性已经结合bootstrapTable的布局框架实现对文件上传下载和删除操作: 一:Html 这里引入了bootstarp、bootstrap-table的js和css文件,请在百度上搜索官网地址下载所需...
  • Asp.Net WebApi 上传文件方法: 实现功能: 1.原生js调用api上传 2.jq ajax调用api上传 上传文件
  • Nestjs+minio 上传下载删除文件

    千次阅读 2019-10-08 16:57:40
    基于上一遍讲了如何利用nestjs 搭建一个restful风格的后端,现在接着讲如何结合minio实现文件上传和下载。 文中涉及到的minio 知识点参考https://blog.csdn.net/zw52yany/article/details/101217708这遍文章 上传 ...
  • restful与js方式文件上传下载,restful方式访问,并且通过js方式下载文件
  • 文章目录一、SpringMVC支持文件下载二、SpringMVC支持文件上传1.导入文件上传的两个jar包2.index.jsp前端页面3.配置文件上传解析器4.文件上传请求处理三、多文件上传 一、SpringMVC支持文件下载 假设要下载项目中的...
  • 上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的。 本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路。 实现文件夹上传,要求:服务端保留层级结构,支持10w级别的...
  • js jsp 文件上传

    2015-10-16 16:08:09
    js 实现文件上传,该项目是javaweb项目,下载下来直接导入eclipse,在D盘创建一个upload文件夹,就可以接收到上传文件
  • dropzone.js是重量轻的JavaScript库,将HTML元素设置为一个降落区,并通过Ajax文件上传到服务器。本文给大家详细介绍Dropzone.js实现文件拖拽上传功能,需要的朋友参考下吧
  • js上传文件

    万次阅读 2017-03-21 16:24:10
    js上传文件,文件上传,文件上传到后台,文件上传到服务器
  • JS 文件上传/下载

    千次阅读 2018-03-23 22:49:28
    项目需要 文件上传/下载 想用一个轻量级的框架,但是在网上搜索都没有找到于是想自己手写一个,但是由于浏览器限制不允许获取本地路径(IE除外)所以还是用了框架 ajaxfileupload 超轻量级的 JSP文件 &lt;...
  • 主要为大家详细介绍了JS原生上传大文件显示进度条,php上传文件关键代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 主要介绍了C#实现文件上传下载Excel文档示例代码,需要的朋友可以参考下
  • C#/.NET js跨域异步上传文件。前端用js异步做利用uploadify这个js库,上传部分在另一个mvc项目中 从而实现跨域上传文件。支持多文件上传 上传部分稍微修改同样适用不是mvc项目,很简单的改动。 代码详细,简单易懂

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 264,335
精华内容 105,734
关键字:

js下载文件和上传文件一样