Springboot+vue Excel导入导出(POI4.0 和 EasyPOI)


我们在进行项目构建的时候,通常在存储大规模的数据之后,我们想要得到这些数据,就需要把这些数据导出,使用一个Excel表格进行保存起来。在这里我们怎么实现呢?接着往下看。

1、POI是什么?

在这里apache提供了一个挺好用的工具,那就是POI,POI是创建和维护操作各种符合 Office Open XML(OOXML)标准和微软的 OLE2 复合文档格式(OLE2)的 Java API。

2、如何使用POI?

那如何使用呢?首先我们在一个需要使用的项目当中进行导入依赖(idea+maven),在这里我们不单单只导入POI依赖,还需要导入一个poi-ooxml支持xls操作的依赖。导入4.0.0的版本,还有其他版本也是可以进行选择的,比如说3.1.14.

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

在这里导入过程所花费的时间还是比较久的。在等待导入完成之后,就是对这个POI进行使用了。你也可以前往官方文档进行预览:https://poi.apache.org/

在这里我就直接上代码了(一个简单的excel表,后面还会对excel表如何设置样式进行说明);在代码当中提供了相对应的注释:

    @PostMapping("/toExcel")
    public void toExcel(HttpServletResponse response) throws IOException {
        //获得数据库当中的数据,这里是已经写好的一个方法,返回的是一个select * 的list集合。
        List<User> list = userService.findAll();

        HSSFWorkbook workbook =  new HSSFWorkbook();
        //创建一个表,是指一个xsl文件可以创建三个表其中的一个表的表名,设置为user info
        HSSFSheet sheet = workbook.createSheet("user info");

        //设置一行(第一行)
        HSSFRow row =null;
        row = sheet.createRow(0); //创建第一个单元格
        row.setHeight((short)(26.5 * 20)); //设置行高,在这里26.5就是这一行的行高
        row.createCell(0).setCellValue("用户信息"); //这个单元格的值

        //设置单元格合并,单元格合并的位置,0到0行,0到4列
        //excel表也是从0行0列开始算起,注意自己设置合并的大小,避免已经设置值了的单元格也被合并导致代码报错
        CellRangeAddress rowRegion = new CellRangeAddress(0,0,0,4);
        sheet.addMergedRegion(rowRegion); //进行合并

		//另起一行,也就是第二行
        row =sheet.createRow(1);
        row.setHeight((short)(22.5*20));
        row.createCell(0).setCellValue("id");//给单元格进行赋值
        row.createCell(1).setCellValue("name");
        row.createCell(2).setCellValue("birthday");
        row.createCell(3).setCellValue("sex");
        row.createCell(4).setCellValue("address");

        //对前面得到的list集合进行遍历
        for (int i =0 ;i<list.size();i++){
            row = sheet.createRow(i+2); //重新找到这一行数据的行数,也就是在前端的基础上再另起一行
            User user =list.get(i); //得到集合遍历的每一行数据
            row.createCell(0).setCellValue(user.getId()); //将值给到单元格
            row.createCell(1).setCellValue(user.getName()); //user是一个实体类对象,获取get方法进行赋值
            row.createCell(2).setCellValue(user.getBirthday());
            row.createCell(3).setCellValue(user.getSex());
            row.createCell(4).setCellValue(user.getAddress());
        }
		
		//设置自适应宽度
        for (int i =0;i<=13 ;i++){
            sheet.autoSizeColumn(i);
        }
		
		//response进行相应数据
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        OutputStream os = response.getOutputStream();
        //这里进行设置了一个文件名,其实也可以不要设置了,
        //在前端进行下载的时候需要重新给定一个文件名进行下载
        response.setHeader("Content-disposition","attachment;filename=User.xls");
        workbook.write(os);
        os.flush();
        os.close();
    }

在这里就是在后端进行获取到数据了,之后我们只需要在前端访问这个路由,创建一个超链接进行下载就行了,接下来就是前端下载了

