我的网络应用程序提供下载。 JavaScript 在点击时创建 url(这取决于用户输入),浏览器应该打开它,这样页面就不会重新加载。
为此,我认为我必须有其他选择:
// Alt1:
window.open(pathToFile);
// Alt2:
var downloadFrame = document.getElementById('downloads');
if (downloadFrame === null) {
downloadFrame = document.createElement('iframe');
downloadFrame.id = 'downloads';
downloadFrame.style.display = 'none';
document.body.appendChild(downloadFrame);
}
downloadFrame.src = pathToFile;
两者都可以在 Firefox 下运行。打开新窗口方法的问题:如果在服务器上创建文件需要更多时间,则新的空选项卡将稍后关闭。 iframe 的问题:如果服务器出现错误,则不会给出任何反馈。
我认为在 Firefox 中 iframe 是更好的解决方案。但 Web 应用程序也必须使用 JavaFX WebView 运行。 JavaFX没有下载功能,我必须自己编写。一种可能的方法是监听位置属性:
final WebView webView = new WebView();
webView.getEngine().locationProperty().addListener(new ChangeListener<String>() {
@Override public void changed(ObservableValue<? extends String> observableValue, String oldLoc, String newLoc) {
if (newLoc.cotains("/download")) {
FileChooser chooser = new FileChooser();
chooser.setTitle("Save " + newLoc);
File saveFile = chooser.showSaveDialog(webView.getEngine().getScene().getWindow());
if (saveFile != null) {
BufferedInputStream is = null;
BufferedOutputStream os = null;
try {
is = new BufferedInputStream(new URL(newLoc).openStream());
os = new BufferedOutputStream(new FileOutputStream(saveFile));
while ((readBytes = is.read()) != -1) {
os.write(b);
}
} finally {
try { if (is != null) is.close(); } catch (IOException e) {}
try { if (os != null) os.close(); } catch (IOException e) {}
}
}
}
}
}
存在一些问题:
- 下载开始取决于url的一部分,因为JafaFX不支持访问http header (这是可以忍受的)
- 如果用户使用相同的 URL 开始下载两次,则只有第一次下载有效(仅当 URL 是新的时才会触发更改事件)。我可以创建唯一的 url(末尾带有 #1、#2 等)。但这很难看。
- 只有“window.open(pathToFile);”方法有效。加载 iframe 不会触发网站的更改位置事件。这是可以预料到的,但我还没有找到合适的监听器。
有人可以帮我解决2.或3.吗?
谢谢!
PS:抱歉我的英语不好。
编辑: 对于2.我找到了一种方法。我不知道它是否好,是否高性能,新的 webview 是否被删除或下载后在缓存中,...... 当出现某些问题时,用户不会得到反馈:
webView.getEngine().setCreatePopupHandler(new Callback<PopupFeatures, WebEngine>() {
@Override public WebEngine call(PopupFeatures config) {
final WebView downloader = new WebView();
downloader.getEngine().locationProperty().addListener(/* The Listener from above */);
return downloader.getEngine();
}
}
请您参考如下方法:
我认为您可能只需要使用 copyURLtoFile 来获取文件...在位置更改时调用该文件,或者仅使用注册的 java 类调用该文件。像这样的事情:
org.apache.commons.io.FileUtils.copyURLToFile(new URL(newLoc), new File(System.getProperty("user.home")+filename));
使用 copyURLToFile 当前页面不必提供文件。我认为注册类(class)可能是最简单的方法......像这样:
PHP 代码:
<a href='#' onclick="app.getfile('$filename' )">Download $filename</a>
Java(javafx 类/窗口中的内联类...在本例中,我的 javafx 窗口位于 jframe 内部):
public class JavaApp {
JFrame cloudFrameREF;
JavaApp(JFrame cloudFrameREF)
{
this.cloudFrameREF = cloudFrameREF;
}
public void getfile(String filename) {
String newLoc = "http://your_web_site.com/send_file.php?filename=" + filename;
org.apache.commons.io.FileUtils.copyURLToFile(new URL(newLoc), new File(System.getProperty("user.home")+filename));
}
}
这部分将放在主 javafx 类中:
Platform.runLater(new Runnable() {
@Override
public void run() {
browser2 = new WebView();
webEngine = browser2.getEngine();
appREF = new JavaApp(cloudFrame);
webEngine.getLoadWorker().stateProperty().addListener(
new ChangeListener<State>() {
@Override public void changed(ObservableValue ov, State oldState, State newState) {
if (newState == Worker.State.SUCCEEDED) {
JSObject win
= (JSObject) webEngine.executeScript("window");
// this next line registers the JavaApp class with the page... you can then call it from javascript using "app.method_name".
win.setMember("app", appREF);
}
}
});
您可能不需要框架引用...我正在修改自己的一些代码来测试这一点,并且该引用对于其他事情很有用...