node项目中使用egg框架上传单个文件(图片)

根据项目,此处上传一个图片

前提需要

:A.HTML模板 B.对应的创建功能逻辑代码 C.数据库创建好表,迁移与变更 D.与数据库连接后的配置,模板渲染
这里只针对上传
这里已经做好了4个功能

开始

1、两个依赖,

await-stream-ready 和 stream-wormhole,
一个是使用await进行文件的读写操作,一个是在文件上传出现异常时能够把流消耗掉。

npm i await-stream-ready stream-wormhole dayjs --save

2、配置:

config/config.default.js
根据项目的需要,查询文档自己配置
参考地址 :eggjs官方地址控制器获取上传的文件

https://eggjs.org/zh-cn/basics/controller.html#%E8%8E%B7%E5%8F%96%E4%B8%8A%E4%BC%A0%E7%9A%84%E6%96%87%E4%BB%B6

config.multipart = {
    fileSize: '50mb', //大小限制
    mode: 'stream', //启用stream流的模式  不会用的话也可以用file
    fileExtensions: ['.xls', '.txt', '.jpg', '.JPG', '.png', '.PNG', '.gif', '.GIF', '.jpeg', '.JPEG'], // 扩展多少种上传的文件格式
  };

3、上传图片逻辑功能(上传单个文件)
app/controller/admin/common.js

'use strict';

const Controller = require('egg').Controller;
// 引入
const fs = require('fs');
const path = require('path');
//故名思意 异步二进制 写入流
const awaitWriteStream = require('await-stream-ready').write;
//管道读入一个虫洞。
const sendToWormhole = require('stream-wormhole');
const dayjs = require('dayjs');
const await = require('await-stream-ready/lib/await');

class CommonController extends Controller {
    // 上传文件
    async upload() {
        const stream = await this.ctx.getFileStream();
        // 基础目录 后期上传文件存放 自动生成uploads
        const uploadBasePath = 'app/public/uploads'
        // 生成唯一文件名
        //生成唯一文件名 
        //Data.now()当前时间戳 
        //path.extname(stream.filename)文件后缀  
        //stream.filename是原来的文件名称 
        //toLocaleLowerCase()生成唯一文件名
        const filename = `${Date.now()}${path.extname(stream.filename).toLocaleLowerCase()}`
        // 生成文件夹
        const dirname = dayjs(Date.now()).format('YYYY/MM/DD')

        function mkdirsSync(dirname) {
            if (fs.existsSync(dirname)) {
                return true
            } else {
                if (mkdirsSync(path.dirname(dirname))) {
                    fs.mkdirSync(dirname)
                    return true
                }
            }
        }

        mkdirsSync(path.join(uploadBasePath, dirname))

        // 生成写入路径
        const target = path.join(uploadBasePath, dirname, filename)

        // 写入流
        const writeStream = fs.createWriteStream(target);

        try {
            // 异步把文件流写入
            await awaitWriteStream(stream.pipe(writeStream))
        } catch (error) {
            // 出现错误,关闭管道
            await sendToWormhole(stream)
            this.ctx.throw(500, error)
        }

        let url = path.join('/public/uploads', dirname, filename).replace(/\\|\//g, '/')

        this.ctx.apiSuccess({
            url
        })
    }
}

module.exports = CommonController;

4、Nunjuck模板引擎对html渲染之前

做到这一步Nunjuck模板引擎肯定都安装了也引用了 ,需要做好模板渲染的代码
例如

class GiftController extends Controller {
    // 创建表单
    async create(){
        const { ctx } = this;
        await ctx.renderTemplate({
            // 页面标题
            title: "创建",
            // 模板类型 form表单,table表格分页
            tempType: "form",
            // 表单配置
            form: {
                // 提交地址
                action: "/admin/gift",
                // 字段配置
                fields:[{
                    label: "图片",
                    type: "file",
                    name: "image",
                    placeholder: "图片"
                }]
            },
            // 新增成功跳转路径
            successUrl:"/admin/gift"
        });
    }
    // 创建逻辑
    async creating(){
        const { ctx,app } = this;
        //参数验证
        ctx.validate({
            image:{
                type:"string",
                required:false,
                desc:"图片"
                }})
        let {image} = ctx.request.body;
        let res = await app.model.Gift.create({ //Gift是前面做数据库迁移与变更时候model中的return
                 image
        })
          ctx.apiSuccess(res)
    }
}

module.exports = GiftController;

还要要在router中配置路由,上传要用到post

router.post('/admin/upload', controller.admin.common.upload);

前面做数据库 创建表的时候,需要上传的图片文件一定要是file,模板渲染代码编写的时候也要是file

5、对view文件夹下的对应的html中进行渲染

<div class="card-body">
        {% if form %}
<form action="{{form.action}}" method="POST">
        {% for item in form.fields %}
 <div class="form-group row">
  <label class="col-form-label col-md-2">{{item.label}}</label>
	<div class="col-md-10">
         {% if item.type === 'file' %}
  <input name="{{item.name}}" type="file" class="form-control" @change="fileUpload($event,'{{ item.name }}')">
    <img :src="form.{{item.name}}" v-if="form.{{item.name}}" class="avatar-lg border rounded p-1 mt-2">
             {% else %}
<input name="{{item.name}}" type="{{item.type}}" class="form-control" placeholder="{{item.placeholder}}..." v-model="form.{{item.name}}">
             {% endif %}
	</div>
	</div>
             {% endfor %}
	<div class="text-right mt-3">
	<button type="submit" class="btn btn-primary" @click.stop.prevent="submit">提 交</button>
      </div>
     </form>
             {% endif %}

</div>
</div>

6、进行html中js模块的编写

<script>
Vueapp = new Vue({
        el:"#vueapp",
        data() {
            return {
    form:{
        {% for item in form.fields %}
        {{ item.name }}:"{{ form.data[item.name] if form.data[item.name] else item.default }}",
        {% endfor %}
    }
            }
        },
 methods: {
   fileUpload(event,name){
       var that = this
       let file = event.target.files
       let formData = new FormData()
       formData.append('file',file[0])
       $.ajax({//想用axios可是封装的promise有问题不报错也不成功 实在不想改代码了就用了ajax
           type:"POST",
           url:"/admin/upload?_csrf={{ctx.csrf|safe}}",
            ontentType:false,
            processData:false,
            data:formData,
            success:function(result){
            that.form[name] = result.data.url
            //提前做好toast功能 这里也可以console或者不写,能知道提交成功就行
             Vueapp.$refs.toast.show({
                    msg:"上传成功",
                    type:"success"
                        })
                    },
           error:function(e){
                Vueapp.$refs.toast.show({
                     msg:e.responseJSON.data,
                          type:"danger"
                        })
                    }
                })
            },
    })
</script>

最后操作演示

点击选择文件会跳出选择框 寻找一个图片就行
下面显示的图片怪异和写的css有关
在这里插入图片描述
点击提交后,因为之前在app/controller/admin/common.js内, const uploadBasePath = ‘app/public/uploads’
所以会在’app/public中自动生成一个文件夹uploads,里面有传来的图片,显示时间戳,后续再上传图片会继续存在这个文件夹内
在这里插入图片描述

然后,打开Navicatt查看数据库,会看到图片已经上传成功
在这里插入图片描述
最后一个就是Tom

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值