之前介绍了一次EasyExcel 1.x 版本的导入导出,网上大部分教程也是基于 1.x 版本。
2.x 版本和1.x版本相差挺大的,用起来也简单很多。
本文以对 User 的导出导出为例。
代码地址:https://github.com/saysky/sensboot
官方文档地址:https://alibaba-easyexcel.github.io/
pom.xml 中添加依赖
注意:主要确保不要有其他版本的依赖或者其他版本的 POI,如果有的话升级 POI 版本
1.User实体类
注意:这里我用的是 lombok 生成 getter/setter 和构造器,用的是 mybatis-plus 作为 ORM 框架
2.UserExcel 用于导入导出的对象
不建议直接在 User 实体类上加 excel 相关注解,所以我们创建了一个专门用于 excel 的类,属性类型这里全部用 String,防止类型不一致无法转换报异常
因为模板下载和导出功能,代码几乎一样,为了减少冗余,我们把导出这部分的代码放到一个新建的工具类里
模板下载其实和导出的意思差不多,只不过数据使我们手写的模板数据,而非真实数据
查询所有用户,然后写入 excel,通过输出流给浏览器
主要是读取excel数据,然后进行自定义校验格式,然后入库。
这里导入都是用同步的,就是全部读取后再做写入操作。
如果需要异步那种,导入几条入库几条可以参考官网文档
具体 service 层入库代码和其他常量等其他代码这里就不贴了,需要完整代码请访问上面提供的 git 地址
有时候导入要求支持多个工作表导入
只需要通过 excelReader.excelExecutor().sheetList() 获得 sheet 列表就行,然后分别进行上面的导入操作
2.x 版本和1.x版本相差挺大的,用起来也简单很多。
本文以对 User 的导出导出为例。
代码地址:https://github.com/saysky/sensboot
官方文档地址:https://alibaba-easyexcel.github.io/
一、依赖
pom.xml 中添加依赖
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>easyexcel</artifactId>
- <version>2.1.4</version>
- </dependency>
注意:主要确保不要有其他版本的依赖或者其他版本的 POI,如果有的话升级 POI 版本
二、实体类和DTO
1.User实体类
- package com.liuyanzhao.sens.entity;
- import com.baomidou.mybatisplus.annotations.TableId;
- import com.baomidou.mybatisplus.annotations.TableName;
- import com.baomidou.mybatisplus.enums.IdType;
- import lombok.AllArgsConstructor;
- import lombok.Builder;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import javax.validation.constraints.NotBlank;
- import java.io.Serializable;
- import java.util.Date;
- /**
- * <pre>
- * 用户信息(MyBatisPlus)
- * </pre>
- *
- * @author : saysky
- * @date : 2017/11/14
- */
- @Data
- @TableName("user")
- @Builder
- @NoArgsConstructor
- @AllArgsConstructor
- public class User implements Serializable {
- private static final long serialVersionUID = -5144055068797033748L;
- /**
- * 编号,自增
- */
- @TableId(type = IdType.AUTO)
- private Long id;
- /**
- * 用户名
- */
- @NotBlank(message = "用户名不能为空")
- private String username;
- /**
- * 显示名称
- */
- private String nickname;
- /**
- * 密码
- */
- private String password;
- /**
- * 邮箱
- */
- private String email;
- /**
- * 头像
- */
- private String avatar;
- /**
- * 0 正常
- * 1 禁用
- * 2 已删除
- */
- private Integer status = 0;
- /**
- * 创建时间
- */
- private Date createdTime;
- /**
- * 创建人用户名
- */
- private String createdBy;
- /**
- * 更新时间
- */
- private Date updatedTime;
- /**
- * 更新人用户名
- */
- private String updatedBy;
- public User(String username, String nickname, String password, String email, String avatar, Integer status, Date createdTime, String createdBy, Date updatedTime, String updatedBy) {
- this.username = username;
- this.nickname = nickname;
- this.password = password;
- this.email = email;
- this.avatar = avatar;
- this.status = status;
- this.createdTime = createdTime;
- this.createdBy = createdBy;
- this.updatedTime = updatedTime;
- this.updatedBy = updatedBy;
- }
- }
注意:这里我用的是 lombok 生成 getter/setter 和构造器,用的是 mybatis-plus 作为 ORM 框架
2.UserExcel 用于导入导出的对象
不建议直接在 User 实体类上加 excel 相关注解,所以我们创建了一个专门用于 excel 的类,属性类型这里全部用 String,防止类型不一致无法转换报异常
- package com.liuyanzhao.sens.excel;
- import com.alibaba.excel.annotation.ExcelProperty;
- import com.alibaba.excel.annotation.write.style.ColumnWidth;
- import com.alibaba.excel.annotation.write.style.HeadRowHeight;
- import lombok.AllArgsConstructor;
- import lombok.Builder;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- /**
- * @author 言曌
- * @date 2020-01-02 11:39
- */
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- @Builder
- @HeadRowHeight(value = 40)
- public class UserExcel {
- /**
- * 用户名
- */
- @ExcelProperty(value = "用户名", index = 0)
- @ColumnWidth(value = 15)
- private String username;
- /**
- * 显示名称
- */
- @ExcelProperty(value = "昵称", index = 1)
- @ColumnWidth(value = 15)
- private String nickname;
- /**
- * 密码
- */
- @ExcelProperty(value = "密码", index = 2)
- @ColumnWidth(value = 20)
- private String password;
- /**
- * 邮箱
- */
- @ExcelProperty(value = "邮箱", index = 3)
- @ColumnWidth(value = 20)
- private String email;
- /**
- * 头像
- */
- @ExcelProperty(value = "头像", index = 4)
- @ColumnWidth(value = 20)
- private String avatar;
- /**
- * 0 正常
- * 1 禁用
- */
- @ExcelProperty(value = "状态\r0正常,1 禁用", index = 5)
- @ColumnWidth(value = 20)
- private String status;
- /**
- * 注册时间 yyyy-MM-dd HH:mm:ss格式
- */
- @ExcelProperty(value = "注册时间", index = 6)
- @ColumnWidth(value = 20)
- private String createdTime;
- }
三、导出工具类
因为模板下载和导出功能,代码几乎一样,为了减少冗余,我们把导出这部分的代码放到一个新建的工具类里
- package com.liuyanzhao.sens.utils;
- import com.alibaba.excel.EasyExcel;
- import com.alibaba.excel.support.ExcelTypeEnum;
- import com.alibaba.excel.write.metadata.style.WriteCellStyle;
- import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
- import org.apache.poi.ss.usermodel.HorizontalAlignment;
- import javax.servlet.http.HttpServletResponse;
- import java.io.OutputStream;
- import java.net.URLEncoder;
- import java.util.List;
- /**
- * @author 言曌
- * @date 2020-01-02 11:21
- */
- public class ExcelUtil {
- /**
- * 导出
- * @param response
- * @param data
- * @param fileName
- * @param sheetName
- * @param clazz
- * @throws Exception
- */
- public static void writeExcel(HttpServletResponse response, List<? extends Object> data, String fileName, String sheetName, Class clazz) throws Exception {
- //表头样式
- WriteCellStyle headWriteCellStyle = new WriteCellStyle();
- //设置表头居中对齐
- headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
- //内容样式
- WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
- //设置内容靠左对齐
- contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
- HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
- EasyExcel.write(getOutputStream(fileName, response), clazz).excelType(ExcelTypeEnum.XLSX).sheet(sheetName).registerWriteHandler(horizontalCellStyleStrategy).doWrite(data);
- }
- private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
- fileName = URLEncoder.encode(fileName, "UTF-8");
- response.setContentType("application/vnd.ms-excel");
- response.setCharacterEncoding("utf8");
- response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
- return response.getOutputStream();
- }
- }
四、模板下载
模板下载其实和导出的意思差不多,只不过数据使我们手写的模板数据,而非真实数据
- /**
- * 下载Excel模板
- */
- @GetMapping("/excel/template")
- public void downloadTemplate(HttpServletResponse response) {
- String fileName = "导入用户模板";
- String sheetName = "导入用户模板";
- List<UserExcel> userList = new ArrayList<>();
- userList.add(new UserExcel("saysky", "言曌", "123456", "847064370@qq.com", "http://xxx.com/xx.jpg", "0", "2017-12-31 12:13:14"));
- userList.add(new UserExcel("qiqi", "琪琪", "123456", "666666@qq.com", "http://xxx.com/xx.jpg", "0", "2018-5-20 13:14:00"));
- try {
- ExcelUtil.writeExcel(response, userList, fileName, sheetName, UserExcel.class);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
五、导出数据
查询所有用户,然后写入 excel,通过输出流给浏览器
- /**
- * 导出
- */
- @GetMapping("/excel/export")
- public void exportData(HttpServletResponse response) {
- String fileName = "用户列表";
- String sheetName = "用户列表";
- DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- List<User> userList = userService.findAll();
- List<UserExcel> userExcelList = new ArrayList<>();
- for (User user : userList) {
- UserExcel userExcel = UserExcel.builder()
- .username(user.getUsername())
- .password(user.getPassword())
- .nickname(user.getNickname())
- .email(user.getEmail())
- .avatar(user.getAvatar())
- .status(String.valueOf(user.getStatus()))
- .createdTime(dateFormat.format(user.getCreatedTime())).build();
- userExcelList.add(userExcel);
- }
- try {
- ExcelUtil.writeExcel(response, userExcelList, fileName, sheetName, UserExcel.class);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
六、导入数据
主要是读取excel数据,然后进行自定义校验格式,然后入库。
这里导入都是用同步的,就是全部读取后再做写入操作。
如果需要异步那种,导入几条入库几条可以参考官网文档
- /**
- * 导入:同步读,单sheet
- * 注意:这里为了介绍 excel导入导出,代码都写在 controller,实际项目开发中,校验和处理代码建议放到 service
- */
- @PostMapping("/excel/import")
- public void importData(MultipartFile file) throws ParseException {
- List<UserExcel> userExcelList = null;
- // 1.excel同步读取数据
- try {
- userExcelList = EasyExcel.read(new BufferedInputStream(file.getInputStream())).head(UserExcel.class).sheet().doReadSync();
- } catch (Exception e) {
- e.printStackTrace();
- }
- // 2.检查是否大于1000条
- if (userExcelList.size() > MAX_USER_IMPORT) {
- throw new GlobalException(CodeMsg.OVER_MAX_USER_IMPORT_LIMIT.fillArgs(MAX_USER_IMPORT));
- }
- // 3.导入校验所有行列格式
- checkImportData(userExcelList);
- // 4.将 userExcelList 转成 userList
- List<User> userList = userExcelList2UserList(userExcelList);
- // 5.入库操作
- userService.batchInsertOrUpdate(userList);
- }
- private void checkImportData(List<UserExcel> userExcelList) {
- // 行号从第2行开始
- int rowNo = 2;
- // 遍历校验所有行和列
- for (UserExcel userExcel : userExcelList) {
- // 1.校验用户名
- String username = userExcel.getUsername();
- if (StringUtils.isEmpty(username)) {
- throw new GlobalException(CodeMsg.IMPORT_FIELD_IS_EAMPTY.fillArgs(rowNo, "用户名"));
- }
- if (username.length() > 20 || username.length() < 4) {
- throw new GlobalException(CodeMsg.IMPORT_FIELD_FORMAT_ERROR.fillArgs(rowNo, "用户名"));
- }
- // 2.校验密码
- String password = userExcel.getPassword();
- if (StringUtils.isEmpty(password)) {
- throw new GlobalException(CodeMsg.IMPORT_FIELD_IS_EAMPTY.fillArgs(rowNo, "密码"));
- }
- if (password.length() > 100 || password.length() < 6) {
- throw new GlobalException(CodeMsg.IMPORT_FIELD_FORMAT_ERROR.fillArgs(rowNo, "密码"));
- }
- // 3.校验昵称
- String nickname = userExcel.getNickname();
- if (StringUtils.isEmpty(nickname)) {
- throw new GlobalException(CodeMsg.IMPORT_FIELD_IS_EAMPTY.fillArgs(rowNo, "昵称"));
- }
- if (nickname.length() > 20 || nickname.length() < 2) {
- throw new GlobalException(CodeMsg.IMPORT_FIELD_FORMAT_ERROR.fillArgs(rowNo, "昵称"));
- }
- // 4.校验Email
- String email = userExcel.getEmail();
- if (StringUtils.isEmpty(email)) {
- throw new GlobalException(CodeMsg.IMPORT_FIELD_IS_EAMPTY.fillArgs(rowNo, "邮箱"));
- }
- if (!EMAIL_PATTERN.matcher(email).matches()) {
- throw new GlobalException(CodeMsg.IMPORT_FIELD_FORMAT_ERROR.fillArgs(rowNo, "邮箱"));
- }
- // 5.校验状态
- String status = userExcel.getStatus();
- if (StringUtils.isEmpty(status)) {
- throw new GlobalException(CodeMsg.IMPORT_FIELD_IS_EAMPTY.fillArgs(rowNo, "状态"));
- }
- if (!"0".equals(status) && !"1".equals(status)) {
- throw new GlobalException(CodeMsg.IMPORT_FIELD_FORMAT_ERROR.fillArgs(rowNo, "状态"));
- }
- // 6.校验注册时间
- String createdTime = userExcel.getCreatedTime();
- if (StringUtils.isEmpty(createdTime)) {
- throw new GlobalException(CodeMsg.IMPORT_FIELD_IS_EAMPTY.fillArgs(rowNo, "注册时间"));
- }
- try {
- DATE_TIME_FORMAT.parse(createdTime);
- } catch (ParseException e) {
- throw new GlobalException(CodeMsg.IMPORT_FIELD_FORMAT_ERROR.fillArgs(rowNo, "注册时间"));
- }
- }
- }
- /**
- * userExcelList转成userList
- *
- * @param userExcelList
- * @return
- */
- private List<User> userExcelList2UserList(List<UserExcel> userExcelList) throws ParseException {
- Date now = new Date();
- List<User> userList = new ArrayList<>();
- for (UserExcel userExcel : userExcelList) {
- User user = User.builder()
- .username(userExcel.getUsername())
- .password(userExcel.getPassword())
- .nickname(userExcel.getNickname())
- .email(userExcel.getEmail())
- .avatar(userExcel.getAvatar())
- .status(Integer.valueOf(userExcel.getStatus()))
- .createdTime(DATE_TIME_FORMAT.parse(userExcel.getCreatedTime())).build();
- user.setCreatedBy("import");
- user.setUpdatedBy("import");
- user.setUpdatedTime(now);
- userList.add(user);
- }
- return userList;
- }
具体 service 层入库代码和其他常量等其他代码这里就不贴了,需要完整代码请访问上面提供的 git 地址
七、多 sheet 导入
有时候导入要求支持多个工作表导入
只需要通过 excelReader.excelExecutor().sheetList() 获得 sheet 列表就行,然后分别进行上面的导入操作
- @PostMapping("/excel/import")
- public void importDataByMoreSheet(MultipartFile file) throws ParseException, IOException {
- List<UserExcel> userExcelList = new ArrayList<>();
- // 1.excel同步读取数据
- try {
- ExcelReader excelReader = EasyExcel.read(new BufferedInputStream(file.getInputStream())).head(UserExcel.class).build();
- List<ReadSheet> sheetList = excelReader.excelExecutor().sheetList();
- List<UserExcel> childUserExcelList = new ArrayList<>();
- for (ReadSheet sheet : sheetList) {
- childUserExcelList = EasyExcel.read(new BufferedInputStream(file.getInputStream())).head(UserExcel.class).sheet(sheet.getSheetNo()).doReadSync();
- }
- userExcelList.addAll(childUserExcelList);
- } catch (Exception e) {
- e.printStackTrace();
- }
- // 2.检查是否大于1000条
- if (userExcelList.size() > MAX_USER_IMPORT) {
- throw new GlobalException(CodeMsg.OVER_MAX_USER_IMPORT_LIMIT.fillArgs(MAX_USER_IMPORT));
- }
- // 3.导入校验所有行列格式
- checkImportData(userExcelList);
- // 4.将 userExcelList 转成 userList
- List<User> userList = userExcelList2UserList(userExcelList);
- // 5.入库操作
- userService.batchInsertOrUpdate(userList);
- }
您可以选择一种方式赞助本站
支付宝扫一扫赞助
微信钱包扫描赞助
赏