docs: 更新代码文档并添加项目元数据

- 为所有主要类和方法添加了详细的 JavaDoc 注释
- 更新了 pom.xml 文件,添加了项目元数据信息
- 优化了代码结构,提高了代码可读性和可维护性
This commit is contained in:
liushuang 2025-08-14 11:48:10 +08:00
parent 7bac7917a0
commit 52620ab108
12 changed files with 497 additions and 24 deletions

107
pom.xml

@ -6,7 +6,39 @@
<groupId>cn.isliu</groupId>
<artifactId>feishu-table-helper</artifactId>
<version>1.0-SNAPSHOT</version>
<version>0.0.1</version>
<name>${project.groupId}:${project.artifactId}</name>
<description>
Feishu Table Assistant makes reading and writing operations on Feishu tables extremely simple.
</description>
<url>https://github.com/luckday-cn/feishu-table-helper</url>
<licenses>
<license>
<name>The Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<developers>
<developer>
<name>liu</name>
<email>luckday@isliu.cn</email>
<url>https://github.com/luckday-cn/feishu-table-helper</url>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/luckday-cn/feishu-table-helper.git</connection>
<developerConnection>scm:git:ssh://github.com/luckday-cn/feishu-table-helper.git</developerConnection>
<url>http://github.com/luckday-cn/feishu-table-helper/tree/master</url>
</scm>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/luckday-cn/feishu-table-helper/issues</url>
</issueManagement>
<properties>
<maven.compiler.source>8</maven.compiler.source>
@ -31,4 +63,77 @@
<version>2.8.9</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<additionalJOptions>
<additionalJOption>-Xdoclint:none</additionalJOption>
</additionalJOptions>
<maxmemory>1024</maxmemory>
<encoding>UTF-8</encoding>
<show>protected</show>
<notree>true</notree>
<!-- Avoid running into Java 8's very restrictive doclint issues -->
<failOnError>false</failOnError>
<doclint>none</doclint>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.4.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
<tokenAuth>true</tokenAuth>
<deploymentName>${project.groupId}:${project.artifactId}:${project.version}</deploymentName>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -14,8 +14,26 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
* 飞书表格助手主入口类
*
* 提供对飞书表格的创建读取和写入操作的统一接口
* 通过实体类注解映射简化对飞书表格的操作
*/
public class FsHelper {
/**
* 创建飞书表格
*
* 根据传入的实体类结构在指定的电子表格中创建一个新的工作表
* 并设置表头样式单元格格式和下拉选项等
*
* @param sheetName 工作表名称
* @param spreadsheetToken 电子表格Token
* @param clazz 实体类Class对象用于解析表头和字段属性
* @param <T> 实体类泛型
* @return 创建成功返回true
*/
public static <T> Boolean create(String sheetName, String spreadsheetToken, Class<T> clazz) {
Map<String, FieldProperty> fieldsMap = PropertyUtil.getTablePropertyFieldsMap(clazz);
List<String> headers = PropertyUtil.getHeaders(fieldsMap);
@ -41,6 +59,17 @@ public class FsHelper {
}
/**
* 从飞书表格中读取数据
*
* 根据指定的工作表ID和电子表格Token读取表格数据并映射到实体类对象列表中
*
* @param sheetId 工作表ID
* @param spreadsheetToken 电子表格Token
* @param clazz 实体类Class对象用于数据映射
* @param <T> 实体类泛型
* @return 映射后的实体类对象列表
*/
public static <T> List<T> read(String sheetId, String spreadsheetToken, Class<T> clazz) {
List<T> results = new ArrayList<>();
Sheet sheet = FsApiUtil.getSheetMetadata(sheetId, FsClientUtil.getFeishuClient(), spreadsheetToken);
@ -64,6 +93,17 @@ public class FsHelper {
return results;
}
/**
* 将数据写入飞书表格
*
* 将实体类对象列表写入到指定的飞书表格中支持新增和更新操作
*
* @param sheetId 工作表ID
* @param spreadsheetToken 电子表格Token
* @param dataList 实体类对象列表
* @param <T> 实体类泛型
* @return 写入操作结果
*/
public static <T> Object write(String sheetId, String spreadsheetToken, List<T> dataList) {
if (dataList.isEmpty()) {
return null;

@ -1,14 +1,33 @@
package cn.isliu.core;
/**
* 实体类基类
*
* 所有需要与飞书表格进行映射的实体类都应该继承此类
* 以便提供统一的唯一标识符管理功能
*/
public abstract class BaseEntity {
/**
* 唯一标识符用于标识表格中的行数据
*/
public String uniqueId;
/**
* 获取唯一标识符
*
* @return 唯一标识符字符串
*/
public String getUniqueId() {
return uniqueId;
}
/**
* 设置唯一标识符
*
* @param uniqueId 唯一标识符字符串
*/
public void setUniqueId(String uniqueId) {
this.uniqueId = uniqueId;
}
}
}

@ -7,22 +7,66 @@ import cn.isliu.core.enums.TypeEnum;
import java.lang.annotation.*;
/**
* 表格属性注解
*
* 用于标记实体类字段与飞书表格列的映射关系
* 支持配置列名字段类型枚举类格式化处理类等属性
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface TableProperty {
/**
* 表格列名
*
* @return 列名字符串
*/
String value() default "";
/**
* 字段名
*
* @return 字段名字符串
*/
String field() default "";
/**
* 字段排序顺序
*
* @return 排序值数值越小越靠前
*/
int order() default Integer.MAX_VALUE;
/**
* 字段类型
*
* @return 字段类型枚举
*/
TypeEnum type() default TypeEnum.TEXT;
/**
* 枚举类
*
* 用于 SINGLE_SELECT MULTI_SELECT 类型的字段
* @return 枚举类Class对象
*/
Class<? extends BaseEnum> enumClass() default BaseEnum.class;
/**
* 字段格式化处理类
*
* 用于自定义字段值的处理逻辑
* @return 字段值处理类Class对象
*/
Class<? extends FieldValueProcess> fieldFormatClass() default FieldValueProcess.class;
/**
* 选项处理类
*
* 用于处理下拉选项等特殊字段类型
* @return 选项值处理类Class对象
*/
Class<? extends OptionsValueProcess> optionsClass() default OptionsValueProcess.class;
}
}

@ -1,35 +1,91 @@
package cn.isliu.core.enums;
/**
* 字段类型枚举
*
* 定义飞书表格支持的字段类型用于在实体类注解中指定字段的数据类型
*/
public enum TypeEnum {
/**
* 单选类型
*/
SINGLE_SELECT("SINGLE_SELECT", "单选"),
/**
* 多选类型
*/
MULTI_SELECT("MULTI_SELECT", "多选"),
/**
* 文本类型
*/
TEXT("TEXT", "文本"),
/**
* 数字类型
*/
NUMBER("NUMBER", "数字"),
/**
* 日期类型
*/
DATE("DATE", "日期"),
/**
* 文本文件类型
*/
TEXT_FILE("TEXT_FILE", "文本文件"),
/**
* 多个文本逗号分割类型
*/
MULTI_TEXT("MULTI_TEXT", "多个文本(逗号分割)"),
TEXT_URL("TEXT_URL", "文本链接")
;
/**
* 文本链接类型
*/
TEXT_URL("TEXT_URL", "文本链接");
private final String code;
private final String desc;
/**
* 获取类型编码
*
* @return 类型编码字符串
*/
public String getCode() {
return code;
}
/**
* 获取类型描述
*
* @return 类型描述字符串
*/
public String getDesc() {
return desc;
}
/**
* 构造函数
*
* @param code 类型编码
* @param desc 类型描述
*/
TypeEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
/**
* 根据编码获取枚举值
*
* @param code 类型编码
* @return 对应的枚举值未找到返回null
*/
public static TypeEnum getByCode(String code) {
for (TypeEnum value : values()) {
if (value.getCode().equals(code)) {
@ -38,4 +94,4 @@ public enum TypeEnum {
}
return null;
}
}
}

@ -5,51 +5,117 @@ import cn.isliu.core.converters.FieldValueProcess;
import cn.isliu.core.enums.BaseEnum;
import cn.isliu.core.enums.TypeEnum;
/**
* 字段属性类
*
* 封装实体类字段的属性信息包括字段名和对应的表格属性注解信息
*/
public class FieldProperty {
/**
* 字段名
*/
private String field;
/**
* 表格属性注解
*/
private TableProperty tableProperty;
/**
* 无参构造函数
*/
public FieldProperty() {
}
/**
* 构造函数
*
* @param field 字段名
* @param tableProperty 表格属性注解
*/
public FieldProperty(String field, TableProperty tableProperty) {
this.field = field;
this.tableProperty = tableProperty;
}
/**
* 获取字段名
*
* @return 字段名字符串
*/
public String getField() {
return field;
}
/**
* 设置字段名
*
* @param field 字段名字符串
*/
public void setField(String field) {
this.field = field;
}
/**
* 获取表格属性注解
*
* @return 表格属性注解对象
*/
public TableProperty getTableProperty() {
return tableProperty;
}
/**
* 设置表格属性注解
*
* @param tableProperty 表格属性注解对象
*/
public void setTableProperty(TableProperty tableProperty) {
this.tableProperty = tableProperty;
}
/**
* 获取字段名注解中的field属性
*
* @return 字段名字符串
*/
public String getFieldField() {
return tableProperty.field();
}
/**
* 获取列名注解中的value属性
*
* @return 列名字符串
*/
public String getFieldName() {
return tableProperty.value();
}
/**
* 获取字段类型
*
* @return 字段类型枚举
*/
public TypeEnum getFieldType() {
return tableProperty.type();
}
/**
* 获取字段格式化处理类
*
* @return 字段值处理类Class对象
*/
public Class<? extends FieldValueProcess> getFieldFormat() {
return tableProperty.fieldFormatClass();
}
/**
* 获取字段枚举类
*
* @return 枚举类Class对象
*/
public Class<? extends BaseEnum> getFieldEnum() {
return tableProperty.enumClass();
}
@ -62,4 +128,4 @@ public class FieldProperty {
'}';
}
}
}

@ -13,7 +13,10 @@ import java.util.ArrayList;
import java.util.List;
/**
* 自定义数据值服务 提供官方SDK未覆盖的数据操作API
* 自定义数据值服务
*
* 提供官方SDK未覆盖的数据操作API封装了对飞书表格数据的批量操作功能
* 包括读取写入插入追加等操作
*/
public class CustomValueService extends FeishuApiClient {

@ -17,10 +17,25 @@ import java.util.stream.Collectors;
import java.lang.reflect.InvocationTargetException;
/**
* 字段转换工具类
*
* 提供将飞书表格数据转换为实体类字段值的工具方法
* 支持不同字段类型的转换处理
*/
public class ConvertFieldUtil {
private static final Logger log = Logger.getLogger(ConvertFieldUtil.class.getName());
private static final Gson gson = new Gson();
/**
* 将位置键转换为字段名
*
* 根据字段属性映射关系将表格中的位置键"A1"转换为实体类字段名
*
* @param jsonObject 包含位置键值对的JSON对象
* @param fieldsMap 字段属性映射关系Map
* @return 转换后的字段名值映射Map
*/
public static Map<String, Object> convertPositionToField(JsonObject jsonObject, Map<String, FieldProperty> fieldsMap) {
Map<String, Object> result = new HashMap<>();
@ -45,6 +60,15 @@ public class ConvertFieldUtil {
return result;
}
/**
* 根据字段规则获取值
*
* 根据字段类型和配置规则处理字段值
*
* @param tableProperty 表格属性注解
* @param value 原始值
* @return 处理后的值
*/
private static Object getValueByFieldRule(TableProperty tableProperty, JsonElement value) {
if (tableProperty == null || value == null || value.isJsonNull()) {
return null;
@ -90,6 +114,14 @@ public class ConvertFieldUtil {
return result;
}
/**
* 获取文本链接
*
* 从JSON元素中提取文本链接信息
*
* @param value JSON元素
* @return 文本链接列表
*/
private static Object getTextUrl(JsonElement value) {
if (value instanceof JsonArray) {
List<String> fileUrls = new ArrayList<>();

@ -29,6 +29,11 @@ import java.util.logging.Logger;
import java.util.logging.Level;
/**
* 飞书API工具类
*
* 封装了与飞书表格API交互的各种操作方法包括数据读取元数据获取单元格合并等操作
*/
public class FsApiUtil {
private static final Gson gson = new Gson();
@ -36,6 +41,18 @@ public class FsApiUtil {
private static final String REQ_TYPE = "JSON_STR";
public static final int DEFAULT_ROW_NUM = 1000;
/**
* 获取工作表数据
*
* 从指定的飞书表格中读取指定范围的数据
*
* @param sheetId 工作表ID
* @param spreadsheetToken 电子表格Token
* @param startPosition 起始位置"A1"
* @param endPosition 结束位置"Z100"
* @param client 飞书客户端
* @return 表格数据对象
*/
public static ValuesBatch getSheetData(String sheetId, String spreadsheetToken, String startPosition, String endPosition, FeishuClient client) {
ValuesBatch valuesBatch = null;
try {
@ -64,6 +81,16 @@ public class FsApiUtil {
return valuesBatch;
}
/**
* 获取工作表元数据
*
* 获取指定工作表的元数据信息包括行列数工作表名称等
*
* @param sheetId 工作表ID
* @param client 飞书客户端
* @param spreadsheetToken 电子表格Token
* @return 工作表对象
*/
public static Sheet getSheetMetadata(String sheetId, FeishuClient client, String spreadsheetToken) {
try {
QuerySpreadsheetSheetReq req = QuerySpreadsheetSheetReq.newBuilder()
@ -98,6 +125,16 @@ public class FsApiUtil {
}
}
/**
* 合并单元格
*
* 在指定工作表中合并指定范围的单元格
*
* @param cell 合并范围"A1:B2"
* @param sheetId 工作表ID
* @param client 飞书客户端
* @param spreadsheetToken 电子表格Token
*/
public static void mergeCells(String cell, String sheetId, FeishuClient client, String spreadsheetToken) {
try {
CustomCellService.CellBatchUpdateRequest batchMergeRequest = CustomCellService.CellBatchUpdateRequest.newBuilder()

@ -13,8 +13,23 @@ import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;
/**
* 飞书表格工具类
*
* 提供处理飞书表格数据和格式的工具方法
* 包括数据处理样式设置选项设置等功能
*/
public class FsTableUtil {
/**
* 获取飞书表格数据
*
* 从指定的工作表中读取并处理表格数据
*
* @param sheet 工作表对象
* @param spreadsheetToken 电子表格Token
* @return 飞书表格数据列表
*/
public static List<FsTableData> getFsTableData(Sheet sheet, String spreadsheetToken) {
// 计算数据范围
@ -71,10 +86,23 @@ public class FsTableUtil {
}).collect(Collectors.toList());
}
/**
* 获取飞书表格数据
*
* @param tableData 表格数据对象
* @return 飞书表格数据列表
*/
private static List<FsTableData> getFsTableData(TableData tableData) {
return getFsTableData(tableData, new ArrayList<>());
}
/**
* 获取飞书表格数据
*
* @param tableData 表格数据对象
* @param ignoreUniqueFields 忽略的唯一字段列表
* @return 飞书表格数据列表
*/
private static List<FsTableData> getFsTableData(TableData tableData, List<String> ignoreUniqueFields) {
List<FsTableData> fsTableList = new LinkedList<>();
@ -308,16 +336,4 @@ public class FsTableUtil {
colorTemplate = colorTemplate.replace("FORE_COLOR", FsConfig.FORE_COLOR).replace("BACK_COLOR", FsConfig.BACK_COLOR);
return colorTemplate;
}
public static void main(String[] args) {
FsConfig.initConfig("cli_a73813628afbd00d", "ouFTDr0Qu5WCgoPS8mgULg6uT0lDEUtX");
String sheetId = "2HokFi";
String spreadsheetToken = "SYRysUIcaheEbNt8KTocxRBinCh";
Sheet sheet = FsApiUtil.getSheetMetadata(sheetId, FsClientUtil.getFeishuClient(), spreadsheetToken);
Map<String, String> headFieldMap = getTitlePostionMap(sheet, spreadsheetToken);
System.out.println(headFieldMap);
}
}

@ -15,12 +15,24 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* 实例生成工具类
*
* 提供根据数据映射关系生成实体类实例的工具方法
* 支持嵌套对象和集合类型的处理
*/
public class GenerateUtil {
private static final Logger log = Logger.getLogger(GenerateUtil.class.getName());
/**
* 根据配置和数据生成DTO对象通用版本
*
* @param fieldPathList 字段路径列表
* @param clazz 实体类Class对象
* @param dataMap 数据映射Map
* @param <T> 实体类泛型
* @return 实体类实例
*/
public static <T> T generateInstance(List<String> fieldPathList, Class<T> clazz, Map<String, Object> dataMap) {
T t;
@ -47,6 +59,11 @@ public class GenerateUtil {
/**
* 递归设置嵌套字段值支持List类型处理
*
* @param target 目标对象
* @param fieldPath 字段路径
* @param value 字段值
* @throws Exception 设置字段时可能抛出的异常
*/
private static void setNestedField(Object target, String fieldPath, Object value)
throws Exception {
@ -54,6 +71,15 @@ public class GenerateUtil {
setNestedFieldRecursive(target, parts, 0, value);
}
/**
* 递归设置嵌套字段值
*
* @param target 目标对象
* @param parts 字段路径分段数组
* @param index 当前处理的字段索引
* @param value 字段值
* @throws Exception 设置字段时可能抛出的异常
*/
private static void setNestedFieldRecursive(Object target, String[] parts, int index, Object value)
throws Exception {
if (index >= parts.length - 1) {
@ -101,7 +127,7 @@ public class GenerateUtil {
try {
nestedObj = field.getType().getDeclaredConstructor().newInstance();
field.set(target, nestedObj);
} catch (Exception e) {
} catch (InstantiationException e) {
// 如果无法创建实例则记录日志并跳过该字段
log.log(Level.WARNING, "无法创建嵌套对象实例: " + field.getType().getName() + ", 字段: " + fieldName, e);
return;
@ -109,7 +135,7 @@ public class GenerateUtil {
}
}
// 递归处理下一级
// 递归处理下一级字段
setNestedFieldRecursive(nestedObj, parts, index + 1, value);
}

@ -15,12 +15,24 @@ import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;
/**
* 属性工具类
*
* 提供处理实体类属性和注解的相关工具方法
* 主要用于解析@TableProperty注解并构建字段映射关系
*/
public class PropertyUtil {
/**
* 获取类及其嵌套类上@TableProperty注解的字段映射关系
* 注解中的值作为keyFieldProperty对象作为value
*
* 此方法是入口方法用于获取一个类及其所有嵌套类中
* @TableProperty注解标记的字段的映射关系
* 注解中的值作为keyFieldProperty对象作为value返回
*
* 对于嵌套属性使用'.'连接符来表示层级关系
* 该方法会过滤掉有子级的字段只返回最底层的字段映射
*
* @param clazz 要处理的类
* @return 包含所有@TableProperty注解字段映射关系的Map嵌套属性使用'.'连接
*/
@ -42,6 +54,11 @@ public class PropertyUtil {
/**
* 递归获取类及其嵌套类上@TableProperty注解的字段映射关系
*
* 这是一个递归方法用于深入处理类的继承结构和嵌套结构
* 收集所有被@TableProperty注解标记的字段信息
*
* 方法会处理循环引用问题并限制递归深度防止栈溢出
*
* @param clazz 当前处理的类
* @param result 存储结果的Map
* @param keyPrefix key的前缀使用注解中的值构建
@ -302,6 +319,9 @@ public class PropertyUtil {
/**
* 判断是否为复杂类型非基本类型包装类型或String
*
* 此方法用于判断一个类是否为复杂类型即需要进一步处理的类型
* 复杂类型通常包含嵌套字段需要递归处理其内部结构
*
* @param clazz 要判断的类
* @return 是否为复杂类型
*/
@ -326,6 +346,15 @@ public class PropertyUtil {
clazz.equals(java.time.LocalDateTime.class));
}
/**
* 从字段属性映射中提取表头列表
*
* 此方法根据字段的@TableProperty注解中的order属性对字段进行排序
* 返回按顺序排列的表头列表用于数据展示时的列顺序
*
* @param fieldsMap 字段属性映射
* @return 按顺序排列的表头列表
*/
@NotNull
public static List<String> getHeaders(Map<String, FieldProperty> fieldsMap) {
return fieldsMap.entrySet().stream()