vue学习笔记:还不会上传文件,10分钟教会你使用input file上传文件

最近在写一个用户上传MP3文件到服务器的小案例,我写一个这样的界面:

 当用户点击input的时候,其实这里并不是input的样式,而是一个div将代替了input的原生样式,这样比较好看一点:

<div class="address">
        <span>选择文件:</span>
        <input type="file" placeholder="" ref="fileadd" @change="getfile" id="filePath">
        <div class="mask" @click="middlefile">{
   
   { filename }}</div>
</div>

我就将input的opacity设置为0:

input {
            opacity: 0;
                    
            cursor: pointer;
}

将mask定位到我们想要的位置,然后通过mask的点击事件来触发input file的点击事件:

        middlefile() {

            this.$refs.fileadd.click()
        },

那么废话不多说,当我拿到这个文件的对象之后发给服务端如何实现?

  getfile(e) {
            this.currentfile = this.$refs.fileadd.files[0]
    }

其实很简单,就是通过axios发送一个formData表单请求就可以了:

comitmusic() {
            let musicform = {}
            this.musicfile.space = Math.round(this.currentfile.size / 10000) / 100 + 'MB'
           
            this.musicfile.url = this.currentfile.name
            musicform.musicinfo = this.musicfile
            musicform.file = this.currentfile
            let formData = new FormData()
            formData.append('file', this.currentfile)
            
            formmusicfile(formData).then(res => {
                if (res.data.state == 200) {
                    console.log(this.currentfile)
                    formData.append('info',JSON.stringify(musicform) )
                    this.$toast.show('文件下载成功', 2000)
                    formmusic(formData).then(res => {
                        if (res.data.state == 200) {
                            this.$toast.show('添加成功', 2000)
                        } else {
                            this.$toast.show(res.data.message)
                        }
                        console.log(res)
                    })

                } else {

                    this.$toast.show(res.data.message)
                }
                console.log(res)
            })


        }

当然我这里还有一些是用来获取MP3文件里面的详细信息的,比如作者、时长等,这里发了两个请求,可以看到两个then,一个是用发给后端来存放数据的,数据存储成功之后就发送第二个请求,将歌曲信息更新并且存入数据库;发送表单请求是因为可以容纳比较大的数据,如果使用json或者是参数的话是传不过去的,使用formdata这个对象,new 出来之后就通过append来放键值对进去,要注意,如果是传的普通对象,需要使用JSON.stringify(musicform)来进行转化,不然后台只会收到空对象{}; 文件对象不用管,因为它不需要在后端的回调函数里面使用,后面使用一个中间件就可以将文件获取并且存储下来;

先来看一下对axios的封装:

import axios from "axios"

export function request(config){
    const instance1  = axios.create({
        baseURL:'http://localhost:8089',
        timeout:30000
    })
    return instance1(config)
    
}

我是建议封装一下axios在使用,真的很方便,这里设置了一个访问时长,因为有时候会因为网卡而导致上传失败,接下来就是要发送请求的方法配置:

import {request} from '../network/request'



export function formmusic(dataload){
    
    console.log(dataload.get('file'))
    return request({
        url: '/music/load',
        method: 'post',
        headers:{
            "Content-Type": "multipart/form-data;",
            'Access-Control-Allow-Origin':'*',
            
        },
        data:dataload
    })

}
export function formmusicfile(dataload){
    return request({
        url: '/music/loadmusic',
        method: 'post',
        headers:{
            "Content-Type": "multipart/form-data;"
        },
        data:dataload
    })

}

配置好后端的URL和一些请求头、请求类型,提交的表单数据存放在data里面,注意这里不要写错了method,不是methods。

let express = require('express')
let router = express.Router()
let music = require('./api/music')
let members = require('./api/members')
const path = require('path')
const multipart = require('connect-multiparty');

const multipartyMiddleware = multipart();

 

const multer = require('multer')
let storage=multer.diskStorage({
	//设置存储路径
    destination:(req,file,cb)=>{
        //console.log("destination:",file);//打印结果如下图
        cb(null,'./resource/music');
    },
    //设置存储的文件名
    filename:(req,file,cb)=>{
        //console.log("filename:",file);//打印结果如下图
        //获取文件的扩展名
        let extname=path.extname(file.originalname);
        var musicfile = req.body
        console.log(musicfile)
        //let musicinfo = JSON.parse(musicfile.info).musicinfo

        filename=file.fieldname+extname;
        cb(null,filename);
    }
})
let upload=multer({storage});



router.post('/music/load', multipartyMiddleware, music.add)
router.post('/music/loadmusic',upload.single('file'),music.addfile)



module.exports = router

没错,就是通过这里的multer插件来将文件获取到并且存储下来,可以看到这里的第二个post请求使用了这个中间件upload.single('file');

可以使用:

npm i multer

来安装这个插件,然后按照上面的配置就行;但是有一个问题,他的文件名是无法按照文件的真实名字命名的,只有一个file名字,不过这怎么可能倒各位呢?这里我的方法是使用两个请求,另一个请求里就是专门做了一个重命名文件的操作,这里就这样配置是没有问题的,注意这里的路径不一定是各位服务器上的结构,按照自己的结构写;

然后就是解析formdata数据了,前面我传了一个formdata数据过来,文件解析了,但是还有一个歌曲的信息对象呢,前端通过formdata.get(键)可以获取到这个对象,但是后端如何获取呢?

各位是不是还在为拿到表单数据为空对象{}而苦闷不堪呢?今天我分享一个中间件,让你们摆脱它,其实前面已经给出了:

const multipart = require('connect-multiparty');
const multipartyMiddleware = multipart();
application.use(multipartyMiddleware)  

就是这个东西,当然也可以放到路由里面

router.post('/music/load', multipartyMiddleware, music.add)

好了,最后给大家看看我是如何更改file名称的:

exports.add = (req, res) => {        //向info表添加数据
    var sql2 = 'insert into musics (music,singer,time,space,position,img) values (?,?,?,?,?,?)'
    var sql1 = 'select * from musics where music = ?'
    var musicfile = req.body
    let musicinfo = JSON.parse(musicfile.info).musicinfo
    console.log(musicinfo)
    db.query(sql1, [musicinfo.music], (err, data) => {
        if (err) {
            return res.send('错误:' + err.message)
        }
        console.log(data.length == 0)
        if (data.length == 0) {
            console.log('执行')
            fs.rename('./resource/music/file.mp3', './resource/music/'+musicinfo.music + '.mp3', (error) => {
                if (error) {
                    return res.send('错误:数据重命名失败' + error.message)
                } else {
                    db.query(sql2, [musicinfo.music, musicinfo.singer, musicinfo.time, musicinfo.space, 'http://localhost:8089/resource/music/' + musicinfo.music + '.mp3', musicinfo.img], (err, data) => {
                        if (err) {
                            return res.send('错误:写入数据库失败' + err.message)
                        }

                        res.send({
                            status: 200,
                            message: '添加成功'
                        })
                    })
                }
            })

        } else {
            res.send({
                state: 500,
                message: '文件已存在!'
            })
        }
    })
}

温馨提示:写后端要特别注意数据格式的解析;

猜你喜欢

转载自blog.csdn.net/aiwanchengxu/article/details/128138951