Java实体类通用字段处理最佳实践 - SkcEntityUtils工具类详解
发布于
# java
优雅处理实体类的通用字段 - SkcEntityUtils工具类详解
在企业级应用开发中,我们经常需要处理实体类的一些通用字段,比如创建人、创建时间、更新人、更新时间以及租户相关信息等。这些字段的处理往往是重复且机械的工作。今天要介绍的SkcEntityUtils
工具类就是为了解决这个问题而设计的,它使用反射和函数式编程的特性,优雅地处理了这些通用字段的赋值问题。
1. 工具类的主要功能
SkcEntityUtils
主要提供了三类字段的自动填充功能:
- 创建相关字段(createId, createName, createTime)
- 更新相关字段(updateId, updateName, updateTime)
- 租户相关字段(tenantsid, tenantName, tenantId)
2. 核心设计
2.1 字段映射配置
工具类使用了三个不可变Map来存储字段名称和对应的值提供者(Supplier):
private static final Map<String, Supplier<?>> createFieldSuppliers;
private static final Map<String, Supplier<?>> updateFieldSuppliers;
private static final Map<String, Supplier<?>> tenantFieldSuppliers;
每个Map在静态初始化块中被初始化,并使用Collections.unmodifiableMap
确保线程安全性。
2.2 函数式编程应用
工具类巧妙地使用了Java 8的Supplier
函数式接口,为每个字段提供值的获取方式:
createMap.put("createId", KaiAuthTokenUtil::getUserId);
createMap.put("createTime", Date::new);
这种设计的优势在于:
- 代码简洁优雅
- 延迟执行,只有在需要时才会调用获取值
- 易于扩展和修改
2.3 反射机制的应用
工具类通过Java反射机制动态设置字段值:
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
if (field.get(entity) == null) {
field.set(entity, valueSupplier.get());
}
这样的设计允许我们:
- 动态访问和修改私有字段
- 只在字段为null时才设置值,避免覆盖已有数据
- 优雅处理字段不存在的情况
3. 使用示例
// 创建实体对象
UserEntity user = new UserEntity();
// 设置创建相关字段
SkcEntityUtils.setCreateFields(user);
// 设置更新相关字段
SkcEntityUtils.setUpdateFields(user);
// 设置租户相关字段
SkcEntityUtils.setTenantFields(user);
4. 最佳实践建议
- 统一字段命名规范:确保实体类中的字段名称与工具类中定义的一致
- 异常处理:根据业务需求适当处理字段不存在的情况
- 权限控制:确保
KaiAuthTokenUtil
在获取用户信息时有正确的权限设置 - 性能考虑:由于使用反射,在高并发场景下需要注意性能影响
5. 扩展性
这个工具类的设计非常容易扩展:
- 添加新的字段映射:只需在相应的Map中添加新的键值对
- 添加新的字段类型:得益于泛型的使用,支持任意类型的字段
- 添加新的功能:可以参考现有模式添加新的字段组
6. 总结
SkcEntityUtils
是一个设计优雅的工具类,它:
- 减少了重复代码
- 提高了代码的可维护性
- 使用现代Java特性提供了优雅的解决方案
- 具有良好的扩展性
附上代码
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Supplier;
@Slf4j
public class SkcEntityUtils {
private static final Map<String, Supplier<?>> createFieldSuppliers;
private static final Map<String, Supplier<?>> updateFieldSuppliers;
private static final Map<String, Supplier<?>> tenantFieldSuppliers;
static {
Map<String, Supplier<?>> createMap = new HashMap<>();
createMap.put("createId", KaiAuthTokenUtil::getUserId);
createMap.put("createName", KaiAuthTokenUtil::getUserName);
createMap.put("createTime", Date::new);
createFieldSuppliers = Collections.unmodifiableMap(createMap);
Map<String, Supplier<?>> updateMap = new HashMap<>();
updateMap.put("updateId", KaiAuthTokenUtil::getUserId);
updateMap.put("updateName", KaiAuthTokenUtil::getUserName);
updateMap.put("updateTime", Date::new);
updateFieldSuppliers = Collections.unmodifiableMap(updateMap);
Map<String, Supplier<?>> tenantMap = new HashMap<>();
tenantMap.put("tenantsid", KaiAuthTokenUtil::getTenantSid);
tenantMap.put("tenantName", KaiAuthTokenUtil::getTenantName);
tenantMap.put("tenantId", KaiAuthTokenUtil::getTenantId);
tenantFieldSuppliers = Collections.unmodifiableMap(tenantMap);
}
public static void setCreateFields(Object entity) {
setFields(entity, createFieldSuppliers);
}
public static void setUpdateFields(Object entity) {
setFields(entity, updateFieldSuppliers);
}
public static void setTenantFields(Object entity) {
setFields(entity, tenantFieldSuppliers);
}
private static void setFields(Object entity, Map<String, Supplier<?>> fieldSuppliers) {
if (entity == null) {
return;
}
Class<?> clazz = entity.getClass();
fieldSuppliers.forEach((fieldName, valueSupplier) -> {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
if (field.get(entity) == null) {
field.set(entity, valueSupplier.get());
}
} catch (NoSuchFieldException | IllegalAccessException e) {
// 如果字段不存在或无法访问,我们可以选择忽略它
// 或者记录日志,取决于您的需求
log.error("no such field {}", fieldName);
}
});
}
}
在实际开发中,这样的工具类可以大大提高开发效率,特别是在处理包含大量通用字段的实体类时。