前言:
在egg中的上传是有两种方法来实现:官方入口
-
File 模式:
-
Stream 模式:
目录:
2、代码中:上传以后,mysql中新增数据,并且,public/ upload/ excel 里面保存我们上传的文件
2、准备一个excel文件,如果是按照我教程的话,第九步就是下载功能的实现,入口点我
4、(非常重要)config/ config.default.js
config.default.js 加入下面的内容,注意白名单,如果你的文件类型默认没有,必须加上,不然会报错,官方解释入口
5、app/ controller/ new/ uploadFile.js
7、serve/ common.js ,这里放给mysql库里存数据的相关代码
实现效果:
1、界面上
2、代码中:上传以后,mysql中新增数据,并且,public/ upload/ excel 里面保存我们上传的文件
这里来讲一讲他的File 模式模式的用法:
后端部分:
1、引入插件:这个插件是用来解析excel内容的必备插件
cnpm install xlsx --save
2、准备一个excel文件,如果是按照我教程的话,第九步就是下载功能的实现,入口点我
3、router文件里面配置路由
module.exports = app => {
//上传-批量用户数据-用的file
app.post('/uploadUserList', controller.new.uploadFile.uploadFiles_file);
}
4、(非常重要)config/ config.default.js
config.default.js 加入下面的内容,注意白名单,如果你的文件类型默认没有,必须加上,不然会报错,官方解释入口
//上传文件所需配置
config.multipart = {
mode: 'file',//启用 file 模式
fileSize: 1048576000,
whitelist: ['.xlsx'] //白名单,把你的文件类型加上,不然会报错
}
官方默认就有的格式
// images
'.jpg', '.jpeg', // image/jpeg
'.png', // image/png, image/x-png
'.gif', // image/gif
'.bmp', // image/bmp
'.wbmp', // image/vnd.wap.wbmp
'.webp',
'.tif',
'.psd',
// text
'.svg',
'.js', '.jsx',
'.json',
'.css', '.less',
'.html', '.htm',
'.xml',
// tar
'.zip',
'.gz', '.tgz', '.gzip',
// video
'.mp3',
'.mp4',
'.avi',
5、app/ controller/ new/ uploadFile.js
6、uploadFile.js
const Controller = require('egg').Controller;
const xlsx = require('xlsx')
const fs = require('fs')
const path = require('path');
class uploadFileController extends Controller {
/**
* @上传文件-将excel文件数据输入到user表
* 两种类型,file和stream
* 这里使用的是file
*/
async uploadFiles_file(){
const {ctx} = this;
const file = ctx.request.files[0]; //获取上传文件,config没有配置,这里file拿不到
if (!file) return ctx.throw(404);
const filename = ctx.request.body.name?ctx.request.body.name:file.filename //文件名称,如果前端没传就直接用文件的
const distPath = path.join('', 'app/public/upload/excel');
const stat = fs.statSync(distPath);
if (!stat.isDirectory()) {
fs.mkdirSync(distPath);
}
const targetPath = path.join('', 'app/public/upload/excel', filename);//目标文件地址
//将上传的文件保存到本地,如果本地有就覆盖
fs.readFile(file.filepath, function (err, data) { // 异步读取文件内容
fs.writeFile(targetPath, data, function (err) { // des_file是文件名,data,文件数据,异步写入到文件
if( err ){
console.log( '文件保存到本地失败,原因:' );
console.log( err );
}else{
console.log('文件保存到本地成功');
// 读取内容
const workbook = xlsx.readFile(targetPath);
const sheetNames = workbook.SheetNames; //获取表名
const sheet = workbook.Sheets[sheetNames[0]]; //通过表名得到表对象
// console.log(sheet);
// console.log('111111111');thead的内容通过 打印sheet 得到
const thead = [sheet.A1.v, sheet.B1.v, sheet.C1.v, sheet.D1.v, sheet.E1.v];
const exceldata = xlsx.utils.sheet_to_json(sheet); //通过工具将表对象的数据读出来并转成json
// console.log(thead);//[ '姓名', '年龄', '地址', '邮箱', '手机号' ]
// console.log(data);//[{'姓名': '张浩','年龄': 12,'地址': '幸福1','邮箱': '1234@.qq.com','手机号': '12345678900'}]
if(exceldata.length>0){
//将excel数据增添到库里
ctx.service.common.addSimCard(exceldata);
}
}
});
})
ctx.body = {
code:200,
masg:'success',
data:'上传成功'
};
}
}
module.exports = uploadFileController;
7、serve/ common.js ,这里放给mysql库里存数据的相关代码
const Service = require('egg').Service;
class CommonService extends Service {
/**
* 上次excel添加到mysql数据库
* @param {Array} headers excel标题栏
* @param {Array} result excel内容
*/
async addSimCard(result) {
const values = []; //[ [1,'张三','13519105845',...] ,[],[]... ]
result.forEach(item=> {
let _arr = [];
_arr[0] = parseInt(Math.random()*100000)
_arr[1] = item['姓名']
_arr[2] = item['手机号']
_arr[3] = item['地址']
_arr[4] = item['年龄']
_arr[5] = item['邮箱']
values.push(_arr);
});
// 重点sql语句
const addSql = 'INSERT INTO user (id,name,phone,address,age,email) VALUES ?';
const _result = await this.app.mysql.query(addSql, [values]);
console.log('上传成功')
}
}
module.exports = CommonService;
前端部分 vue+element:
1、封装文件: uploadAndDown.vue
<template>
<el-upload
v-if="Refresh"
class="upload-demo"
ref="upload"
:action="action"
:headers="headers"
:multiple="multiple"
:data="data"
:name="name"
:with-credentials="cookieOK"
:show-file-list="showFileList"
:drag="drag"
:accept="accept"
:list-type="listType"
:auto-upload="autoUpload"
:file-list="fileList"
:disabled="is_disabled"
:on-preview="handlePreview"
:on-remove="handleRemove"
:on-success="handleSuccess"
:on-error="handleError"
:on-progress="handleProgress"
:on-exceed="handleExceed"
:on-change="onChange"
:before-upload="beforeUpload"
:before-remove="beforeRemove"
:http-request="httpRequest"
>
<el-button slot="trigger" type="primary" icon="el-icon-upload2">选取文件</el-button>
<el-button style="margin-left: 10px;"
type="success"
@click="submitUploadSD"
:disabled="fileList.length==0"
:title="fileList.length==0?'请先选中文件':''"
icon="el-icon-upload">开始上传</el-button>
<el-button type="danger"
v-if="fileList.length>0"
icon="el-icon-delete"
@click.stop="clearFiles"
title="清空选中文件"
circle></el-button>
<el-button style="margin-left: 10px;"
type="primary"
@click.stop="downFile"
icon="el-icon-download">下载模板</el-button>
<!--提示信息-->
<div slot="tip" class="el-upload__tip" v-if="tip_text!=''">{{tip_text}}</div>
</el-upload>
</template>
<script>
//element的上传文件组件
export default {
props:{
/**
* 自动上传参数
* */
autoUpload:{ // 是否需要选取完自动上传功能
type: Boolean,
default: false
},
action:{//上传的地址
type: String,
default: ''
},
headers: {//设置上传的请求头部
type:Object,
default: () => {
return {}
}
},
data: {//上传时额外带的参数
type:Object,
default: () => {
return {}
}
},
name:{//上传的文件字段名
type: String,
default: 'file'
},
cookieOK:{//支持发送 cookie 凭证信息
type: Boolean,
default: true
},
/**
* 公共参数
* */
showFileList:{//是否显示已上传文件列表
type: Boolean,
default: true
},
drag:{//是否启用拖拽上传
type: Boolean,
default: false
},
accept:{//接受文件类型-图片上传类型-不同的格式之间以逗号隔开
type: String,
// default:'.doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document'
default: '.xlsx,.xls'
},
listType:{ // 文件列表的类型 - text/picture/picture-card
type: String,
default: 'text'
},
fileList:{//已上传的文件列表,
type:Array,
default: () => {
// { 默认格式
// name: 'food.jpeg',
// url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'
// }
return []
}
},
is_disabled:{//是否禁止,true是禁止,false不禁止
type: Boolean,
default: false
},
multiple:{//是否可以多选
type: Boolean,
default: true
},
limit:{//最大允许上传个数
type: Number,
default: 30
},
tip_text:{//提示信息
type: String,
default: ''
},
/**
* 手动上传参数
* */
needFromUpload:{ // form表单,将上传的file文件通过 formUpload 方法发送出去
type: Boolean,
default: false
},
},
watch: {},
data() {
return {
Refresh:true,//强制刷新
}
},
created() {
},
mounted() {
},
methods: {
/**
* 上传-默认事件
* */
//文件列表移除文件时的钩子
handleRemove(file, fileList) {
console.log('当前移除的是'+file);
},
//点击文件列表中已上传的文件时的钩子
handlePreview(file) {
console.log('当前点击的是'+file);
},
//文件上传成功时的钩子
handleSuccess(response, file, fileList) {
console.log('文件上传成功');
},
//文件上传失败时的钩子
handleError(err, file, fileList) {
console.log('文件上传失败');
},
//文件上传时的钩子
handleProgress(event, file, fileList) {
console.log(file);
},
//文件超出个数限制时的钩子
handleExceed(files, fileList) {
console.log('文件超出个数限制');
},
//覆盖默认的上传行为,可以自定义上传的实现
httpRequest(){
},
//删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false 或者返回 Promise 且被 reject,则停止删除。
beforeRemove(file, fileList) {
console.log('当前删除的文件'+file);
this.fileList.forEach((item,index)=>{
if(item == file){
this.fileList.splice(index,1)
}
})
},
/**
* 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
*/
onChange(file, fileList) {
this.fileList = fileList;
console.log('当前的选中文件:');
console.log(fileList);
},
/**
* 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。
*/
beforeUpload(file) {
console.log(file);
},
/**
* 上传-自定义事件
* */
submitUpload() {
this.$refs.upload.submit();
},
//清空已上传的文件列表(该方法不支持在 before-upload 中调用)
clearFiles(){
this.$refs.upload.clearFiles();
this.fileList = [];
},
//取消上传某个文件
abortFiles(file){
this.$refs.upload.abort(file);
},
/**
* 手动上传点击确认
* */
submitUploadSD(){
let arr = this.fileList;
let str = {
fileList:arr
}
this.$emit('uploadFile',str);
},
/**
* 下载模板点击
* */
downFile(){
this.$emit('downFile');
},
/**
* 手动刷新上传组件
* */
RefreshUpload(){
let arr = this.fileList;
this.Refresh = false;
this.$nextTick(()=>{
this.Refresh = true;
})
},
},
components: {},
beforeDestroy() {
}
}
</script>
<style lang='scss' scoped>
</style>
2、调用封装文件
<upload-and-down
class="uploadAndDown"
@uploadFile="uploadFile"
@downFile="downFile">
</upload-and-down>
3、上传和下载的事件
/**
* 上传
* */
uploadFile(str){
let fileList = str.fileList;
let formData = new FormData
fileList.forEach(item=>{
formData.append('file',item.raw)
})
this.$axios({
method:'post',
url:'http://localhost:7001/uploadUserList',
data:formData,
headers:{
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(res => {
this.$message.success('上传成功')
})
},
//下载事件
downFile(){
console.log('点击下载按钮');
// 创建隐藏的可下载链接
var eleLink = document.createElement('a');
eleLink.style.display = 'none';
eleLink.href = 'http://localhost:7001/toexecl';
// 触发点击
document.body.appendChild(eleLink);
eleLink.click();
// 然后移除
document.body.removeChild(eleLink);
}