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); //創(chuàng)建以日期格式的文件夾
        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 服務(wù)層
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); //創(chuàng)建以日期格式的文件夾
        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) {
        //如果出現(xiàn)錯誤,關(guān)閉管道
        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 服務(wù)層
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.七牛云對象存儲創(chuàng)建域名和配置域名的 CNAME

(1)創(chuàng)建域名

域名管理/創(chuàng)建域名

image.png

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

    image.png

  • 阿里云域名解析

云解析DNS/域名解析/解析設(shè)置

image.png
  • 配置成功


    image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肚吏,一起剝皮案震驚了整個濱河市方妖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌罚攀,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雌澄,死亡現(xiàn)場離奇詭異斋泄,居然都是意外死亡,警方通過查閱死者的電腦和手機镐牺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進店門炫掐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人睬涧,你說我怎么就攤上這事募胃∑煅洌” “怎么了?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵痹束,是天一觀的道長检疫。 經(jīng)常有香客問我,道長祷嘶,這世上最難降的妖魔是什么屎媳? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮论巍,結(jié)果婚禮上烛谊,老公的妹妹穿的比我還像新娘。我一直安慰自己嘉汰,他們只是感情好丹禀,可當我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鞋怀,像睡著了一般双泪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上接箫,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天攒读,我揣著相機與錄音,去河邊找鬼辛友。 笑死薄扁,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的废累。 我是一名探鬼主播邓梅,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼邑滨!你這毒婦竟也來了日缨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤掖看,失蹤者是張志新(化名)和其女友劉穎匣距,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哎壳,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡毅待,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了归榕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尸红。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出外里,到底是詐尸還是另有隱情怎爵,我是刑警寧澤,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布盅蝗,位于F島的核電站鳖链,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏风科。R本人自食惡果不足惜撒轮,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贼穆。 院中可真熱鬧题山,春花似錦、人聲如沸故痊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愕秫。三九已至慨菱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間戴甩,已是汗流浹背符喝。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留甜孤,地道東北人协饲。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像缴川,于是被迫代替她去往敵國和親茉稠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,876評論 2 361