【问题标题】:Design of DTO from Model for an API从 API 模型设计 DTO
【发布时间】:2017-12-20 18:38:35
【问题描述】:

我正在为一些社交网络后端设计一个使用 Spring Boot 的 API。我当前的模型如下所示:

public class User {

    private long id;
    private String handle;
    private String name;
    private List<User> followers;
    private List<User> following;

    // Getters setters etc

现在,我创建了与上述结构非常相似的 DTO。我的问题是,有时我想准确地返回上面的内容(这很好),但有时我不希望这样。

例如,当某人只对寻找用户的关注者感兴趣时,我不想包括关注者和关注者(我只对idhandlename 感兴趣,因此计算followers 和@ 987654326@ 对所有这些用户来说是一种难以置信的资源浪费)。

在我当前的实现中,这些字段以null 值返回,我认为这不是一个好主意。我应该创建一个没有这些列表的单独 DTO 吗?或者有更优雅的方法吗?

【问题讨论】:

  • 我认为如果你在你的 api 中创建另一个层,你可以通过 id 向用户发出请求以仅获取部分值,我认为更优雅,如果你获取所有值只是为了获取一个值是没有意义的来自 DTO 响应。

标签: java spring spring-boot api-design


【解决方案1】:

这是一个有争议的问题。如果您不想创建单独的 dto,有几种方法可以做到。这取决于您要使用的数据访问方法:

使用 Spring Data JPA 可以在投影中返回实体。您只需要为您的实体添加一个额外的构造函数:

public interface UserRepository extends JpaRepository<User, Long> {
    @Query("select new User(u.id,u.name) from User u")
    List<User> findAllUserItems();
}

或同样使用 JPA EntityManger:

    public List<User> findAllUserItems() {
        return entityManager.createQuery("select new User(u.id,u.name) from User u", User.class)
                .getResultList();
    }

如果您想知道不必要的空字段并且您正在使用 Jackson,则可以配置为忽略空字段。对于 Spring Boot:

spring.jackson.default-property-inclusion=non_null

或使用 Java 配置:

    @Bean
    public Jackson2ObjectMapperBuilder objectMapperBuilder() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        return builder;
    }

或者对于非 Spring Boot 项目:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(converter());
    }

    @Bean
    public HttpMessageConverter converter() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        return new MappingJackson2HttpMessageConverter(objectMapper);
    }
}

另外,如果你打算使用 Hibernate Session。要直接映射到 dto,您可以使用 AliasToBeanResultTransformer:

  public List<UserDto> findAllUserItems() {
            return session.createQuery("select u.id as id,u.name as name from User u")
                    .setResultTransformer(Transformers.aliasToBean(UserDto.class))
                    .list();
 }

【讨论】:

    【解决方案2】:

    假设你可以这样尝试。

    @Entity
    public class User implements Serializable {
    
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        private Long id;
    
        @ManyToOne
        private User parent;
    
        @OneToMany(mappedBy="parent")
        private List<User> followers;
    
        @OneToMany(mappedBy="parent")
        private List<User> following;
    
        // Getters, Setters etc....
    }
    

    这个post 也可能会有所帮助。

    【讨论】:

    • 这如何准确回答这个问题? OP 想知道他如何防止某些字段在使用 DTO 的 REST API 中返回,而您的解决方案只是一个实体?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 2013-04-02
    • 1970-01-01
    • 2020-05-03
    • 1970-01-01
    • 1970-01-01
    • 2014-03-09
    相关资源
    最近更新 更多