java 导出excel

2023-05-16

目录

    • 一、动态下拉框
    • 二、合并行单元格
    • 三、复杂表头
    • 四、批量生成文件上传到文件服务器,再从文件服务器批量下载压缩成压缩包后导出

一、动态下拉框

在这里插入图片描述如何得到这样一张表格?在单元格中插入可选下拉框。
思路分析:
① excel 表头每个字段对应实体的每个字段
② 表头字段是从注解 @ExcelProperty的value中取得的(参考alibaba的写excel方法)
③那么,是否可以自定义1个注解,通过这个注解得到下拉框的值

使用的工具类:easyexcel

第一步,自定义一个注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface ExplicitConstraint {

    //定义注解类型元素(基本数据类型,String,Class,枚举,注解,数组)
    Class<? extends EasyExcelSelect> sourceClass();

    String value() default "";

}

第二步,定义一个抽象类

public abstract class EasyExcelSelect {

    /**
     * 得到下拉框的值
     *
     * @return
     */
    public abstract String[] selectValue(Object value);
}

第三步,定义一个实现类

public class DictEasySelect extends EasyExcelSelect {
    @Override
    public String[] selectValue(Object value) {
        if(ObjectUtils.allNotNull(value)){
            //用BeanFactory来获取bean
            RemoteDataDictService remoteDataDictService = SpringUtils.getBean(RemoteDataDictService.class);
            //查出字典中该字段的所有可能值
            List<DictTreeVo> list = remoteDataDictService.findDictList(value.toString());
            if(StringUtils.isNotEmpty(list)){
                return list.stream().map(DictTreeVo::getDictName).toArray(String[]::new);
            }
        }
        return null;
    }

}

第四步,new一个实体,并在需要下拉的字段上引用该注解

@ApiModel("试题批量导入模板")
@ColumnWidth(value = 10)
@HeadRowHeight(5)
@ContentRowHeight(5)
@HeadFontStyle(fontHeightInPoints = 12)
public class TopicTemplateDto {

    
    @ApiModelProperty(value = "试题类型", required = true)
    @ExcelProperty(value = "试题类型",index = 3)
    @ExplicitConstraint(sourceClass = DictEasySelect.class,value = Constants.SUBJECT_TYPE)
    private Integer topicType;

}

第五步,实现excel导出功能

/**
     * 导出动态下拉框
     */
    public static ExportVo writeExcel(String fileName, Class clazz) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        //下拉列表集合(key 是列,value 是字段)
        Map<Integer, String[]> map = new HashMap<>();
        //利用反射获取所有声明的字段
        Field[] fields = clazz.getDeclaredFields();
        fields = Arrays.stream(fields).filter(field -> null != field.getAnnotation(ExcelProperty.class)).toArray(Field[]::new);

        try {
            getSelect(map, fields);
        } catch (Exception e) {

        }

        ExcelWriter excelWriter = EasyExcel.write(byteArrayOutputStream, clazz).registerWriteHandler(
                new SheetWriteHandler() {
                    @Override
                    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {

                    }

                    @Override
                    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
                        //定义一个工作簿
                        Sheet sheet = writeSheetHolder.getSheet();
                        //DataValidationHelper(数据有效对象),指定工作表中的数据有效对象
                        DataValidationHelper dataValidationHelper = sheet.getDataValidationHelper();
                        map.forEach((k, v) -> {
                            //CellRangeAddressList(单元格地址范围):指定某列某行。
                            //指定下拉列表的作用域(k列,1-1000行)
                            CellRangeAddressList rangeAddressList = new CellRangeAddressList(1, 1000, k, k);

                            //createExplicitListConstraint:只能满足较少枚举的下拉框,20个以内;createFormulaListConstraint可以实现较多枚举的下拉框
                            DataValidationConstraint dataValidationConstraint = dataValidationHelper.createExplicitListConstraint(v);
                            //DataValidation(数据验证),添加有效性数据
                            DataValidation validation = dataValidationHelper.createValidation(dataValidationConstraint, rangeAddressList);

                            /**兼容性*/
                            //instanceof 判断一个对象是否是一个类的实例
                            if (validation instanceof XSSFDataValidation) {
                                validation.setSuppressDropDownArrow(true);
                                validation.setShowErrorBox(true);
                            } else {
                                validation.setSuppressDropDownArrow(false);
                            }
                            sheet.addValidationData(validation);

                        });

                    }
                }

        ).build();
        WriteSheet sheet = EasyExcel.writerSheet().build();
        excelWriter.write(null, sheet).finish();
        return new ExportVo(fileName, byteArrayOutputStream.toByteArray());
    }

