最近为客户开发OA系统,excel导入导出是必备的功能,在项目开发中技术造型时,采用了阿里的EasyExcel框架。
EasyExcel概览
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。 github地址:https://github.com/alibaba/easyexcel
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便。
Springboot整合EasyExcel
1.在springboot项目pom.xml加添加 maven依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
- 代码展示
User实现类:
@Data
public class User {
@TableId(value = "id",type= IdType.AUTO)
@ExcelIgnore //导出时忽略
protected Integer id;
@ExcelProperty(value = "用户账号",index = 0)
private String userName;
@ExcelProperty(value = "密码",index = 1)
private String password;
@ExcelProperty(value = "真实姓名")
private String realName;
@ExcelProperty(value = "手机号")
private String phone;
@ExcelProperty(value = "邮箱")
private String email;
@ExcelProperty(value = "备注")
private String remark;
@ExcelProperty(value ="创建时间",converter = LocalDateTimeConverter.class)
protected LocalDateTime createTime;
}
LocalDateTimeConverter:时间转换成字符串
public class LocalDateTimeConverter implements Converter<LocalDateTime> {
@Override
public Class<LocalDateTime> supportJavaTypeKey() {
return LocalDateTime.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public LocalDateTime convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
return LocalDateTime.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
@Override
public CellData convertToExcelData(LocalDateTime value, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
return new CellData(value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
}
//导出导入代码
@RestController
@RequestMapping("/sys/user")
@Slf4j
public class SysUserController {
@Autowired
private IUserService iUserService;
@ApiOperation(value = "addUser", notes = "addUser")
@RequestMapping(value = "/addUser", method = RequestMethod.POST)
public String addUser() {
Instant instant = new Date().toInstant();
ZoneId zoneId = ZoneId.systemDefault();
LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
List<User> users = new ArrayList<>();
for (int i = 1; i <= 100; i++) {
User user = new User();
user.setUserName("打工人" + i);
user.setPassword(IdWorker.getIdStr());
user.setPhone("18898765432");
user.setRealName("打工人" + i);
user.setRemark("remark-" + i);
user.setEmail(IdWorker.getId() + "@163.com");
user.setCreateTime(localDateTime);
users.add(user);
}
iUserService.saveOrUpdateBatch(users);
return "add user ok!";
}
@ApiOperation(value = "importUserExel", notes = "importUserExel")
@RequestMapping(value = "/importUserExel", method = RequestMethod.POST)
public void importUserExel(@RequestParam MultipartFile file) throws Exception {
InputStream inputStream = file.getInputStream();
List<User> users = EasyExcel.read(inputStream)
// 这个转换是成全局的, 所有java为string,excel为string的都会用这个转换器。
// 如果就想单个字段使用请使用@ExcelProperty 指定converter
.registerConverter(new StringConverter())
// 注册监听器,可以在这里校验字段
.registerReadListener(new UserImportListener())
.head(User.class)
// 设置sheet,默认读取第一个
.sheet()
// 设置标题所在行数
.headRowNumber(2)
.doReadSync();
users.forEach(user -> {
log.info(JSON.toJSONString(user));
});
iUserService.saveOrUpdateBatch(users);
}
@GetMapping("/export")
public void export(HttpServletResponse response) throws IOException {
// 生成数据
// List<User> Users = Lists.newArrayList();
List<User> Users = iUserService.list();
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("导出测试用户数据", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), User.class)
.sheet("sheet0")
// 设置字段宽度为自动调整,不太精确
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
.doWrite(Users);
}
}
总结
很简单优雅地完成excel的导入导出,后续再补充其他案例,更多案例可参考
地址:https://www.yuque.com/easyexcel/doc/easyexcel