Java 操作 Excel:生成数据、设置单元格样式、设置数据有效性(hutool)

news2024/11/23 11:50:08

必读信息

该篇文章,主要通过 Java 代码对 Excel 文件的常用操作,包括:生成表格、修改单元格样式、设置数据有效性。

该篇文章,在官网文献下增加个人的看法和理解,如文中有出现不符、错误或需要补充的地方,欢迎指正,非常感谢。

该篇文章操作 Excel 使用了 hutool 的工具包以及 poi 的依赖,其中 hutool 是一个超级无敌宇宙 perfect 的一个工具包,建议每一个 Java 程序员都要了解下(不是广告,真的不是广告 😊)。

  • hutool 官方文档地址:https://hutool.cn/docs

  • hutool API 文档地址:https://apidoc.gitee.com/dromara/hutool

首先给出下面所有案例代码使用的依赖:

  • gradle 项目

    // hutool 依赖,我这里使用的是目前最新的版本 5.8.21
    implementation 'cn.hutool:hutool-all:5.8.21'
    // 操作 Excel 的必须依赖
    implementation 'org.apache.poi:poi-ooxml:5.2.3'
    implementation 'xerces:xercesImpl:2.12.2'
    // 日志依赖,非必须引入,如果项目中已经引入过那就去掉下面两个依赖
    testImplementation 'io.basc.framework:log4j2:1.8.3'
    implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
    
  • maven 项目

    <!-- hutool 依赖,我这里使用的是目前最新的版本 5.8.21 -->
    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.8.21</version>
    </dependency>
    <!-- 操作 Excel 的必须依赖 -->
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>5.2.3</version>
    </dependency>
    <dependency>
      <groupId>xerces</groupId>
      <artifactId>xercesImpl</artifactId>
      <version>2.12.2</version>
    </dependency>
    <!-- 日志依赖,非必须引入,如果项目中已经引入那就无需引入下面两个依赖 -->
    <dependency>
      <groupId>io.basc.framework</groupId>
      <artifactId>log4j2</artifactId>
      <version>1.8.3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>2.20.0</version>
    </dependency>
    

非常重要的提示:hutool 的版本与 poi-ooxml、xercesImpl 要对应,不然你会看见你代码都是红色的,版本选择参考 hutool 文档下的这句话:

说明 hutool-4.x 的 poi-ooxml 版本需高于 3.17(别问我 3.8 版本为啥不行,因为 3.17 > 3.8 ) hutool-5.x的 poi-ooxml 版本需高于 4.1.2 hutool-5.6.x支持 poi-ooxml 版本高于 5.0.0 xercesImpl版本高于 2.12.0(非必须)

生成表格

用 hutool 生成 Excel 超级超级简单,在 hutool 官方文档上也给出了多种生成 Excel 的案例方法:https://hutool.cn/docs/#/poi/Excel%E7%94%9F%E6%88%90-ExcelWriter

List 生成表格数据

通过 List 写入数据,可以一次写入一行,也可以一次性写入多行,下面代码用了一些 hutool 的工具类,需要注意引入的 import 。

下面有几个比较重要的方法:

  • ExcelUtil.getWriter():新建一个空的 Excel 文件,可以传入布尔值,true / false 生成 xlsx / xls 文件。
  • writer.writeHeadRow():该方法用于写入表头数据,之所以用这个方法写入表头,可以方便设置表头的样式。
  • writer.writeRow():向表格中写入单行数据。
  • writer.write():向表格中写入数据,该方法有很多重载方法。
  • writer.flush():将 excel 文件写入到本地磁盘。
  • writer.close():资源释放,流操作完都要进行释放。
package top.shijialeya.hutool;

import cn.hutool.core.lang.UUID;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author 17279
 */
public class ExcelDemo01 {
    public static void main(String[] args) {
        // 生成一个新的 excel 文件(参数:true 生成 xlsx 文件;false 生成 xls 文件;)
        ExcelWriter writer = ExcelUtil.getWriter(true);

        // 向 excel 中写入表头信息
        writer.writeHeadRow(Arrays.asList("唯一标识", "账户编码", "用户姓名", "账号状态"));

        // 一次性向 excel 中写入一行数据
        List<String> rowData = Arrays.asList(UUID.randomUUID().toString(true), "001", "派大星", "正常状态");
        writer.writeRow(rowData);

        // 一次性向 excel 中写入多行数据
        List<List<String>> multiRowData = new ArrayList<>();
        multiRowData.add(Arrays.asList(UUID.randomUUID().toString(true), "002", "海绵宝宝", "正常状态"));
        multiRowData.add(Arrays.asList(UUID.randomUUID().toString(true), "003", "章鱼哥", "正常状态"));
        multiRowData.add(Arrays.asList(UUID.randomUUID().toString(true), "004", "瘸老板", "禁用状态"));
        writer.write(multiRowData);

        // 将 excel 文件保存到本地
        writer.flush(new File("D:\\test.xlsx"));

        // 资源释放
        writer.close();
    }
}

