2013-02-27 3 views
35

В архитектуре моего приложения я обычно отправляю объект или список объектов с уровня доступа к данным на веб-уровень через сервисный уровень, в котором эти объекты преобразуются из DAO объект к объекту DTO и наоборот. Веб-уровень не имеет доступа к объектам 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

ответ

19

Вы можете посмотреть на dozer который является

Java Bean для Java Bean картографа, который рекурсивно копирует данные из одного объекта к другому. Как правило, эти Java-бобы будут иметь разные сложные типы.

Another better link...

2

Вы можете использовать отражение, чтобы найти все get методы в вашем DAO объектов и вызвать эквивалентный set метод в DTO. Это будет работать, только если все такие методы существуют. Для этого должно быть легко найти пример кода.

22

Вы можете использовать Apache Commmons Beanutils. API:

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

Он копирует значения свойств из компонента «origin» в компонент «destination» для всех случаев, когда имена свойств одинаковы.

Теперь я собираюсь отключить тему. Использование DTO в основном рассматривается как анти-шаблон в EJB3. Если ваш DTO и ваши объекты домена очень похожи, нет необходимости дублировать коды. DTO по-прежнему имеет свои достоинства, особенно для экономии пропускной способности сети, когда задействован удаленный доступ. У меня нет деталей о вашей архитектуре приложения, но если слои, о которых вы говорили, являются логическими слоями и не пересекают сеть, я не вижу необходимости в DTO.

+14

Правда, это анти-шаблон в EJB-стране. Но в новом мире смарт-клиентов (т. Е. На стороне клиента MVC) он быстро становится необходимостью. Вы не хотите тянуть весь графический объект на клиентскую сторону, а только то, что вам действительно нужно. Следовательно, DTO. –

+0

Это хорошее предложение. Но что, если DTO имеет только 4 свойства, а фактический объект имеет 50 свойств. В моем случае, когда я использую copyProperties, как указано здесь, он перезаписывает фактический объект только с помощью свойств. Остальные 46 свойств становятся нулевыми. Так ли это должно вести себя? – HopeKing

2

Не хотите ли lambdaj's 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); 
    } 
} 
Смежные вопросы