【发布时间】:2015-04-25 14:16:12
【问题描述】:
我同时使用 JavaFX 和 JavaFX WebEngine 中的 javascript 引擎来开发应用程序。我想从 javascript 获得反馈以进行调试。 WebEngine 中的控制台输出会发生什么?有什么方法可以访问它,或者在 java 中重定向到 System.out?
【问题讨论】:
标签: webview javafx-8 javafx-webengine
我同时使用 JavaFX 和 JavaFX WebEngine 中的 javascript 引擎来开发应用程序。我想从 javascript 获得反馈以进行调试。 WebEngine 中的控制台输出会发生什么?有什么方法可以访问它,或者在 java 中重定向到 System.out?
【问题讨论】:
标签: webview javafx-8 javafx-webengine
以下代码将console.log() 重定向到JavaBridge.log():
import netscape.javascript.JSObject;
[...]
public class JavaBridge
{
public void log(String text)
{
System.out.println(text);
}
}
// Maintain a strong reference to prevent garbage collection:
// https://bugs.openjdk.java.net/browse/JDK-8154127
private final JavaBridge bridge = new JavaBridge();
[...]
webEngine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) ->
{
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("java", bridge);
webEngine.executeScript("console.log = function(message)\n" +
"{\n" +
" java.log(message);\n" +
"};");
});
【讨论】:
console.log() 的电话由于某种原因没有被接听。
newValue == State.SCHEDULED 或其他什么时候?否则我们会在同一个请求中无缘无故地覆盖console.log。
bridge(例如,作为对象的成员变量,而不是局部变量) .我认为我的网桥在可以从 JavaScript 调用之前已被垃圾收集(另请参阅 stackoverflow.com/a/41903154 了解有关 setMember 和垃圾收集的详细信息)
您只需添加消息侦听器即可查看输出中发生的情况。您不必为每个加载的页面注入带有 console.log 等函数的重新定义的 js 桥
WebConsoleListener.setDefaultListener((webView, message, lineNumber, sourceId) -> {
System.out.println(message + "[at " + lineNumber + "]");
});
【讨论】:
我喜欢另辟蹊径。我们使用 log4j,所以我创建了一个 javascript 包装器,如下所示:
module.exports = {
levels:[ "ALL", "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF"],
level:"INFO",
error:function(msg){
if(this.isErrorEnabled()){
console.error(msg)
}
},
warn:function(msg){
if(this.isWarnEnabled()){
console.warn(msg)
}
},
info:function(msg){
if(this.isInfoEnabled()){
console.log("INFO: "+msg)
}
},
debug:function(msg){
if(this.isDebugEnabled()){
console.log("DEBUG: "+msg)
}
},
trace:function(msg){
if(this.isTraceEnabled()){
console.log("TRACE: "+msg)
}
},
isErrorEnabled:function(){
return this.isEnabled("ERROR");
},
isWarnEnabled:function(){
return this.isEnabled("WARN");
},
isInfoEnabled:function(){
return this.isEnabled("INFO");
},
isDebugEnabled:function(){
return this.isEnabled("DEBUG");
},
isTraceEnabled:function(){
return this.isEnabled("TRACE");
},
isEnabled:function(statementLevel){
return this.levels.indexOf(this.level)<=this.levels.indexOf(statementLevel);
}
}
然后在 javascript 的开头我检查日志是否存在并设置它:
if(window.log == undefined){
window.log = require("./utils/log4j-wrapper")
window.log.level = "INFO"
}
如果您在加载 url 之前直接在引擎上设置 Log4j 记录器,例如:
WebEngine webEngine = webView.getEngine()
JSObject win = (JSObject) webEngine.executeScript("window")
win.setMember("log", log) //log being the java log4j logger
如果我直接在浏览器中打开或者从 JavaFX 程序中的 WebView 运行,我可以通过这种方式登录。并且具有与您的 WebView 控制器包相匹配的 javascript 日志记录级别的额外好处。只是较大 javascript 视图的替代方案。
【讨论】: