EasyExcel导入、导出数据

EasyExcel

官方解析

Java解析、生成Excel比较有名的框架有Apache poijxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。
easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便

网站

  • 官方网站:https://easyexcel.opensource.alibaba.com/
  • github地址:https://github.com/alibaba/easyexcel
  • gitee地址:https://gitee.com/easyexcel/easyexcel

写Excel

最简单写

示例

模板对象

@Data
@EqualsAndHashCode
public class DemoData {
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private String dateTime;
    @ExcelProperty("数字标题")
    private Double doubleData;
    /**
     * 忽略这个字段
     */
    @ExcelIgnore
    private String ignore;
}

插入值

private List<DemoData> data() {
        List<DemoData> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
            DemoData data = new DemoData();
            data.setString("字符串" + i);
            data.setDateTime(new DateTime().toString("yyyy-MM-dd HH:mm:ss"));
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }

开始写

/**
     * 最简单的写
     * <p>
     * 1. 创建excel对应的实体对象 参照{@link DemoData}
     * <p>
     * 2. 直接写即可
     */
    @Test
    public void simpleWrite() {
        // 注意 simpleWrite在数据量不大的情况下可以使用(5000以内,具体也要看实际情况),数据量大参照 重复多次写入
        // 写法1 JDK8+
        // since: 3.0.0-beta1
        String path = "D:\\excel\\";
        String fileName = path + "simpleWrite.xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入excelType参数即可
        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
        System.out.println("excel导出成功");
    }

根据参数只导出指定列

示例:排除导出日期时间列

模板对象和插入值和以上一致

开始写

@Test
    public void excludeOrIncludeWrite() {
        String path = "D:\\excel\\";
        String fileName = path + "excludeOrIncludeWrite" + ".xlsx";
        // 这里需要注意 在使用ExcelProperty注解的使用,如果想不空列则需要加入order字段,
        // 而不是index,order会忽略空列,然后继续往后,而index,不会忽略空列,在第几列就是第几列。
        // 根据用户传入字段 假设我们要忽略 date
        Set<String> excludeColumnFiledNames = new HashSet<String>();
        //将不想导出的列放到一个集合中
        excludeColumnFiledNames.add("dateTime");
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        EasyExcel.write(fileName, DemoData.class).excludeColumnFieldNames(excludeColumnFiledNames).sheet("模板")
                .doWrite(data());
        System.out.println("excel导出成功");
    }

指定写入的列

①、使用index格式

示例:使用index会出现空列情况

模板对象

//index,不会忽略空列,在第几列就是第几列。
@Data
@EqualsAndHashCode
public class IndexData {
    @ExcelProperty(value = "字符串标题", index = 0)
    private String string;
    @ExcelProperty(value = "日期标题", index = 1)
    private String dateTime;
    /**
     * 这里设置3 会导致第二列空的
     */
    @ExcelProperty(value = "数字标题", index = 3)
    private Double doubleData;
}

插入值

private List<IndexData> data() {
        List<IndexData> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
            IndexData data = new IndexData();
            data.setString("字符串" + i);
            data.setDateTime(new DateTime().toString("yyyy-MM-dd HH:mm:ss"));
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }

开始写

/**
     * 指定写入的列
     * <p>1. 创建excel对应的实体对象 参照{@link IndexData}
     * <p>2.
     * <p>3. 直接写即可
     */
    @Test
    public void indexWrite() {
        String path = "D:\\excel\\";
        String fileName = path + "indexWrite" + ".xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        EasyExcel.write(fileName, IndexData.class).sheet("模板").doWrite(data());
    }

②、使用order格式

示例:使用order格式不会出现空列情况

模板对象

//order,不会出现空列情况
@Data
@EqualsAndHashCode
public class OrderData {
    @ExcelProperty(value = "字符串标题", order = 0)
    private String string;
    @ExcelProperty(value = "日期标题", order = 1)
    private String dateTime;
    /**
     * 这里设置3 不会出现空列情况
     */
    @ExcelProperty(value = "数字标题", order = 3)
    private Double doubleData;
}

插入值

private List<OrderData> data() {
        List<OrderData> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
            OrderData data = new OrderData();
            data.setString("字符串" + i);
            data.setDateTime(new DateTime().toString("yyyy-MM-dd HH:mm:ss"));
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }

开始写

/**
     * 指定写入的列
     * <p>1. 创建excel对应的实体对象 参照{@link OrderData}
     * <p>2.
     * <p>3. 直接写即可
     */
    @Test
    public void OrderWrite() {
        String path = "D:\\excel\\";
        String fileName = path + "OrderWrite" + ".xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        EasyExcel.write(fileName, OrderData.class).sheet("模板").doWrite(data());
    }

复杂头写入

类似类似插入单元格

示例

