références croisées Activité utilisant GWT avec Gin
-
27-10-2019 - |
Question
J'ai une application GWT MVP en utilisant Activités et lieux. Ceci est inspiré par l'échantillon de Mauro Bertapelle (dans ce fil ), apparemment basé sur une partie du travail de ' Thomas Broyer .
Voici le problème: je LoginActivity faire un appel RPC, qui, pour une connexion réussie, renvoie un utilisateur. Cet utilisateur a un rôle (par exemple, admin, utilisateur régulier, invité). Plusieurs vues et activités, y compris un NavigatorView, dépendent de ce rôle pour ce qu'ils montrent ou faire. Comment puis-je obtenir cette instance de l'utilisateur aux autres activités?
Je n'ai pas ClientFactory; injection (Gin) est utilisé pour instancier les vues dans les ActivityProviders qui fournissent mes activités / présentateurs et les ActivityProviders sont injectés dans mon ActivityMapper. Donc, cela peut réduire à une question de Gin: comment puis-je obtenir la référence de l'utilisateur où il est nécessaire? Cela semble être similaire à cette question SO sur les références mondiales dans MVP.
Considérez-moi comme un débutant Gin, c'est ma première tentative de l'utiliser. Je devine que il y a un « chemin Gin » pour y arriver, mais je ne sais pas Gin assez bien pour connaître la meilleure façon de le faire (si Gin doit être utilisé du tout).
Une grande partie grâce.
Modifier 1: Malgré tous mes efforts à la recherche SO pour une question similaire, je viens de trouver cette question qui est à peu près identique à la mienne (est l'algorithme de SO pour trouver des liens "connexes" mieux que la recherche?). Je pense que la réponse Gin David est sur la bonne voie.
Je ne pense pas qu'une solution de EventBus est possible. Je suis les directives Google qui impliquent instanciation Activité à chaque endroit changement, donc un seul événement en lui-même ne suffira pas.
La solution
J'ai eu des exigences similaires sur un récent projet.
Quand je reçois une réponse de connexion (ou déconnexion) RPC-je envoyer un AuthenticationEvent personnalisé sur EventBus. Toutes les activités qui sont intéressés à ce écouter cet événement. AuthenticationEvent a une référence à l'objet appuser qui est nul si l'utilisateur vient de se déconnecter. Appuser contient toutes les données nécessaires (privilèges, groupes, etc ..) afin que les activités puissent inspecter et agir.
A propos de références globales: vous pouvez avoir une classe avec des méthodes statiques fournissant des données que vous avez besoin. Cette classe contient des références en interne singleton aux instances nécessaires. Dans mon exemple, j'ai méthode AppUtils.getCurrentUser statique (). En interne, il contient une référence à appuser et écoute également AuthenticationEvent pour définir / réinitialiser ce champ.
Comme une note de côté: ne comptez pas sur le côté client pour faire respecter les restrictions d'accès - vous devez séparer vos RPC servlets en deux groupes: public et privé. Public est accessible par tout le monde (ce qui est fondamentalement connexion / déconnexion RPC et d'autres informations publiques RPC), tandis que RPC privé requiert que l'utilisateur doit être authentifié. Les restrictions d'accès peuvent être définies par chemin / servlet: http: // Code .google.com / appengine / docs / java / config / webxml.html # Security_and_Authentication
Mise à jour:
-
Comme vous l'avez dit, la classe avec des méthodes statiques n'est pas conseillé dans cette configuration, car il n'est pas remplaçable, ce qui empêche l'essai (qui est le point de l'ensemble de l'utilisation GIN).
-
La solution consiste à injecter un globals de maintien de classes d'utilité (les AppUtils) dans des activités qui ont besoin des variables globales. AppUtils doivent être déclarés singleton en configuration GIN comme une instance est suffisant pour l'application entière.
-
Pour utiliser
Provider
ou non est une question si vous voulez retarder l'initialisation des dépendances (Apputil est la dépendance). Depuis AppUtils est un singleton pour l'application tout cela n'a aucun sens de l'avoir paresseux initialisé. -
Parfois, vous aurez une situation où vous avez plusieurs activités présentées à l'écran (dans mon cas, il était MenuBar et InfoBar). Dans ce cas, lorsque l'utilisateur se connecte, vous aurez besoin d'un moyen de les informer du changement. Utilisez EventBus.
Autres conseils
Quelque chose que j'utilise sur le côté serveur avec Guice, et travaillerait aussi bien sur le côté client, est de se lier à un fournisseur personnalisé. Dans votre cas, cependant, vous auriez à faire le fournisseur un singleton et pousser la valeur en elle depuis le rappel RPC (plutôt que le tirant d'un contexte). Vous auriez d'abord besoin d'un fournisseur spécifique:
@Singleton
public class CurrentUserProvider implements Provider<User> {
private User currentUser;
public User get() { return currentUser; }
public void setCurrentValue(User currentUser) {
this.currentUser = currentUser;
}
}
Vous seriez lier User
au fournisseur: bind(User.class).toProvider(CurrentUserProvider.class)
Dans votre rappel RPC que vous souhaitez injectez un CurrentUserProvider
afin que vous puissiez setCurrentValue
mais partout ailleurs vous souhaitez injectez Provider<User>
garder CurrentUserProvider
comme un détail de mise en œuvre. Pour les objets de très courte durée, vous pourriez injecter directement une valeur User
plutôt que d'un Provider<User>
.
Si vous devez notifier des objets du changement de valeur, vous pouvez envoyer un événement sur le bus événement mondial.
Sinon, vous pouvez toujours utiliser le type de CurrentUserProvider
de béton (qui ne pas avoir à mettre en œuvre Provider
plus) et peut-être faire un HasValueChangeHandlers
pour que vous puissiez enregistrer des écouteurs sur elle plutôt que sur le bus d'événements (mais vous auriez à nettoyage après vous dans le onStop
de vos activités et onCancel
pour éviter les fuites de mémoire, alors qu'il est pris en charge automatiquement si vous vous inscrivez des gestionnaires sur le bus d'événement dans onStart
).
(si vous me demandez, je préfère aller loin avec l'authentification à partir de l'application lorsque cela est possible)