指定服务返回字段的最佳方法

2024-01-10

我们使用 Java EE 7 和 WildFly 9 来开发移动/Web 应用程序的自定义后端。后端是一个经典的三层系统,具有通信逻辑(JAX-RS)、业务逻辑(Session EJB)和持久层(Hibernate)。

业务逻辑层由一组服务组成,每个服务都由一个接口和一个 EJB 实现定义。我们假设

public interface IPostService {
    List<PostDTO> getAllPosts();
}

and

@Stateless
public class PostService implements IPostService {
    List<PostDTO> getAllPosts(){
    // retrieving my Posts through Hibernate
    }

having

public class PostDTO {

    private Long id;
    private String title;
    // UserDTO is a VEEERY big object
    private UserDTO author;

    // getters and setters
}

让我们假设,有时,客户只对帖子感兴趣id and title。 API端点将接收一个查询参数,其中包含要获取的字段列表。因此,JSON 序列化的 DTO 应该只包含 postid and title。目标是避免为了加载非常大的数据而进行不必要的处理UserDTO不需要时对象。

一个简单的解决方案是添加自定义List<String> desiredFields参数为getAllPosts()。这不太让我信服,因为我们需要将此参数添加到几乎every服务方法。

这样做的最佳实践是什么?是否有用于此目的的 Java EE 对象?


我的回答做了一些额外的假设:

  • 使用 JPA 2.1,您可以利用实体​​图有条件地获取实体的部分内容,无论是惰性的还是急切的。
  • 将 JAX-RS 与 Jackson JSON 提供程序一起使用,您可以使用@JsonView执行相同的操作将对象渲染为 JSON。

考虑以下示例:用户具有一组角色。默认情况下,角色是惰性获取的,不需要以 JSON 形式呈现。但在某些情况下,您希望立即获取它们,因为您希望它们以 JSON 格式呈现。

@Entity
@NamedQueries({
    @NamedQuery(name = "User.byName", query = "SELECT u FROM User u WHERE u.name = :name"),
    @NamedQuery(name = "Users.all", query = "SELECT u FROM User u ORDER BY u.name ASC")
})
@NamedEntityGraph(name = "User.withRoles", attributeNodes = {
    @NamedAttributeNode("roles") // make them fetched eager
})
public class User implements Serializable {

    public static interface WithoutRoles {}
    public static interface WithRoles extends WithoutRoles {}

    @Id
    private Long id;

    @Column(unique = true, updatable = false)
    private String name;

    @ManyToMany // fetched lazy by default
    @JoinTable(/* ... */)
    private Set<Role> roles;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // include in JSON only when "@JsonView(WithRoles.class)" is used:
    @JsonView(WithRoles.class)
    public Set<Role> getRoles() {
        if (roles == null)
            roles = new HashSet<>();
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

}

@Entity
public class Role implements Serializable {
    /* ... */
}

以下是加载用户的代码,无论是否具有角色:

public User getUser(String name, boolean withRoles) {
    TypedQuery<User> query = entityManager.createNamedQuery("User.byName", User.class)
        .setParameter("name", name);

    if (withRoles) {
        EntityGraph<User> graph = (EntityGraph<User>) entityManager.createEntityGraph("User.withRoles");
        query.setHint("javax.persistence.loadgraph", graph);
    }

    try {
        return query.getSingleResult();
    } catch (NoResultException e) {
        return null;
    }
}

public List<User> getAllUsers() {
    return entityManager.createNamedQuery("Users.all", User.class)
        .getResultList();
}

现在是 REST 资源:

@RequestScoped @Path("users")
public class UserResource {

    private @Inject UserService userService;

    // user list - without roles
    @GET @Produces(MediaType.APPLICATION_JSON)
    @JsonView(User.WithoutRoles.class)
    public Response getUserList() {
        List<User> users = userService.getAllUsers();
        return Response.ok(users).build();
    }

    // get one user - with roles
    @GET @Path("{name}") @Produces(MediaType.APPLICATION_JSON)
    @JsonView(User.WithRoles.class)
    public Response getUser(@PathParam("name") String name) {
        User user = userService.getUser(name, true);
        if (user == null)
            throw new NotFoundException();

        return Response.ok(user).build();
    }

}

因此,在持久性方面(JPA、Hibernate)您可以使用延迟获取来防止加载实体的某些部分,而在 Web 层(JAX-RS、JSON)您可以使用@JsonView决定在实体的(反)序列化中应处理哪些部分。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

指定服务返回字段的最佳方法 的相关文章

随机推荐

  • 如何从 coverity-scan 中删除项目

    我已经注册了一个项目覆盖扫描 https scan coverity com在过去 我现在想从覆盖扫描中删除该项目 或者至少从我的仪表板上删除该项目 但最好我想完全删除该项目 我被困住了 因为网络界面中似乎没有这样的选项 我错过了什么吗 你
  • RxJS first() for Observable.of() - 序列中没有元素

    对于我的测试 我试图用以下方法模拟事件流Observable of 但当我尝试时 const actions Observable of in the function that is tested actions filter actio
  • VS 2015编译cocos2d-x 3.3错误“fatal error C1189: #error: MacroDefinition of snprintf与标准库函数声明冲突”

