[记录六]Vue+node+koa2+mysql+nginx+redis,全栈开发小程序和管理员管理系统项目——服务端图片上传与下载

本项目需要涉及前端上传图片与显示图片,为此自己实践一下图片相关的东西,挺有意思所以就分享出来。
实现思路:服务端的处理方式是将前端上传的文件保存在服务端本地,然后重命名该文件名字,再将图片在服务端的路径存入表中,前端请求图片地址的时候去服务端找出文件并返回给前端显示。

在routes文件夹下新建一个common.js文件

//common.js
//导入所需模块
const router = require('koa-router')()
const api = require('../controllers/api')
const common = require('../util/comon')
const path = require('path')
const fs = require('fs')
const formidable = require('formidable')
const MimeLookup = require('mime-lookup')
const mime = new MimeLookup(require('mime-db'))
router.prefix('/common')

上传图片

//common.js
//上传图片
router.post('/addUploadImg', async (ctx, next) => {
    
    
  console.log(ctx.req)
  let form = new formidable.IncomingForm()
  form.hash = "md5"
  form.multiples = false //默认只能上传一个文件,更多form的配置参考node-formidable
  form.maxFileSize = 2 * 1024 * 1024 //设置文件最大不超过2M
  let type = ['image/png','image/gif','image/jpg','image/jpeg','image/webp']//支持上传的图片类型
  function formImage() {
    
    
    return new Promise((resolve, reject) => {
    
    
      form.parse(ctx.req, async function (err, fields, files) {
    
    //注意:跟express有差异,这里要传入ctx.req
      let file = files['file']
      if (file) {
    
    
        let flag = await common.checkFile(file.type, file.size) //校验文件的大小和类型
        console.log('校验通过'+flag)
        if (flag) {
    
     //文件校验通过
          const oldpath = file['_writeStream'].path //系统缓存上传的文件地址
          const dir = path.join(__dirname, `../common/upload/img`)
          const fileFormat = file.name.split('.')
          file.name = `${
     
     file.hash}_${
     
     Date.now()}.${
     
     fileFormat[fileFormat.length - 1]}` //通过file.hash加时间戳生成文件名
          const newpath = `common/upload/img/${
     
     file.name}`
          if (!fs.existsSync(dir)) {
    
     //先判断文件夹名是否存在,不存在则生成根据XXX生成对应的文件夹
            fs.mkdirSync(dir)
          }
          //如果是非WINDOWS系统,可以用fs.renameSync()来实现,这里为了兼容用了node的pipe来实现
          let readStream = fs.createReadStream(oldpath)
          let writeStream = fs.createWriteStream(newpath)
          readStream.pipe(writeStream) //这里文件已经上传成功
          resolve(ctx.origin + "/" + newpath) //返回完整的文件地址
        } else {
    
    
            reject(null)
          }
      } else {
    
    
          reject(null)
        }
      })
    })
  }
  await formImage()
    .then(res => {
    
     
      ctx.body = {
    
    
        code: 200,
        status: 200,
        data: res,
        message:'上传成功'
      }
    }).catch(err => {
    
     
      ctx.body = {
    
    
        code: 400,
        status: 200,
        data: {
    
    },
        message:'上传失败'
      }
    }
  )
})

下载图片

//common.js
//显示图片
router.get('/upload/img/:imgUrl', async (ctx, next) => {
    
    
  url=ctx.url
  let index = url.lastIndexOf('/')
  imgUrl = url.substring(index + 1, url.length)
  let filePath = path.join(__dirname, `../common/upload/img/${
     
     imgUrl}`)
  file = fs.readFileSync(filePath)//读取文件
  // console.log(await watermark.addWatermark(file, options))
  let mimeType = mime.lookup(filePath) //读取图片文件类型
  ctx.set('content-type', mimeType) //设置返回类型
  ctx.body = file //返回图片
})

这里下载的意思是前端拿到图片链接,直接img src="https://***/upload/img.123sdjfhg.png"的时候服务端其实是需要响应前端的这个地址请求的,上面是收到请求后去服务端获取图片并读取然后返回文件回给前端。假设有做token校验是否可以请求api的话,建议将“/common/upload/”接口的路由放入白名单(免token)中去。

文件结构

最终在项目中呈现的结构是:
在这里插入图片描述
至此就完成前端图片上传和下载的需求了,感谢观看!

上一篇:使用swagger自动生成接口文档
上一篇:生成请求日志

猜你喜欢

转载自blog.csdn.net/Smell_rookie/article/details/108886254