getSelect方法

 /**
     * 筛选下拉框表头
     */
    public static void getSelect(Map<Integer, String[]> maps, Field[] fields) throws IllegalAccessException, InstantiationException {
        ExcelProperty excelProperty;
        ExplicitConstraint explicitConstraint;
        Class<? extends EasyExcelSelect> selectClass;
        EasyExcelSelect easyExcelSelect;
        String[] value;
        for (int i = 0; i < fields.length; i++) {
            //反射获取excelProperty和explicitConstraint注解类的值
            excelProperty = fields[i].getAnnotation(ExcelProperty.class);
            explicitConstraint = fields[i].getAnnotation(ExplicitConstraint.class);
            if (null != explicitConstraint) {
                selectClass = explicitConstraint.sourceClass();
                //调用无参构造方法进行实例化
                easyExcelSelect = selectClass.newInstance();
                value = easyExcelSelect.selectValue(explicitConstraint.value());

                if (null != value && value.length > 0) {
                    if (excelProperty.index() == -1) {
                        maps.put(i, value);
                    } else {
                        maps.put(excelProperty.index(), value);
                    }
                }
            }
        }
    }

二、合并行单元格

在这里插入图片描述
法一:

 CellRangeAddress cellRangeAddress =  new CellRangeAddress(startRow,endRow,firstCol,lastCol);

法二:
easypoi实现表格导出(实现一对多,合并单元格)

三、复杂表头

在这里插入图片描述

EasyExcel.write(fileName)             
                .head(header).sheet(sheetName)
                .doWrite(dataList);

easyexcel的.head(header)方法接受一个List<List>对象作为动态表头:
List 对应一列,T对应该列中每行单元格的数据。在列表中的位置下标对应excel中的位置。
在这里插入图片描述例如:3行5列的表头
在这里插入图片描述

List<List<String>> dataList = new ArrayList<>();
List<List<String>> header = new ArrayList<>();

//第一列
List<String> col1 = new ArrayList<>();
col1.add("T11");
col1.add("T12");
col1.add("T13");
header.add(col1);
//第二列
List<String> col2 = new ArrayList<>();
col2.add("T11");
col2.add("T12");
col2.add("T23");
header.add(col2);

//第三列
List<String> col3 = new ArrayList<>();
col3.add("T11");
col3.add("T32");
col3.add("T23");
header.add(col3);

//第四列
List<String> col4 = new ArrayList<>();
col4.add("T41");
col4.add("T32");
col4.add("T23");
header.add(col4);

//第五列
List<String> col5 = new ArrayList<>();
col5.add("T41");
col5.add("T52");
col5.add("T53");
header.add(col5);

EasyExcel.write(fileName)
                .head(header).sheet(sheetName)
                .doWrite(dataList);


四、批量生成文件上传到文件服务器,再从文件服务器批量下载压缩成压缩包后导出

1.批量生成文件

 try {
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                //把
                workbook.write(outputStream);
                byte[] bytes = outputStream.toByteArray();
                //一定要关闭流
                outputStream.close();
                MultipartFile file = new MockMultipartFile("file", “newFileName”, ContentType.APPLICATION_OCTET_STREAM.toString(), bytes);
                files.add(file);
            } catch (Exception e) {
                e.printStackTrace();
            }

2.批量下载excel打包成压缩包

 ByteArrayOutputStream bos = new ByteArrayOutputStream();
 ZipOutputStream zos = new ZipOutputStream(bos, Charset.forName("utf-8"));
 ByteArrayInputStream bis;
