【发布时间】:2012-01-16 01:10:54
【问题描述】:
我正在编写一个 GWT/GAE(Java) 应用程序。 GWT 自带的自动生成的 hello word 示例生成如下代码:
<table align="center">
<tr>
<td colspan="2" style="font-weight:bold;">Please enter your name:</td>
</tr>
<tr>
<td id="nameFieldContainer"></td>
<td id="sendButtonContainer"></td>
</tr>
在客户端 Java(到 JavaScript)中,它像这样访问 HTML 元素:
final Button sendButton = new Button("Send");
final TextBox nameField = new TextBox();
nameField.setText("GWT User");
我添加了一个容器字段以表明我可以使用 HTML 元素以编程方式添加一个链接:someStuffContainer。我还添加了另一个字段,通过调用 RPC 服务来填写注销 URL:logoutUrlContainer。 (是的,我知道现在有一种更简单的方法可以做到这一点:GWT/GAE(Java): when combined with GAE, app.yaml / web.xml user authentication and login/logout not really working。我只是想看看我是否可以让它工作。)请注意, someStuffContainer 只是为了使它成为一个受控实验:将通过使用在服务器端生成的注销链接填写该 URL 以编程方式添加 URL;这将在下面相关。
<tr colspan="2">
<td id="someStuffContainer"></td>
</tr>
<tr colspan="2">
<td id="logoutUrlContainer"></td>
</tr>
在客户端 Java(到 JavaScript)中,我这样做了:
// make it clear that we can add something to the page
final HTML someStuffHTML = new HTML
("<a href=https://www.google.com/search?q=zap>some stuff 3</a>");
// provide the user with a logout URL; FIX: do this by just
// providing a link to a generic logout servlet, rather than by
// proactively creating the logout link here.
final HTML userStatusHTML = new HTML();
GWT.log("userStatusService.getStatus()");
userStatusService.getStatus
("/", new AsyncCallback<UserStatusServiceResponse>() {
public void onFailure(Throwable caught) {
GWT.log("userStatusService.onFailure()");
LogUtil.logThrowable(caught);
}
public void onSuccess(UserStatusServiceResponse result) {
GWT.log("userStatusService.onSuccess()");
if (result.loggedIn) {
userStatusHTML.setHTML("<a href=\""+ result.logOutUrl+
"\">log out</a>");
} else {
// FIX: we should actually redirect to the base page
userStatusHTML.setHTML("<a href=\""+ result.logInUrl+
"\">log in</a>");
}
}
});
RootPanel.get("someStuffContainer").add(someStuffHTML);
RootPanel.get("logoutUrlContainer").add(userStatusHTML);
这一切都在程序化 HTML 显示并单击注销 url 将用户注销的意义上起作用。 (要查看这项工作,您必须在另一个选项卡中打开注销 url;如果您转到另一个页面,GWT devmode 插件会崩溃;它似乎进入了一种状态,它只是不断抱怨应用程序需要重新编译并您无法退出该状态。此外,您必须重新加载应用程序引擎才能要求您再次登录;如果您已注销并且客户端仍在运行,您可以继续使用该应用程序,除非打开您正在检查用户的服务器端是否已登录。)
在我看来,容器字段“logoutUrlContainer”的名称根本不重要。因此,在签入之前,我想我会清理代码并将其重命名为更通用的名称,这反映了我可能将该容器用于更通用的用户状态小部件的事实。所以我将“logoutUrlContainer”重命名为“userStatusContainer”;我在 .html 和客户端 Java(编译为 JavaScript)中重命名了它。现在,这一行得到了一个空指针异常,而不是工作:
RootPanel.get("logoutUrlContainer").add(userStatusHTML);
我是一位经验丰富的编码员:我确定要复制和粘贴以使字符串匹配。我检查了使用 emacs 中的搜索功能。我使用 ant clean 来清理整个项目。我使用 grep 对整个项目中可能被 ant clean 遗漏的任何二进制文件(例如类文件)进行 grep 处理,并且不知何故仍然包含旧名称。我重新启动了服务器,关闭了包含该应用程序的浏览器选项卡,等等。我重复所有这些。我反复得到空指针异常。我想我一遍又一遍地做了这一切至少一个小时。请注意, someStuffContainer 始终有效;不知何故 RootPanel.get() 总是找到它,而没有找到 userStatusContainer。最后,无奈之下,我只是重新命名了容器字符串。它立即起作用。我签到了。
这到底是怎么回事? ant clean 缺少什么吗?这是我自己扩展的 ant clean 目标:
<target name="clean" description="Cleans this project">
<delete dir="gwt-unitCache" failonerror="false" />
<delete dir="war/myapp" failonerror="false" />
<delete dir="war/WEB-INF/classes" failonerror="false" />
<delete dir="war/WEB-INF/lib" failonerror="false" />
<delete dir="war/WEB-INF/deploy" failonerror="false" />
<delete file="war/WEB-INF/appengine-web.xml" failonerror="false" />
<delete file="war/WEB-INF/web.xml" failonerror="false" />
</target>
我没有删除所有 war/WEB-INF 的唯一原因是我使用可选的 app.yaml 来配置 Java Google App Engine,而不是自己编辑 .xml 文件。
我的 ant clean 目标是否遗漏了什么?这种体验真的让我不想用GWT了。
更新:我想我知道发生了什么:javascript 正在重新编译,但我从未想过 GWT 开发插件会允许缓存页面。后来我更改了欢迎文件列表,旧的欢迎文件仍在显示。研究配置文件,我想不出任何可能的方法。最后我只是点击重新加载并显示新文件。
无论如何,缓存可以解释这个问题中报告的错误。我不知道 GWT 正在做什么以允许缓存页面,尤其是在开发模式下。你认为在做了 15 年的网络开发人员之后,我可能更早地想到了这一点。但是我无法想象人们怎么可能对缓存效果如此草率,尤其是在开发框架中。
我正在运行最新版本的 OS X 10.6.8 (x86)。 我的浏览器是 Chrome:16.0.912.63(官方版本 113337) $ java -版本 java版本“1.6.0_29” Java(TM) SE 运行时环境 (build 1.6.0_29-b11-402-10M3527) Java HotSpot(TM) 64 位服务器 VM(内部版本 20.4-b02-402,混合模式) 我正在使用 gwt-2.4.0。
【问题讨论】:
标签: java google-app-engine gwt ant