express+mysql+multer 从零实现文件的上传 下载 删除

目录架构(草草的写的,还没有整理过文件)

├─ bin/www     // 主程序入口
├─ dbConnect   // mysql 连接数据库
├─ routes      // 路由文件
│  ├─ download.js // 下载文件
│  ├─ upload.js   // 上传文件
│  ├─ query.js    // 查询已上传文件列表
│  └─ delete.js   // 通过ID删除文件
├─ static      // 静态资源 用于存放上传的文件
└─ app.js      // express核心文件

package.json (主要引用的包)

  • multer 用于文件上传 只能用于接收formdata形式上传的文件
  • mysql 连接数据库 绑定新旧文件名 API中会使用到
  • uuid 用于生成UUID来重命名文件 防止文件名重复导致的覆盖或错误的产生

初始化项目 安装包

npm install express -g # 全局安装express
npm install express-generator -g # 全局安装express生成器

express uploadTestDemo # 初始化项目
cd uploadTestDemo
yarn install # 安装express需要的依赖文件

yarn add multer mysql uuid # 安装项目需要的依赖文件

实现文件上传功能

博文的代码并不是全部代码,我会在最下方放上github地址,功能的测试都是用postman完成的

基础功能

文件routes/upload.js,上传文件接口

var multer = require('multer'); 
var uuid = require('uuid/v1');

// 定制上传控件
var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    // 保存的路径,备注:需要手动创建,如果目录不存在 上传时会报错
    cb(null, 'static/')
  },
  filename: function (req, file, cb) {
    let fileFormat = (file.originalname).split('.') // 取后缀
    // 设置保存时的文件名,uuid + 后缀
    cb(null, uuid() + '.' + fileFormat[fileFormat.length - 1])
  }
})

var upload = multer({
  storage,
})

router.post('/', upload.single('file'), function (req, res, next) {
  // 上传完成后返回文件名
  res.json({
    code: 0,
    data: {
      fliename: req.file.filename
    },
    msg: 'success'
  })
  res.end()
})

加入MySQL 保存原始文件信息及上传后的文件名称

创建文件dbConnect/index.js,用来进行MySQL的配置及连接。

var mysql = require('mysql')

// 创建连接
let connection = mysql.createConnection({
  host: '127.0.0.1',        // 主机名
  user: 'root',             // 用户名
  password: 'root',         // 密码
  database: 'testDatabase'  // 要连接数据库
})

// 执行创建连接
connection.connect();

module.exports = connection

修改刚刚的upload.js文件,加入对上传文件信息的保存功能

var sqlConnect = require('../dbconnect/index');

/** 新增数据SQL语句
 * @params { String } staticname 静态资源名
 * @params { String } filename 原文件名称
 * @params { String } mime 上传文件的mime类型
 * @params { Number } size 上传文件的大小(kb)
 */
var addSql = 'INSERT INTO uploadfiles(staticname, filename, mime, size) VALUES(?, ?, ?, ?)';

router.post('/', upload.single('file'), function (req, res, next) {
  var addSqlParams = [ // 设置新增字段数据 对应addSql中的四个参数
    req.file.filename,
    req.file.originalname,
    req.file.mimetype,
    req.file.size
  ];
  
  // 执行数据库方法
  sqlConnect.query(addSql, addSqlParams, (err, result) => {
    if (!err) {
      res.json({
        code: 0,
        data: {
          fliename: req.file.filename
        },
        msg: 'success'
      })
    } else {
      res.json({
        code: 0,
        data: {},
        msg: `error ${err.message}`
      })
    }
    res.end()
  })
})

测试上传功能

在测试前需要去数据库创建这个数据库和对应的表结构

