egg.js上传图片到本地与上传到七牛云对象存储

1.html方式上传

<form action="/back/banner/upload?_csrf=<%=csrf%>" method="POST" enctype="multipart/form-data">
    广告标题:<input type="text" name="title" />
    链接地址:<input type="text" name="link"/>
    类型:<select name="type">
            <option value="0">PC</option>
            <option value="1">APP</option>
            <option value="2">H5</option>
          </select>
    上传图片:<input type="file" id="file" name="img_url" />
    <input type="submit" class="btn_yes"  value="提交">
</form>


2.ajax方式上传

<div class="uploadBody">
    广告标题:<input type="text" name="title" />
    链接地址:<input type="text" name="link"/>
    类型:<select name="type">
            <option value="0">PC</option>
            <option value="1">APP</option>
            <option value="2">H5</option>
            </select>
    上传图片:<input type="file" id="file" name="img_url" />
            <button class="btn_yes" type="submit">提交</button>
</div>
<script src="js/jquery-1.11.0.min.js"></script>
<script>
$(function () {
    $('.btn_yes').click(function(event){
        var formData = new FormData();
        formData.append('title', $("input[name='title']").val());
        formData.append('type', $("select[name='type']").val());
        formData.append('link', $("input[name='link']").val());
        formData.append('img_url', $("input[type=file]")[0].files[0]);
        
        $.ajax({
            url: '/back/banner/upload?_csrf=<%-csrf%>',
            type: 'post',
            data: formData,
            cache: false,
            contentType: false,
            processData: false,
            success: function (req) {
                console.log(req);
            },
            error: function (err) {
                console.log(err.statusText);
                return false;
            }
        });
    })
});
</script>

3.egg.js后端上传图片保存到本地

(1)安装依赖包
  • 安装mz-modules包
    cnpm install mz-modules --save
  • 安装时间格式化插件
    cnpm i silly-datetime --save
(2)schema
module.exports = app => {
  const mongoose = app.mongoose;
  const Schema = mongoose.Schema;
  const BannerSchema = new Schema({
    title: { type: String },
    type: {
      type: Number,
      default: 0  //0:PC;1:APP;2:H5
    },
    img_url: { type: String },
    link: { type: String },
    status: { type: Number, default: 1 },
    create_time: { type: Date, default: Date.now },
    update_time: { type: Date, default: null }
  });
  return mongoose.model('Banner', BannerSchema, 'banner');
};
(3)service\utils
const path = require("path");
const mkdirp = require('mz-modules/mkdirp');
const sd = require('silly-datetime');
const Service = require("egg").Service;

class UtilsService extends Service {
    async getUploadFile(filename){
        let date = sd.format(new Date(),'YYYYMMDD');
        let dir = path.join('app/public/back/upload', date);
        await mkdirp(dir); //创建以日期格式的文件夹
        let timestamp = new Date().getTime();
        let uploadDir = path.join(dir,timestamp + path.extname(filename));
        return {
            uploadDir: uploadDir,
            saveDir: uploadDir.slice(3).replace(/\\/g,'/')
        }
    }
}
module.exports = UtilsService;
(4)Controller 控制层
'use strict';
const fs = require('fs');
const pump = require('mz-modules/pump');
const Controller = require('egg').Controller;

class BannerController extends Controller {
  async upload() {
    const { ctx } = this;
    let files = {};
    let stream;
    let parts = ctx.multipart({ autoFields: true });
    while((stream = await parts()) != null){
        if (!stream.filename){  //图片名称  xxx.png
            break;
        }
        let filedname = stream.fieldname;  //字段名称 img_url
        let dir = await ctx.service.tools.getUploadFile(stream.filename);
        let target = dir.uploadDir;
        let writeStream = fs.createWriteStream(target);
        await pump(stream, writeStream);
        files = Object.assign(files, {[filedname]: dir.saveDir});
    }
    var obj = Object.assign(files, parts.field);
    //console.log(JSON.stringify(obj));
    var result = await ctx.service.back.banner.upload(obj);
    if(result){
        ctx.helper.success({ctx, code:0});
    }else{
        ctx.helper.fail({ctx, code:1, res:result });
    }
  }
}
module.exports = BannerController;
(5)Service 服务层
const Service = require('egg').Service;
const mongoose = require('mongoose');

class BannerService extends Service {
  async upload(obj) {
    const {ctx} = this;
    return await new ctx.model.Banner(obj).save();
  }
}

module.exports = BannerService;

4.egg.js后端上传图片到七牛云对象存储

(1)安装依赖包
  • 安装mz-modules包
    cnpm install mz-modules --save

  • 安装时间格式化插件
    cnpm i silly-datetime --save

  • 安装七牛云对象存储node.js包
    cnpm install qiniu --save

  • 安装stream-wormhole包
    cnpm install stream-wormhole --save

(2)配置config.default.js
  config.qiniu = {
    accessKey: ' ', //Access Key
    secretKey: ' ', //Secret Key
    bucket: ' ', //要上传的空间名
    domainName: ' ' //空间绑定的域名
  }
