• elementUI加springboot实现上传excel文件给后端并读取excel


    前言

    最近在研究如何通过vue的elemenetui框架加上springboot去实现从前端上传文件给后端,在进行文件查找的时候,大部分我进行查找的都是怎么上传文件给服务器,所以也为了记录,就计划写下本文章;
    同时,本次实现上传excel并对excel的内容进行读取

    需求了解

    在我的项目中,我需要做一个签到打卡的功能,其中人员方面是希望用导入的方式进行导入,
    用的是elementuiupload组件,在做这个的时候,最麻烦和难搞的是怎么连到后端,虽然说在elementui的官方文档里,写的是对里面的action进行操作,但是看了很多都不知道怎么去进行下一步的操作;好在,经过学习和了解,终于把它给完成了,那么我们来具体看看怎么做吧。

    前端代码

    在我的前端项目中,我是用一个按钮封装upload,具体如下

    <template>
    	<div>
    		 <el-upload
              style="display: inline-block"
              action="string"
              :limit="1"
              :file-list="fileList"
              :on-error="loadFileError"
              :on-success="loadFileSuccess"
              :before-upload="beforeUpload"
              accept=".xlsx,.xls"
              :show-file-list="false"
              :http-request="uploadFile"
              ><el-button type="success">导入el-button>el-upload
            >
    	div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    其中

    limit: 代表一次可上传的文件数量
    file-list: 代表自己定义的属性
    on-error: 代表导入文件失败的时候提示的方法
    on-success:代表导入文件成功提示的方法
    before-upload:代表在上传前检查文件的格式、数据大小、信息等,判定文件是否能够上传
    show-file-list:代表是否显示文件列表,false不显示
    http-request:本次用来进行上传给后端的方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    然后就是正式的script的代码了。
    定义的属性

    export default {
      name: "conferenceSignCard",
      data() {
        return {
          fileList: [], // 导入的文件
        };
      },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    导入文件失败的时候提示的方法

        // 导入失败,其中$message为elementui的消息提醒组件
        loadFileError() {
          this.$message({
            message: "文件上传失败!",
            type: "error",
          });
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    导入文件成功提示的方法

        loadFileSuccess() {
          this.$message({
            message: "文件上传成功!",
            type: "success",
          });
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    上传前检查文件的格式、数据大小、信息等,判定文件是否能够上传

        // 导入前检查文件
        beforeUpload(file) {
          const extension = file.name.split(".")[1] === "xls";
          const extension2 = file.name.split(".")[1] === "xlsx";
          const isLt2M = file.size / 1024 / 1024 < 2;
          if (!extension && !extension2) {
            this.$message({
              message: "上传模板只能是 xls、xlsx格式!",
              type: "error",
            });
          }
          if (!isLt2M) {
            console.log("上传模板大小不能超过 2MB!");
            this.$message({
              message: "上传模板大小不能超过 2MB!",
              type: "error",
            });
          }
          return extension || extension2 || isLt2M;
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    进行上传给后端的方法

        // 导入文件
        uploadFile(param) {
          //this.$router.go(0);
          const File = param.file;
          let formDataInfo = new FormData();
          formDataInfo.append("file", File);
          const config = {
            url: "/signCard/loadConferenceFile",
            method: "post",
            data: formDataInfo,
          };
          // http为我所在项目封装了router的js代码,如果需要传递给后端,需要
          // 如上方代码我写的信息进行传递即可
          http(config)
            .then((res) => {
              this.$message({
                message: res.data,
                type: "success",
              });
            });
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    或者写成

        uploadFile(param){
          const File = param.file;
          let formDataInfo = new FormData();
          formDataInfo.append("file", File);
          loadConferenceFile(formDataInfo).then((res) => {
              this.$message({
                message: res.data,
                type: "success",
              });
          });
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    loadConferenceFile(formDataInfo){
        return axios.post("/signCard/loadConferenceFile",formDataInfo)
      }
    
    • 1
    • 2
    • 3

    两者二选一,就只是axios的调用形式有区别
    那么到这里我们的前端就写完了,它是一个按钮,可导入xlsx和xls文件格式
    在这里插入图片描述
    同时,用这个方式调用其实有一个问题,如果不刷新,就会在每次刷新只能调用一次,所以我有写一个定时器,每次调用后隔一秒进行刷新页面;
    当然如果有更好的方式,能够知道为什么会出现这个情况,可以告诉我怎么修改
    那么,具体的加定时器后的代码如下

        // 导入文件
        uploadFile(param) {
          //this.$router.go(0);
          const File = param.file;
          let formDataInfo = new FormData();
          formDataInfo.append("file", File);
          const config = {
            url: "/signCard/loadConferenceFile",
            method: "post",
            data: formDataInfo,
          };
          http(config)
            .then((res) => {
              this.$message({
                message: res.data,
                type: "success",
              });
            })
            .then(() => {
              this.startTimer();
            });
        },
            startTimer() {
          this.redurceTime = 1;
          this.timer = setInterval(() => {
            this.redurceTime--;
            if (this.redurceTime == 0) {
              this.clearTimer();
              this.$router.go(0);
            }
          }, 1000);
        },
        clearTimer() {
          if (this.timer) {
            clearInterval(this.timer);
            this.timer = null;
          }
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    在这里我添加了这么几个属性

      data() {
        return {
          fileList: [], // 导入的文件
          ConferenceList: [], // 会议列表
          timer: null, // 定时器
          redurceTime: 0, // 剩余时间
        };
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    后端代码

    ok,那么现在我们的前端部分正式ok了,由前面我们知道我后端调用的路径为

    /signCard/loadConferenceFile
    
    • 1

    并且为post调用
    那么到后端,我springboot的controller层的代码为:

    import com.ht.exam.service.SignCardService;
    import org.apache.ibatis.annotations.Param;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.annotation.Resource;
    import java.io.File;
    
    @RestController
    @RequestMapping("/signCard/*")
    public class SignCardController {
        @Resource
        private SignCardService signCardService;
    
        // 上传导入会议人员的文件
        @PostMapping("/loadConferenceFile")
        public String loadConferencePersonFile(@RequestParam("file") MultipartFile file) {
            return signCardService.loadConferencePersonFile(file);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    service层代码为

    @Service
    public class SignCardService {
        public String loadConferencePersonFile(MultipartFile file) {
    		// 在这里写具体的功能逻辑
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    以上,我们就完成了后端的接收了,接收之后,那就需要解析文件
    首先,我们需要引入poi的依赖

    <dependency>
        <groupId>org.apache.poigroupId>
        <artifactId>poi-ooxmlartifactId>
        <version>3.9version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    然后是具体的读取文件

    @Service
    public class SignCardService {
        public String loadConferencePersonFile(MultipartFile file) {
    // 读取文件
    	InputStream inputStream = null;
        try{
            inputStream = file.getInputStream();
        }catch (IOException e){
            return "文件读取失败";
        }
    // 创建excel实例
            Workbook wb = null;
    // 判断格式是.xlsx还是.xls
            if (file.getOriginalFilename().matches("^.+\\.(?i)(xlsx)$")) {
                try {
                    wb = new XSSFWorkbook(inputStream);
                }catch (IOException e) {
                    return "读取excel(xlsx)失败!";
                }
    
            } else {
                try {
                    wb = new HSSFWorkbook(inputStream);
                }catch (IOException e) {
                    return "读取excel(xls)失败!";
                }
            }
            // 获取excel第一个表格
            Sheet sheet = wb.getSheetAt(0);
            if (sheet == null) {
                return new ResultVO(ResultCode.ERROR.getCode(),"该文件没有数据!");
            }
            // 获取列数
            int column = sheet.getRow(0).getPhysicalNumberOfCells();
            // 获取行数
            int rows = sheet.getLastRowNum();
            List<String> empNoList = new ArrayList<>();
            // 遍历Excel
            for (int i = 1; i <= sheet.getLastRowNum();i++) {
                Row row = sheet.getRow(i);
                if (row == null) {
                    continue;
                }
                // 遍历列数,工号
                if (row.getCell(0) !=null) {
                    row.getCell(0).setCellType(CellType.STRING);
                    String empNo = row.getCell(0).getStringCellValue();
                    // 不为空获取工号
                    if (StringUtils.isNotEmpty(empNo)) {
                        empNoList.add(empNo);
                    }
                }
            }
            // 然后以上是读取,往下写自己需要的功能
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    在poi中
    sheet指的是
    在这里插入图片描述
    row指的是行
    在这里插入图片描述
    cell指的是列
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    结语

    以上为我实现上传excel文件给后端并读取excel的具体过程

  • 相关阅读:
    MySQL调优参数配置详解
    MySQL查询性能优化七种硬核之索引下推
    MySQL之SQL语句优化
    三维重建---第四章 三维重建及极几何
    SpringCloud Alibaba——记录一种nacos配置中心动态刷新不起效的解决方式(@ConfigurationProperties)
    MySQL 函数 索引 事务 管理
    策略验证_卖出口诀_长箭射天股价落地
    运维团队如何加强安全设备监控与日志管理
    Vue城市选择器示例(省市区三级)
    异步FIFO设计的仿真与综合技术(6)
  • 原文地址:https://blog.csdn.net/xc9711/article/details/126099859