生成的文件如下:

请添加图片描述

Map 生成表格数据

通过 Map 的键值对向 Excel 中添加数据。有两个需要注意的地方:

  1. 表格的表头会按照数组中第一个 Map 的 key 生成,比如说:我在第二个 Map 中存在一个 key 为性别的值,但第一个 Map 中并没有性别 key,那么生成的表格中将不会有性别这一列,生成的表头只以数组的第一个 Map 的 key 生成。
  2. 这种方式生成的表格,列的顺序是没法控制的。
// 生成一个新的 excel 文件(参数:true 生成 xlsx 文件;false 生成 xls 文件;)
ExcelWriter writer = ExcelUtil.getWriter(true);

// 创建 Map 的集合对象
List<Map<String, Object>> rowData = new ArrayList<>();
rowData.add(new HashMap<String, Object>() {{
  put("唯一标识", UUID.randomUUID().toString(true));
  put("账户编码", "001");
  put("用户姓名", "派大星");
  put("账号状态", "正常状态");
}});
rowData.add(new HashMap<String, Object>() {{
  put("唯一标识", UUID.randomUUID().toString(true));
  put("账户编码", "002");
  put("用户姓名", "海绵宝宝");
  put("账号状态", "正常状态");
}});
rowData.add(new HashMap<String, Object>() {{
  put("唯一标识", UUID.randomUUID().toString(true));
  put("账户编码", "003");
  put("用户姓名", "章鱼哥");
  put("账号状态", "正常状态");
}});
rowData.add(new HashMap<String, Object>() {{
  put("唯一标识", UUID.randomUUID().toString(true));
  put("账户编码", "004");
  put("用户姓名", "瘸老板");
  put("账号状态", "禁用状态");
}});

// 一次性写出内容,使用默认样式
writer.write(rowData);

// 将 excel 文件保存到本地
writer.flush(new File("D:\\test.xlsx"));

// 资源释放
writer.close();

生成的文件如下:
在这里插入图片描述

实体类生成表格数据

通过自定的实体对象生成 Excel,主要注意以下两点:

  1. 生成列的顺序和定义实体字段的顺序一致。
  2. @Alias() 注解可以用于设置实体属性与列的别名,如果没有设置那么列名为实体的属性名称。除此之外,还可以通过方法 writer.addHeaderAlias(实体字段名称, 字段别名) 来灵活设置别名。
// 自定的实体对象
import cn.hutool.core.annotation.Alias;

public class User {
    @Alias(value = "唯一标识")
    private String id;
    @Alias(value = "账户编码")
    private String code;
    @Alias(value = "用户姓名")
    private String username;
    @Alias(value = "账号状态")
    private String status;
  
		// 【注意】 getter\setter 方法这里省略,自己生成一下就好了
  
    public User(String id, String code, String username, String status) {
        this.id = id;
        this.code = code;
        this.username = username;
        this.status = status;
    }
}
// 生成一个新的 excel 文件(参数:true 生成 xlsx 文件;false 生成 xls 文件;)
ExcelWriter writer = ExcelUtil.getWriter(true);

// 创建集合对象
List<User> userList = new ArrayList<>();
userList.add(new User(UUID.randomUUID().toString(true), "001",  "派大星", "正常状态"));
userList.add(new User(UUID.randomUUID().toString(true), "002",  "海绵宝宝", "正常状态"));
userList.add(new User(UUID.randomUUID().toString(true), "003",  "章鱼哥", "正常状态"));
userList.add(new User(UUID.randomUUID().toString(true), "004",  "瘸老板", "禁用状态"));

// 自定义别名
// writer.addHeaderAlias("id", "唯一标识");
// writer.addHeaderAlias("code", "账户编码");
// ...

// 写出内容
writer.write(userList);

// 将 excel 文件保存到本地
writer.flush(new File("D:\\test.xlsx"));

// 资源释放
writer.close();

生成的文件如下:

在这里插入图片描述

指定单元格生成数据

向指定位置的单元格写入指定的数据,这种方式一般很少用。不过这种方式能满足绝大部分的应用场景。

主要使用了下面的这个方法:

  • excel.writeCellValue():向指定单元格中写入数据,方法有三个参数:列号、行号、单元格的值,行号 0 开始
