SpringBoot 整合eazyPoi 4.3.0 数据导入导出

SpringBoot 整合eazyPoi 4.3.0 数据导入导出,第1张

SpringBoot 整合eazyPoi 4.3.0 数据导入导出

目录
  • 依赖
  • 注解用法说明
    • @ExcelTarget 绑定Id
    • @Excel 用在字段上面
    • @ExcelCollection
    • 实体代码
  • Excel导出
    • 正常数量导出(1-2W条)
    • 大数据量导出
    • 多sheet导出
    • 单元格超链接
  • Excel导入
    • importParams参数
    • 正常导入 importExcel
    • 大数据量 importExcelBySax
    • 异步
    • 读取合并的表头
    • 验证导入(筛出符合与不符合的数据)
    • 表头的groupName
    • 导入图片
    • CSV导入
    • excel转换csv
  • Excel转html

依赖


    cn.afterturn
    easypoi-spring-boot-starter
    4.3.0

注解用法说明

  • @Excel 用在字段上面
  • @ExcelCollection 表示根对象中的list
  • @ExcelEntity 表示根对象中的实体
  • @ExcelIgnore 忽略导出
  • @ExcelTarget 绑定Id
@ExcelTarget 绑定Id

解决了相同的实体去映射Excel 但是表头名字不太相同 实现根据班级不同映射不同名字



这里的@ExcelTarget 表示使用X这个对象是可以针对不同字段做不同处理
同样的ExcelEntity 和ExcelCollection 都支持这种方式

@Excel 用在字段上面 属性类型默认值功能nameStringnull列名,支持ExcelTargetneedMergebooleanfasle纵向合并单元格(用于含有list中,单个的单元格,合并list创建的多个row)orderNumString“0”列的排序,支持ExcelTargetreplaceString[]{}字符替换 导出是{“替换值_源”,“替换值_源”}savePathString“upload”导入文件保存路径,如果是图片可以填写,默认是upload/className/ IconEntity这个类对应的就是upload/Icon/typeint1导出类型 1 是文本 2 是图片,3 是函数,10 是数字 默认是文本widthdouble10列宽heightdouble10列高,后期打算统一使用@ExcelTarget的height,这个会被废弃,注意isStatisticsbooleanfasle自动统计数据,在追加一行统计,把所有数据都和输出[这个处理会吞没异常,请注意这一点]isHyperlinkbooleanFALSE超链接,如果是需要实现接口返回对象isimportFieldbooleanTRUE校验字段,看看这个字段是不是导入的Excel中有,如果没有说明是错误的Excel,读取失败,支持ExcelTargetexportFormatString“”导出的时间格式,以这个是否为空来判断是否需要格式化日期importFormatString“”导入的时间格式,以这个是否为空来判断是否需要格式化日期formatString“”时间格式,相当于同时设置了exportFormat 和 importFormatdatabaseFormatString“yyyyMMddHHmmss”导出时间设置,如果字段是Date类型则不需要设置 数据库如果是string 类型,这个需要设置这个数据库格式,用以转换时间格式输出numFormatString“”数字格式化,参数是Pattern,使用的对象是DecimalFormatimageTypeint1导出类型 1 从file读取 2 是从数据库中读取 默认是文件 同样导入也是一样的suffixString“”文字后缀,如值实90 suffix="%" 变成90%isWrapbooleanTRUE是否换行 即支持nmergeRelyint[]{}合并单元格依赖关系,比如第二列合并是基于第一列 则{0}就可以了mergeVerticalbooleanfasle纵向合并内容相同的单元格fixedIndexint-1对应excel的列,忽略名字isColumnHiddenbooleanFALSE导出隐藏列

看下如何使用 在下面有完全代码可以copy

@Data
@ExcelTarget("user1")
@Accessors(fluent = true)
public class TestBean implements Serializable {
    @Excel(name = "A班级编号_user1,B班级编号_user2" ,//表头名称
            width = 15.0, //宽度
            orderNum = "0", //排序 这个排序在@ExcelEntity中也可以连贯使用  ExcelCollection内的Excel不可以连贯使用
            needMerge = true)
    private Integer id;
    @Excel(name = "姓名",width = 15.0,orderNum = "1",needMerge = true)
    private String name;
    @Excel(name = "性別",
            replace = {"男_1","女_2"}, //字符替换  源实1代表男  2代表女
            suffix = "生",//添加后缀
            orderNum = "2",needMerge = true)
    private int sex;
    @Excel(name = "生日", databaseFormat = "yyyyMMddHHmmss",//如果是字符串的话>>同步数据库格式
            format = "yyyy-MM-dd HH:mm:ss",//设置导入导出格式
            orderNum = "3",
            needMerge = true)
    private Date bir;
    @ExcelIgnore //不生成数据
    @Excel(name = "生日2", databaseFormat = "yyyy-MM-dd HH:mm:ss",format = "yyyy-MM-dd HH:mm:ss",orderNum = "4")
    private Date bir2;
    @Excel(name = "照片",type = 2,//设置数据类型 2是图片
            imageType = 1,//图片使用方式
            orderNum = "8",width = 30,height = 30)
    private String img;
    @Excel(name = "照片2",type = 2,imageType = 2,orderNum = "8",width = 30,height = 30)
    private byte[] img1;

