最近在总结项目项目中用到的知识点,EasyExcel 是一个技术点:EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
我之前用过apache的poi技术来读取本地的excel文件,但是他有一个显著的缺点就是 在处理的数据非常多的时候,非常消耗内存,并且很容易出现异常的情况,所以在选择技术工具的时候选择了阿里的easyExcel。
因为我负责的项目采用的是spring boot框架,所以我这里主要讲解一下如何在spring boot项目里面集成EasyExcel
EasyExcel 官方文档说明 EasyExcel 文档使用说明,大家在使用的过程中可以参考者官方文档
一、 pom.xml 导入相关依赖
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.6</version>
</dependency>
二、读取excel
- 编写相关的工具类
我在项目里面用到的是读取单个sheet ,但是有好多情况是需要调用多个sheet的,所以下面我也把读取多个sheet的方法写在了这里
/**
* 读取 Excel(多个 sheet)
*
* @param excel 文件
* @param rowModel 实体类映射,继承 BaseRowModel 类
* @return Excel 数据 list
*/
public static List<Object> readExcel(MultipartFile excel, BaseRowModel rowModel) throws Exception {
ExcelListener excelListener = new ExcelListener();
ExcelReader reader = getReader(excel, excelListener);
if (reader == null) {
return null;
}
for (Sheet sheet : reader.getSheets()) {
if (rowModel != null) {
sheet.setClazz(rowModel.getClass());
}
reader.read(sheet);
}
return excelListener.getDatas();
}
/**
* 读取某个 sheet 的 Excel
*
* @param excel 文件
* @param rowModel 实体类映射,继承 BaseRowModel 类
* @param sheetNo sheet 的序号 从1开始
* @return Excel 数据 list
*/
public static List<Object> readExcel(MultipartFile excel, BaseRowModel rowModel, int sheetNo) throws Exception {
return readExcel(excel, rowModel, sheetNo, 1);
}
/**
* 读取某个 sheet 的 Excel
*
* @param excel 文件
* @param rowModel 实体类映射,继承 BaseRowModel 类
* @param sheetNo sheet 的序号 从1开始
* @param headLineNum 表头行数,默认为1
* @return Excel 数据 list
*/
public static List<Object> readExcel(MultipartFile excel, BaseRowModel rowModel, int sheetNo, int headLineNum) throws Exception {
ExcelListener excelListener = new ExcelListener();
ExcelReader reader = getReader(excel, excelListener);
if (reader == null) {
return null;
}
reader.read(new Sheet(sheetNo, headLineNum, rowModel.getClass()));
return excelListener.getDatas();
}
/**
* 返回 ExcelReader
*
* @param excel 需要解析的 Excel 文件
* @param excelListener new ExcelListener()
*/
private static ExcelReader getReader(MultipartFile excel, ExcelListener excelListener) throws Exception {
String filename = excel.getOriginalFilename();
if (filename == null || (!filename.toLowerCase().endsWith(".xls") && !filename.toLowerCase().endsWith(".xlsx"))) {
throw new Exception("文件格式错误!");
}
InputStream inputStream;
try {
inputStream = new BufferedInputStream(excel.getInputStream());
return new ExcelReader(inputStream, null, excelListener, false);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
- 对应的相关实体类,需要加==@ExcelProperty==注解,在于你读取的excel的位置
@Data
public class CompanyPersonImportVo extends BaseRowModel {
/**
* 用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段
* 读取到数据,所以建议使用索引来匹配(index 从0开始
* 因为我需要导入的excel表格第一列是序号列,
* 不需要,所以我设置的索引是从1开始,这个需要根据自己的实际情况)
*/
@ColumnWidth(13) // 设置 Cell 宽度 (这个看自己的情况,按需引用)
@ExcelProperty(value = "姓名", index = 1)
private String name;
@ExcelProperty(value = "性别", index = 2)
private String sex;
@ExcelProperty(value = "出生日期", index = 3)
private String birthday;
@ExcelProperty(value = "工作单位", index = 4)
private String company;
@ExcelProperty(value = "现任职级", index = 5)
private String leval;
@ExcelProperty(value = "任职时间", index = 6)
private String workDay;
@ExcelProperty(value = "备注", index = 7)
private String remark;
}
3. Controller调用样例说明
@PostMapping("assistUploadExcel")
@ResponseBody
public AjaxResult assistUploadExcel(MultipartFile fileupload) {
Object objList = null;
try {
objList = ExcelUtil.readExcel(fileupload, new CompanyPersonImportVo(), 1, 3);
} catch (Exception e) {
return AjaxResult.error("导入失败!");
}
if (objList == null) {
return AjaxResult.error("导入的数据不能为空");
}
List<CompanyPersonImportVo> orderList = (List) objList;
if (orderList.size() > 0) {
// orderList 其实就是我们将excel表格里面的一行行信息封装成一个个实体,存到List里面
//接下来就是调用自己的Service 方法,对这些数据进行处理了
return AjaxResult.success(map.get("msg"));
}else {
return AjaxResult.error("导入的数据不能为空");
}
}
这样我们读取表格的功能就写完了,接下我们来看读取excel表格
三、写excel
我在项目里面用到的是将一个列表信息 写到一个excel里面,并下载到本地(支持写 多个sheet),因为我用到的就是导出多个sheet,哈哈
导出一个sheet 相对的比较简单,原理是相同的。
- 编写导出工具类
/**
* @ClassName ExcelUtil
* @Description : 用于生成指定目录的Excel不用ReisterConverter
*
* @param path
* @param T
* @param sheetName
* @param res
* @Return : boolean
* @Author : zte
* @Date : 2020/6/24 8:48
*/
public static boolean generatorExcelWithoutConverter(String path, Class T, String sheetName, List<? extends Object> res){
try{
EasyExcel.write(path, T).sheet(sheetName).doWrite(res);
}
catch (Exception e){
log.error(e.getMessage());
return false;
}
return true;
}
/**
* @ClassName ExcelUtil
* @Description : 用于生成指定目录的Excel使用指定的ReisterConverter
*
* @param path
* @param T
* @param sheetName
* @param res
* @param converter
* @Return : boolean
* @Author : zte
* @Date : 2020/6/24 8:51
*/
public static boolean generatorExcelWithConverter(String path, Class T, String sheetName, List<? extends Object> res, Converter converter){
try{
EasyExcel.write(path, T).registerConverter(converter).sheet(sheetName).doWrite(res);
}
catch (Exception e){
log.error(e.getMessage());
return false;
}
return true;
}
//生成多个sheet
public static boolean generatorExcelWithoutConverter(String filename, Class<Info> infoClass, String infoName, List<Info> infos, Class<DetailedInfoLog> detailedInfoLogClass, String allName, List<DetailedInfoLog> detailedInfoLogs, HttpServletResponse response) {
try{
ExcelWriter excelWriter = EasyExcel.write(filename).build();
//获取sheet0对象
WriteSheet mainSheet = EasyExcel.writerSheet(0, "sheet1Name").head(infoClass).build();
//向sheet0写入数据 传入空list这样只导出表头
excelWriter.write(infos,mainSheet);
//获取sheet1对象
WriteSheet detailSheet = EasyExcel.writerSheet(1, "sheet2Name").head(detailedInfoLogClass).build();
//向sheet1写入数据 传入空list这样只导出表头
excelWriter.write(detailedInfoLogs,detailSheet);
excelWriter.finish();
}
catch (Exception e){
log.error(e.getMessage());
return false;
}
return true;
}
- 编写对应的Controller Demo
@RequestMapping(value = "/saveExcel/{uiId}", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
@ResponseBody
public AjaxResult saveExcel(Model model,@PathVariable("uiId") Long uiId, HttpServletResponse response) throws IOException {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");
List<DetailedInfoLog> detailedInfoLog = detailedInfoLogService.list(....); //定义自己的查询条件
List<DetailedInfoLog> detailedInfoLogs = detailedInfoLogService.list(....);
String name = "asd";
// 定义自己导出文件的名字
String filename = URLEncoder.encode(name + '-' + dateTimeFormatter.format(LocalDateTime.now()), "UTF-8");
try{
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + filename + ".xlsx");
List<Info> infos = new ArrayList<>();
infos.add(info);
//新建ExcelWriter
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
//获取sheet0对象
WriteSheet mainSheet = EasyExcel.writerSheet(0, "健康档案").head(Info.class).build();
//向sheet0写入数据 传入空list这样只导出表头
excelWriter.write(infos,mainSheet);
//获取sheet1对象
WriteSheet detailSheet = EasyExcel.writerSheet(1, "所有病史").head(DetailedInfoLog.class).build();
//向sheet1写入数据 传入空list这样只导出表头
excelWriter.write(detailedInfoLogs,detailSheet);
//关闭流
excelWriter.finish();
} catch (Exception var10) {
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
Map<String, String> map = new HashMap();
map.put("status", "failure");
map.put("message", "下载文件失败" + var10.getMessage());
response.getWriter().println(JSON.toJSONString(map));
}
return AjaxResult.success();
}
到这里我们的操作就写完了。