You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何实现Dto与Entity互转?UserDto转UserEntity及表创建方案

一、先修正UserEntity配置,保证数据库表正确生成

首先要修正JPA注解的错误,确保实体类能被JPA正确解析并生成对应表结构:

import jakarta.persistence.*; // 或 javax.persistence.*,根据你的JPA版本选择
import java.util.List;

@Entity
@Table(name = "user") // 可指定表名,不指定默认以类名小写作为表名
public class UserEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 主键自增,根据数据库类型调整策略
    private int id;

    // 注意:userId字段无明确业务意义,建议删除,否则会生成多余的数据库列
    // private int userId;

    @Column(name = "parent_id")
    private Integer parentId; // 用Integer类型,支持存储null(根节点的父ID应为null)

    private String name;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "parent_id", referencedColumnName = "id") // 明确关联父表的主键字段
    private List<UserEntity> users;

    // JPA必须的无参构造函数
    public UserEntity() {}

    // Getter & Setter方法
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }

    public Integer getParentId() { return parentId; }
    public void setParentId(Integer parentId) { this.parentId = parentId; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public List<UserEntity> getUsers() { return users; }
    public void setUsers(List<UserEntity> users) { this.users = users; }
}

关键配置说明:

  • @Id必须大写,否则JPA无法识别主键
  • 添加@GeneratedValue指定主键生成策略,避免手动维护主键值
  • parentId用Integer类型,适配根节点无父ID的场景(int类型无法存储null)
  • @OneToMany添加orphanRemoval = true,确保删除父节点时自动清理关联的子节点(可选,根据业务需求调整)
  • 必须提供无参构造函数,JPA实例化实体时依赖该方法

配置完成后,JPA会自动生成一张user表,结构如下:

字段名类型约束
idint主键、自增
parent_idint外键(关联id)、允许为空
namevarchar允许为空
二、实现UserDto与UserEntity的相互映射

方式1:手动编写映射工具类

适合简单场景,无需引入第三方依赖:

import java.util.ArrayList;
import java.util.List;

public class UserMapper {
    // UserDto转UserEntity
    public static UserEntity dtoToEntity(UserDto dto) {
        if (dto == null) return null;

        UserEntity entity = new UserEntity();
        entity.setId(dto.getId());
        entity.setName(dto.getName());

        // 递归转换嵌套的子节点列表,并设置子节点的parentId
        if (dto.getUsers() != null && !dto.getUsers().isEmpty()) {
            List<UserEntity> childEntities = new ArrayList<>();
            for (UserDto childDto : dto.getUsers()) {
                UserEntity childEntity = dtoToEntity(childDto);
                childEntity.setParentId(entity.getId());
                childEntities.add(childEntity);
            }
            entity.setUsers(childEntities);
        }
        return entity;
    }

    // UserEntity转UserDto
    public static UserDto entityToDto(UserEntity entity) {
        if (entity == null) return null;

        UserDto dto = new UserDto();
        dto.setId(entity.getId());
        dto.setName(entity.getName());

        // 递归转换嵌套的子节点列表
        if (entity.getUsers() != null && !entity.getUsers().isEmpty()) {
            List<UserDto> childDtos = new ArrayList<>();
            for (UserEntity childEntity : entity.getUsers()) {
                childDtos.add(entityToDto(childEntity));
            }
            dto.setUsers(childDtos);
        }
        return dto;
    }

    // 批量转换方法(可选)
    public static List<UserEntity> dtoListToEntityList(List<UserDto> dtoList) {
        if (dtoList == null) return null;
        List<UserEntity> entityList = new ArrayList<>();
        for (UserDto dto : dtoList) {
            entityList.add(dtoToEntity(dto));
        }
        return entityList;
    }

    public static List<UserDto> entityListToDtoList(List<UserEntity> entityList) {
        if (entityList == null) return null;
        List<UserDto> dtoList = new ArrayList<>();
        for (UserEntity entity : entityList) {
            dtoList.add(entityToDto(entity));
        }
        return dtoList;
    }
}

使用示例:

// DTO转Entity
UserDto userDto = new UserDto();
userDto.setId(1);
userDto.setName("张三");
UserEntity userEntity = UserMapper.dtoToEntity(userDto);

// Entity转DTO
UserDto convertedDto = UserMapper.entityToDto(userEntity);

方式2:使用MapStruct自动生成映射代码

适合复杂场景,减少重复代码编写,需引入第三方依赖:

1. 添加Maven依赖

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version>
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.5.5.Final</version>
    <scope>provided</scope>
</dependency>

2. 定义Mapper接口

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.List;

@Mapper
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    // UserDto转UserEntity,忽略parentId(需手动设置)
    @Mapping(target = "parentId", ignore = true)
    UserEntity dtoToEntity(UserDto dto);

    // 递归转换子节点列表
    List<UserEntity> dtoListToEntityList(List<UserDto> dtoList);

    // UserEntity转UserDto
    UserDto entityToDto(UserEntity entity);

    // 递归转换子节点列表
    List<UserDto> entityListToDtoList(List<UserEntity> entityList);
}

3. 使用示例

// DTO转Entity
UserDto userDto = new UserDto();
userDto.setId(1);
userDto.setName("张三");
UserEntity userEntity = UserMapper.INSTANCE.dtoToEntity(userDto);

// 手动设置子节点的parentId
if (userEntity.getUsers() != null) {
    for (UserEntity child : userEntity.getUsers()) {
        child.setParentId(userEntity.getId());
    }
}

// Entity转DTO
UserDto convertedDto = UserMapper.INSTANCE.entityToDto(userEntity);

关键说明

  • MapStruct会在编译时自动生成映射实现类,无需手动编写转换逻辑
  • 子节点的parentId需手动设置,因为DTO中没有该字段,无法自动映射
三、额外注意事项
  • Spring Boot环境下,需在application.properties中配置JPA自动建表:spring.jpa.hibernate.ddl-auto=update(开发环境),生产环境建议设置为none,手动管理表结构
  • 递归映射时注意层级深度,避免栈溢出,层级过深建议改用迭代方式处理
  • 保持DTO和Entity的字段类型兼容,减少类型转换错误

内容的提问来源于stack exchange,提问作者Taron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 20:56:05