第二十天、文件上传下载实现

一、文件上传

1、multer中间件

再上传文件时,我们通常会使用到他。Multer用于处理multipart/form-data 类型的表单数据。首先我们先安装它:

cnpm install multer --save

2、使用

首先在form表单中我们需要设置enctype为:multipart/form-data表单类型。同时我们也需要用到fs模块对文件重命名。下面是单文件上传实例:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <form action="http://localhost:8080/" method="post" enctype="multipart/form-data">
            <input type="file" name="files" value="指定文件">
            <br><br>
            <input type="submit" value="上传">
        </form>
    </body>
</html>

node代码:

const express=require("express");
const multer=require('multer');
//初始化上传对象
var upload=multer({dest:'./upload/'});
var fs = require('fs');


var app=express();

app.use("/",upload.single("files"),function(req,res){   //files为input type="file"的name值
    var oldFile=req.file.destination+req.file.filename; //指定旧文件
    var newFile=req.file.destination + req.file.originalname;   //指定新文件
    fs.rename(oldFile,newFile,function(err){
        if(err){
            res.send('上传失败!');
        }else{
            res.send('上传成功!');
        }
    });
});

app.listen(8080);

在这里我们可以指定单个文件上传到根目录的upload文件夹里。这里值得注意的是req.file会返回文件的基本信息:

  fieldname: ***,   //input type="file"的name值
  originalname: ***,    //用户计算机上的文件的名称
  encoding: '***',      //文件编码
  mimetype: ***',       //文件的 MIME 类型
  destination: './***/',        //保存路径
  filename: ***,        //保存在 destination 中的文件名
  path: ***,        //已上传文件的完整路径
  size: **      //文件大小(字节单位)

3、上传多个文件

在HTML找中input type="file"需要加上multiple来实现过滤,multiple不写参数则可以读取·所有文件。而在服务端上,我们需要将single()改为array(“name”,num);的形式来接收多个文件的上传请求。最后对他们全部进行重命名。在这之前我们首先看看multer支持哪些文件上传方式:

.single(fieldname)  //接受一个以 fieldname 命名的文件。.fields(fields)
.array(fieldname[, maxCount])   //接受一个以 fieldname 命名的文件数组。可以配置 maxCount 来限制上传的最大数量。
.fields(fields) //接受指定 fields 的混合文件。fields是一个拥有name和maxCount的数组对象。
.none()     //只接受文本域。如果任何文件上传到这个模式,将发生 "LIMIT_UNEXPECTED_FILE" 错误。
.any()  //接受一切上传的文件。

下面我们将会演示如何上传多个文件:
html:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <form action="http://localhost:8080/" method="post" enctype="multipart/form-data">
            <input type="file" name="files" value="指定文件" multiple>
            <br><br>
            <input type="submit" value="上传">
        </form>
    </body>
</html>

node代码:

const express=require("express");
const multer=require('multer');
var upload=multer({dest:'./upload/'});
var fs = require('fs');


var app=express();

app.use("/",upload.array("files",5),function(req,res,next){
    req.files.forEach(function(ele,index){
        console.log(ele);
        var oldFile=ele.destination+ele.filename;   //指定旧文件
        var newFile=ele.destination+ele.originalname;   //指定新文件
        fs.rename(oldFile,newFile,function(err){
            err?console.log('上传失败!'):console.log('上传成功!');
        });
    });
    res.send("成功上传");
});

app.listen(8080);

这里,我们获取文件信息是通过req.files来获取,他是由数组构成的对象,之后用foreach循环对其进行重命名即可。

4、通过limits来限制上传文件

Multer通过使用limits这个对象来对数据进行限制,它允许使用以下参数:

Key Description Default
fieldNameSize   field 名字最大长度    100 bytes
fieldSize   field 值的最大长度    1MB
fields  非文件 field 的最大数量 无限
fileSize    在 multipart 表单中,文件最大长度 (字节单位)   无限
files   在 multipart 表单中,文件最大数量  无限
parts   在 multipart 表单中,part 传输的最大数量(fields + files)    无限
headerPairs 在 multipart 表单中,键值对最大组数 2000
如果你上传的文件超出这些设定,MulterError模块将会启用,该模块在node_modules/multer/lib/multer-error.js上:

我们可以使用err.code定位到该错误,他有7种code方式,不同设置会返回不同code;

LIMIT_PART_COUNT
LIMIT_FILE_SIZE
LIMIT_FILE_COUNT
LIMIT_FIELD_KEY
LIMIT_FIELD_VALUE
LIMIT_FIELD_COUNT
LIMIT_FIELD_COUNT

下面就给大家做个简单实例:
html依然不变,js代码如下:

const express=require("express");
const multer=require('multer');
var upload=multer({dest:'./upload/',limits:{fileSize: 1024 * 1024 * 20,files: 5}});
var fs = require('fs');

var app=express();

app.use("/",upload.array("files",5),function(req,res,next){
    req.files.forEach(function(ele,index){
        var oldFile=ele.destination+ele.filename;   //指定旧文件
        var newFile=ele.destination+ele.originalname;   //指定新文件
        fs.rename(oldFile,newFile,function(err){
            err?console.log('上传失败!'):console.log('上传成功!');
        });
    });
    next();
    res.send("上传成功!");
});

app.use(function(err,req,res,next){
    if (err.code==='LIMIT_FILE_SIZE'){
        res.send('File is too large');
    }else if(err.code==='LIMIT_FILE_COUNT'){
        res.send('Too many files');
    }
})

