在我的应用程序体系结构中,我通常通过服务层将对象或对象列表从数据访问层发送到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中有一个方法,我可以复制所有这些属性来创建其他对象的列表?
这个话题可能听起来很主观,但我真的想从你们专家那里知道,在最大字段具有相同字符串的情况下,对象从一种形式转换到另一种形式的方法。
您可以使用Apache commons beauutils。API是
org.apache.commons.beanutils.PropertyUtilsBean.copyProperties(Object dest, Object orig)
。
在所有属性名称相同的情况下,它将属性值从"源"bean复制到"目标"bean。
现在我要跑题了。在EJB3中,使用DTO通常被认为是一种反模式。如果您的DTO和域对象非常相似,则确实没有必要重复代码。DTO仍然有优点,特别是在涉及远程访问时节省网络带宽。我不了解您的应用程序架构的细节,但是如果您谈到的层是逻辑层,并且不跨网络,我认为不需要DTO。你可以看一下dozer
Java Bean到Java Bean映射器,递归地将数据从一个对象复制到另一个对象。通常,这些Java bean将具有不同的复杂类型。
我有一个需要从JPA实体转换为DTO的应用程序,我考虑了一下,最后使用org.springframework.beans.BeanUtils.copyProperties
复制简单属性,并扩展和使用org.springframework.binding.convert.service.DefaultConversionService
转换复杂属性。
我的服务细节是这样的:
@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);
}
}
我建议您应该使用映射器的库之一: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文件添加一些逻辑。
lambdaj的项目函数不会做你正在寻找的?
它看起来像这样:
List<UserDTO> userNDtos = project(users, UserDTO.class, on(User.class).getUserName(), on(User.class).getFullName(), .....);
(为UserDTO定义相应的构造函数…)
您可以使用反射来查找DAO对象中的所有get
方法,并调用DTO中的等效set
方法。只有当所有这些方法都存在时,这才会起作用。这应该很容易找到示例代码。
最简单的技巧是SERIALIZE Object_A
和DESERIALIZE使用Object_B.class
:
如果你正在使用Spring或Spring-boot,可能你的类路径中已经有了Jackson库:
import com.fasterxml.jackson.databind.ObjectMapper;
:
ObjectMapper objectMapper = new ObjectMapper();
Object_B objB = objectMapper.readValue(objectMapper.writeValueAsString(objA), Object_B.class);