    @ExcelEntity  //表示这是一个实体  其实相当于在根实体中添加其他字段的感觉
    private Card card;

    @ExcelCollection(name = "物品",orderNum = "7")//这个集合会在这个对象内循环遍历..之前的字段数据只在第一行显示
    private List orders;
@ExcelCollection 属性类型默认值功能idStringnull定义IDnameStringnull定义集合列名,支持ExcelTargetorderNumint0排序,支持ExcelTargettypeClassArrayList.class导入时创建对象使用 实体代码

3个实体

@Data
@ExcelTarget("user1")
@Accessors(fluent = true)
public class TestBean implements Serializable {
    public static String imgPath="imgs/company/baidu.png";
    @Excel(name = "A班级编号_user1,B班级编号_user2" ,//表头名称
            width = 15.0, //宽度
            orderNum = "0", //排序 这个排序在@ExcelEntity中也可以连贯使用  ExcelCollection内的Excel不可以连贯使用
            needMerge = true)
    private Integer id;
    @Excel(name = "姓名",width = 15.0,orderNum = "1",needMerge = true)
    private String name;
    @Excel(name = "性別",
            replace = {"男_1","女_2"}, //字符替换  源实1代表男  2代表女
            suffix = "生",//添加后缀
            orderNum = "2",needMerge = true)
    private int sex;
    @Excel(name = "生日", databaseFormat = "yyyyMMddHHmmss",//如果是字符串的话>>同步数据库格式
            format = "yyyy-MM-dd HH:mm:ss",//设置导入导出格式
            orderNum = "3",
            needMerge = true)
    private Date bir;
    @ExcelIgnore //不生成数据
    @Excel(name = "生日2", databaseFormat = "yyyy-MM-dd HH:mm:ss",format = "yyyy-MM-dd HH:mm:ss",orderNum = "4")
    private Date bir2;
    @Excel(name = "照片",type = 2,//设置数据类型 2是图片
            imageType = 1,//图片使用方式
            orderNum = "8",width = 30,height = 30)
    private String img;
    @Excel(name = "照片2",type = 2,imageType = 2,orderNum = "8",width = 30,height = 30)
    private byte[] img1;

    @ExcelEntity  //表示这是一个实体  其实相当于在根实体中添加其他字段的感觉
    private Card card;

    @ExcelCollection(name = "物品",orderNum = "7")//这个集合会在这个对象内循环遍历..之前的字段数据只在第一行显示
    private List orders;

    //获取10条 完整数据
    public static List getListUser(){
        List list=new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            list.add(new TestBean().id(i).name("姓名"+i).bir(new Date()).sex(i%2==0?1:2).card(new Card())
            .orders(getOrder())
                    .img(imgPath));
        }
        return list;
    }
    //只获取根对象数据  没有图片,list,实体
    public static List getBigListFor10000(int page){
        List list=new ArrayList<>();
        for (int i = page; i <= page*10000; i++) {
            list.add(new TestBean().id(i).name("姓名"+i).bir(new Date()).sex(i%2==0?1:2));
        }
        return list;
    }
    public static List getOrder(){
        List list=new ArrayList<>();
        for (int i = 1; i <=3 ; i++) {
            list.add(new Order().id(i).name("物品"+i));
        }
        return list;
    }



    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSex() {
        return sex;
    }

    public void setSex(int sex) {
        this.sex = sex;
    }

    public Date getBir() {
        return bir;
    }

    public void setBir(Date bir) {
        this.bir = bir;
    }

    public Date getBir2() {
        return bir2;
    }

    public void setBir2(Date bir2) {
        this.bir2 = bir2;
    }

    public String getImg() {
        return img;
    }

    public void setImg(String img) {
        this.img = img;
    }

    public byte[] getImg1() {
        return img1;
    }

    public void setImg1(byte[] img1) {
        this.img1 = img1;
    }