模板对象

@Getter
@Setter
@EqualsAndHashCode
public class ComplexHeadData {
    @ExcelProperty({"主标题", "字符串标题"})
    private String string;
    @ExcelProperty({"主标题", "日期标题"})
    private Date date;
    @ExcelProperty({"主标题", "数字标题"})
    private Double doubleData;
}

插入值

private List<ComplexHeadData> data() {
        List<ComplexHeadData> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
            ComplexHeadData data = new ComplexHeadData();
            data.setString("字符串" + i);
            data.setDateTime(new DateTime().toString("yyyy-MM-dd HH:mm:ss"));
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }

开始写

/**
     * 复杂头写入
     * <p>1. 创建excel对应的实体对象 参照{@link ComplexHeadData}
     * <p>2.
     * <p>3. 直接写即可
     */
    @Test
    public void complexHeadWrite() {
        String path = "D:\\excel\\";
        String fileName = path + "complexHeadWrite" + ".xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        EasyExcel.write(fileName, ComplexHeadData.class).sheet("模板").doWrite(data());
    }

重复多次写入(写到单个或者多个Sheet)

①、写到同一个sheet

示例:同一个数据重复写了五次

模板对象

@Data
@EqualsAndHashCode
public class DemoData {
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private String dateTime;
    @ExcelProperty("数字标题")
    private Double doubleData;
    /**
     * 忽略这个字段
     */
    @ExcelIgnore
    private String ignore;
}

插入值

private List<DemoData> data() {
        List<DemoData> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
            DemoData data = new DemoData();
            data.setString("字符串" + i);
            data.setDateTime(new DateTime().toString("yyyy-MM-dd HH:mm:ss"));
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }

写到同一个sheet

/**
     * 重复多次写入
     * <p>
     * 1. 创建excel对应的实体对象
     * 3. 直接调用二次写入即可
     */
    @Test
    public void repeatedWrite() {
        // 方法1: 如果写到同一个sheet
        String path = "D:\\excel\\";
        String fileName = path + "repeatedWrite" + ".xlsx";
        // 这里 需要指定写用哪个class去写
        try (ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build()) {
            // 这里注意 如果同一个sheet只要创建一次
            WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
            // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来
            for (int i = 0; i < 5; i++) {
                // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
                List<DemoData> data = data();
                excelWriter.write(data, writeSheet);
            }
        }
    }

②、写到不同的sheet 同一个对象

示例

开始写入

// 方法2: 如果写到不同的sheet 同一个对象
        // 这里 指定文件
        try (ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build()) {
            // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面
            for (int i = 0; i < 5; i++) {
                // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样
                WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).build();
                // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
                List<DemoData> data = data();
                excelWriter.write(data, writeSheet);
            }
        }

③、写到不同的sheet 不同的对象

示例

开始写入

// 方法3 如果写到不同的sheet 不同的对象
        // 这里 指定文件
        try (ExcelWriter excelWriter = EasyExcel.write(fileName).build()) {
            // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面
            for (int i = 0; i < 5; i++) {
                // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样。这里注意DemoData.class 可以每次都变,我这里为了方便 所以用的同一个class
                // 实际上可以一直变
                WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).head(DemoData.class).build();
                // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
                List<DemoData> data = data();
                excelWriter.write(data, writeSheet);
            }
        }

日期、数字或者自定义格式转换

示例

模板对象

@Data
@EqualsAndHashCode
@Component
public class DemoData{
    @ExcelProperty(value = "字符串标题",index = 0)
    private String title;
    
    @ExcelProperty(value = "日期标题",index = 1)
    private String dateTime;

    @NumberFormat("#.##%")
    @ExcelProperty(value = "数字标题",index = 2)
    private Double doubleData;
    /**
     * 忽略这个字段
     */
    @ExcelIgnore
    private String ignore;
}

插入值

private List<DemoData> data() {
        List<DemoData> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
            DemoData data = new DemoData();
            data.setTitle("字符串" + i);
            data.setDateTime(new DateTime().toString("yyyy年MM月dd日HH时mm分ss秒"));
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }

开始导入

/**
     * 日期、数字或者自定义格式转换
     * <p>3. 直接写即可
     */
    @Test
    public void converterWrite() {
        String path = "D:\\excel\\";
        String fileName = path + "converterWrite" + ".xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
    }

web中的写(实战篇)

实现用户数据导出

前端代码

<el-col :span="1.5">
        <el-button v-if="canAdd" type="primary" size="small" @click="handleExportExcel">导出<i class="el-icon-upload2"></i>
        </el-button>
      </el-col> 

methods:{
	handleExportExcel(){
      window.open("http://localhost:8800/shiyi/system/user/export")
    }
}

后端代码

导出模板数据