// 生成一个新的 excel 文件(参数:true 生成 xlsx 文件;false 生成 xls 文件;)
ExcelWriter writer = ExcelUtil.getWriter(true);

// 一次性向 excel 中写入多行数据
List<List<String>> rowData = new ArrayList<List<String>>() {{
  add(Arrays.asList("唯一标识", "账户编码", "用户姓名", "账号状态"));
  add(Arrays.asList(UUID.randomUUID().toString(true), "001", "派大星", "正常状态"));
  add(Arrays.asList(UUID.randomUUID().toString(true), "002", "海绵宝宝", "正常状态"));
  add(Arrays.asList(UUID.randomUUID().toString(true), "003", "章鱼哥", "正常状态"));
  add(Arrays.asList(UUID.randomUUID().toString(true), "004", "瘸老板", "禁用状态"));
}};

// 遍历每一行的数据,索引 0 开始
for (int rowNum = 0; rowNum < rowData.size(); rowNum++) {
  List<String> cellData = rowData.get(rowNum);
  // 遍历该行每一个单元格,索引 0 开始
  for (int cellNum = 0; cellNum < cellData.size(); cellNum++) {
    // 向每一个单元格中设置值(参数:列号、行号、单元格的值,行号 0 开始)
    writer.writeCellValue(cellNum, rowNum, cellData.get(cellNum));
  }
}

// 将 excel 文件保存到本地
writer.flush(new File("D:\\test.xlsx"));

// 资源释放
writer.close();

生成的文件如下:

在这里插入图片描述

修改单元格样式

这个修改表格的样式感觉工具里面有很多 bug,遇到的问题我会一一列出来。

行高和列宽

  • 设置默认的行高,所有的行高

    writer.setDefaultRowHeight(height) 行高范围:0 ~ 409,为 0 时表示隐藏。

  • 指定列的列宽

    writer.setColumnWidth(columnIndex, width) 列宽范围:0 ~ 255 字符,0 表示为隐藏,列号从 0 开始。

  • 指定行的行高

    writer.setRowHeight(rownum, height) 行高范围:0 ~ 409,为 0 时表示隐藏,行号从 0 开始。

需要特别注意的是:setDefaultRowHeight() 和 setRowHeight() 方法不能一起使用,当两者同时出现时,只会生效 setRowHeight() 方法的内容,而 setDefaultRowHeight() 完全不起效果。

案例代码:

// 指定默认的行高
writer.setDefaultRowHeight(25);
// 给指定列设置列宽,列的索引 0 开始(宽度单位:字符 1 ~ 256)
writer.setColumnWidth(0, 36);
// 给指定行设置行高,与 setDefaultRowHeight() 选择其一 
// writer.setRowHeight(1, 35);

结果:
在这里插入图片描述

表头样式

在 hutool 操作 excel 有一个表头的概念

  • 通过 writer.writeHeadRow() 写入表格数据,这个数据就是表头的数据。
  • 通过 writer.write() 写入 Map 类型的数据,Map 的 key 也是表头数据。
  • 通过实体对象写入表格,注解 @Alias 指定的名称也为表头数据。
  • 当通过 writer.writeCellValue() 方法写入的数据不属于表头。

默认生成的表头是灰底黑字居中的样式:
在这里插入图片描述

可以对表头的样式进行修改:

// 获得表头单元格样式对象
CellStyle headCellStyle = writer.getHeadCellStyle();
// 设置表头前景色
headCellStyle.setFillForegroundColor(IndexedColors.LIGHT_YELLOW.getIndex());
// 创建字体样式
Font headCellFont = writer.createFont();
// 设置字体颜色
headCellFont.setColor(IndexedColors.DARK_RED.index);
// 设置字体大小
headCellFont.setFontHeightInPoints((short) 12);
// 设置字体类型
headCellFont.setFontName("Microsoft YaHei UI");
// 设置字体加粗
headCellFont.setBold(true);
// 设置斜体
headCellFont.setItalic(true);
// 设置删除线
headCellFont.setStrikeout(true);
headCellStyle.setFont(headCellFont);

效果如下:
在这里插入图片描述

设置全局样式

这种方式可以修改除表头以外含有数据的单元格样式,表头的样式不会修改。

// 设置前景色(下面两个语句)
rowStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rowStyle.setFillForegroundColor(IndexedColors.LIGHT_YELLOW.getIndex());
// 创建字体样式
Font cellFont = writer.createFont();
// 设置字体颜色
cellFont.setColor(IndexedColors.DARK_RED.index);
// 设置字体大小
cellFont.setFontHeightInPoints((short) 16);
// 设置字体类型
cellFont.setFontName("Microsoft YaHei UI");
rowStyle.setFont(cellFont);

