普遍地,你只向那些登陆成功的用户展示你的基于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