@Data
@Builder
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
public class UserDto implements Serializable {
    @ApiModelProperty(value = "用户账号")
    @ExcelProperty(value = {"用户信息数据","用户账号"},order = 0)
    private String username;

    @ApiModelProperty(value = "登录密码")
    @ExcelProperty(value = {"用户信息数据","登录密码"},order = 1)
    private String password;

    @ApiModelProperty(value = "状态")
    @ExcelProperty(value = {"用户信息数据","状态"},order = 2)
    private Integer status;

    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    @ExcelProperty(value = {"用户信息数据","创建时间"},order = 3)
    private String createTime;

    @ApiModelProperty(value = "最后更新时间")
    @ExcelProperty(value = {"用户信息数据","最后更新时间"},order = 4)
    @TableField(fill = FieldFill.UPDATE)
    private String updateTime;

    @ApiModelProperty(value = "最后登录时间")
    @ExcelProperty(value = {"用户信息数据","最后登录时间"},order = 5)
    @TableField(fill = FieldFill.UPDATE)
    private String lastLoginTime;

    @ApiModelProperty(value = "IP地址")
    @ExcelProperty(value = {"用户信息数据","IP地址"},order = 6)
    private String ipAddress;

    @ApiModelProperty(value = "IP来源")
    @ExcelProperty(value = {"用户信息数据","IP来源"},order = 7)
    private String ipSource;

    @ApiModelProperty(value = "登录系统")
    @ExcelProperty(value = {"用户信息数据","登录系统"},order = 8)
    private String os;

    @ApiModelProperty(value = "浏览器")
    @ExcelProperty(value = {"用户信息数据","浏览器"},order = 9)
    private String browser;
}

数据的值从数据库中查询得到

开始导出

public void export(HttpServletResponse response) throws IOException {
        //文件需要设置成StandardCharsets.ISO_8859_1编码,否则导出的excel文件名乱码
        String excelName = new String("用户信息数据.xlsx".getBytes(), StandardCharsets.ISO_8859_1);
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf8");
        response.setHeader("Content-disposition", "attachment;filename=" + excelName );
    	//从数据库查询所有用户数据
        List<User> userList = baseMapper.selectList(null);

        List<UserDto> userDtoList = new ArrayList<>();
        //数据格式化
        userList.stream().forEach(user -> {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date cTime = user.getCreateTime();
            Date uTime = user.getUpdateTime();
            Date lTime = user.getLastLoginTime();
            //日期格式化
            String createTime = simpleDateFormat.format(cTime);
            String updateTime = simpleDateFormat.format(uTime);
            String lastLoginTime = simpleDateFormat.format(lTime);

            UserDto userDto = new UserDto();
            userDto.setBrowser(user.getBrowser());
            userDto.setUsername(user.getUsername());
            userDto.setPassword(user.getPassword());
            userDto.setIpAddress(user.getIpAddress());
            userDto.setIpSource(user.getIpSource());
            userDto.setOs(user.getOs());
            userDto.setStatus(user.getStatus());
            userDto.setCreateTime(createTime);
            userDto.setUpdateTime(updateTime);
            userDto.setLastLoginTime(lastLoginTime);
            userDtoList.add(userDto);
        });
        ServletOutputStream outputStream = response.getOutputStream();
        EasyExcel.write(outputStream, UserDto.class)
                .sheet("user")
                .doWrite(userDtoList);
    	
    }

controller层

@GetMapping("/export")
@ApiOperation(value = "导出用户数据", httpMethod = "GET", response = ResponseResult.class, notes = "导出用户数据")
    public void excel(HttpServletResponse response) throws IOException {
        userService.export(response);
    }

浏览器直接访问:http://localhost:端口号/export

读Excel

实现用户数据导入

web中的读(实战篇)

模板对象

@Data
@Builder
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
public class UserDto implements Serializable {
    @ApiModelProperty(value = "用户账号")
    @ExcelProperty(value = {"用户信息数据","用户账号"},order = 0)
    private String username;

    @ApiModelProperty(value = "登录密码")
    @ExcelProperty(value = {"用户信息数据","登录密码"},order = 1)
    private String password;

    @ApiModelProperty(value = "状态")
    @ExcelProperty(value = {"用户信息数据","状态"},order = 2)
    private Integer status;

    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    @ExcelProperty(value = {"用户信息数据","创建时间"},order = 3)
    private String createTime;

    @ApiModelProperty(value = "最后更新时间")
    @ExcelProperty(value = {"用户信息数据","最后更新时间"},order = 4)
    @TableField(fill = FieldFill.UPDATE)
    private String updateTime;

    @ApiModelProperty(value = "最后登录时间")
    @ExcelProperty(value = {"用户信息数据","最后登录时间"},order = 5)
    @TableField(fill = FieldFill.UPDATE)
    private String lastLoginTime;