效果如下:
在这里插入图片描述

设置行样式

这里有几个坑的地方:

  • 设置背景色的时候只能用 setFillPattern() 和 setFillForegroundColor() 两个方法共同控制,setFillBackgroundColor() 和 setFillForegroundColor() 这两个方法不能无法修改背景的颜色。【这里巨坑】
  • 在设置字体样式的时候,我们通过 writer.createFont() 创建的字体,这个字体不在 CellStyle 上,所以要重新执行 setFont() 和 setRowStyleIfHasData()。
  • 跟 writer.setRowStyleIfHasData() 有一个类似的 setRowStyle() 方法,如果使用的是 setRowStyle() 方法,那么行单元格中存在数据的单元格的样式会被替换,也就是有内容的单元格样式不会有效果。【这里也巨坑】

案例代码:

// 获得第二行的样式
CellStyle rowStyle = writer.getOrCreateRowStyle(1);
// 设置前景色(下面两个语句)
rowStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rowStyle.setFillForegroundColor(IndexedColors.LIGHT_YELLOW.getIndex());
// 创建字体样式
Font cellFont = writer.createFont();
// 设置字体颜色
cellFont.setColor(IndexedColors.DARK_RED.index);
// 设置字体大小
cellFont.setFontHeightInPoints((short) 16);
// 设置字体类型
cellFont.setFontName("Microsoft YaHei UI");
rowStyle.setFont(cellFont);
// 设置第二行的表格样式(要重新设置 Style)
writer.setRowStyleIfHasData(1, rowStyle);

效果如下:

在这里插入图片描述

设置列样式

方式与设置单行样式相近,获取样式和设置样式的方法不一样:

writer.getOrCreateColumnStyle() 获取列的样式对象。

writer.setColumnStyleIfHasData() 方法有三个参数:列号、开始行号、样式,列号和行号都是 0 开始。

// 获得第二列的样式
CellStyle rowStyle = writer.getOrCreateColumnStyle(1);
// 设置前景色(下面两个语句)
rowStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rowStyle.setFillForegroundColor(IndexedColors.LIGHT_YELLOW.getIndex());
// 创建字体样式
Font cellFont = writer.createFont();
// 设置字体颜色
cellFont.setColor(IndexedColors.DARK_RED.index);
// 设置字体大小
cellFont.setFontHeightInPoints((short) 16);
// 设置字体类型
cellFont.setFontName("Microsoft YaHei UI");
rowStyle.setFont(cellFont);
// 设置第二列的表格样式(参数:列号、开始行号、样式,列号和行号都是 0 开始)
writer.setColumnStyleIfHasData(1, 1, rowStyle);

效果如下:
在这里插入图片描述

指定单元格样式

选定指定的单元格,修改单元格的样式:

// 获得第二行第二列的样式
CellStyle rowStyle = writer.createCellStyle(1, 1);
// 设置前景色(下面两个语句)
rowStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rowStyle.setFillForegroundColor(IndexedColors.LIGHT_YELLOW.getIndex());
// 创建字体样式
Font cellFont = writer.createFont();
// 设置字体颜色
cellFont.setColor(IndexedColors.DARK_RED.index);
// 设置字体大小
cellFont.setFontHeightInPoints((short) 16);
// 设置字体类型
cellFont.setFontName("Microsoft YaHei UI");
rowStyle.setFont(cellFont);

效果如下:

在这里插入图片描述

设置数据有效性

Excel 的数据有效性有以下几种:
在这里插入图片描述

上面有八种数据有效性(任何值、整数、小数、序列、日期、时间、文本长度、自定义),但在 POI 中可以认为存在以下几种类型:

  1. CellType.NUMERIC 数值类型,包括:整数、小数、日期、时间。
  2. CellType.STRING 字符串类型,包括:任何值、序列、文本长度。
  3. CellType.FORMULA 公式类型,包括:自定义。
  4. CellType.BLANK 空值,只要是单元格为空,都是这个类型。
  5. CellType.BOOLEAN 布尔类型。(没怎么用到这个)
  6. CellType.ERROR 错误单元格。(没怎么用到这个)

整数

如下案例:设置单元格只能输入 1 ~ 100 的整数。

