egg(十):上传excel文件并解析内容,存到mysql数据库,并保存到本地,vue+egg实现前后端

以你之姓@ 2022-09-16 11:09 124阅读 0赞

前言:

在egg中的上传是有两种方法来实现:官方入口

  • File 模式:

  • Stream 模式:

目录:

实现效果:

1、界面上

2、代码中:上传以后,mysql中新增数据,并且,public/ upload/ excel 里面保存我们上传的文件

这里来讲一讲他的File 模式模式的用法:

后端部分:

1、引入插件:这个插件是用来解析excel内容的必备插件

2、准备一个excel文件,如果是按照我教程的话,第九步就是下载功能的实现,入口点我

3、router文件里面配置路由

4、(非常重要)config/ config.default.js

config.default.js 加入下面的内容,注意白名单,如果你的文件类型默认没有,必须加上,不然会报错,官方解释入口

5、app/ controller/ new/ uploadFile.js

6、uploadFile.js

7、serve/ common.js ,这里放给mysql库里存数据的相关代码

前端部分 vue+element:

1、封装文件: uploadAndDown.vue

2、调用封装文件

3、上传和下载的事件

到此结束!


实现效果:

1、界面上

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBAUG9ubmVudWx0_size_20_color_FFFFFF_t_70_g_se_x_16

2、代码中:上传以后,mysql中新增数据,并且,public/ upload/ excel 里面保存我们上传的文件

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBAUG9ubmVudWx0_size_8_color_FFFFFF_t_70_g_se_x_16

这里来讲一讲他的File 模式模式的用法:

后端部分:

1、引入插件:这个插件是用来解析excel内容的必备插件

  1. cnpm install xlsx --save

2、准备一个excel文件,如果是按照我教程的话,第九步就是下载功能的实现,入口点我

3、router文件里面配置路由

  1. module.exports = app => {
  2. //上传-批量用户数据-用的file
  3. app.post('/uploadUserList', controller.new.uploadFile.uploadFiles_file);
  4. }

4、(非常重要)config/ config.default.js

config.default.js 加入下面的内容,注意白名单,如果你的文件类型默认没有,必须加上,不然会报错,官方解释入口

  1. //上传文件所需配置
  2. config.multipart = {
  3. mode: 'file',//启用 file 模式
  4. fileSize: 1048576000,
  5. whitelist: ['.xlsx'] //白名单,把你的文件类型加上,不然会报错
  6. }
  7. 官方默认就有的格式
  8. // images
  9. '.jpg', '.jpeg', // image/jpeg
  10. '.png', // image/png, image/x-png
  11. '.gif', // image/gif
  12. '.bmp', // image/bmp
  13. '.wbmp', // image/vnd.wap.wbmp
  14. '.webp',
  15. '.tif',
  16. '.psd',
  17. // text
  18. '.svg',
  19. '.js', '.jsx',
  20. '.json',
  21. '.css', '.less',
  22. '.html', '.htm',
  23. '.xml',
  24. // tar
  25. '.zip',
  26. '.gz', '.tgz', '.gzip',
  27. // video
  28. '.mp3',
  29. '.mp4',
  30. '.avi',

" class="reference-link">watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBAUG9ubmVudWx0_size_20_color_FFFFFF_t_70_g_se_x_16 1

5、app/ controller/ new/ uploadFile.js

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBAUG9ubmVudWx0_size_6_color_FFFFFF_t_70_g_se_x_16

