DTO 模式:在两个对象之间复制属性的最佳方式

2022-08-31 22:08:57

在我的应用程序体系结构中,我通常通过服务层将数据访问层的对象或对象列表发送到Web层,其中这些对象从DAO对象转换为DTO对象,反之亦然。Web 层对 DAO 对象没有任何访问权限,DAO 层不使用 DTO。

为了演示,我通常将代码编写为:

@Transactional(readOnly = true)
public List<UserDTO> getAllUserAsUserDTO() {
    List<UserDTO> userDTOs = new ArrayList<UserDTO>();

    for(User user : getAllUser()) {
        userDTOs.add(constructUserDTO(user));
    }

    return userDTOs;
}

private UserDTO constructUserDTO(User user) {
    UserDTO userDTO = new UserDTO();
    userDTO.setFullName(user.getFullName());
    userDTO.setId(user.getId());
    userDTO.setUsername(user.getUsername());
    userDTO.setRole(user.getRole());
    userDTO.setActive(user.isActive());
    userDTO.setActiveText(user.isActive() ? "Active" : "Inactive");
    return userDTO;
}

此处的用户是数据库实体:

@javax.persistence.Entity
@Table(name = "USER")
public class User extends Entity {

    @Transient
    private static final long serialVersionUID = -112950002831333869L;

    private String username;
    private String fullName;
    private boolean active;
    private String role;
    // other fields

    public User() {
        super();
    }

    @NaturalId
    @Column(name = "USERNAME", nullable = false)
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Column(name = "FULL_NAME")
    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    @Column(name = "ACTIVE", nullable = false)
    public boolean isActive() {
        return active;
    }

    public void setActive(boolean active) {
        this.active = active;
    }

    @Column(name = "ROLE")
    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }
}

这是UserDTO:

public class UserDTO extends BaseDTO {

    private static final long serialVersionUID = -3719463614753533782L;

    private String username;
    private String fullName;
    private String role;
    private String activeText;
    private Boolean active;
    //other properties

    public UserDTO() {
        super();
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public String getActiveText() {
        return activeText;
    }

    public void setActiveText(String activeText) {
        this.activeText = activeText;
    }

    public Boolean getActive() {
        return active;
    }

    public void setActive(Boolean active) {
        this.active = active;
    }
}

所以我想知道这是否是在两个对象之间复制属性的唯一方法。我想我不确定。此外,我正在使用lambdaj,那么此API中是否有一种方法可以复制所有这些属性以创建其他对象的列表?

这个主题可能听起来很主观,但我真的很想从你们的专家那里知道,在最大字段具有相同的字符串的情况下,可以完成对象从一种形式到另一种形式的转换的方法。


答案 1

您可以使用Apache Commmons Beanutils。该接口是

org.apache.commons.beanutils.PropertyUtilsBean.copyProperties(Object dest, Object orig).

对于属性名称相同的所有情况,它将属性值从“原点”Bean 复制到“目标”Bean。

现在我要跑题了。在 EJB3 中使用 DTO 通常被认为是一种反模式。如果您的 DTO 和域对象非常相似,则实际上无需重复代码。DTO仍然有优点,特别是在涉及远程访问时节省网络带宽。我没有关于您的应用程序体系结构的详细信息,但是如果您谈论的层是逻辑层并且不跨网络,那么我认为不需要DTO。


答案 2

你可以看看推土机,这是一个

Java Bean 到 Java Bean 映射器,它以递归方式将数据从一个对象复制到另一个对象。通常,这些 Java Bean 将具有不同的复杂类型。

另一个更好的链接...