// 创建 Excel 文件
ExcelWriter writer = ExcelUtil.getWriter(new File("D:\\code\\xxx.xlsx"));
Sheet sheet = writer.getSheet();
// 插入表头数据
writer.writeHeadRow(new ArrayList<String>() {{
  add("年龄");
}});
// 设置数据有效性
String minNum = "1";
String maxNum = "100";
// 创建数据有效性助手对象
DataValidationHelper helper = sheet.getDataValidationHelper();
// 创建整数有效性
// 参数1:BETWEEN 介于两者之间;NOT_BETWEEN 不在两者之间;EQUAL 相等;NOT_EQUAL 不等;GREATER_THAN 大于;LESS_THAN 小于;GREATER_OR_EQUAL 大于等于;LESS_OR_EQUAL 小于等于;
DataValidationConstraint constraint = helper.createIntegerConstraint(DataValidationConstraint.OperatorType.BETWEEN, minNum, maxNum);
// 四个参数分别是:起始行、终止行、起始列、终止列(需要注意,因为表头已经占了一行,所以行以 1 开始)
DataValidation validation = helper.createValidation(constraint, new CellRangeAddressList(1, 65535, 0, 0));
validation.createErrorBox("输入有误", String.format("请输入%s~%s之间的整数", minNum, maxNum));
// 文件兼容处理【必须】
if (validation instanceof XSSFDataValidation) {
  validation.setShowErrorBox(true);
  validation.setSuppressDropDownArrow(true);
} else {
  validation.setSuppressDropDownArrow(false);
}
sheet.addValidationData(validation);
// 资源释放
writer.close();

效果如下:

在这里插入图片描述

需要注意的地方:

  • CellRangeAddressList(1, 65535, 0, 0) 方法处,这里没办法控制列下的所有行,只能通过指定范围的行,65535 还可以换成更大的数,行列的索引从 0 开始。
  • 文件兼容处理的代码必须要加上,不然会出现不生效的问题。

小数

如下案例:设置单元格只能输入 1 ~ 3 的数值。

// 创建 Excel 文件
ExcelWriter writer = ExcelUtil.getWriter(new File("D:\\code\\xxx.xlsx"));
Sheet sheet = writer.getSheet();
// 插入表头数据
writer.writeHeadRow(new ArrayList<String>() {{
  add("身高(m)");
}});
// 设置数据有效性
String minNum = "0";
String maxNum = "3";
// 创建数据有效性助手对象
DataValidationHelper helper = sheet.getDataValidationHelper();
// 创建整数有效性
// 参数1:ANY 任意值;INTEGER 整数;DECIMAL 小数;LIST 列表;DATE 时间;TIME 时间;TEXT_LENGTH 文本长度;FORMULA 正则/公式;
// 参数2:BETWEEN 介于两者之间;NOT_BETWEEN 不在两者之间;EQUAL 相等;NOT_EQUAL 不等;GREATER_THAN 大于;LESS_THAN 小于;GREATER_OR_EQUAL 大于等于;LESS_OR_EQUAL 小于等于;
DataValidationConstraint constraint = helper.createNumericConstraint(
  DataValidationConstraint.ValidationType.DECIMAL,
  DataValidationConstraint.OperatorType.BETWEEN,
  minNum,
  maxNum
);
// 四个参数分别是:起始行、终止行、起始列、终止列(需要注意,因为表头已经占了一行,所以以 1 开始)
DataValidation validation = helper.createValidation(constraint, new CellRangeAddressList(1, 65536, 0, 0));
validation.createErrorBox("输入有误", String.format("请输入%s~%s之间的数值", minNum, maxNum));
// 文件兼容处理【必须】
if (validation instanceof XSSFDataValidation) {
  validation.setShowErrorBox(true);
  validation.setSuppressDropDownArrow(true);
} else {
  validation.setSuppressDropDownArrow(false);
}
sheet.addValidationData(validation);
// 资源释放
writer.close();

效果如下:

在这里插入图片描述

序列/下拉

如下案例:添加下拉选择功能。

// 创建 Excel 文件
ExcelWriter writer = ExcelUtil.getWriter(new File("D:\\code\\xxx.xlsx"));
Sheet sheet = writer.getSheet();
// 插入表头数据
writer.writeHeadRow(new ArrayList<String>() {{
  add("序列/下拉");
}});
// 设置数据有效性
// 创建数据有效性助手对象
DataValidationHelper helper = sheet.getDataValidationHelper();
// 创建整数有效性
DataValidationConstraint constraint = helper.createExplicitListConstraint(
  new String[]{"类型1", "类型2", "类型3"}
);
// 四个参数分别是:起始行、终止行、起始列、终止列(需要注意,因为表头已经占了一行,所以以 1 开始)
DataValidation validation = helper.createValidation(constraint, new CellRangeAddressList(1, 65536, 0, 0));
validation.createErrorBox("输入有误", "请选择下拉选项的值");
// 文件兼容处理【必须】
if (validation instanceof XSSFDataValidation) {
  validation.setShowErrorBox(true);
  validation.setSuppressDropDownArrow(true);
} else {
  validation.setSuppressDropDownArrow(false);
}
sheet.addValidationData(validation);
// 资源释放
writer.close();