6、uploadFile.js

  1. const Controller = require('egg').Controller;
  2. const xlsx = require('xlsx')
  3. const fs = require('fs')
  4. const path = require('path');
  5. class uploadFileController extends Controller {
  6. /**
  7. * @上传文件-将excel文件数据输入到user表
  8. * 两种类型,file和stream
  9. * 这里使用的是file
  10. */
  11. async uploadFiles_file(){
  12. const {ctx} = this;
  13. const file = ctx.request.files[0]; //获取上传文件,config没有配置,这里file拿不到
  14. if (!file) return ctx.throw(404);
  15. const filename = ctx.request.body.name?ctx.request.body.name:file.filename //文件名称,如果前端没传就直接用文件的
  16. const distPath = path.join('', 'app/public/upload/excel');
  17. const stat = fs.statSync(distPath);
  18. if (!stat.isDirectory()) {
  19. fs.mkdirSync(distPath);
  20. }
  21. const targetPath = path.join('', 'app/public/upload/excel', filename);//目标文件地址
  22. //将上传的文件保存到本地,如果本地有就覆盖
  23. fs.readFile(file.filepath, function (err, data) { // 异步读取文件内容
  24. fs.writeFile(targetPath, data, function (err) { // des_file是文件名,data,文件数据,异步写入到文件
  25. if( err ){
  26. console.log( '文件保存到本地失败,原因:' );
  27. console.log( err );
  28. }else{
  29. console.log('文件保存到本地成功');
  30. // 读取内容
  31. const workbook = xlsx.readFile(targetPath);
  32. const sheetNames = workbook.SheetNames; //获取表名
  33. const sheet = workbook.Sheets[sheetNames[0]]; //通过表名得到表对象
  34. // console.log(sheet);
  35. // console.log('111111111');thead的内容通过 打印sheet 得到
  36. const thead = [sheet.A1.v, sheet.B1.v, sheet.C1.v, sheet.D1.v, sheet.E1.v];
  37. const exceldata = xlsx.utils.sheet_to_json(sheet); //通过工具将表对象的数据读出来并转成json
  38. // console.log(thead);//[ '姓名', '年龄', '地址', '邮箱', '手机号' ]
  39. // console.log(data);//[{'姓名': '张浩','年龄': 12,'地址': '幸福1','邮箱': '1234@.qq.com','手机号': '12345678900'}]
  40. if(exceldata.length>0){
  41. //将excel数据增添到库里
  42. ctx.service.common.addSimCard(exceldata);
  43. }
  44. }
  45. });
  46. })
  47. ctx.body = {
  48. code:200,
  49. masg:'success',
  50. data:'上传成功'
  51. };
  52. }
  53. }
  54. module.exports = uploadFileController;

7、serve/ common.js ,这里放给mysql库里存数据的相关代码

  1. const Service = require('egg').Service;
  2. class CommonService extends Service {
  3. /**
  4. * 上次excel添加到mysql数据库
  5. * @param {Array} headers excel标题栏
  6. * @param {Array} result excel内容
  7. */
  8. async addSimCard(result) {
  9. const values = []; //[ [1,'张三','13519105845',...] ,[],[]... ]
  10. result.forEach(item=> {
  11. let _arr = [];
  12. _arr[0] = parseInt(Math.random()*100000)
  13. _arr[1] = item['姓名']
  14. _arr[2] = item['手机号']
  15. _arr[3] = item['地址']
  16. _arr[4] = item['年龄']
  17. _arr[5] = item['邮箱']
  18. values.push(_arr);
  19. });
  20. // 重点sql语句
  21. const addSql = 'INSERT INTO user (id,name,phone,address,age,email) VALUES ?';
  22. const _result = await this.app.mysql.query(addSql, [values]);
  23. console.log('上传成功')
  24. }
  25. }
  26. module.exports = CommonService;

前端部分 vue+element:

1、封装文件: uploadAndDown.vue

  1. <template>
  2. <el-upload
  3. v-if="Refresh"
  4. class="upload-demo"
  5. ref="upload"
  6. :action="action"
  7. :headers="headers"
  8. :multiple="multiple"
  9. :data="data"
  10. :name="name"
  11. :with-credentials="cookieOK"
  12. :show-file-list="showFileList"
  13. :drag="drag"
  14. :accept="accept"
  15. :list-type="listType"
  16. :auto-upload="autoUpload"
  17. :file-list="fileList"
  18. :disabled="is_disabled"
  19. :on-preview="handlePreview"
  20. :on-remove="handleRemove"
  21. :on-success="handleSuccess"
  22. :on-error="handleError"
  23. :on-progress="handleProgress"
  24. :on-exceed="handleExceed"
  25. :on-change="onChange"
  26. :before-upload="beforeUpload"
  27. :before-remove="beforeRemove"
  28. :http-request="httpRequest"
  29. >
  30. <el-button slot="trigger" type="primary" icon="el-icon-upload2">选取文件</el-button>
  31. <el-button style="margin-left: 10px;"
  32. type="success"
  33. @click="submitUploadSD"
  34. :disabled="fileList.length==0"
  35. :title="fileList.length==0?'请先选中文件':''"
  36. icon="el-icon-upload">开始上传</el-button>
  37. <el-button type="danger"
  38. v-if="fileList.length>0"
  39. icon="el-icon-delete"
  40. @click.stop="clearFiles"
  41. title="清空选中文件"
  42. circle></el-button>
  43. <el-button style="margin-left: 10px;"
  44. type="primary"
  45. @click.stop="downFile"
  46. icon="el-icon-download">下载模板</el-button>
  47. <!--提示信息-->
  48. <div slot="tip" class="el-upload__tip" v-if="tip_text!=''">{
  49. {tip_text}}</div>
  50. </el-upload>
  51. </template>
  52. <script>
  53. //element的上传文件组件
  54. export default {
  55. props:{
  56. /**
  57. * 自动上传参数
  58. * */
  59. autoUpload:{ // 是否需要选取完自动上传功能
  60. type: Boolean,
  61. default: false
  62. },
  63. action:{//上传的地址
  64. type: String,
  65. default: ''
  66. },
  67. headers: {//设置上传的请求头部
  68. type:Object,
  69. default: () => {
  70. return {}
  71. }
  72. },
  73. data: {//上传时额外带的参数
  74. type:Object,
  75. default: () => {
  76. return {}
  77. }
  78. },
  79. name:{//上传的文件字段名
  80. type: String,
  81. default: 'file'
  82. },
  83. cookieOK:{//支持发送 cookie 凭证信息
  84. type: Boolean,
  85. default: true
  86. },
  87. /**
  88. * 公共参数
  89. * */
  90. showFileList:{//是否显示已上传文件列表
  91. type: Boolean,
  92. default: true
  93. },
  94. drag:{//是否启用拖拽上传
  95. type: Boolean,
  96. default: false
  97. },
  98. accept:{//接受文件类型-图片上传类型-不同的格式之间以逗号隔开
  99. type: String,
  100. // default:'.doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document'
  101. default: '.xlsx,.xls'
  102. },
  103. listType:{ // 文件列表的类型 - text/picture/picture-card
  104. type: String,
  105. default: 'text'
  106. },
  107. fileList:{//已上传的文件列表,
  108. type:Array,
  109. default: () => {
  110. // { 默认格式
  111. // name: 'food.jpeg',
  112. // url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'
  113. // }
  114. return []
  115. }
  116. },
  117. is_disabled:{//是否禁止,true是禁止,false不禁止
  118. type: Boolean,
  119. default: false
  120. },
  121. multiple:{//是否可以多选
  122. type: Boolean,
  123. default: true
  124. },
  125. limit:{//最大允许上传个数
  126. type: Number,
  127. default: 30
  128. },
  129. tip_text:{//提示信息
  130. type: String,
  131. default: ''
  132. },
  133. /**
  134. * 手动上传参数
  135. * */
  136. needFromUpload:{ // form表单,将上传的file文件通过 formUpload 方法发送出去
  137. type: Boolean,
  138. default: false
  139. },
  140. },
  141. watch: {},
  142. data() {
  143. return {
  144. Refresh:true,//强制刷新
  145. }
  146. },
  147. created() {
  148. },
  149. mounted() {
  150. },
  151. methods: {
  152. /**
  153. * 上传-默认事件
  154. * */
  155. //文件列表移除文件时的钩子
  156. handleRemove(file, fileList) {
  157. console.log('当前移除的是'+file);
  158. },
  159. //点击文件列表中已上传的文件时的钩子
  160. handlePreview(file) {
  161. console.log('当前点击的是'+file);
  162. },
  163. //文件上传成功时的钩子
  164. handleSuccess(response, file, fileList) {
  165. console.log('文件上传成功');
  166. },
  167. //文件上传失败时的钩子
  168. handleError(err, file, fileList) {
  169. console.log('文件上传失败');
  170. },
  171. //文件上传时的钩子
  172. handleProgress(event, file, fileList) {
  173. console.log(file);
  174. },
  175. //文件超出个数限制时的钩子
  176. handleExceed(files, fileList) {
  177. console.log('文件超出个数限制');
  178. },
  179. //覆盖默认的上传行为,可以自定义上传的实现
  180. httpRequest(){
  181. },
  182. //删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false 或者返回 Promise 且被 reject,则停止删除。
  183. beforeRemove(file, fileList) {
  184. console.log('当前删除的文件'+file);
  185. this.fileList.forEach((item,index)=>{
  186. if(item == file){
  187. this.fileList.splice(index,1)
  188. }
  189. })
  190. },
  191. /**
  192. * 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
  193. */
  194. onChange(file, fileList) {
  195. this.fileList = fileList;
  196. console.log('当前的选中文件:');
  197. console.log(fileList);
  198. },
  199. /**
  200. * 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。
  201. */
  202. beforeUpload(file) {
  203. console.log(file);
  204. },
  205. /**
  206. * 上传-自定义事件
  207. * */
  208. submitUpload() {
  209. this.$refs.upload.submit();
  210. },
  211. //清空已上传的文件列表(该方法不支持在 before-upload 中调用)
  212. clearFiles(){
  213. this.$refs.upload.clearFiles();
  214. this.fileList = [];
  215. },
  216. //取消上传某个文件
  217. abortFiles(file){
  218. this.$refs.upload.abort(file);
  219. },
  220. /**
  221. * 手动上传点击确认
  222. * */
  223. submitUploadSD(){
  224. let arr = this.fileList;
  225. let str = {
  226. fileList:arr
  227. }
  228. this.$emit('uploadFile',str);
  229. },
  230. /**
  231. * 下载模板点击
  232. * */
  233. downFile(){
  234. this.$emit('downFile');
  235. },
  236. /**
  237. * 手动刷新上传组件
  238. * */
  239. RefreshUpload(){
  240. let arr = this.fileList;
  241. this.Refresh = false;
  242. this.$nextTick(()=>{
  243. this.Refresh = true;
  244. })
  245. },
  246. },
  247. components: {},
  248. beforeDestroy() {
  249. }
  250. }
  251. </script>
  252. <style lang='scss' scoped>
  253. </style>

