使用 GWT 和 Gin 的跨活动引用

发布于 2024-11-04 04:34:08 字数 1326 浏览 0 评论 0原文

我有一个使用“活动”和“地点”的 GWT MVP 应用程序。这受到 Mauro Bertapelle 示例的启发(位于 此线程),显然是基于关于 Thomas Broyer 的一些作品。

问题是:我让 LoginActivity 进行 RPC 调用,成功登录后会返回一个 User。该用户有一个角色(例如,管理员、普通用户、访客)。多个视图和活动(包括 NavigatorView)的显示或操作都依赖于此角色。如何将此用户实例获取到其他活动?

我没有 ClientFactory;注入(Gin)用于实例化提供我的活动/演示者的 ActivityProvider 中的视图,并将 ActivityProvider 注入到我的 ActivityMapper 中。因此,这可能会简化为一个杜松子酒问题:如何在需要的地方获取用户参考?这似乎类似于这个关于全局引用的问题在 MVP 中。

假设我是一个杜松子酒新手,这是我第一次尝试使用它。我猜测有一种“杜松子酒方式”可以实现这一点,但我对杜松子酒的了解还不够,不知道做到这一点的最佳方法(如果应该使用杜松子酒的话)。

非常感谢。

编辑1:尽管我尽了最大努力搜索类似的问题,但我刚刚发现这个问题与我的几乎相同(SO算法是否比搜索更好地查找“相关”链接?)。我认为大卫的杜松子酒答案是正确的。

我认为 EventBus 解决方案是不可能的。我遵循 Google 指南,其中涉及在每个位置实例化 Activity变化,因此单个事件本身是不够的。

I have a GWT MVP application using Activities and Places. This is inspired by Mauro Bertapelle's sample (in this thread), apparently based on some of Thomas Broyer's work.

Here's the problem: I have LoginActivity make an RPC call, which for a successful login, returns a User. This user has a role (e.g., admin, regular user, guest). Several Views and Activities, including a NavigatorView, depend on this role for what they show or do. How do I get this User instance to the other Activities?

I do not have a ClientFactory; injection (Gin) is used for instantiating the Views in the ActivityProviders which provide my Activities/Presenters, and the ActivityProviders are injected into my ActivityMapper. So this may reduce to a Gin question: how do I get the user reference where it's needed? This seems to be similar to this SO question about global references in MVP.

Consider me a Gin newbie, this is my first attempt at using it. I'm guessing there is a "Gin way" to make this happen, but I don't know Gin well enough to know the best way to do this (if Gin should be used at all).

Much thanks.

Edit 1: Despite my best efforts searching SO for a similar question, I just found this question which is pretty much identical to mine (is the SO algorithm for finding "Related" links better than the search?). I'm thinking that the Gin answer by David is on the right track.

I don't think that an EventBus solution is possible. I'm following the Google guidelines which involve instantiating Activity at every Place change, so a single Event by itself will not suffice.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

街道布景 2024-11-11 04:34:08

我在服务器端使用 Guice 并在客户端也能正常工作的方法是绑定到自定义提供程序。但在您的情况下,您必须使提供程序成为单例,并从 RPC 回调中将值推送到其中(而不是从某些上下文中将其拉出)。
您首先需要一个特定的提供程序:

@Singleton
public class CurrentUserProvider implements Provider<User> {
  private User currentUser;

  public User get() { return currentUser; }
  public void setCurrentValue(User currentUser) {
    this.currentUser = currentUser;
  }
}

User 绑定到提供程序:bind(User.class).toProvider(CurrentUserProvider.class)
在 RPC 回调中,您将注入 CurrentUserProvider,以便您可以 setCurrentValue,但在其他任何地方,您都将注入 Provider 以保持 CurrentUserProvider 作为实现细节。对于生命周期非常短的对象,您可以直接注入 User 值,而不是 Provider

如果您需要通知对象值更改,您可以在全局事件总线上调度一个事件。