效果如下:

在这里插入图片描述

日期

如下案例:

// 创建 Excel 文件
ExcelWriter writer = ExcelUtil.getWriter(new File("D:\\code\\xxx.xlsx"));
Sheet sheet = writer.getSheet();
// 插入表头数据
writer.writeHeadRow(new ArrayList<String>() {{
  add("日期");
}});
// 设置数据有效性
String min = "date(1970,1,1)";
String max = "date(2024,12,32)";
// 创建数据有效性助手对象
DataValidationHelper helper = sheet.getDataValidationHelper();
// 创建整数有效性
// 参数1:BETWEEN 介于两者之间;NOT_BETWEEN 不在两者之间;EQUAL 相等;NOT_EQUAL 不等;GREATER_THAN 大于;LESS_THAN 小于;GREATER_OR_EQUAL 大于等于;LESS_OR_EQUAL 小于等于;
DataValidationConstraint constraint = helper.createDateConstraint(
  DataValidationConstraint.OperatorType.BETWEEN, min, max, "YYYY/MM/DD"
);
// 四个参数分别是:起始行、终止行、起始列、终止列(需要注意,因为表头已经占了一行,所以以 1 开始)
DataValidation validation = helper.createValidation(constraint, new CellRangeAddressList(1, 65536, 0, 0));
validation.createErrorBox("输入有误", String.format("请输入%s~%s范围内的日期值", "1970/1/1", "2024/12/32"));
// 文件兼容处理【必须】
if (validation instanceof XSSFDataValidation) {
  validation.setShowErrorBox(true);
  validation.setSuppressDropDownArrow(true);
} else {
  validation.setSuppressDropDownArrow(false);
}
sheet.addValidationData(validation);
// 资源释放
writer.close();

效果如下:

在这里插入图片描述

特别注意:

  • helper.createDateConstraint(OperatorType, min, max, dateFormat) 设置 min,max 时,一定要用 date() 函数,如 date(2020,12,12)

时间

案例如下:

// 创建 Excel 文件
ExcelWriter writer = ExcelUtil.getWriter(new File("D:\\code\\xxx.xlsx"));
Sheet sheet = writer.getSheet();
// 插入表头数据
writer.writeHeadRow(new ArrayList<String>() {{
  add("日期");
}});
// 设置数据有效性
String min = "time(9,0,0)";
String max = "time(18,0,0)";
// 创建数据有效性助手对象
DataValidationHelper helper = sheet.getDataValidationHelper();
// 创建整数有效性
// 参数1:BETWEEN 介于两者之间;NOT_BETWEEN 不在两者之间;EQUAL 相等;NOT_EQUAL 不等;GREATER_THAN 大于;LESS_THAN 小于;GREATER_OR_EQUAL 大于等于;LESS_OR_EQUAL 小于等于;
DataValidationConstraint constraint = helper.createTimeConstraint(
  DataValidationConstraint.OperatorType.BETWEEN, min, max
);
// 四个参数分别是:起始行、终止行、起始列、终止列(需要注意,因为表头已经占了一行,所以以 1 开始)
DataValidation validation = helper.createValidation(constraint, new CellRangeAddressList(1, 65536, 0, 0));
validation.createErrorBox("输入有误", String.format("请输入%s~%s范围内的时间值", "9:00:00", "18:00:00"));
// 文件兼容处理【必须】
if (validation instanceof XSSFDataValidation) {
  validation.setShowErrorBox(true);
  validation.setSuppressDropDownArrow(true);
} else {
  validation.setSuppressDropDownArrow(false);
}
sheet.addValidationData(validation);
// 资源释放
writer.close();

效果如下:

在这里插入图片描述

特别注意:

  • helper.createTimeConstraint() 传递的 time 值要用 time(),如:time(12,30,0)

文本长度

案例如下:

// 创建 Excel 文件
ExcelWriter writer = ExcelUtil.getWriter(new File("D:\\code\\xxx.xlsx"));
Sheet sheet = writer.getSheet();
// 插入表头数据
writer.writeHeadRow(new ArrayList<String>() {{
  add("字符");
}});
// 设置数据有效性
String min = "0";
String max = "10";
// 创建数据有效性助手对象
DataValidationHelper helper = sheet.getDataValidationHelper();
// 创建整数有效性
// 参数1:BETWEEN 介于两者之间;NOT_BETWEEN 不在两者之间;EQUAL 相等;NOT_EQUAL 不等;GREATER_THAN 大于;LESS_THAN 小于;GREATER_OR_EQUAL 大于等于;LESS_OR_EQUAL 小于等于;
DataValidationConstraint constraint = helper.createTextLengthConstraint(DataValidationConstraint.OperatorType.BETWEEN, min, max);
// 四个参数分别是:起始行、终止行、起始列、终止列(需要注意,因为表头已经占了一行,所以以 1 开始)
DataValidation validation = helper.createValidation(constraint, new CellRangeAddressList(1, 65536, 0, 0));
validation.createErrorBox("输入有误", String.format("请输入%s以内的字符数", max));
// 文件兼容处理【必须】
if (validation instanceof XSSFDataValidation) {
  validation.setShowErrorBox(true);
  validation.setSuppressDropDownArrow(true);
} else {
  validation.setSuppressDropDownArrow(false);
}
sheet.addValidationData(validation);
// 资源释放
writer.close();

效果如下:

在这里插入图片描述

本篇文章加入了一些本人狭隘的想法和理解,如有出现错误之处,欢迎指正,非常感谢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1091364.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CVE-2017-12615 Tomcat远程命令执行漏洞

漏洞简介 2017年9月19日&#xff0c;Apache Tomcat官方确认并修复了两个高危漏洞&#xff0c;漏洞CVE编号&#xff1a;CVE-2017-12615和CVE-2017-12616&#xff0c;其中 远程代码执行漏洞&#xff08;CVE-2017-12615&#xff09; 当 Tomcat 运行在 Windows 主机上&#xff0c;…

AutoDL平台transformers环境搭建

AutoDL平台transformers环境搭建 租借GPU可以参考 AutoDL平台租借GPU详解 一、激活base环境 1.进入终端 vim ~/.bashrc2、然后按英文模式的 i 进入编辑&#xff0c;按键盘下键到最后输入 source root/miniconda3/etc/profile.d/conda.sh3、然后先按键盘Esc键&#xff0c…

Linux系统编程01

C语言程序编译过程 多个源文件生成一个可执行文件的过程 预处理阶段主要是将带 # 号的类似于 #include #define #ifdef等进行处理替换 gcc -S 下面讲解C语言源代码编译成汇编语言之后&#xff0c;之间的对应情况 源代码 使用gcc -S test15.c -o test15.s指令让源代码进行编译…

Adaptive AUTOSAR CM模块介绍(五)

Proxy Class API’s proxy class类提供类&#xff08;静态&#xff09;方法来FindService() 实例&#xff0c;服务是动态的&#xff0c;因此&#xff0c;AUTOSAR提供了两个方法来提供发现服务。 StartFindService():是一个类方法&#xff0c;它在后台启动一个周期性的“FindS…

联想电脑的Microsoft Edge启动总是百度页面的修改方法

前言 拿到联想电脑&#xff0c;打开浏览器的搜索引擎默认是百度&#xff0c;在浏览器中的设置总是更改不了。这是因为联想管家启动浏览器保护&#xff0c;我们是无法更改的&#xff0c;除非在联想管家中更改启动页的打开网址。操作流程往下看。 操作 &#x1f388;打开联想管…

苹果放出快捷指令专题介绍页面,大大提高了 Mac 使用效率

近日&#xff0c;苹果发布 macOS Sonoma 更新的同时&#xff0c;还上线了“《快捷指令》助你效率倍增”专题页面&#xff0c;其目标是在 Mac 上让好用的 App 更强大。 快捷指令功能可以让设备自动完成常用或繁琐的操作&#xff0c;大大提升 Mac 的效率。 快捷指令能帮你在《邮…

4.Python-用Python,Ajax实现MySQL数据库的新增数据

题记 用python&#xff0c;ajax实现mysql数据库的新增数据。以下是一个简单的实例和操作过程。 安装flask模块 pip install flask 安装mysql.connector模块 pip install mysql-connector-python 编写app.py文件 app.py文件如下&#xff1a; 块引用可能显示不完整&#x…

为什么Excel插入图片不显示,点击能够显示

今天在做Excel表格时&#xff0c;发现上传图片后不能显示&#xff0c;但是点击还是能够出现图片的 点击如下 点击能看到&#xff0c;但是不显示&#xff1f;那么只需鼠标右键点击浮动即可显示

fastjson 1.2.24 反序列化导致任意命令执行漏洞