3、如何将表保存?

我们使用一个按钮,给按钮绑定一个单击事件,
在这里将路由地址进行封装:

export function toExcel(callback) {
  return request({
    url: "/toExcel", //完整路由地址
    method: 'post', //请求类型
    procgress: true,
    back: callback,
    responseType: 'blob'  //响应类型,避免乱码
  })
}

在事件当中访问这个路由,创建一个下载链接进行下载。

//在使用之前我们需要将刚才封装好的toExcel进行导入到这个vue文件当中。
  import {toExcel} from '@/api/ordering' //上面的文件的地址。
      //导出excel表
      exportExcel() {
        toExcel().then((data) => {
          this.downloadFile(data)
        })
      },
      /**
       * 文件导出
       */
      downloadFile(data) {
        if (!data) {
          return
        }
        const link = document.createElement('a');
        let blob = new Blob([data], {
          type: 'application/vnd.ms-excel'
        });
        link.style.display = 'none';
        link.href = URL.createObjectURL(blob);

        link.setAttribute('download', 'user info' + '.xls');
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
      },

到这里,就实现了在前端获取数据并且下载一个xls文件。但是在这里我们的xls文件也只是一个很简单的表,一点也不美观。那我们又该如何设置这个excel表的样式呢?

4、POI的样式如何设置?

POI给我们提供了一个样式类HSSFCellStyle,使用HSSFWorkbook对象的createCellStyle方法创建一个这样的样式对象。

HSSFWorkbook workbook = new HSSFWorkbook();
HSSFCellStyle setBorder = workbook.createCellStyle();

在这里创建号这个样式对象后,在使用的时候,对要使用的row对象进行使用即可。如下:给第一列加上这个样式,(当然了,在这里这个样式还没有任何值,还没进行设置)

row.getCell(0).setCellStyle(setBorder);

4.1、背景色的设置

在这里使用setFillForegroundColor方法给定颜色,setFillPattern给定填充规则,在这里的IndexedColors的枚举类给出了其颜色的名称。

setBorderTable.setFillForegroundColor(IndexedColors.CORNFLOWER_BLUE.getIndex());
setBorderTable.setFillPattern(FillPatternType.SOLID_FOREGROUND);

单击这个IndexedColors即可进入到这个枚举类当中进行查看。
在这里插入图片描述

4.2、字体的设置

在表格当中不可避免的就是字体的设置了,在进行设置字体的时候,POI提供了一个HSSFFont字体类,同样的要使用HSSFWorkbook对象的createFont方法创建一个字体样式对象。

HSSFFont font = workbook.createFont();
font.setFontName("宋体");
font.setFontHeightInPoints((short) 12);//设置字体大小
font.setBold(true);//是否加粗
setBorder.setFont(font); //设置字体后应用

在这里对于不同的版本设置也是有点不一致的地方,注意区别。

4.3、设置居中显示

在前面我们以及有了合并单元格的操作了,但是对于合并了的单元格怎么设置其文字的居中显示呢?在这里直接使用对应的两个设置位置的方法即可。

setBorder.setAlignment(HorizontalAlignment.CENTER); // 水平居中
setBorder.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中

4.4、设置文字换行显示

再将单元格进行合并之后,文字为了美观在某些地方还需设置换行显示,这又如何实现呢?在这里POI提供了一个自动换行的方法setWrapText,和上面一样代码如下:

setBorderTableData.setWrapText(true);

但是这里excel也只会根据判断显示是否换行,在这里还提供了转义字符,可以进行强制换行。使用如下:/r/n 即表示强制换行,这样A和B就会进行换行了。

row.createCell(0).setCellValue(A+ "\r\n" + B);

整体的关于excel表的样式大致使用到这些就用导出一个还行的表了。

在这里插入图片描述

5、使用EasyPOI进行导出

首先加入easypoi的依赖,这里还是基于springboot微服务进行操作:

        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-web</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-annotation</artifactId>
            <version>3.1.0</version>
        </dependency>

