GWT : best way to do an initial RPC call at startu

2020-06-28 04:41发布

What is the best way to perform an initial RPC call at startup with GWT?

I would like to retrieve configuration data that are dynamically generated on the server side, when a user loads a page. but If I do an asynchronous RPC call from the browser to retrieve the data, I sometimes don't get a response before the page is fully loaded, resulting in the page not having access to that configuration data. (no Thread.sleep() function for example)

thanks


thanks to @Steve-J's response, I found a solution...

Basically the idea is the following:

  • create a new StartupCompleted event
  • start the initial RPC call in the onModuleLoad()
  • in the onSucess method of that RPC call, fire a StartupCompleted event
  • at the end of the go() method of the App Controller, instead of inserting the default action in the History [ with a History.newItem("default"); ], or to fire the current History state if called through a bookmark [ with a History.fireCurrentHistoryState(); ], don't do anything
  • register a handler for the new StartupCompleted event on the eventbus
  • when the StartupCompleted event is fired, catch it and at that time, insert the default action in the history or fire the current history state

et voila...

The initial RPC call is completed before doing anything else...

Is there anything wrong with that approach?

Note that as suggested by @Tom-Miette it is nice have a simple "loading..." message until the StartupCompleted event is received.

标签: gwt rpc
4条回答
smile是对你的礼貌
2楼-- · 2020-06-28 05:14

FWIW I had a solution that involves suspending EntryPoint.onModuleLoad() until the RPC returns.

I was using dependency injection and GWTP Dispatch which kind of complicated the bootstrap process. I also wanted the result to be a singleton instance in my system (client side).

The result was a GWT native (no command pattern) RPC call that launched dependency injection upon success.

EntryPoint class snippet:

@Override
public void onModuleLoad() {
    SessionInfoProvider.init(new Runnable() {
        @Override
        public void run() {
            // can now complete setup
            AppInjector injector = GWT.create(AppInjector.class);
            injector.bootstrap();
        }
    });
}

SessionInfoProvider snippet:

public class SessionInfoProvider implements Provider<SessionInfo> {
private static SessionInfo.Bean sessionInfo;

/**
 * Needs to be called before the module is used.
 */
public static void init(final Runnable onCompletion) {
    GreetingServiceAsync s = GWT.create(GreetingService.class);
    s.loadSessionInfo(new AsyncCallback<SessionInfo.Bean>() {
        @Override
        public void onFailure(Throwable caught) {
            GWT.log("Failed to retrieve Session Info");
        }

        @Override
        public void onSuccess(SessionInfo.Bean result) {
            GWT.log("Successfully retrieved session info bean.  Username:" + result.getUserName());
            sessionInfo = result;
            onCompletion.run();
        }
    });
}

@Override
public SessionInfo get() {
    if (sessionInfo == null) throw illegalState("Session Info not ready.");
    return sessionInfo;
}
}
查看更多
冷血范
3楼-- · 2020-06-28 05:23

Not sure if its the best way but a good way is to avoid the initial call altogether and use a jsp page instead of a html page as your entry point into the application. You can then set variables for your initial state in javascript in the page server side e.g.

<script type="text/javascript">
    var InitialState = {
    "userName" : "<%= userName %>",
    "emailAddress" : "<%= emailAddress %>",
    etc...
};

In your GWT app you can read these values using the GWT Dictionary class

Dictionary state = Dictionary.getDictionary("InitialState");
String userName = state.get("userName");
String emailAddress = state.get("emailAddress");
查看更多
我想做一个坏孩纸
4楼-- · 2020-06-28 05:35

Are you using messaging for control flow? I do the RPC call, and on success, I send the message that triggers the first active popup for the user to interact with. On failure, a different message is fired that triggers a popup to tell the user that he can't proceed.

Don't forget to enable the glass panel on your popups so that the user can't mess with anything in the background while he is waiting.

Update: From the comments: "But my problem is that the user can bookmark a page, and go directly to it without any interaction. I may end up in a case where I have not received the result of the RPC call, but where I am generating the page he has requested. Even if in that generation I try to check if I've received the result, I can't pause until that's the case before completing the generation of the page."

Ah, I see. OK, GWT has a solution for this. You should look at Activities and Places. When the user bookmarks a "page", he is really bookmarking the state of the GWT application. When he returns to that "page", the Activity is fired and automatically calls the start() method. This is your opportunity to retrieve data from a server and do any other setup that is required. Once you have your data, your start() method proceeds to set up what is called the "view". From the user's perspective, the "page" has "loaded".

查看更多
放我归山
5楼-- · 2020-06-28 05:36

Cover your html page with a kind of "loading screen":

<div 
id="loading"
style="
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background: black;
  color: white;"
>
  Loading...
</div>

and just remove it when the RPC has succeeded/failed:

RootPanel.get("loading").getElement().removeFromParent();
查看更多
登录 后发表回答