CREATE TABLE `uploadfiles` (
  `id`         bigint(20)   NOT NULL     AUTO_INCREMENT,
  `staticname` varchar(100) NOT NULL     COMMENT '静态资源地址',
  `filename`   varchar(100) DEFAULT NULL COMMENT '文件名',
  `mime`       varchar(100) DEFAULT NULL COMMENT '上传文件mime类型',
  `size`       double       DEFAULT NULL COMMENT '文件大小 kb',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;

然后在postman中将请求配置为下图,发送后得到的返回数据为保存在后端static目录中的文件名
在这里插入图片描述
可以看到通过post请求后端成功返回了文件名。从下图看到文件已经存到对应的文件夹下,并将文件信息保存到数据库中了。
在这里插入图片描述在这里插入图片描述

下载文件接口 routes/upload.js

基础下载

router.get('/', function (req, res, next) {
  if (!req.query.filename) { // 确定需要的参数存在
    res.status(400).json({
      code: 1,
      data: '',
      msg: 'The file name field of the query failed!'
    })
    return res.end()
  }

  let filename = req.query.filename
  res.download('./static/' + filename)
})

验证所需参数的部分其实可以封装起来 写一个validField工具类,但是因为时间原因 没有封装 后期进行优化的时候可以改。
通过请求上面的接口在浏览器中会出现下载提示,如下:
在这里插入图片描述

加入更名下载功能

修改download.js文件

var sqlConnect = require('../dbconnect/index');

// 通过staticname查询的SQL
var querySql = 'SELECT * FROM uploadfiles WHERE staticname = ?'

router.get('/', function (req, res, next) {
  if (!req.query.filename) {
    res.status(400).json({
      code: 1,
      data: '',
      msg: 'The file name field of the query failed!'
    })
    return res.end()
  }
  let filename = req.query.filename
  sqlConnect.query(querySql, [filename], (err, result)=>{
    if(err || result.length===0) { // 如果查询报错或是是未找到文件的时候返回错误信息
      res.json({
        code: 0,
        data: false,
        msg: `downloadFileError ${err || 'not found file!'}`
      })
      res.end()
    } else {
      res.download(`./static/${filename}`, result[0].filename)
    }
  })
})

谷歌浏览器不好测试 所以使用了Firefox进行,请求之后的结果如下,可以发现浏览器下载器 成功更改了下载时的文件名称。
在这里插入图片描述

已上传文件查询功能 routes/query.js

因为现在只有通过上传时返回的数据和数据库才能知道已经上传的文件,不是很方便 所以单独做一条用于展示已上传文件列表的接口,方便展示。

var express = require('express');
var sqlConnect = require('../dbconnect/index');
var router = express.Router();

// 查询SQL语句
var querySql = 'SELECT * FROM uploadfiles'

/* GET query listing. */
router.get('/', function(req, res, next) {
  sqlConnect.query(querySql, function(err, result){
    if (!err) {
      //将结果以json形式返回到前台
      res.json({
        code: 0,
        data: result,
        msg: 'success'
      });
    } else {
      res.json({
        code: 1,
        data: [],
        msg: 'query database error'
      })
    }
    res.end()
  })
});

module.exports = router;

删除文件接口

删除功能:既要删除数据库中的数据同时删除本地文件。
分步骤
1.查询数据库 判断对应ID的数据是否存在
2.删除数据库中的上传记录
3.删除本地文件

var sqlConnect = require('../dbconnect/index');
var fs = require('fs'); // nodejs fileSystem

var deleteSql = 'DELETE FROM uploadfiles WHERE id = ?' // 通过ID删除
var queryOneSql = 'SELECT * FROM uploadfiles WHERE id = ?' // 通过ID查询

router.delete('/:id', function (req, res, next) {
  let id = req.params.id
  new Promise((resolve, reject) => { // 查询记录
    sqlConnect.query(queryOneSql, [id], (err, result) => {
      if (err || result.length === 0) {
        reject(err)
      } else {
        let dataObj = result[0]
        resolve(dataObj)
      }
    })
  }).then(result => { // 删除记录
    return new Promise((resolve, reject) => {
      sqlConnect.query(deleteSql, [id], (err, res) => {
        if (!err) {
          resolve(result)
        } else {
          reject(err)
        }
      })
    })
  }).then(result => { // 删除磁盘文件
    fs.unlinkSync(`./static/${result.staticname}`)
    res.json({
      code: 0,
      data: false,
      msg: `delete id ${result.id} success`
    })
  }).catch(err=>{ // 异常响应
    res.json({
      code: 1,
      data: [],
      msg: `error: ${err}`
    })
  }).finally(()=>{ // 结束请求
    res.end()
  })
})

其实仔细想想,应该不用在删除前进行一次查询操作,直接删除可以减少步骤。在后面的维护再优化吧。

postman测试请求

在这里插入图片描述
最后贴上项目的github地址,如果有什么不足之处也可以通过github联系我
https://github.com/766aya/fileUploadDemo

结束语

总结一下,这个上传功能只是简单的实现了一下,并没有深究其中的原理。在项目中很多的请求和SQL操作其实可以进行二次封装从而简化代码量,增加代码的可阅读性。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值