java可通过自定义@fieldmap注解配合反射实现entity到dto的字段映射转换:注解标记源字段名或忽略字段,工具类遍历dto字段、读取源对象对应值并设入,支持基础类型自动转换。

Java 中可以通过自定义注解配合反射,实现轻量级的实体(Entity)到数据传输对象(DTO)的字段映射与赋值。核心思路是:用注解标记字段映射关系,运行时通过反射读取源对象字段值,按规则写入目标 DTO 对应字段。
定义映射注解 @FieldMap
创建一个运行时保留的注解,用于指定字段映射来源:
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldMap {
String value() default ""; // 指定源字段名,为空则默认同名
boolean ignore() default false; // 是否忽略该字段
}
编写通用转换工具类
使用反射遍历 DTO 的所有声明字段,检查是否有 @FieldMap 注解,然后从源对象中提取对应值并设入:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
public class EntityToDtoConverter {
public static <t> T convert(Object source, Class<t> targetClass) {
try {
T target = targetClass.getDeclaredConstructor().newInstance();
// 遍历 DTO 的每个字段
for (Field targetField : targetClass.getDeclaredFields()) {
targetField.setAccessible(true);
FieldMap annotation = targetField.getAnnotation(FieldMap.class);
if (annotation == null || annotation.ignore()) continue;
// 确定源字段名
String sourceFieldName = annotation.value();
if (sourceFieldName.isEmpty()) {
sourceFieldName = targetField.getName();
}
// 从 source 中获取对应字段值
Object value = getFieldValue(source, sourceFieldName);
if (value != null) {
setFieldValue(target, targetField, value);
}
}
return target;
} catch (Exception e) {
throw new RuntimeException("转换失败", e);
}
}
private static Object getFieldValue(Object obj, String fieldName) {
try {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
return null;
}
}
private static void setFieldValue(Object target, Field field, Object value) {
try {
// 类型兼容性简单处理(如 Long → long、String → Integer)
Class> targetType = field.getType();
if (value.getClass() != targetType && targetType.isAssignableFrom(value.getClass())) {
field.set(target, value);
} else if (targetType == Integer.class || targetType == int.class) {
field.set(target, Integer.parseInt(String.valueOf(value)));
} else if (targetType == Long.class || targetType == long.class) {
field.set(target, Long.parseLong(String.valueOf(value)));
} else if (targetType == String.class) {
field.set(target, String.valueOf(value));
} else {
field.set(target, value);
}
} catch (Exception e) {
// 忽略不匹配字段,或记录日志
}
}
}</t></t>
使用示例
假设有如下实体和 DTO:
public class UserEntity {
private Long id;
private String userName;
private Integer age;
// getter/setter...
}
public class UserDTO {
@FieldMap("id") private Long userId;
@FieldMap("userName") private String name;
@FieldMap("age") private Integer userAge;
@FieldMap(ignore = true) private String unused;
// getter/setter...
}
// 调用
UserEntity entity = new UserEntity();
entity.setId(100L);
entity.setUserName("Alice");
entity.setAge(25);
UserDTO dto = EntityToDtoConverter.convert(entity, UserDTO.class);
// dto.userId == 100L, dto.name == "Alice", dto.userAge == 25
注意事项与扩展方向
这个简易方案适合学习和小规模场景,实际项目中建议注意以下几点:
- 反射性能较低,可考虑缓存 Field 对象或生成字节码(如用 ByteBuddy)
- 类型转换仅支持常见基础类型,复杂嵌套对象需递归处理或引入 converter 接口
- 缺少空安全、泛型擦除处理、集合字段映射等高级能力
- 生产环境推荐使用成熟框架如 MapStruct(编译期生成)、Dozer 或 ModelMapper(运行时反射+配置)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