或者,您始终可以使用具体的 CurrentUserProvider 类型(不必再实现 Provider),并可能将其设为 HasValueChangeHandlers,以便您可以在其上而不是在事件总线上注册侦听器(但您必须在活动的 onStoponCancel 中自行清理以避免内存泄漏,而如果您在 onStart 中的事件总线上注册处理程序,它会自动处理。

(如果你问我,我宁愿尽可能从应用程序内进行身份验证)

Something that I'm using on the server-side with Guice, and would work just as well on the client-side, is to bind to a custom Provider. In your case though, you'd have to make the provider a singleton and push the value into it from your RPC callback (rather than pulling it from some context).
You'd first need a specific provider:

@Singleton
public class CurrentUserProvider implements Provider<User> {
  private User currentUser;

  public User get() { return currentUser; }
  public void setCurrentValue(User currentUser) {
    this.currentUser = currentUser;
  }
}

You'd bind User to the provider: bind(User.class).toProvider(CurrentUserProvider.class)
In your RPC callback you'd inject a CurrentUserProvider so you can setCurrentValue but everywhere else you'd inject Provider<User> to keep CurrentUserProvider as an implementation detail. For very short-lived objects, you could directly inject a User value rather than a Provider<User>.

If you need to notify objects of the value change, you could dispatch an event on the global event bus.

Alternately, you could always use the concrete CurrentUserProvider type (which wouldn't have to implement Provider anymore) and possibly make it a HasValueChangeHandlers so you could register listeners on it rather than on the event bus (but you'd have to clean-up after yourself in your activities' onStop and onCancel to avoid memory leaks, whereas it's taken care of automatically if you register handlers on the event bus in onStart).

(if you ask me, I'd rather go away with authenticating from within the app whenever possible)

星軌x 2024-11-11 04:34:08

我最近的一个项目也有类似的要求。

当我从登录(或注销)RPC 收到回复时,我在 EventBus 上发送自定义的 AuthenticationEvent。所有对此感兴趣的活动都会监听此事件。 AuthenticationEvent 有一个对 AppUser 对象的引用,如果用户刚刚注销,则该对象为空。 AppUser 包含所有必要的数据(权限、组等),以便活动可以检查它并对其采取行动。

关于全局引用:您可以拥有一个带有静态方法的类,提供您需要的数据。该类在内部保存对所需实例的单例引用。在我的示例中,我有静态方法 AppUtils.getCurrentUser()。它在内部保存对 AppUser 的引用,并监听 AuthenticationEvent 来设置/重置该字段。

附带说明:不要依赖客户端来实施访问限制 - 您应该将 RPC servlet 分为两组:公共和私有。任何人都可以访问公共(这基本上是登录/注销 RPC 和其他一些公共信息 RPC),而私有 RPC 需要对用户进行身份验证。可以按路径/Servlet 设置访问限制:http://code .google.com/appengine/docs/java/config/webxml.html#Security_and_Authentication

更新:

  1. 正如您所指出的,在此设置中不建议使用具有静态方法的类,因为它是不可替换的,这会妨碍测试(这是使用 GIN 的全部意义)。 正如您

  2. 解决方案是将保存全局变量的实用程序类 (AppUtils) 注入到需要全局变量的活动中。 AppUtils 应在 GIN 配置中声明为单例,因为一个实例足以满足整个应用程序的需要。

  3. 是否使用Provider只是一个问题,如果你想延迟初始化依赖(AppUtil是依赖)。由于 AppUtils 是整个应用程序的单例,因此对其进行延迟初始化是没有意义的。

  4. 有时您会遇到屏幕上显示多个活动的情况(在我的例子中是菜单栏和信息栏)。在这种情况下,当用户登录时,您将需要一种方法来通知他们更改。使用EventBus。

I had similar requirements on a recent project.

When I get a reply from login (or logout) RPC I send a custom AuthenticationEvent on EventBus. All activities that are interested in this listen for this event. AuthenticationEvent has a reference to AppUser object which is null if user just logged out. AppUser contains all necessary data (privileges, groups, etc..) so that activities can inspect it and act upon it.

About global references: you can have a class with static methods providing data that you need. This class internally holds singleton references to needed instances. In my example I have static method AppUtils.getCurrentUser(). Internally it holds a reference to AppUser and also listens to AuthenticationEvent to set/reset this field.

As a side note: don't rely on client side to enforce access restrictions - you should separate your RPC servlets into two groups: public and private. Public can be accessed by anybody (this is basically login/logout RPC and some other public info RPC), while private RPC requires user to be authenticated. Access restrictions can be set per path/servlet: http://code.google.com/appengine/docs/java/config/webxml.html#Security_and_Authentication

Update:

  1. As you noted, class with static methods is not advisable in this setup, because it is not replaceable and this prevents testing (which is the whole point of using GIN).

  2. The solution is to inject a utility class holding globals (AppUtils) into activities that need the globals. AppUtils should be declared singleton in GIN configuration as one instance is enough for the whole app.

  3. To use Provider or not is just a question if you want to delay the initialization of dependencies (AppUtil is dependency). Since AppUtils is a singleton for the whole app it makes no sense to have it lazy initialized.

  4. Sometimes you will have a situation where you have multiple Activities shown on screen (in my case it was MenuBar and InfoBar). In this case, when user logs in you will need a way to notify them of the change. Use EventBus.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文