fastjson 1.2.24 反序列化导致任意命令执行漏洞 文章目录 fastjson 1.2.24 反序列化导致任意命令执行漏洞1 在线漏洞解读:2 环境搭建2.1 启动&#xff1a;2.2 已启动&#xff1a;访问端口8090 3 影响版本&#xff1a;4 漏洞复现4.1 访问页面4.2 bp抓包&#xff0c;修改参数4.2.…

每日一题 136. 只出现一次的数字(简单,位运算)

异或运算性质&#xff0c;两个相等的数作异或运算得零&#xff0c;任何数与零作异或运算保持不变 所以整个数组的异或和就是答案 class Solution:def singleNumber(self, nums: List[int]) -> int:ans 0for i in nums:ans ^ ireturn ans一行代码&#xff0c;reduce作累积操…

「AI反诈与智能风控」闭门研讨会报名丨青源Workshop第26期

青源Workshop丨No.26 AI反诈与智能风控&#xff1a;信息安全的矛与盾 AI红利接踵而至&#xff0c;安全风险如影随形。过去几年&#xff0c;人工智能技术的迅速发展催生了包括金融、电子商务、社交网络、医疗保健等众多应用场景。AI应用落地带来新安全风险&#xff0c;安全防护难…

Netty源码编译

Netty源码编译 想了解Netty源码&#xff0c;最好先从 netty-example 开始&#xff0c;多跑几个 example&#xff0c;了解Netty的实际应用。 编译 netty-example 会出现很多乱七八糟的问题&#xff0c;根本原因是因为缺少 io.netty.util.collection 包。 解决方法 1.先 instal…

渗透测试漏洞挖掘技巧

文章目录 一、使用.json进行敏感数据泄漏二、如何查找身份验证绕过漏洞三、在Drupal上找到隐藏的页面四、遗忘的数据库备份五、电子邮件地址payloads六、HTTP主机头&#xff1a;localhost七、通过篡改URI访问管理面板八、通过URL编码空格访问管理面板九、篡改URI绕过403十、Byp…

C# OpenVINO Cls 图像分类

效果 耗时 class idbrown_bear, score0.86 preprocess time: 0.00ms infer time: 2.72ms postprocess time: 0.02ms Total time: 2.74ms项目 代码 using OpenCvSharp; using Sdcb.OpenVINO; using Sdcb.OpenVINO.Natives; using System; using System.Diagnostics; using Sys…

忘记开机密码啦!我教你用ventoy找回密码

文章目录 一、前言二、实战过程三、动态演示四、原理解析五、总结 一、前言 当你有一天突然忘记了开机密码怎么办&#xff1f;又要上电脑店花个几十块让人弄&#xff1f;在上一章《你该自己学学安装操作系统了&#xff0c;小白一学就会&#xff08;ventoy装系统超详细&#xff…

舍弃Java模式,从头开始,用Rust书写编程的未来

沉迷于Rust之美&#xff1a;类型安全、内存安全、注重正确性&#xff0c;这叫人如何不爱呢&#xff1f; 在开发Apollo&#xff08;一款Python应用&#xff09;时&#xff0c;遇到了许多错误。如果我使用Rust&#xff0c;大多数错误都能被编译器捕获&#xff08;虽然无法做到百…

ubuntu联网图标消失

sudo service NetworkManager stopsudo rm /var/lib/NetworkManager/NetworkManager.statesudo service NetworkManager start执行 sudo rm /var/lib/NetworkManager/NetworkManager.state 命令将删除位于 /var/lib/NetworkManager 目录下的 NetworkManager.state 文件。

(C语言进阶)笔试题详解

一.要点回顾 1.一维整形数组 (1)sizeof()对一维整形数组的应用 #include<stdio.h> int main() {int a[] {1,2,3,4};printf("%d\n", sizeof(a));//16 //sizeof(数组名),数组名表示整个数组&#xff0c;计算的是整个数组的大小&#xff0c;单位是字节printf…

微信小程序备案流程操作详解

1、2023年9月1号小程序开始必须备案了,各位小程序商城只需要按流程自主去微信小程序后台操作即可; 2、对未上架的微信小程序,从2023年9月1号开始需先备案才能上架; 3、对存量已上架的小程序,需在2024年3月31号前完成备案即可。逾期未完成备案,平台将按照备案相关规定于…

英语学习工具推荐

无论您是初学者还是想要巩固英语能力的学习者&#xff0c;我们都为您提供了一个高效而便捷的英语学习工具。 英语复读机&#xff0c;您可以随时输入您想要复读的英语单词、句子或者文章。我们的复读机会循环播放您输入的内容&#xff0c;帮助您加深记忆、提高听力和口语表达能力…