image.png
(3)schema
module.exports = app => {
  const mongoose = app.mongoose;
  const Schema = mongoose.Schema;
  const BannerSchema = new Schema({
    title: { type: String },
    type: {
      type: Number,
      default: 0  //0:PC;1:APP;2:H5
    },
    img_url: { type: String },
    link: { type: String },
    status: { type: Number, default: 1 },
    create_time: { type: Date, default: Date.now },
    update_time: { type: Date, default: null }
  });
  return mongoose.model('Banner', BannerSchema, 'banner');
};
(4)service\utils
const path = require("path");
const mkdirp = require('mz-modules/mkdirp');
const sd = require('silly-datetime');
//qiniu
const fs = require("fs");
const qiniu = require("qiniu");
const sendToWormhole = require("stream-wormhole");
const Service = require("egg").Service;

class UtilsService extends Service {
    async getUploadFile(filename){
        let date = sd.format(new Date(),'YYYYMMDD');
        let dir = path.join('app/public/back/upload', date);
        await mkdirp(dir); //创建以日期格式的文件夹
        let timestamp = new Date().getTime();
        let uploadDir = path.join(dir,timestamp + path.extname(filename));
        return {
            uploadDir: uploadDir,
            saveDir: uploadDir.slice(3).replace(/\\/g,'/')
        }
    }

  async uploadQiNiu(stream, filename, localFilePath) {
    const { ctx } = this;
    const mac = new qiniu.auth.digest.Mac(this.config.qiniu.accessKey, this.config.qiniu.secretKey);
    const options = { scope: this.config.qiniu.bucket };
    const putPolicy = new qiniu.rs.PutPolicy(options);
    const uploadToken = putPolicy.uploadToken(mac);
    let config = new qiniu.conf.Config();
    config.zone = qiniu.zone.Zone_z2;

    try {
        const formUploader = new qiniu.form_up.FormUploader(config);
        const putExtra = new qiniu.form_up.PutExtra();
        const imgUrl = await new Promise((resolve, reject) => {
        formUploader.putFile(uploadToken, filename, localFilePath, putExtra, (respErr, respBody, respInfo) => {
            if (respErr) {
                    reject("上传失败");
            }
            if (respInfo.statusCode == 200) {
                    resolve(this.config.qiniu.domainName + "/" + respBody.key);
            } else {
                    reject("上传失败");
            }
            // 上传之后删除本地文件
            fs.unlinkSync(localFilePath);
          });
        });
        if (imgUrl !== "") {
                return { url: imgUrl };
        } else {
                return false;
        }
    } catch (err) {
        //如果出现错误,关闭管道
        await sendToWormhole(stream);
        return false;
    }
    }
}
module.exports = UtilsService;
(5)helper.js
module.exports = {
    errorCode: {
        0: '成功',
        1: '失败',
    },
    success: ({ ctx, code=0, res = null }) => {
        ctx.status = 200
        ctx.body = {
          code: code,
          message: ctx.helper.errorCode[code],
          data: res
        }
    },
    fail: ({ ctx, code = 1, res=null }) => {
        ctx.status = 200
        ctx.body = {
          code: code,
          message: ctx.helper.errorCode[code],
          data: res
        }
    }
}
(6)Controller 控制层
'use strict';
const fs = require('fs');
const pump = require('mz-modules/pump');
const path = require("path");
const Controller = require('egg').Controller;

class BannerController extends Controller {
   async upload() {
    const { ctx } = this;
    let stream;
    let files = {};
    let parts = ctx.multipart({ autoFields: true });
    while((stream = await parts()) != null) {
      if (!stream.filename) { //图片名称  xxx.png
        break;
      }
      let filedname = stream.fieldname;  //字段名称 img_url
      let dir = await ctx.service.tools.getUploadFile(stream.filename);
      let filename = dir.filename;
      let localFilePath = path.join(__dirname, "../../" + dir.saveDir);
      //console.log("dirname:" + __dirname); //H:\vuejs\example\xiaomi\app\controller\back
      let writeStream = fs.createWriteStream(localFilePath);
      // 上传到本地
      await pump(stream, writeStream); 
      // 上传七牛云对象存储
      let qiniu = await ctx.service.utils.uploadQiNiu(stream, filename, localFilePath);
      if(qiniu) {
        files = Object.assign(files, {[filedname]: qiniu.url});
      }else{
        ctx.helper.fail({ctx, code:1});
      }
    }
    var obj = Object.assign(files, parts.field);
    var result = await ctx.service.back.banner.upload(obj);
    if(result){
      ctx.helper.success({ctx, code:0});
    }else{
      ctx.helper.fail({ctx, code:1, res:result });
    }
  }
}
module.exports = BannerController;
(7)Service 服务层
const Service = require('egg').Service;
const mongoose = require('mongoose');

class BannerService extends Service {
  async upload(obj) {
    const {ctx} = this;
    return await new ctx.model.Banner(obj).save();
  }
}

module.exports = BannerService;

5.七牛云对象存储 新建存储空间

空间管理/新建空间

image.png

6.七牛云对象存储创建域名和配置域名的 CNAME

(1)创建域名

域名管理/创建域名

image.png

(2)配置域名的 CNAME
  • 复制CNAME cdn-dengwq-com-idvc8ce.qiniudns.com 到阿里云的云解析DNS

    image.png

  • 阿里云域名解析

云解析DNS/域名解析/解析设置

image.png
  • 配置成功


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