今天玩了一下vue springboot利用easypoi实现excel的导出,以前没玩过导入导出,只不过听说过看别人用过,怎么说呢,想玩就玩一下吧,毕竟结合自己业务场景需要才会考虑是否使用。先简单介绍一下easypoi。
1.不太熟悉poi的
2.不想写太多重复太多的
3.只是简单的导入导出的
4.喜欢使用模板的
若poi都不知道的童鞋请自行百度。。。
Easypoi的目标不是替代poi,而是让一个不懂导入导出的快速使用poi完成Excel和word的各种操作,而不是看很多api才可以完成这样工作。
因为我也是第一次使用,这里还是先将easypoi的官方文档放这儿吧:
点我查看Easypoi官方文档
咋先从前端开始吧,总要一步步来嘛,下面看代码(仔细看注释):
<template>
<div>
<!-- 这里只演示导出,导入也差不多 -->
<!-- <el-button class="el-icon-upload" type="success">导入</el-button> -->
<el-button class="el-icon-download" type="success" @click="exportExcel()">导出</el-button>
</div>
</template>
<script>
export default {
name: "importandexport",
data() {
return {
extp: this.exportExceltype,
};
},
props: ["exportExceltype"],//父组件向子传递过来的值,用于判断是那个组件过来的
methods: {
exportExcel() {
const extpurl = ""; //导出请求地址
//这里就是判断来自哪个父组件,从而发送不同的请求路径
if (this.extp == "user") {
this.extpurl = "/exportUser";
} else if (this.extp == "role") {
this.extpurl = "/exportRole";
}
this.$axios
.get(this.extpurl, {
responseType: "blob" })
.then((res) => {
const blob = new Blob([res.data], {
//取响应回来的数据
type: "application/vnd.ms-excel;charset=utf-8",
});
const href = window.URL.createObjectURL(blob); // 创建下载的链接
const downloadElement = document.createElement("a");
downloadElement.href = href;
downloadElement.download = decodeURI(res.headers["filename"]);
document.body.appendChild(downloadElement);
downloadElement.click(); // 点击下载
document.body.removeChild(downloadElement); // 下载完成移除元素
window.URL.revokeObjectURL(href); // 释放掉blob对象
})
.catch((fail) => {
console.error(fail);
});
},
},
};
</script>
<style scoped>
</style>
上面的是公用的子组件,还缺少父组件,看下面代码:
<template>
<div>
<el-row style="margin: 18px 0px 0px 18px ">
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/admin/dashboard' }"
>管理中心</el-breadcrumb-item
>
<el-breadcrumb-item>用户管理</el-breadcrumb-item>
<el-breadcrumb-item>用户信息</el-breadcrumb-item>
</el-breadcrumb>
</el-row>
<bulk-registration @onSubmit="listUsers()"></bulk-registration>
<el-card style="margin: 18px 2%;width: 95%">
<el-table
v-loading="loading"
:data="users.slice((currentPage-1)*pageSize,currentPage*pageSize)"
stripe
:default-sort="{ prop: 'id', order: 'ascending' }"
style="width: 100%"
:max-height="tableHeight"
>
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column prop="id" label="id" sortable width="100">
</el-table-column>
<el-table-column prop="username" label="用户名" fit> </el-table-column>
<el-table-column prop="name" label="真实姓名" fit> </el-table-column>
<el-table-column prop="phone" label="手机号" fit> </el-table-column>
<el-table-column prop="email" label="邮箱" show-overflow-tooltip fit>
</el-table-column>
<el-table-column label="状态" sortable width="100">
<template slot-scope="scope">
<el-switch
v-model="scope.row.enabled"
active-color="#13ce66"
inactive-color="#ff4949"
@change="value => commitStatusChange(value, scope.row)"
>
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
<el-button @click="editUser(scope.row)" type="text" size="small">
编辑
</el-button>
<el-button @click="delUser(scope.row)" type="text" size="small">
移除
</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
layout="total, prev, pager, next, jumper"
@current-change="handleCurrentChange"
:page-size="pageSize"
:current-page="currentPage"
:total="total">
</el-pagination>
</el-card>
< !--放入组件,如不知道父组件如何向子组件传值的,也可以好好看看
:exportExceltype 指子组件中的 props: ["exportExceltype"]
excelobj 则就是当前父组件中的data里面的属性,并指定了固定值-->
<ImportAndExport :exportExceltype="excelobj"></ImportAndExport>
</div>
</template>
<script>
//导入导出excel
import ImportAndExport from '@/components/common/ImportAndExport'
export default {
name: "UserProfile",
components: {
ImportAndExport },
data() {
return {
excelobj:'user',//指定当前组件导入导出的标识,传入子组件即导入导出组件中判断
};
},
};
</script>
<style scoped></style>
这里我只保留了需要的代码,其他代码无关紧要,详细看注释,很简单的东西我也写得很详细了。。。
至此,前端部分已经完成,现在我讲一下导出思路:由前端通过判断不同页面需要导出的请求路径,然后通过设置请求方式、参数。像后端发起请求,后端通过easypoi的工具方法、注解。生成需要的excel或者word文档,然后给前端响应返回。前端再进行接收处理,并进行下载。
如果是,实现导入的话,思路也一样,只不过后端处理稍微变化了。(实质上也就是将数据库的数据组成list或者map然后交给easypoi处理)。
首先引入easypoi所需依赖:
<!--easypoi导入导出-->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.1.3</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.1.3</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.1.3</version>
</dependency>
或者使用这个:
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.0.0</version>
</dependency>
package top.wangxingjun.separate.dto;
import cn.afterturn.easypoi.excel.annotation.Excel;
import top.wangxingjun.separate.dto.base.OutputConverter;
import top.wangxingjun.separate.entity.AdminRole;
import top.wangxingjun.separate.entity.User;
import lombok.Data;
import lombok.ToString;
import java.util.List;
/**
* @author wxj
* @Date 2020/8/10
*/
@Data
@ToString
public class UserDTO implements OutputConverter<UserDTO, User> {
@Excel(name = "编号")
private int id;
@Excel(name = "账号")
private String username;
@Excel(name = "真实姓名")
private String name;
@Excel(name = "手机号")
private String phone;
@Excel(name = "邮箱")
private String email;
@Excel(name = "状态",replace = {
"启用_true","禁用_false"})
private boolean enabled;
}
这里使用了 @Excel 是关键注解,必不可少,name表示指定生成的excel的对应列明,replace 则表示用来做转换的,如:数据库表的性别字段,数据库字段值使用0或1表示,而前台需要显示男或女,导出的话,格式是 replace = {“前台显示值_数据库字段值”,“前台显示值_数据库字段值”} 用 _ 隔开。如果是导出,把前台显示值与数据库字段值调换下位置就可以了~更多用法请求官方文档查看或者百度使用。
直接看代码:
/**
* 用户信息导出
*/
@GetMapping("api/exportUser")
public void exportUser(HttpServletResponse response) throws Exception {
List<UserDTO> list = userService.list();
ExcelUtil.exportExcel(list, null, "sheet1", UserDTO.class, "用户信息", response);
}
没错,就这么几行代码,当然了,还要有个工具类,是我封装好的,网上也有很多的咯。下面看工具类:
package top.wangxingjun.separate.util;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import lombok.extern.log4j.Log4j2;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* @ProjectName: separate
* @Package: top.wangxingjun.separate.util
* @ClassName: ExcelUtil
* @Author: wxj
* @Description: Excel导入导出工具类
* @Date: 2020/8/25 10:07
* @Version: 1.0
*/
@Log4j2
public class ExcelUtil {
/**
* Map集合导出
*
* @param list 需要导出的数据
* @param fileName 导出的文件名
* @param response HttpServletResponse对象
*/
public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws Exception{
defaultExport(list, fileName, response);
}
/**
* 复杂导出Excel,包括文件名以及表名(不创建表头)
*
* @param list 需要导出的数据
* @param title 表格首行标题(不需要就传null)
* @param sheetName 工作表名称
* @param pojoClass 映射的实体类
* @param fileName 导出的文件名(如果为null,则默认文件名为当前时间戳)
* @param response HttpServletResponse对象
*/
public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName,
HttpServletResponse response) throws Exception{
defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName));
}
/**
* 复杂导出Excel,包括文件名以及表名(创建表头)
*
* @param list 需要导出的数据
* @param title 表格首行标题(不需要就传null)
* @param sheetName 工作表名称
* @param pojoClass 映射的实体类
* @param fileName 导出的文件名
* @param isCreateHeader 是否创建表头
* @param response HttpServletResponse对象
*/
public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName,
boolean isCreateHeader, HttpServletResponse response) throws Exception{
ExportParams exportParams = new ExportParams(title, sheetName);
exportParams.setCreateHeadRows(isCreateHeader);
defaultExport(list, pojoClass, fileName, response, exportParams);
}
/**
* 默认导出方法
*
* @param list 需要导出的数据
* @param pojoClass 对应的实体类
* @param fileName 导出的文件名
* @param response HttpServletResponse对象
* @param exportParams 导出参数实体
*/
private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response,
ExportParams exportParams) throws Exception{
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
downloadExcel(fileName, workbook, response);
}
/**
* 默认导出方法
*
* @param list Map集合
* @param fileName 导出的文件名
* @param response HttpServletResponse对象
*/
private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response)throws Exception {
Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
if (null != workbook) {
downloadExcel(fileName, workbook, response);
}
}
/**
* Excel导出
*
* @param fileName Excel导出
* @param workbook Excel对象
* @param response HttpServletResponse对象
*/
public static void downloadExcel(String fileName, Workbook workbook, HttpServletResponse response) throws Exception{
try {
if (StringUtils.isEmpty(fileName)) {
throw new RuntimeException("导出文件名不能为空");
}
String encodeFileName = URLEncoder.encode(fileName, "UTF-8");
response.setHeader("content-Type", "application/vnd.ms-excel; charset=utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + encodeFileName);
response.setHeader("FileName", encodeFileName);
response.setHeader("Access-Control-Expose-Headers", "FileName");
workbook.write(response.getOutputStream());
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 根据文件路径来导入Excel
*
* @param filePath 文件路径
* @param titleRows 表标题的行数
* @param headerRows 表头行数
* @param pojoClass 映射的实体类
* @return
*/
public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws Exception{
//判断文件是否存在
if (StringUtils.isBlank(filePath)) {
return null;
}
ImportParams params = new ImportParams();
params.setTitleRows(titleRows);
params.setHeadRows(headerRows);
List<T> list = null;
try {
list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
} catch (NoSuchElementException e) {
log.error("模板不能为空", e);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return list;
}
/**
* 根据接收的Excel文件来导入Excel,并封装成实体类
*
* @param file 上传的文件
* @param titleRows 表标题的行数
* @param headerRows 表头行数
* @param pojoClass 映射的实体类
* @return
*/
public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws Exception{
if (file == null) {
return null;
}
ImportParams params = new ImportParams();
params.setTitleRows(titleRows);
params.setHeadRows(headerRows);
List<T> list = null;
try {
list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
} catch (NoSuchElementException e) {
log.error("excel文件不能为空", e);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return list;
}
/**
* 文件转List
*
* @param file
* @param pojoClass
* @param
* @return
*/
public static <T> List<T> fileToList(MultipartFile file, Class<T> pojoClass) throws Exception{
if (file.isEmpty()) {
throw new RuntimeException("文件为空");
}
List<T> list = ExcelUtil.importExcel(file, 1, 1, pojoClass);
if (CollectionUtils.isEmpty(list)) {
throw new RuntimeException("未解析到表格数据");
}
return list;
}
}
excel导出所需要的都准备好了,下面来看一下我的效果:
好了今天的分享就到这里了,结束~~