    public Card getCard() {
        return card;
    }

    public void setCard(Card card) {
        this.card = card;
    }

    public List getOrders() {
        return orders;
    }

    public void setOrders(List orders) {
        this.orders = orders;
    }
    //校验文件目录
    public static String existsDir(){
        String dir="D:/eazyPoi/";
        File savefile = new File(dir);
        if (!savefile.exists()) {
            savefile.mkdirs();
        }
        return dir;
    }


}
@Accessors(fluent = true)
@ExcelTarget("card1")
@Data
public class Card{
    @Excel(name = "身份z",orderNum = "5")
    private String id ;
    @Excel(name = "地址",orderNum = "6")
    private String addr;
    public Card() {
        this.id = "123212321";this.addr = "北京市朝阳区";
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }
}
@Accessors(fluent = true)
@ExcelTarget("order1")
@Data
public class Order{
    @Excel(name = "序号",orderNum = "1")
    public int id ;
    @Excel(name = "物品",orderNum = "2")
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
Excel导出 正常数量导出(1-2W条)
package com.ruoyi.web.eazyPoi;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.handler.inter.IExcelExportServer;
import cn.afterturn.easypoi.handler.inter.IWriter;
import org.apache.poi.hssf.record.DVALRecord;
import org.apache.poi.ss.usermodel.Workbook;


import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Test {


    public static void main(String[] args) throws Exception {
        Test.exportExcel();
    }

    //1万条以下的方法
    public static void exportExcel()throws Exception{
        ExportParams exportParams=new ExportParams("用戶信息表", "用戶信息");
        List listUser = TestBean.getListUser();
        Workbook sheets = ExcelExportUtil.exportExcel(exportParams, TestBean.class, listUser);
        sheets.write(new FileOutputStream(TestBean.existsDir()+System.currentTimeMillis() +".xls"));
        sheets.close();
    }

}

大数据量导出

这里面的这个@Override是一个循环函数,obj是外层传的queryParams(参4)但是page会一直循环到>obj 比比如我们分10页的数据 page会循环超过10

  • sql条件分页到最后一页后查询为
public class Test {


    public static void main(String[] args) throws Exception {
        Test.exportExcel();
    }

    public static void exportBigExcel()throws Exception{
        Workbook     workbook = null;
        Date         start    = new Date();
        ExportParams exportParams=new ExportParams("用戶信息表", "用戶信息");
        workbook = ExcelExportUtil.exportBigExcel(exportParams, TestBean.class, new IExcelExportServer() {
            
            @Override
            public List selectListForExcelExport(Object obj, int page) {
                //page是从1开始递增**(应该做成外面传几就截止到几但并不是回直加)所以手动限制下
                if((int)obj==page){return null;};
                //最后返回的表格对象
                List listUser = new ArrayList<>();
                //模拟业务分页查询
                listUser.addAll(TestBean.getBigListFor10000(page));
                return listUser;
            }
        },10);
        workbook.write(new FileOutputStream(TestBean.existsDir()+System.currentTimeMillis() +".xlsx"));
        workbook.close();
    }
    
}
 
多sheet导出 
    public void moveSheet(){
        //sheet集合信息
        List> sheetList=new ArrayList>();
        //循环方式创建2个sheet
        for (int i = 0; i <2 ; i++) {
            //获取数据
            List listUser = TestBean.getListUser();
            //封装sheet信息
            Map mapData=new HashMap();
            ExportParams params = new ExportParams();
            //sheet名称
            params.setSheetName("学生信息表"+i);
            mapData.put("title",params);//表格信息
            mapData.put("entity",TestBean.class);//实体类
            mapData.put("data",listUser);//列表集
            sheetList.add(mapData);//sheet集合
        }
        //导出
        Workbook workbook = ExcelExportUtil.exportExcel(sheetList, ExcelType.XSSF);
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("D:/home/excel/测试多Sheet.xls");
            workbook.write(fos);
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
单元格超链接
@Data
public class HyperlinkEntity {
    @Excel(name = "名称", isHyperlink = true)
    private String name;
    @Excel(name = "URL")
    private String url;
    @Excel(name="备注")
    private String comment;
}    
    @Test
    public void test() throws Exception {
        //数据集合
        List list = new ArrayList();
        HyperlinkEntity client = new HyperlinkEntity();
        client.setName("百度");
        client.setUrl("https://www.baidu.com/");
        client.setComment("XXXXXXXXXX");
        list.add(client);
        client = new HyperlinkEntity();
        client.setName("新浪");
        client.setUrl("http://www.sina.com.cn/");
        client.setComment("XXXXXXXXXX");
        list.add(client);

        //表格信息
        ExportParams params = new ExportParams("超链接测试", "超链接测试", ExcelType.XSSF);
        //设置拦截
        params.setDataHandler(new ExcelDataHandlerDefaultImpl() {
            
            @Override
            public Hyperlink getHyperlink(CreationHelper creationHelper, Object obj, String name, Object value) {
                Hyperlink link = creationHelper.createHyperlink(HyperlinkType.URL);
                System.out.println(name);
                System.out.println(value);
                HyperlinkEntity e = (HyperlinkEntity) obj;
                link.setAddress(e.getUrl());//超链接地址
                link.setLabel(e.getName());//返回此超链接的文本标签
                HyperlinkType type = link.getType();//获取超链接类型HyperlinkType枚举
                return link;
            }
        });
        Workbook workbook = ExcelExportUtil.exportExcel(params, HyperlinkEntity.class, list);
        FileOutputStream fos = new FileOutputStream("D:/home/excel/ExcelExportForlink.xlsx");
        workbook.write(fos);
        fos.close();
    }
Excel导入 importParams参数 值类型默认值功能titleRowsint0表格标题行数,默认0headRowsint1表头行数,默认1startRowsint0设置开始读取的位置,也就是从标题下0为全部 1读取第一行以后的数据keyIndexint0主键设置,如何这个cell没有值,就跳过 或者认为这个是list的下面的值,这一列必须有值,不然认为这列为无效数据startSheetIndexint0与sheetNum两个配合使用 在多个sheet时 有10个sheet我们想读取1-4个sheetsheetNumint1上传表格需要读取的sheet 数量,默认为1needSavebooleanFALSE是否需要保存上传的ExcelneedVerfiybooleanFALSE是否需要校验上传的ExcelsaveUrlString“upload/excelUpload”保存上传的Excel目录,默认是 如 TestEntity这个类保存路径就是upload/excelUpload/Test/yyyyMMddHHmss_ 保存名称上传时间_五位随机数verifyHanlderIExcelVerifyHandlernull校验处理接口,自定义校验lastOfInvalidRowint0最后的无效行数,不读的行数readRowsint0手动控制读取的行数实测设置head后 2=第一行数据importFieldsString[]nullexcel文件中必须要有的字段,必须要有这些数据keyMarkString“:”Key-Value 读取标记,以这个为Key,后面一个Cell 为Value,多个改为ArrayListreadSingleCellbooleanFALSE按照Key-Value 规则读取全局扫描Excel,但是跳过List读取范围提升性能,仅仅支持titleRows + headRows + startRows 以及 lastOfInvalidRowdataHanlderIExcelDataHandlernull数据处理接口,以此为主,replace,format都在这后面 正常导入 importExcel

需要把实体里面图片的字段的Excel注释掉

    //普通正常表格
    public void importExcel1() {
        importParams params = new importParams();
        params.setTitleRows(1);
        params.setHeadRows(1);
        params.setStartRows(0);//设置开始读取的位置,也就是从标题下0为全部  1读取第一行以后的数据
//        params.setKeyIndex(1);//
//        params.setStartSheetIndex(0); params.setSheetNum(1);//两个配合使用  在多个sheet时   有10个sheet我们想读取1-4个sheet
//        params.setReadRows(3);//实测设置head后 2=第一行数据
        params.setimportFields(new String[]{"姓名","性別"});//excel文件中必须要有的字段,必须要有这些数据
//        params.setReadRows(4);
        File file = new File(getWebRootPath("import/B.xlsx"));
        List list = ExcelimportUtil.importExcel(file,TestBean.class, params);
        list.stream().forEach(i-> System.out.println(i.toString()));
    }
大数据量 importExcelBySax
    //导入大量数据
    public void importExcelBySax() throws FileNotFoundException {
        
        importParams params = new importParams();
        params.setTitleRows(1);
        List list=new ArrayList<>();
        ExcelimportUtil.importExcelBySax(
                new FileInputStream(
                        new File(getWebRootPath("import/ExcelExportMsgClient.xlsx"))),
                TestBean.class, params, new IReadHandler() {
                    @Override//读取的每一行
                    public void handler(TestBean o) {
                        list.add(o);
                        System.out.println(ReflectionToStringBuilder.toString(o));
                    }
                    @Override
                    public void doAfterAll() {
                        System.out.println("数据执行完毕的处理");
                    }
                });
    }

异步

从官方的demo中看得出 没快哪里去

    public void asyncTask(){
        importParams params =new importParams();
        params.setHeadRows(1);
        params.setTitleRows(1);
        params.setConcurrentTask(true);//开启异步
        params.setCritical(500);
        List objects = ExcelimportUtil.importExcel(
                new File(getWebRootPath("import/B.xlsx")),
                TestBean.class,
                params
        );
        objects.stream().forEach(i-> System.out.println(i.toString()));
    }

读取合并的表头

    //普通正常表格
    public void importExcel1() {
        importParams params = new importParams();
        params.setTitleRows(1);//标题1行
        params.setHeadRows(2);//表头一共是2行
        File file = new File(getWebRootPath("import/B.xlsx"));
        List list = ExcelimportUtil.importExcel(file,TestBean.class, params);
        list.stream().forEach(i-> System.out.println(i.toString()));
    }

验证导入(筛出符合与不符合的数据)

官方给出挺多的demo,有点繁琐,觉得这个是比较实用的
在实体类中添加hibernate的字段验证注解
这个不需要额外引入依赖
主要验证这3个位置

    public void validFieldimport() throws IOException {
        importParams params=new importParams();
        params.setTitleRows(1);
        params.setHeadRows(2);
        params.setNeedVerify(true);//设置需要验证
        params.setVerifyGroup(new Class[]{ValidGroup.class});//设置验证分组
        ExcelimportResult importResult = ExcelimportUtil.importExcelMore(new File(getWebRootPath("import/B.xlsx")), TestBean.class, params);
        //符合验证
        List list = importResult.getList();
        //不符合验证
        List failList = importResult.getFailList();
        //获取map
        Map map = importResult.getMap();
        //导出验证的数据
        importResult.getWorkbook().write(new FileOutputStream("D:/eazyPoi/validExcel.xlsx"));
        //不符合的数据
        importResult.getFailWorkbook().write(new FileOutputStream("D:/eazyPoi/failValidExcel.xlsx"));
        System.out.println("是否验证失败"+importResult.isVerifyFail());
    }

bir 字段没有加验证分组 所以不参与验证

失败导出的excel会有提示

表头的groupName


导入图片
    @Excel(name = "公司LOGO", type = 2 ,width = 40 , height = 30,imageType = 1,
            savePath="D:\javaProject\")
    private String companyLogo;

CSV导入

新建C.csv文件

id,name,sex,bir
1,小明,1,1991-08-08
2,小张,1,1991-09-08
3,小红,2,1991-09-08

public  void importCSV()throws Exception{
       Date start = new Date();
       CsvimportParams params = new CsvimportParams(CsvimportParams.UTF8);
       CsvimportUtil.importCsv(new FileInputStream(
                       new File(getWebRootPath("import/C.csv"))),
               Map.class, params, new IReadHandler() {
                   @Override
                   public void handler(Map o) {
                       System.out.println(JSON.toJSONString(o));
                   }

                   @Override
                   public void doAfterAll() {

                   }
               });
}

excel转换csv

Excel

    public void excel2Csv()throws Exception{
        //输出的CSV
        FileOutputStream fos    = new FileOutputStream("D:\eazyPoi\aa.csv");
        importParams     params = new importParams();
        params.setTitleRows(1);
        params.setHeadRows(1);
        CsvExportParams csvExportParams = new CsvExportParams();
        csvExportParams.setEncoding(CsvExportParams.GBK);//可使用UTF8
        IWriter ce = CsvExportUtil.exportCsv(csvExportParams, TestBean.class, fos);
        ExcelimportUtil.importExcelBySax(
                new FileInputStream(
                        new File(getWebRootPath("import/B.xlsx"))),
                TestBean.class, params, new IReadHandler() {
                    private List list = new ArrayList<>();
                    @Override
                    public void handler(TestBean o) {
                        //读取后添加到list
                        list.add(o);
                    }
                    @Override
                    public void doAfterAll() {
                        //读取结束后转换输出
                        ce.write(list);
                        list.clear();
                        System.out.println("succcess--------------------------------");
                    }
                });
    }

CSV 红框为实体类注解字段

Excel转html

    public void testToAllHtmlWorkbookAndImage()throws Exception{
        Workbook wb = new XSSFWorkbook(new FileInputStream(new File(getWebRootPath("import/B.xlsx"))));
        String     html = ExcelXorHtmlUtil.excelToHtml(new ExcelToHtmlParams(wb, true, "D:\eazyPoi\"));
        FileWriter fw   = new FileWriter("D:/eazyPoi/B.html");
        fw.write(html);
        fw.close();
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/4997223.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-14
下一篇 2022-11-14

发表评论

登录后才能评论

评论列表(0条)