前言

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

需求了解

在我的项目中,我需要做一个签到打卡的功能,其中人员方面是希望用导入的方式进行导入,
用的是elementui的upload组件,在做这个的时候,最麻烦和难搞的是怎么连到后端,虽然说在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>

其中

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

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

export default {
  name: "conferenceSignCard",
  data() {
    return {
      fileList: [], // 导入的文件
    };
  },
}

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

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

导入文件成功提示的方法

    loadFileSuccess() {
      this.$message({
        message: "文件上传成功!",
        type: "success",
      });
    },

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

    // 导入前检查文件
    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;
    },

进行上传给后端的方法

    // 导入文件
    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",
          });
        });
    },

或者写成

    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",
          });
      });
    },
loadConferenceFile(formDataInfo){
    return axios.post("/signCard/loadConferenceFile",formDataInfo)
  }

两者二选一,就只是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;
      }
    },

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

  data() {
    return {
      fileList: [], // 导入的文件
      ConferenceList: [], // 会议列表
      timer: null, // 定时器
      redurceTime: 0, // 剩余时间
    };
  },

后端代码

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

/signCard/loadConferenceFile

并且为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);
    }
}

service层代码为

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

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

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.9</version>
</dependency>

然后是具体的读取文件

@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);
                }
            }
        }
        // 然后以上是读取,往下写自己需要的功能
}

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

结语

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

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