本章提供了java使用阿里的easyexcel实现Excel导入,导出示例,还有网络下载的方法。
模板大家可以随意制作,本例中使用模板表头及数据已经截图,以供参考。
easyexcel背景:
Java解析,生成Excel比较有名的框架有Apache poi,jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版的Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大.easyexcel重写了POI对07版的Excel的解析,能够原本一个3M的Excel的用POI sax依然需要100M左右内存降低到KB级别,并且再大的Excel中不会出现内存溢出,03版依赖POI的萨克斯模式。在上层做了模型转换的封装,让使用者更加简单方便。
优缺点比较:
easyexcel在解析耗时上比poiuserModel模式弱了一些主要原因是我内部采用了反射做模型字段映射,中间我也加了缓存,但感觉这点差距可以接受的但在内存消耗上差别就比较明显了,easye userxodel就不一大了,简直就要爆掉了。想想一个excel解析200M,同时有20个人再用估计一台机器就挂了。
本例中,工具类整合了easyexcel的导入导出,对导入的数据操作在监听类中实现,在这里可以做一些自己的业务逻辑,这也是使用easyexcel的一个原因,可以更加清晰的去关注业务逻辑。
1.准备:d:\\ .xlsx
内容如下:
2.添加依赖(建议去maven仓库搜索easyexcel下载最新的依赖)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>1.1.2-beat1</version>
</dependency>
3.添加Excel的映射实体
public class ExcelEntity extends BaseRowModel {
@ExcelProperty(index = 0 , value = "工号")
private String staff_code;
@ExcelProperty(index = 1 , value = "姓名")
private String name;
@ExcelProperty(index = 2 , value = "性别")
private String sex;
@ExcelProperty(index = 3 , value = "联系电话")
private String tel;
@ExcelProperty(index = 4 , value = "邮箱")
private String email;
@ExcelProperty(index = 5 , value = "微信号")
private String weixin;
@ExcelProperty(index = 6 , value = "部门")
private Integer department_id;
@ExcelProperty(index = 7 , value = "职位")
private Integer position_id;
public String getStaff_code() {
return staff_code;
}
public void setStaff_code(String staff_code) {
this.staff_code = staff_code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getWeixin() {
return weixin;
}
public void setWeixin(String weixin) {
this.weixin = weixin;
}
public Integer getDepartment_id() {
return department_id;
}
public void setDepartment_id(Integer department_id) {
this.department_id = department_id;
}
public Integer getPosition_id() {
return position_id;
}
public void setPosition_id(Integer position_id) {
this.position_id = position_id;
}
@Override
public String toString() {
return "ExcelEntity{" +
"staff_code="" + staff_code + "\"" +
", name="" + name + "\"" +
", sex="" + sex + "\"" +
", tel="" + tel + "\"" +
", email="" + email + "\"" +
", weixin="" + weixin + "\"" +
", department_id=" + department_id +
", position_id=" + position_id +
"}";
}
}
4.添加导入数据监听类
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.mon.excelUtils.entity.ExcelEntity;
import java.util.ArrayList;
import java.util.List;
/** 解析监听器,
* 每解析一行会回调invoke()方法。
* 整个excel解析结束会执行doAfterAllAnalysed()方法
*
* 下面只是我写的一个样例而已,可以根据自己的逻辑修改该类。
*/
public class ExcelListener extends AnalysisEventListener {
//自定义用于暂时存储data。
//可以通过实例获取该值
private List<Object> datas = new ArrayList<Object>();
public void invoke(Object object, AnalysisContext context) {
System.out.println("当前行:"+context.getCurrentRowNum());
System.out.println(object);
datas.add(object);//数据存储到list,供批量处理,或后续自己业务逻辑处理。
doSomething(object);//根据自己业务做处理
}
private void doSomething(Object object) {
ExcelEntity excel = (ExcelEntity) object;
//1、入库调用接口
}
public void doAfterAllAnalysed(AnalysisContext context) {
// datas.clear();//解析结束销毁不用的资源
}
public List<Object> getDatas() {
return datas;
}
public void setDatas(List<Object> datas) {
this.datas = datas;
}
}
5.编写导入导出工具类
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.mon.excelUtils.entity.ExcelEntity;
import com.mon.excelUtils.listen.ExcelListener;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class ExcelUtils {
/**
* @param is 导入文件输入流
* @param clazz Excel实体映射类
* @return
*/
public static Boolean readExcel(InputStream is, Class clazz){
BufferedInputStream bis = null;
try {
bis = new BufferedInputStream(is);
// 解析每行结果在listener中处理
AnalysisEventListener listener = new ExcelListener();
ExcelReader excelReader = EasyExcelFactory.getReader(bis, listener);
excelReader.read(new Sheet(1, 1, clazz));
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
/**
*
* @param os 文件输出流
* @param clazz Excel实体映射类
* @param data 导出数据
* @return
*/
public static Boolean writeExcel(OutputStream os, Class clazz, List<? extends BaseRowModel> data){
BufferedOutputStream bos= null;
try {
bos = new BufferedOutputStream(os);
ExcelWriter writer = new ExcelWriter(bos, ExcelTypeEnum.XLSX);
//写第一个sheet, sheet1 数据全是List<String> 无模型映射关系
Sheet sheet1 = new Sheet(1, 0,clazz);
writer.write(data, sheet1);
writer.finish();
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
public static void main(String[] args) {
//1.读Excel
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\.xlsx");
Boolean flag = ExcelUtils.readExcel(fis, ExcelEntity.class);
System.out.println("导入是否成功:"+flag);
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
if (fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//2.读Excel
FileOutputStream fos = null;
try {
fos = new FileOutputStream("D:\\export.xlsx");
//FileOutputStream fos, Class clazz, List<? extends BaseRowModel> data
List<ExcelEntity> list = new ArrayList<>();
for (int i = 0; i < 5; i++){
ExcelEntity excelEntity = new ExcelEntity();
excelEntity.setName("我是名字"+i);
list.add(excelEntity);
}
Boolean flag = ExcelUtils.writeExcel(fos,ExcelEntity.class,list);
System.out.println("导出是否成功:"+flag);
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
if (fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
6.大功告成!在ExcelUtils中运行主方法,简单的导入导出就已经完成了!
7.运行结果截图:
7.1导入数据控制台打印:
7.2导出数据添加姓名+循环次数:
另外,阿里easyexcel还提供了复杂格式的表头使用,和表格样式,有需要的小伙伴可以去github上一睹真容。
附:阿里巴巴开源easyexcel github地址:https:///alibaba/easyexcel
8.最后多一嘴,文件导入,导出,下载模板的时候,Controller层的写法也加上来,记录一下。
/**
* @Auther : guojianmin
* @Date : /5/24 17:03
* @Description : TODO用一句话描述此类的作用
*/
@Api(tags = "ExcelDownloadController", description = "Excel 导入下载模板,导出 相关接口")
@RestController
@RequestMapping("/excel")
public class ExcelDownloadController {
private static final Logger log = LoggerFactory.getLogger(ExcelDownloadController.class);
@Resource
StaffService staffService;
/**
* 单个文件上传
* @param file
* @return
*/
@ApiOperation(value="接口说明",httpMethod="POST",notes="单个文件上传")
@RequestMapping(value = "/upload")
public ResponseMsg upload(@RequestParam("file") MultipartFile file) {
ResponseMsg msg = new ResponseMsg();
try {
if (file.isEmpty()) {
msg.setMsg("文件为空");
msg.setResult(false);
return msg;
}
// 获取文件名
String fileName = file.getOriginalFilename();
log.info("上传的文件名为:" + fileName);
// 获取文件的后缀名
String suffixName = fileName.substring(fileName.lastIndexOf("."));
log.info("文件的后缀名为:" + suffixName);
//创建一个临时文件,用于暂时存放
File tmpFile = File.createTempFile("tmp", null);
//将MultipartFile 转换为 File 临时文件
file.transferTo(tmpFile);
//将临时文件转为输入流
InputStream inputStream = new FileInputStream(tmpFile);
ExcelUtils.readExcel(inputStream, ExcelModel.class);
msg.setResult(true);
msg.setMsg("上传成功");
//上传完成 删除临时文件
tmpFile.delete();
return msg;
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
msg.setResult(false);
msg.setMsg("上传失败");
return msg;
}
/**
* 下载模板,用于填写导入数据
* @param request
* @param response
*/
@ApiOperation(value="接口说明",httpMethod="POST",notes="下载模板,用于填写导入数据")
@RequestMapping("/downloadExcel")
public void cooperation(HttpServletRequest request, HttpServletResponse response) {
ServletOutputStream out = null;
try {
out = response.getOutputStream();
response.setContentType("multipart/form-data");
response.setCharacterEncoding("utf-8");
String fileName = "导入模板";
response.setHeader("Content-disposition", "attachment;filename="+ URLEncoder.encode(fileName,"UTF-8")+".xlsx");
ExcelUtils.writeExcel(out,ExcelModel.class,null);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 导出数据文件
* @param request
* @param response
*/
@ApiOperation(value="接口说明",httpMethod="POST",notes="导出数据文件")
@RequestMapping("/downloadExcelData")
public void cooperationData(HttpServletRequest request, HttpServletResponse response) {
ServletOutputStream out = null;
try {
out = response.getOutputStream();
response.setContentType("multipart/form-data");
response.setCharacterEncoding("utf-8");
String fileName = "导出明细";
response.setHeader("Content-disposition", "attachment;filename="+ URLEncoder.encode(fileName,"UTF-8")+".xlsx");
//List<ExcelModel> data = 此处为 数据接口 返回一个list ;
//把数据明细放在list data中
System.out.println("把数据明细放在list data中:请完善查询数据接口调用,并把查询结果写入list data中");
Boolean flag = ExcelUtils.writeExcel(out, ExcelModel.class, data);
System.out.println("导出是否成功:"+flag);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
9.最后,真的是最后,顺便了解一下Java 中File类的createNewFile()与createTempFile(), delete和deleteOnExit区别
感谢博主:/kungfupanda/p/9472137.html