    当我使用Visual Studio 2015编译cocos2d x 版本3 3 时 出现错误 说 致命错误 C1189 error snprintf 的宏定义与标准库函数声明冲突 编译源文件 base s3tc cpp 源代码是 ifdef
  • 使用Delphi消费oData服务建议

    我即将启动一个需要 Delphi XE Windows 32 客户端来使用的项目oData http www odata org 网络服务 我可以使用一些粗略和可读的测试代码正确查询服务 但是编写一个框架来处理 oData 协议 所有过滤
  • 如何使用 Kotlin 修复此错误,找不到 Fragment 构造函数?

    我正在开发Android使用 Kotlin 的应用程序 在我的应用程序中包含Tab with ViewPager所以我实现了两个选项卡 当我移动到另一个活动并压缩到选项卡视图活动时 应用程序将停止并且logcat显示下面的错误 java l
  • 如何使用模板创建排序映射整数索引

    我有数据结构 template
  • 使用 C# 删除换行符

    我从名为 Description 的数据库字段获取一个字符串 它有换行符 它看起来像这样 项目标题 此处为描述 这是项目的描述 我怎样才能删除换行符 我尝试了以下功能 但它不起作用 public string FormatComments
  • 设置div动态填充剩余高度?

    所以 我的代码类似于 div style width 100 min height 1 display block background color 000 img src header image svg div div Some con
  • 在 Python 中检测 NUMLOCK / CAPSLOCK / SCRLOCK 按键/按键

    在我正在开发的游戏中 我想检测NUMLOCK keypress or keyup 就像在按下时注册一个 回调 函数 我并不是要求阅读它state在某一特定时刻 我已经可以做到了 https github com MestreLion pyr
  • 有没有办法在设置类的任何属性时调用方法?

    因此 我想做的是在设置 C 类中的任何属性时调用单个 propertyWasSet 函数 相反 在获取属性时调用 propertyWasGot 我还想知道调用了哪个属性的 get 我想维护一个 设置 属性的字典 并检查 获取 操作是否已设置
  • Angular 库包依赖项

    我使用 CLI 创建并捆绑了一个 Angular 7 2 0 库 ng g 库 MyLibrary ng 构建 MyLibrary 这给了我my libary umd js我需要的捆绑包 目前 所有依赖项都作为peerDependency
  • 如何在同一场战争的多个 jar 中使用相同的 CamelContext

    我使用的是camel 2 16 2 我需要在多个jar 中使用一个 CamelContext 因为我需要将所有 Camel 路由器放入一个 CamelContext 中 所以我的战争将把所有这些罐子作为 Maven 工件 请告诉我如何处理上
  • 设施位置的动态规划算法

    沿着一条线 在位置 a 1 a 2 a n 处有 n 栋房屋 我们希望沿着同一条线设置移动便盆 以便每间房屋都位于至少一个移动便盆的距离 R 内 这些便携式便盆仅限于指定位置 b 1 b 2 b m 令 c i 为在位置 b i 设置移动便
  • openapi-generator 复制 swagger-ui 中的端点

    openapi generator maven plugin 版本 6 3 0 在 Spring Boot 3 应用程序中配置如下
  • 分区比排序更容易吗?

    这是一个在我脑海里徘徊了一段时间的问题 假设我有一个项目列表和它们的等价关系 并且比较两个项目需要恒定的时间 我想退回一部分物品 例如链表的列表 每个链表包含所有等效项 实现此目的的一种方法是将等价性扩展到项目的排序并对其进行排序 使用排序
  • 在无向图中记录 DFS 搜索中的前驱

    我试图使用此线程中的代码 提升DFS back edge https stackoverflow com questions 19346820 boost dfs back edge 19391511 noredirect 1 commen
  • String.count() 是如何工作的? [复制]

    这个问题在这里已经有答案了 我是 python 和学习的新手 如所给出的here https www tutorialspoint com python string count htm count 方法在字符串上使用时给出子字符串在字符串
  • 如何为Java类创建两个接口,一个只读,一个读写?

    我正在用 Java 为一款两人纸牌游戏编写一个游戏引擎 我的学生将为该游戏编写 AI 玩家 人工智能玩家将轮流在他们面前的 桌子 的 场地 上打牌 他们可以用自己场上的牌攻击对方场上的牌 卡片可以面朝上或面朝下 GameEngine 类允许
  • 如何根据构建变体更改 AndroidManifest.xml 文件?

    我有一个具有多个构建变体的应用程序 这些变体用于为不同公司构建同一应用程序的版本 因此 我有几个不同的变体来构建不同的应用程序 com acme app1 com schmoe app2 com yop app3 etc build gra
  • 指定服务返回字段的最佳方法

    我们使用 Java EE 7 和 WildFly 9 来开发移动 Web 应用程序的自定义后端 后端是一个经典的三层系统 具有通信逻辑 JAX RS 业务逻辑 Session EJB 和持久层 Hibernate 业务逻辑层由一组服务组成