app.listen(8080);

5、ajax图片上传

图片上传实现步骤

通过jquery监听input change事件,这样我们可以获取到上传的图片流信息,从而可以获取到图片的地址、大小、格式以及名称等信息

这里创建3个数组,imgName、imgSrc、imgFile分别用于存放上传图片的名称、url地址以及图片流信息

var fileList = this.files;
        for(var i = 0; i < fileList.length; i++) {
            var imgSrcI = getObjectURL(fileList[i]);
            imgName.push(fileList[i].name);
            imgSrc.push(imgSrcI);
            imgFile.push(fileList[i]);
        }

getObjectURL方法是一个用于获取本地图片的地址,使用该url可以显示图片

function getObjectURL(file) {
    var url = null ;
    if (window.createObjectURL!=undefined) { // basic
        url = window.createObjectURL(file) ;
    } else if (window.URL!=undefined) { // mozilla(firefox)
        url = window.URL.createObjectURL(file) ;
    } else if (window.webkitURL!=undefined) { // webkit or chrome
        url = window.webkitURL.createObjectURL(file) ;
    }
    return url ;
}
控制上传图片大小、格式以及上传数量
    $('#upload').on('change',function(){        
          if(imgSrc.length==4){
            return alert("最多只能上传4张图片");
        }
        var imgSize = this.files[0].size;  //b
        if(imgSize>1024*1024*1){//1M
            return alert("上传图片不能超过1M");
        }
        if(this.files[0].type != 'image/png' && this.files[0].type != 'image/jpeg' && this.files[0].type != 'image/gif'){
            return alert("图片上传格式不正确");
        }
    })
图片预览

创建一个addNewContent方法用于动态展示添加的图片实现图片预览,在每次上传图片的时候调用该方法

function addNewContent(obj) {
    $(obj).html("");
    for(var a = 0; a < imgSrc.length; a++) {
        var oldBox = $(obj).html();
        $(obj).html(oldBox + '<li class="content-img-list-item"><img src="'+imgSrc[a]+'" alt=""><a index="'+a+'" class="hide delete-btn"><i class="ico-delete"></i></a></li>');
    }
}
图片删除

1.通过监听鼠标的mouseover事件,显示图片删除按钮

$('.content-img-list').on('mouseover','.content-img-list-item',function(){
        $(this).children('a').removeClass('hide');
    });

2.监听鼠标的mouseleave事件,隐藏图片删除按钮

$('.content-img-list').on('mouseleave','.content-img-list-item',function(){
        $(this).children('a').addClass('hide');
    });

3.获取图片index下标属性,通过js的splice方法删除数组元素,重新调用addNewContent方法遍历图片数组显示预览图片

$(".content-img-list").on("click",'.content-img-list-item a',function(){
            var index = $(this).attr("index");
            imgSrc.splice(index, 1);
            imgFile.splice(index, 1);
            imgName.splice(index, 1);
            var boxId = ".content-img-list";
            addNewContent(boxId);
            if(imgSrc.length<4){//显示上传按钮
                $('.content-img .file').show();
            }
      });
图片上传提交

这里主要使用FormData来拼装好数据参数,提交到后台

var formFile = new FormData();

遍历imgFile图片流数组拼装到FormData中

 $.each(imgFile, function(i, file){
            formFile.append('myFile[]', file);
        });

添加其他参数

    formFile.append("type", type); 
        formFile.append("content", content); 
        formFile.append("mobile", mobile); 

最后使用ajax提交内容

 $.ajax({
            url: 'http://zhangykwww.yind123.com/webapi/feedback',
            type: 'POST',
            data: formFile,
            async: true,  
            cache: false,  
            contentType: false, 
            processData: false, 
            // traditional:true,
            dataType:'json',
            success: function(res) {
                console.log(res);
            }
        })

以上就实现了图片上传、图片预览和图片删除的功能

jquery设置 ajax属性

processData : false, // 告诉jQuery不要去处理发送的数据
contentType : false,// 告诉jQuery不要去设置Content-Type请求头

二、文件下载

文件下载非常简单,仅需通过res.download()执行即可,他可以写为3种形式:

res.download('/report-12345.pdf');

以下是一个对选择对应文件进行下载的实例: html:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <form action="http://localhost:8080/" method="post" enctype="application/x-www-form-urlencoded">
            <input type="file" name="files" value="选择下载的文件"><br><br>
            <input type="submit" value="下载">
        </form>
    </body>
</html>

js:

const express=require("express");
const bodyParser=require("body-parser");

var app=express();

var jsonParser = bodyParser.json();
var urlencodedParser = bodyParser.urlencoded({ extended: false });

app.post('/',urlencodedParser,function(req,res){
    res.download("./public/"+req.body.files,err=>{
        if(err){
            res.send("下载失败!");
        }else{
            console.log("下载成功!");
        }
    });
});

app.listen(8080);

我们可以选择根目录public下的文件对其进行下载。

日期:2021/12/13

学习参考视频:*https://www.bilibili.com/video/BV1i7411G7kW?p=57&t=1403.1

学习参考文档参考部分相关视频文案和课件,仅供个人学习和记录

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,552评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,666评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,519评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,180评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,205评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,344评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,781评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,449评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,635评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,467评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,515评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,217评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,775评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,851评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,084评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,637评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,204评论 2 341

推荐阅读更多精彩内容