2、调用封装文件

  1. <upload-and-down
  2. class="uploadAndDown"
  3. @uploadFile="uploadFile"
  4. @downFile="downFile">
  5. </upload-and-down>

3、上传和下载的事件

  1. /**
  2. * 上传
  3. * */
  4. uploadFile(str){
  5. let fileList = str.fileList;
  6. let formData = new FormData
  7. fileList.forEach(item=>{
  8. formData.append('file',item.raw)
  9. })
  10. this.$axios({
  11. method:'post',
  12. url:'http://localhost:7001/uploadUserList',
  13. data:formData,
  14. headers:{
  15. 'Content-Type': 'application/x-www-form-urlencoded'
  16. }
  17. }).then(res => {
  18. this.$message.success('上传成功')
  19. })
  20. },
  21. //下载事件
  22. downFile(){
  23. console.log('点击下载按钮');
  24. // 创建隐藏的可下载链接
  25. var eleLink = document.createElement('a');
  26. eleLink.style.display = 'none';
  27. eleLink.href = 'http://localhost:7001/toexecl';
  28. // 触发点击
  29. document.body.appendChild(eleLink);
  30. eleLink.click();
  31. // 然后移除
  32. document.body.removeChild(eleLink);
  33. }

到此结束!

发表评论

表情:
评论列表 (有 0 条评论,124人围观)

还没有评论,来说两句吧...

相关阅读