如何在浏览器和Java Web Start小程序之间进行通信

8

现状

我们目前使用一个小程序来执行一些操作,之后它会重定向当前页面。从本质上讲,你可以将这个小程序看作是以下内容:

public class ExampleApplet extends Applet {
    @Override
    public void init() {
        Button redirect = new Button("Redirect");
        this.add(redirect);
        final String target = this.getParameter("targetPage");
        redirect.addActionListener((ActionEvent e) -> {
            try {
                getAppletContext().showDocument(new URL(target), "_parent");
            } catch (MalformedURLException ex) {}
        });
    }
}

以最简单的方式调用小程序:

<applet code="com.example.applet.ExampleApplet.class" archive="${appletUrl}" width="100" height="30">
    <param name="targetPage" value="http://localhost:8080/applet/"/>
</applet><br/><br/>

${appletUrl} 返回应用程序 JAR 的位置。

因此,该 applet 不过是一个简单的按钮,调用 getAppletContext().showDocument(new URL(target), "_parent"); 刷新当前页面。长期以来,它一直能够成功地完成其工作。现在出现了问题。

迁移

众所周知,Chrome 不支持 Applets。然而,由于 IE 和 FireFox 仍然支持它们,此问题被搁置了一段时间。但到了 2016 年底,它们也将停止支持 Applets。因此,我们决定使用 JWS 和 JNLP 迁移该 applet。

对于这个简单的重定向按钮示例的迁移,将生成以下 html 片段和 JNLP 文件:

<a href="${jnlpUrl}">Launch JNLP</a>

${jnlpUrl} 返回 JNLP 文件的位置,即:

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" codebase="http://localhost:8080/applet/assets/1.0-SNAPSHOT-DEV/app/assets/" href="jnlp/example.jnlp">
    <security>
        <all-permissions/>
    </security>
    <resources>
        <j2se version="1.5+" initial-heap-size="32m" max-heap-size="128m" />
        <property name="jnlp.versionEnabled" value="false"/>
        <jar href="applets/ExampleApplet.jar" main="true"/>
    </resources>
    <applet-desc name="code" main-class="com.example.applet.ExampleApplet.class" width="30" height="30" >
        <param name="targetPage" value="http://localhost:8080/applet/"/>
    </applet-desc>
</jnlp>

到目前为止,同样的小程序已经成功部署为JWS应用程序。由于它是在浏览器之外执行的,因此可以从任何浏览器中使用。这也有点问题。
问题是,代码行getAppletContext().showDocument(new URL(target), "_parent");仍然会重定向,但它正在使用默认浏览器,如migration documentation所述。
对于AppletContext.showDocument(URL url,String target),Java Web Start技术将忽略target参数。与AppletContext.showDocument类似,Java Web Start应用程序可以使用BasicService.showDocument API使用系统的默认网络浏览器显示HTML页面。
因此,如果我的默认浏览器是FireFox,但我碰巧在IE / Chrome中浏览此启用了JWS的小程序,则将在FireFox中打开一个新标签页。这是一个问题,因为我在原始浏览器中存储了信息(例如登录信息)!
发现:
由于应用程序在浏览器外运行,我很难想到与原始浏览器进行通信的可能性。我不能使用JavaScript,因为它不在浏览器内运行。我也无法定义一个系统独立的方法来打开原始浏览器中的选项卡。我也考虑过WebSockets,因为它们可以直接通信,但据我所读,它非常高级并且需要一个服务器,而不是一个简单的小程序。
是否有可能在小程序打开新窗口时,在原始浏览器之间进行通信(例如WebSockets和参数)或传递会话?

我知道这个问题......但在你的情况下,为什么要使用小程序来简单地刷新浏览器窗口呢?为什么不只是使用纯 JavaScript 而没有任何小程序呢?在构建你的 jnlp 的位置,你可以以某种方式插入身份验证信息作为另一个参数,然后小程序可以将其附加到其他浏览器中的 showDocument。 - Stefan Hegny
很遗憾,@StefanHegny,这个小程序所做的事情不仅仅是刷新。它比Javascript能实现的更多。重定向小程序只是我面临的问题的一个最小示例。不过,我会尝试将所需参数附加到目标URL中。这是一个不错的起点! - Jaims
好的,我猜到了...我有类似的问题(https://stackoverflow.com/questions/37315819/java-web-start-applet-opening-new-browser-window-tab-ignoring-target),但我想我要放弃了...祝你好运。 - Stefan Hegny
Chrome不支持Applets。虽然IE和FireFox仍然支持它们,但这已经被搁置了一段时间。到2016年底,它们也将不再支持它们。因此,我们决定使用JWS和JNLP迁移applet。但是您有点混淆了。1)首先,Applet启动绝不会使用JWS / JNLP。2)自从引入JWS以来,就一直可以启动自由浮动的Applet,但是在大约1.6.0_10左右,他们添加了在网页内嵌入JWS启动的Applet的功能。4)当Chrome删除插件时,两种形式的嵌入式Applet都不可能。 - Andrew Thompson
  1. 对于自由浮动的小程序,只要用户安装了Java插件,点击JNLP链接就可以直接传递给JavaWS启动器,然后插件会从那里处理。现在他们已经取消了对插件的支持(已经在我的Chrome中),如果我点击JNLP链接,它只会下载它,我必须在下载中双击该文件。
  2. 几乎忘了,只有嵌入式Java小程序才能与网页中的JS交互。如果小程序最初是自由浮动的,或者被拖出了网页,它将无法进行交互。
- Andrew Thompson
2个回答

5

我已经找到了一个可行的解决方案。

由于applet失去了与浏览器和其会话的所有连接,提供通信的另一种方法是使用WebSocketsComet。在我的情况下,我使用了Atmosphere框架和Tapestry-Atmosphere实现来使用Comet,因为Tapestry是我正在使用的视图框架。

不深入探讨Tapestry的实现,我已经做了以下事情:

  • 在客户端浏览器上设置一个Topic,以典型的发布/订阅方式监听广播消息。
  • 将当前浏览用户的唯一Topic ID与发送请求的URL一起提供给Applet。使用Topic ID作为url的请求参数。
  • 服务器端有接收Topic作为请求参数的请求端点。使用此参数,向Topic发送广播(可能为空)。
  • 客户端Topic接收通知并在自身中执行事件。该事件是重新呈现页面特定内容。

由于它使用Comet(但也可以使用WebSockets),因此它直接在浏览器中发生。每个订阅该Topic的浏览器实际上都会发生,但这里只有一个。

使得从小程序的简单请求中更新页面成为可能。小程序只需要将一行代码 getAppletContext().showDocument(new URL(target), "_parent"); 更改为 new URL(target).openConnection().getInputStream();。其中,target 是包含请求参数的URL。请保留HTML标签。

2
这是对一个旧帖子的回答。我们在我们的环境中遇到了类似的情况。以下是解决方法。
此处链接:Can an Applet that uses JavaScript to communicate with web server be migrated to JWS? 解决方法与James描述的类似。我们在服务器端维护了一个以uid为键的请求哈希表。Web应用程序随后长轮询服务器以检查JWS状态;而JWS则向服务器POST状态。
我们没有使用任何第三方组件;它只是简单地连接到URL。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接