最近在写一个用户上传MP3文件到服务器的小案例,我写一个这样的界面:
当用户点击input的时候,其实这里并不是input的样式,而是一个div将代替了input的原生样式,这样比较好看一点:
选择文件:
{{ filename }}
我就将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: '文件已存在!'
})
}
})
}
温馨提示:写后端要特别注意数据格式的解析;