在使用EasyPOI的时候对导出的数据用实体类进行保存,所以我们只需要对实体类进行相关的配置即可:通过@Excel注解来标识导出的Excel表头对应的列名称。在这里插入图片描述
之后就是导出接口编写了,直接通过queryWrapper查所有数据再塞给workbook,到这里也就完成了导出数据。

    @PostMapping("/studentinfo/export")
    @ApiOperation(value = "导出学生信息 response", notes = "/studentinfo/export")
    public void export(HttpServletResponse response, @RequestBody @ApiParam(name = "studentInfo", value = "studentInfo", required = true) StudentInfo studentInfo) {
        try {
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=user.xls");
            ExportParams exportParams = new ExportParams();
            Workbook workbook = ExcelExportUtil.exportExcel(exportParams, StudentInfo.class, studentInfoMapper.selectList(null));
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

再往后就是前端访问这个接口进行文件下载。这里使用vue脚手架搭建了一个前端项目,并且引入了axios。通过axios发送请求获取返回的文件流到前端进行文件下载。


      doExport() {
        this.toInterface("http://localhost:9999/studentinfo/export", this.searchForm)
      },

      toInterface(url, param, isForm) {
        let mergeOptions = {
          url: url,
          method: "post",
          headers: {
            Accept: "*",
            "Content-Type": "application/x-www-form-urlencoded; charset=utf-8;",
          },
          data: param,
          responseType: "blob",
        };
        mergeOptions.paramType = "body";
        mergeOptions.headers["Content-Type"] =
          "application/json; charset=UTF-8";
        axios(mergeOptions)
          .then(function(response) {
            console.log(response)
            var blob = new Blob([response.data], {
              type: "application/vnd.ms-excel"
            });
            var href = window.URL.createObjectURL(blob); //创建下载的链接
            var link = document.createElement("a");
            link.href = href;
            link.setAttribute("download", "学生信息.xls");
            document.body.appendChild(link);
            link.click(); //点击下载

            document.body.removeChild(link); //下载完成移除元素
            window.URL.revokeObjectURL(href); //释放掉blob对象
          })
          .catch(function(error) {
            console.error(error);
          });
      },

6、使用EasyPOI进行导入

还是跟导出一样,使用一个配置对应@Excel注解的实体类进行操作,这里我们只需要在前端页面发送请求(后端接口)并且附带上文件,后端接口获取文件之后进行解析入库即可。首先就是前端上传文件操作。直接上代码:

			<el-upload
			  class="upload-demo"
			  ref="upload"
			  action="http://localhost:9999/student/grade/import"
			  :on-preview="handlePreview"
			  :on-remove="handleRemove"
			  :file-list="fileList"
			  :auto-upload="false">
			  <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
			  <el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">上传到服务器</el-button>
			  <div slot="tip" class="el-upload__tip">只能上传xlxs/xls文件</div>
			</el-upload>

这都没啥好说的,直接在elementUI上的导入组件,自需要替换掉地址即可。接下来就是后端这个接口的编写了,

  @PostMapping("/student/grade/import")
  public String importExcel(@RequestParam("file") MultipartFile file) {
    ImportParams importParams = new ImportParams();
    importParams.setNeedVerfiy(false);
    try {
      ExcelImportResult<StudentGrade> result =
          ExcelImportUtil.importExcelMore(file.getInputStream(), StudentGrade.class, importParams);
      // 当这里就把excel文件的内容根据@Excel注解转换成了对应的实体对象,后续的入库操作这里就省略了
      List<StudentGrade> studnetGradeList = result.getList();
      // 入库操作 。。。。
      log.info("从Excel导入数据一共 {} 行 ", studnetGradeList.size());
    } catch (IOException e) {
      log.error("导入失败:{}", e.getMessage());
    } catch (Exception e1) {
      log.error("导入失败:{}", e1.getMessage());
    }
    return "导入成功";
  }
  • 9
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Modify_QmQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值