2013-02-27 68 views
35

在我的应用程序的架构之间复制性我一般是从数据访问层,通过服务层,在这些对象将会被从DAO改变了网络层发送对象的对象或列表的最佳方法反对一个对象,反之亦然。 Web层不具有对DAO对象的任何访问权限,并且DAO层不使用DTO。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中有一种方法,我可以通过它复制所有这些属性来创建其他对象列表?

本主题可能听起来很主观的,但我真的想从各位专家通过对象从一种形式到另一种的转变可以在最大字段具有相同的字符串进行的方式就知道了。

+0

的可能的复制(https://stackoverflow.com/questions/1432764/any-tool- for-java-object-to-object-mapping) – tkruse 2017-12-12 05:24:44

回答

19

你可以看看dozer这是一个

的Java Bean为Java Bean映射器,循环地将数据从一个对象到另一个对象。通常,这些Java Beans将具有不同的复杂类型。

Another better link...

2

您可以使用反射来找到所有的get方法在DAO对象,并呼吁在DTO相当于set方法。这只有在所有这些方法都存在时才有效。应该很容易为此找到示例代码。

22

您可以使用Apache Commmons Beanutils。 API是

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

它从“原点”豆到“目的地”豆对所有情况下的属性名称是相同的副本的属性值。

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

+14

确实,这是EJB域中的反模式。但在新的智能客户端(即客户端MVC)中,它很快成为必需品。你不想把整个对象图拉到客户端,而只是你真正需要的东西。因此,一个DTO。 – 2013-05-28 19:37:29

+0

这是一个很好的建议。但是如果DTO只有4个属性而实际的对象有50个属性呢?我的情况是,当我使用这里提到的copyProperties时,它会被仅有属性的实际对象覆盖。其余的46个属性都为空。这是如何预期的行为? – HopeKing 2017-05-15 12:44:01

2

不会lambdaj的project function做你正在寻找什么?

它会是这个样子:

List<UserDTO> userNDtos = project(users, UserDTO.class, on(User.class).getUserName(), on(User.class).getFullName(), .....); 

(相应地定义构造函数UserDTO ...)

另见here的例子...

4

我有我需要从JPA实体DTO转换的应用程序,我想了想,终于想出了用org.springframework.beans.BeanUtils.copyProperties用于复制简单的属性,也扩展并使用org.springframework.binding.convert.service.DefaultConversionService来转换复杂属性。

详细我的服务是这样的:[?任何工具,Java对象,对象映射]

@Service("seedingConverterService") 
public class SeedingConverterService extends DefaultConversionService implements ISeedingConverterService { 
    @PostConstruct 
    public void init(){ 
     Converter<Feature,FeatureDTO> featureConverter = new Converter<Feature, FeatureDTO>() { 

      @Override 
      public FeatureDTO convert(Feature f) { 
       FeatureDTO dto = new FeatureDTO(); 
       //BeanUtils.copyProperties(f, dto,"configurationModel"); 
       BeanUtils.copyProperties(f, dto); 
       dto.setConfigurationModelId(f.getConfigurationModel()==null?null:f.getConfigurationModel().getId()); 
       return dto; 
      } 
     }; 

     Converter<ConfigurationModel,ConfigurationModelDTO> configurationModelConverter = new Converter<ConfigurationModel,ConfigurationModelDTO>() { 
      @Override 
      public ConfigurationModelDTO convert(ConfigurationModel c) { 
       ConfigurationModelDTO dto = new ConfigurationModelDTO(); 
       //BeanUtils.copyProperties(c, dto, "features"); 
       BeanUtils.copyProperties(c, dto); 
       dto.setAlgorithmId(c.getAlgorithm()==null?null:c.getAlgorithm().getId()); 
       List<FeatureDTO> l = c.getFeatures().stream().map(f->featureConverter.convert(f)).collect(Collectors.toList()); 
       dto.setFeatures(l); 
       return dto; 
      } 
     }; 
     addConverter(featureConverter); 
     addConverter(configurationModelConverter); 
    } 
}