动态主页

     普遍地,你只向那些登陆成功的用户展示你的基于GWT的app,在这篇文章中,我们来介绍几种完成用户验证的方法,同时高效地利用网络。

     1.RPC的静态网页

     2.在web.xml中作安全约束

     3.用servelet作主页

     4.基于模板的主页

RPC的静态网页

一般的做法是在EntryPoint 的onModuleLoad() 方法中调用GWT-RPC服务来验证用户是否已经登录。这种方式在装载GWT模块的时候发起一个GWT-RPC请求。代码如下:

public void onModuleLoad() {
  // loginService is a GWT-RPC service that checks if the user is logged in
  loginService.checkLoggedIn(new AsyncCallback<Boolean> {
    public void onSuccess(Boolean loggedIn) {
      if (loggedIn) {
        showApp();
      } else {
        Window.Location.assign("/login");
      }
    }
    // ...onFailure()
  }
}

此时让我们来考虑一下如果用户没有登录会发生哪些事情:

    1.你的app被请求和你的GWT主页(yourmodule.html)被下载

    2.module.nocache.js被请求和下载

    3.基于浏览器类型的MD5.cache.htm被选择和下载

    4.你的GWT模块被下载并发起GWT-RPC请求验证用户是否已经登录--如果没有,需要跳转到        登录页面

总共有4次服务器请求,仅仅只是为了跳转到登录页面。并且步骤3下载了整个app.即使你善于code-splitting,但至少,为了验证用户是否登录,一部分代码是必须被下载的。

       最理想的情况是只在用户被认证通过的情况下展示你的GWT app。那样,可以跳过步骤2,只有在用户登录了的情况下才执行步骤2。

      在web.xml中作安全约束

另外一个办法是在web.xml中作安全约束,例如,利用google app engine ,你可以定义一个安全约束去约束那些用 Google Accounts登录的用户对所有页面(包括静态主页)的一个访问权限(具体查看Security and Authentication)。如果用户没有登录,google app engine会将用户重定向到Google Accounts的登录页面。

      用servelet作主页

一个更好的办法是用java servlet生成html主页来代替静态的html主页,这种灵活的方法可以自定义认证规则,同时还可以根据不同用户产生不同的页面内容。下面是一个例子:

public class GwtHostingServlet extends HttpServlet {

 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {

   resp.setContentType("text/html");
   resp.setCharacterEncoding("UTF-8");

   // Print a simple HTML page including a <script> tag referencing your GWT module as the response
   PrintWriter writer = resp.getWriter();
   writer.append("<html><head>")
       .append("<script type=\"text/javascript\" src=\"sample/sample.nocache.js\"></script>")
       .append("</head><body><p>Hello, world!</p></body></html>");
  }
}

  这个servlet发回响应然后执行GWT模块,这个过程就像是应用静态html一样。记住我们现在在servlet中生成html代码,我们可以根据不同的请求生成不同的页面内容。因此,我们可以做更多有趣的事情。

   下面的例子用google app 的 Users API 来检查用户是否登录。即使你不用app engine,但是你可以想象下面的代码与servlet中的代码有哪些稍微不同。

    // In GwtHostingServlet's doGet() method...

PrintWriter writer = resp.getWriter();
writer.append("<html><head>");

UserService userService = UserServiceFactory.getUserService();
if (userService.isUserLoggedIn()) {
  // Add a <script> tag to serve your app's generated JS code
  writer.append("<script type=\"text/javascript\" src=\"sample/sample.nocache.js\"></script>");
  writer.append("</head><body>");
  // Add a link to log out
  writer.append("<a href=\"" + userService.createLogoutURL("/") + "\">Log out</a>");
} else {
  writer.append("</head><body>");
  // Add a link to log in
  writer.append("<a href=\"" + userService.createLoginURL("/") + "\">Log in</a>");
} 
writer.append("</body></html>"); 

  这个servlet现在只向登录的用户展示你的GWT app,同时在页面上显示登录和注销的链接。

但是,我们还可以利用动态主页生成的servlet来做更多有趣的事情。假使你想传递一些像用户邮箱地址之类的数据从servlet到GWT以便GWT模块加载的时候邮箱地址已经存在。

   你可以在onModuleLoad()方法中发起GWT-RPC请求,但是这意味着你发送了一次请求来下载你的GWT模块,然后发起另外一次请求来获得这个数据。一个更高效的办法是将这些初始化数据保存在javascript的变量中写到主页页面里。

// In GwtHostingServlet's doGet() method...
writer.append("<html><head>");
writer.append("<script type=\"text/javascript\" src=\"sample/sample.nocache.js\"></script>");

// Open a second <script> tag where we will define some extra data
writer.append("<script type=\"text/javascript\">");

// Define a global JSON object called "info" which can contain some simple key/value pairs
writer.append("var info = { ");

// Include the user's email with the key "email"
writer.append("\"email\" : \"" + userService.getCurrentUser().getEmail() + "\"");

// End the JSON object definition
writer.append(" };");

// End the <script> tag
writer.append("</script>");
writer.append("</head><body>Hello, world!</body></html>");

 现在,你的GWT代码可以利用JSNI获得这些数据,像下面这样:

public native String getEmail() /*-{
  return $wnd.info['email'];
}-*/;

 另外,你也可以考虑GWT的 Dictionary 类

public void onModuleLoad() {
  // Looks for a JS variable called "info" in the global scope
  Dictionary info = Dictionary.getDictionary("info");
  String email = info.get("email");
  Window.alert("Welcome, " + email + "!");
}

      基于模板的主页

当你需要增加许多动态元素到你的主页中的时候,你值得考虑用一些模板类语言像jsp来增加你代码的可读性。下面是jsp代替servlet的例子:

<!-- gwt-hosting.jsp -->
<html>
 <head>
<%
   UserService userService = UserServiceFactory.getUserService();
   if (userService.isUserLoggedIn()) {
%>
    <script type="text/javascript" src="sample/sample.nocache.js"></script>
    <script type="text/javascript">
      var info = { "email" : "<%= userService.getCurrentUser().getEmail() %>" };
    </script>
  </head>
  <body>
  <a href="<%= userService.createLogoutURL(request.getRequestURI()) %>">Log out</a>
<%
   } else {
%>
  </head>
  <body>
    <a href="<%= userService.createLoginURL(request.getRequestURI()) %>">Log in</a>
<%
   }
%>
 </body>
</html>

 你可以在web.xml 中声明这个jsp页面作为你的欢迎页面,

<welcome-file-list>  
<welcome-file>gwt-hosting.jsp</welcome-file>
</welcome-file-list>

 以上是一些基本例子,这些例子都是基于最小http请求次数来动态访问你的GWT app。运用这些技术,你可以消除GWT-RPC请求在你的模块被加载的时候,这也就意味着更少的用户等待时间和更快的GWT 应用。

原文地址:http://www.gwtproject.org/articles/dynamic_host_page.html

相关推荐