在我的应用程序架构中,我通常通过服务层将对象或对象列表从数据访问层发送到Web层,其中这些对象从DAO对象转换为{{3}对象,反之亦然。 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;
}
}
所以我想知道这是否是在两个对象之间复制属性的唯一方法。我想我不确定。我也在使用DTO,所以在这个API中是否有一个方法可以复制所有这些属性以创建其他对象的列表?
这个主题可能听起来很主观,但我真的想从专家那里了解到,在最大字段具有相同字符串的情况下,可以将对象从一种形式转换为另一种形式的方式。
答案 0 :(得分:26)
您可以使用Apache Commmons Beanutils。 API是
org.apache.commons.beanutils.PropertyUtilsBean.copyProperties(Object dest, Object orig)
。
它从&#34; origin&#34;复制属性值。豆到目的地&#34; bean适用于属性名称相同的所有情况。
现在我要离题了。使用DTO主要被认为是EJB3中的反模式。如果您的DTO和您的域对象非常相似,则实际上不需要重复代码。 DTO仍然具有优点,特别是在涉及远程访问时节省网络带宽。我没有关于您的应用程序架构的详细信息,但如果您谈到的层是逻辑层而不是跨网络,我认为不需要DTO。
答案 1 :(得分:21)
您可以查看dozer这是
Java Bean to Java Bean映射器,以递归方式将数据从一个对象复制到另一个对象。通常,这些Java Bean将具有不同的复杂类型。
答案 2 :(得分:4)
我有一个应用程序需要从实体转换为DTO,我想到了它并最终使用org.springframework.beans.BeanUtils.copyProperties
来复制简单属性并扩展和使用{{1用于转换复杂属性。
详细说明我的服务是这样的:
org.springframework.binding.convert.service.DefaultConversionService
答案 3 :(得分:2)
您可以使用反射来查找 DAO 对象中的所有get
方法,并在 DTO 中调用等效的set
方法。只有存在所有这些方法时,这才有效。为此找到示例代码应该很容易。
答案 4 :(得分:2)
lambdaj的project function不会做你想要的吗?
它看起来像这样:
List<UserDTO> userNDtos = project(users, UserDTO.class, on(User.class).getUserName(), on(User.class).getFullName(), .....);
(相应地定义UserDTO的构造函数......)
另见here示例......
答案 5 :(得分:1)
我建议您使用映射器的一个库:Mapstruct,ModelMapper等。 使用Mapstruct,您的映射器将如下所示:
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper( UserMapper.class );
UserDTO toDto(User user);
}
带有所有getter和setter的真实对象将自动从此界面生成。您可以像这样使用它:
UserDTO userDTO = UserMapper.INSTANCE.toDto(user);
您还可以为使用@AfterMapping注释的activeText字段添加一些逻辑。