    @ApiModelProperty(value = "IP地址")
    @ExcelProperty(value = {"用户信息数据","IP地址"},order = 6)
    private String ipAddress;

    @ApiModelProperty(value = "IP来源")
    @ExcelProperty(value = {"用户信息数据","IP来源"},order = 7)
    private String ipSource;

    @ApiModelProperty(value = "登录系统")
    @ExcelProperty(value = {"用户信息数据","登录系统"},order = 8)
    private String os;

    @ApiModelProperty(value = "浏览器")
    @ExcelProperty(value = {"用户信息数据","浏览器"},order = 9)
    private String browser;
}

开始导入

//用户数据导入
    @Override
    public void excelImport(MultipartFile file) throws IOException {
        List<UserDto> list = new ArrayList<>();
        EasyExcel.read(file.getInputStream(), UserDto.class, new PageReadListener<UserDto>(dataList -> {
            for (UserDto demoData : dataList) {
                //将JSON对象转换成实体类
                UserDto entity = JSONObject.parseObject(JSONObject.toJSONString(demoData), UserDto.class);
                list.add(entity);
            }
        })).sheet().doRead();
        //将导入的用户数据保存到数据库中
        list.stream().forEach(userDto ->{
            //设置值
            UserInfo userInfo = new UserInfo();
            userInfo.setAvatar("http://img.shiyit.com/66bb121d47e94b89945d29bb6e3e6cab.jpg");
            userInfo.setIntro("游客");
            String nickname = "游客" + RandomUtils.generationCapital(4) + RandomUtils.generationNumber(6);
            userInfo.setNickname(nickname);
            //用户信息绑定
            userInfoMapper.insert(userInfo);

            //查询获取userInfoId
            LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserInfo::getNickname,nickname);
            UserInfo selectOne = userInfoMapper.selectOne(wrapper);
            Integer userInfoId = selectOne.getId();

            User user = new User();
            user.setUsername(userDto.getUsername());
            //密码加密
            user.setPassword(AesEncryptUtils.aesEncrypt(userDto.getPassword()));
            user.setStatus(userDto.getStatus());
            user.setRoleId(2);
            user.setLoginType(1);
            user.setUserInfoId(userInfoId);
            user.setOs(userDto.getOs());
            user.setIpAddress(userDto.getIpAddress());
            user.setIpSource(userDto.getIpSource());
            user.setBrowser(userDto.getBrowser());
            userService.save(user);
        });
    }

//PageReadListener此监听器可以自己实现,这里用的是官方封装好的。

Controller层

@PostMapping("/import")
@ApiOperation(value = "导入用户数据", httpMethod = "GET", response = ResponseResult.class, notes = "导入用户数据")
    public ResponseResult excelImport(MultipartFile file) throws IOException {
        userService.excelImport(file);
        return ResponseResult.success();
    }
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目,可以轻松地导入导出海量数据。它支持多种数据源,如List、Map、JavaBean等,并且可以自定义样式、格式等。 使用EasyExcel进行导出,只需要定义好表头和数据源,然后调用相关API即可。例如: ``` // 定义表头 List<List<String>> head = new ArrayList<List<String>>(); List<String> head0 = new ArrayList<String>(); head0.add("姓名"); List<String> head1 = new ArrayList<String>(); head1.add("年龄"); head.add(head0); head.add(head1); // 定义数据源 List<List<Object>> data = new ArrayList<List<Object>>(); for (int i = 0; i < 1000000; i++) { List<Object> item = new ArrayList<Object>(); item.add("张三" + i); item.add(i); data.add(item); } // 导出Excel ExcelWriter writer = EasyExcel.write("demo.xlsx").build(); WriteSheet sheet = EasyExcel.writerSheet("Sheet1").build(); writer.write(head, sheet); writer.write(data, sheet); writer.finish(); ``` 使用EasyExcel进行导入,只需要定义好数据模型和监听器,然后调用相关API即可。例如: ``` // 定义数据模型 public class User { @ExcelProperty("姓名") private String name; @ExcelProperty("年龄") private Integer age; // 省略getter/setter方法 } // 定义监听器 public class UserListener extends AnalysisEventListener<User> { private List<User> userList = new ArrayList<User>(); @Override public void invoke(User user, AnalysisContext context) { userList.add(user); } @Override public void doAfterAllAnalysed(AnalysisContext context) { // 处理完所有数据后的操作 } public List<User> getUserList() { return userList; } } // 导入Excel ExcelReader reader = EasyExcel.read("demo.xlsx", User.class, new UserListener()).build(); ReadSheet sheet = EasyExcel.readSheet(0).build(); reader.read(sheet); List<User> userList = ((UserListener) reader.getEventListener()).getUserList(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

six-key

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值