//内部调用文件服务接口,string 是文件名,byte[]是文件字节
 Map<String, byte[]> maps = this.remoteFileService.downloadFiles(userIds, FileTypeEnums.ARCHIVES_FILE.getCode());
        try {
            if (StringUtils.isNotEmpty(maps)) {
                for (Map.Entry<String, byte[]> entry : maps.entrySet()) {
                    bis = new ByteArrayInputStream(entry.getValue());
                    zos.putNextEntry(new ZipEntry(entry.getKey()));
                    int temp;
                    while ((temp = bis.read()) != -1) {
                        zos.write(temp);
                    }
                    bis.close();
                }
            }

            zos.close();
            bos.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ExportVo(Constants.DRIVER_ARCHIVE_FILE_ZIP, bos.toByteArray());

3.FeignClient内部调用文件服务,①要在注解里加consumes说明 ②参数用@requestPart注解

    @ApiOperation(value = "批量处理文件到文件服务器")
    @PostMapping( value = "/file/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResultVo uploadFileList(@RequestPart("relevanceDtos")List<MultipartFile> files, @RequestParam("revelanceIds") List<Long> revelanceIds){
        return this.fileService.uploadFileList(files, revelanceIds);
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java 导出excel 的相关文章

  • OSGi:如果不取消服务会发生什么

    这是我获取 OSGi 服务的方式 ServiceReference reference bundleContext getServiceReference Foo class getName Foo foo Foo bundleContex
  • 比较两个文本文件的最快方法是什么,不将移动的行视为不同

    我有两个文件非常大 每个文件有 50000 行 我需要比较这两个文件并识别更改 然而 问题是如果一条线出现在不同的位置 它不应该显示为不同的 例如 考虑这个文件A txt xxxxx yyyyy zzzzz 文件B txt zzzzz xx
  • 运行具有外部依赖项的 Scala 脚本

    我在 Users joe scala lib 下有以下 jar commons codec 1 4 jar httpclient 4 1 1 jar httpcore 4 1 jar commons logging 1 1 1 jar ht
  • JavaFX 中具有自定义内容的 ListView

    How i can make custom ListView with JavaFx for my app I need HBox with image and 2 Labels for each line listView 您可以通过查看
  • 如何在不超过最大值的情况下增加变量?

    我正在为学校开发一个简单的视频游戏程序 我创建了一个方法 如果调用该方法 玩家将获得 15 点生命值 我必须将生命值保持在最大值 100 并且由于我目前的编程能力有限 我正在做这样的事情 public void getHealed if h
  • 如何模拟从抽象类继承的受保护子类方法?

    如何使用 Mockito 或 PowerMock 模拟由子类实现但从抽象超类继承的受保护方法 换句话说 我想在模拟 doSomethingElse 的同时测试 doSomething 方法 抽象超类 public abstract clas
  • 画透明圆,外面填充

    我有一个地图视图 我想在其上画一个圆圈以聚焦于给定区域 但我希望圆圈倒转 也就是说 圆的内部不是被填充 而是透明的 其他所有部分都被填充 请参阅这张图片了解我的意思 http i imgur com zxIMZ png 上半部分显示了我可以
  • Excel 数字缩写格式

    这是我想要完成的任务 Value Display 1 1 11 11 111 111 1111 1 11k 11111 11 11k 111111 111 11k 1111111 1 11M 11111111 11 11M 11111111
  • Hazelcast 分布式锁与 iMap

    我们目前使用 Hazelcast 3 1 5 我有一个简单的分布式锁定机制 应该可以跨多个 JVM 节点提供线程安全性 代码非常简单 private static HazelcastInstance hInst getHazelcastIn
  • 如何在Power Query中对N列求和

    我的数据每月都会更新 因此我尝试创建一个强大的查询表 该表将显示我创建的枢转 N 列的总和 但我似乎不知道如何在强大的查询中执行此操作 我目前有这个代码 旋转后 创建要求和的列的列表 添加索引列以限制每行 添加一列 该列对该行的列进行求和
  • 输入新行并复制上面单元格中的公式

    我正在尝试创建一个 Excel 宏来执行以下操作 在文档末尾输入新行 复制上面单元格中的公式 到目前为止我有这个 Sub New Delta Go to last cell Range A4 Select Selection End xlD
  • 两个日期之间的小时数在 Excel 中不起作用

    根据要求 我提供了一张简化的屏幕截图来说明该问题 如您所见 我减去了两个日期并将其格式化为 h mm ss 为什么这不能提供两个日期之间经过的总小时数 有一个更好的方法吗 下面有一个很好的答案 但我试图弄清楚为什么按照此屏幕截图中所示的方式
  • 如何使用 Maven 打包并运行具有依赖项的简单命令行应用程序?

    我对 java 和 Maven 都是全新的 所以这可能非常简单 如果我遵循maven2hello world此处的说明 http maven apache org guides getting started maven in Five m
  • 有没有一种快速方法可以从 Jar/war 中删除文件,而无需提取 jar 并重新创建它?

    所以我需要从 jar war 文件中删除一个文件 我希望有类似 jar d myjar jar file I donot need txt 的内容 但现在我能看到从 Linux 命令行执行此操作的唯一方法 不使用 WinRAR Winzip
  • 测试弱引用

    在 Java 中测试弱引用的正确方法是什么 我最初的想法是执行以下操作 public class WeakReferenceTest public class Target private String value public Targe
  • 我可以创建自定义 java.* 包吗?

    我可以创建一个与预定义包同名的自己的包吗在Java中 比如java lang 如果是这样 结果会怎样 这难道不能让我访问该包的受保护的成员 如果不是 是什么阻止我这样做 No java lang被禁止 安全管理器不允许 自定义 类java
  • HQL Hibernate 内连接

    我怎样才能在 Hibernate 中编写这个 SQL 查询 我想使用 Hibernate 来创建查询 而不是创建数据库 SELECT FROM Employee e INNER JOIN Team t ON e Id team t Id t
  • 在VBA中初始化全局变量

    在 Excel 2003 中 如何声明全局变量并仅在打开工作簿时初始化它们一次 我有一些由几个宏使用的参数 基本上是输入文件的路径 目前 我的代码如下所示 global path1 path2 as string sub initPaths
  • 为什么这个作业不起作用?

    我有课Results which extends ArrayList
  • hashcode 的默认实现为以相同方式构造的对象返回不同的值

    我在这里编写一个示例代码 public class Test private int i private int j public Test TODO Auto generated constructor stub public Test

随机推荐

  • 关于&0xFF的理解

    做协议解析时候 xff0c 一个byte的0xFE xff0c 直接转化int xff0c 应该是254 xff0c 但是最终结果是 2 xff0c 在网上一查 xff0c 有的人说是因为java用补码表示的byte 网址 xff1a ht
  • tensoflow2.x中tensor转numpy问题

    这里写自定义目录标题 AttributeError 39 Tensor 39 object has no attribute 39 numpy 39 AttributeError Tensor object has no attribute
  • A算法与A*算法区别

    A算法由 f n 61 g n 43 h n 俩个因素决定 xff0c g n 是这一步的代价函数 h n 是这一步的预估函数 xff1b 对于A 算法来说 xff0c 评判函数也是 f n 61 g n 43 h n 这个 xff0c 只
  • PARWAN处理器架构特点

    PARWAN处理器架构特点 PARWAN处理器结构图 xff08 搬运工系列 xff09 各个部分说明 xff1a Applied toCategtoriesSignal Name FunctionallyAC 累加计数器 Register
  • PX4源码学习一--Pix和APM的区别

    pixhawk是硬件平台 xff0c PX4是pixhawk的原生固件 xff0c 专门为pixhawk开发的 APM xff08 Ardupilot Mega xff09 也是硬件 Ardupilot是APM的固件 xff0c 所以称Ar
  • px4源码学习三--px4源码结构分析

    px4源码结构分析 Px4源码目录 cmake xff1a 是存放的 Cmake 编辑脚本文件夹 xff0c 其中 Cmake Configs 是存放的不同硬件的编译脚本 xff0c nuttx mindpx v2 default 是 PI
  • px4源码学习五--固定翼位置控制模块

    fw pos control模块 class landingslope 为固定翼着陆的角度变化模块 calulateSlopeValues void private 更新H1 H0 d1 根据log xff08 H0 H1 xff09 的比
  • px4源码学习六--uORB模块研究

    UORB模块研读 uORB函数解析 xff1a uORB模块 xff08 Micro Object Request Broker xff0c 微对象请求代理器 xff09 uORB是Pixhawk系统中关键的一个模块 xff0c 肩负了数据
  • Ubuntu开机进入busybox

    Ubuntu开机进入busybox 一般是因为ubuntu的文件系统出了问题 xff0c 所以需要在bushbox中进行扫描修复 看一下错误信息 xff0c 然后在busybox的命令行中运行fsck ext4 y dev sda1 xff
  • 关于JAVA文件都在没问题,没有错误提示波浪线,但编译时候提示找不到对应包的问题

    使用springboot做电商网站时候 修改了一点小功能 然后运行不了 提示XX XXX domain XX类找不到等一大堆类都找不到 但是对应包是存在的 而且在编辑框里没有红色的错误提示波浪线 所以 猜测应该不是代码的问题 又因为我们是g
  • c++泛型编程编译问题

    undefined reference to 模板类 c 43 43 泛型编程时候 xff0c 由于 h文件中放声明 xff0c cpp里放实现 xff0c main里调用 xff0c 编译时候 xff0c 就出现这样的问题 解决方法 xf
  • STM32CUBEMX的freertos一般使用方法笔记

    一 使用STM32CubeMX创建FreeRTOS操作系统 LED闪烁的配置 接下来配置时钟 xff0c 点击生成 此处为用户代码编写处 xff1b 开启这个选项便可以使用更加精确的延时 在代码区添加 便可以 xff01 二 任务挂起和取消
  • Qt5之QStatus状态栏

    1 一些常见用法 xff0c 来自其他优秀博文 xff1a https www cnblogs com toby zhang p 5729629 html 2 我这里添加状态了 xff0c 状态栏上放了一个QLabel控件显示时间 创建和添
  • 主函数一定要有while(1)吗?

    主函数一定要有while 1 吗 xff1f 在我两次移植例程时 xff0c 执行的结果都不对 xff0c 后来检查发现 xff0c 缺省了while 1 xff0c 加上之后结果就正确了 xff0c 这让我百思不得其解 xff0c 于是我
  • 解决error:legacy boot of uefi media

    错误 uefi媒体的传统引导 可能你的是GPT分区 xff0c 要改成UEFI引导 按F2 进入bios更换其他引导 xff0c 不同的品牌有自己进入的bios的方式 xff0c 我的是F2 按F10保存 解决
  • MongoDB安全实战之SSL协议加密

    邓开表同学实战MongoDB系列文章 xff0c 非常不错 xff0c 赞 xff01 大力推荐 xff01 本文主要讲述MongoDB的SSL协议加密的使用和配置的实战经验 xff0c 非常值得一看 前面系列文章 xff1a MongoD
  • 关于开源项目——C语言实现FTP服务器的结构解析

    项目地址 xff1a https github com beckysag ftp 针对此开源项目的说明 xff0c 结构分析 服务端整体框架 xff1a 1 从命令行输入得到服务端绑定端口号 2 设置套接口选项 xff0c 创建监听套接字
  • Nvidia Xavier NX 刷机 内置EMMC 带固态版

    Nvidia Xavier NX 刷机 内置EMMC 带固态版 前言一 烧录系统1 准备linux系统的电脑一台2 下载SDK Manager3 烧录过程 二 将NX系统迁移到NVME固态硬盘上1 格式化分区2 将EMMC SD卡的root
  • 关于vscode安装包下载太慢解决方法(详解)

    方法一 第一步 vscode官网选择下载版本 vscode官网 这里直接按系统选择合适的版本进行下载 xff01 第二步 进入下载界面 xff08 这一步别着急 xff0c 一定要进入下载过程 xff09 这里一定要点击保存 xff01 下
  • java 导出excel

    目录 一 动态下拉框二 合并行单元格三 复杂表头四 批量生成文件上传到文件服务器 xff0c 再从文件服务器批量下载压缩成压缩包后导出 一 动态下拉框 如何得到这样一张表格 xff1f 在单元格中插入可选下拉框 思路分析 xff1a exc