War*_*kst 5 ajax jquery javafx javafx-webengine
我正在JavaFX中开发一个依赖于WebView(以及WebEngine)的数据挖掘应用程序.挖掘分两步进行:首先,用户使用UI导航到WebView中的网站,以配置可以搜索有趣数据的位置.其次,使用定期运行的后台任务,WebEngine加载相同的文档并尝试从加载的文档中提取数据.
这适用于大多数情况,但最近我遇到了使用AJAX呈现内容的页面遇到的麻烦.要检查是否已WebEngine加载文档,我听loadWorker的stateProperty.如果状态转换为successcesfull,我知道文档已加载(与可能在document.ready()上运行的任何javascript或等效文件一起).这是因为如果我没有弄错的话,javascript会在JavaFX线程上执行(来源:https://blogs.oracle.com/javafx/entry/communicating_between_javascript_and_javafx).但是,如果启动了AJAX调用,则javascript执行完成,引擎让我知道文档已准备就绪,但显然不是因为优秀的AJAX调用内容可能仍然会发生变化.
有没有办法解决这个问题,注入一个钩子,以便在AJAX调用结束时通知我?我已经尝试安装一个默认的完整处理程序,$.ajaxSetup()但这很狡猾,因为如果ajax调用覆盖整个处理程序,则不会调用默认值.另外,我只能在首次加载文档后注入它(然后一些AJAX调用可能已经在运行).我已经使用upcall测试了这个注入,它适用于在命令上启动的AJAX调用(在注入默认处理程序之后),它们不提供自己的完整处理程序.
我正在寻找两件事:第一:挂钩到AJAX调用的完成处理程序的通用方法,其次:等待WebEngine完成所有AJAX调用并在事后通知我的方法.
我也有这个问题并通过提供我自己的实现来解决它sun.net.www.protocol.http.HttpURLConnection,我用它来处理任何AJAX请求.我的类,方便地调用AjaxHttpURLConnection,挂钩到getInputStream()函数,但不返回其原始输入流.相反,我给了一个PipedInputStream回到的实例WebEngine.然后,我读取来自原始输入流的所有数据,并将其传递给我的管道流.这样,我获得了2个好处:
首先,您必须告诉Java使用URLConnection实现而不是默认实现.为此,您必须提供自己的版本URLStreamHandlerFactory.你可以在这里找到很多关于SO(例如这一个)或通过Google的主题.要设置工厂实例,请在main方法的早期将以下内容放在某处.这就是我的样子.
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
public class MyApplication extends Application {
// ...
public static void main(String[] args) {
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("http".equals(protocol)) {
return new MyUrlConnectionHandler();
}
return null; // Let the default handlers deal with whatever comes here (e.g. https, jar, ...)
}
});
launch(args);
}
}
Run Code Online (Sandbox Code Playgroud)
其次,我们必须提出自己的方法Handler,告诉程序何时使用哪种类型的URLConnection.
import java.io.IOException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import sun.net.www.protocol.http.Handler;
import sun.net.www.protocol.http.HttpURLConnection;
public class MyUrlConnectionHandler extends Handler {
@Override
protected URLConnection openConnection(URL url, Proxy proxy) throws IOException {
if (url.toString().contains("ajax=1")) {
return new AjaxHttpURLConnection(url, proxy, this);
}
// Return a default HttpURLConnection instance.
return new HttpURLConnection(url, proxy);
}
}
Run Code Online (Sandbox Code Playgroud)
最后但同样重要的是,来了AjaxHttpURLConnection.
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.net.Proxy;
import java.net.URL;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.io.IOUtils;
import sun.net.www.protocol.http.Handler;
import sun.net.www.protocol.http.HttpURLConnection;
public class AjaxHttpURLConnection extends HttpURLConnection {
private PipedInputStream pipedIn;
private ReentrantLock lock;
protected AjaxHttpURLConnection(URL url, Proxy proxy, Handler handler) {
super(url, proxy, handler);
this.pipedIn = null;
this.lock = new ReentrantLock(true);
}
@Override
public InputStream getInputStream() throws IOException {
lock.lock();
try {
// Do we have to set up our own input stream?
if (pipedIn == null) {
PipedOutputStream pipedOut = new PipedOutputStream();
pipedIn = new PipedInputStream(pipedOut);
InputStream in = super.getInputStream();
/*
* Careful here! for some reason, the getInputStream method seems
* to be calling itself (no idea why). Therefore, if we haven't set
* pipedIn before calling super.getInputStream(), we will run into
* a loop or into EOFExceptions!
*/
// TODO: timeout?
new Thread(new Runnable() {
public void run() {
try {
// Pass the original data on to the browser.
byte[] data = IOUtils.toByteArray(in);
pipedOut.write(data);
pipedOut.flush();
pipedOut.close();
// Do something with the data? Decompress it if it was
// gzipped, for example.
// Signal that the browser has finished.
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
} finally {
lock.unlock();
}
return pipedIn;
}
}
Run Code Online (Sandbox Code Playgroud)
WebEngine对象,那么告诉哪个实际打开了URLConnection哪个以及哪个浏览器已完成加载可能会很棘手.AjaxHttpURLConnection是在相应的url包含时ajax=1.就我而言,这已经足够了.由于我对html和http不太好,但我不知道是否WebEngine可以以任何不同的方式发出AJAX请求(例如标题字段?).如果有疑问,您可以简单地总是返回我们修改的url连接的实例,但这当然意味着一些开销.WebEngine以类似的方式获取您发送的请求数据.只需包装该getOutputStream()函数并放置另一个中间流以捕获正在发送的内容,然后将其传递给原始输出流.