JavaFX 8 WebEngine:如何在java中将console.log()从javascript导入System.out?

17 webview javafx-8 javafx-webengine

我在JavaFX WebEngine中使用JavaFX和javascript引擎来开发应用程序.我想从javascript获取反馈以进行调试.WebEngine中的控制台输出会发生什么?有什么办法可以访问它,或者在java中重定向到System.out吗?

Gil*_*ili 25

以下代码重定向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" +
        "};");
});
Run Code Online (Sandbox Code Playgroud)

  • 似乎没有工作.我对`console.log()`的调用由于某种原因没有被提取. (3认同)
  • 不确定我们是否需要在每次状态更改时都执行此操作 - 也许只是在“newValue == State.SCHEDULED”或其他情况下?否则,我们会在同一个请求中无缘无故地多次覆盖“console.log”。 (2认同)
  • 如果这对你来说像对我一样默默地失败了,可以尝试的一件事是在持久范围内初始化“bridge”(例如,作为对象的成员变量,而不是局部变量)。我认为我的桥在从 JavaScript 调用之前就被垃圾收集了(另请参阅 /sf/answers/2933220811/ 了解有关“setMember”和垃圾收集的详细信息) (2认同)

dzi*_*ysk 9

您也可以添加消息监听器,看看输出中发生了什么.您不必console.log为每个加载的页面重新定义函数注入js桥

WebConsoleListener.setDefaultListener((webView, message, lineNumber, sourceId) -> {
    System.out.println(message + "[at " + lineNumber + "]");
});
Run Code Online (Sandbox Code Playgroud)

  • 遗憾的是,WebConsoleListener 在最新版本的 Java 中不可用。 (3认同)

小智 6

我喜欢往另一个方向走。我们使用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);
    }
  }
Run Code Online (Sandbox Code Playgroud)

然后在javascript的开头,我检查是否存在日志并进行设置:

if(window.log == undefined){
  window.log = require("./utils/log4j-wrapper")
  window.log.level = "INFO"
}
Run Code Online (Sandbox Code Playgroud)

这样一来,如果您在加载URL之前直接在引擎上设置Log4j记录器,例如:

WebEngine webEngine = webView.getEngine()
JSObject win = (JSObject) webEngine.executeScript("window")
win.setMember("log", log)  //log being the java log4j logger
Run Code Online (Sandbox Code Playgroud)

这样,如果我直接在浏览器中打开或者正在JavaFX程序的WebView中运行它,则可以登录。并且具有使javascript登录级别与您的WebView控制器程序包相匹配的附加好处。只是较大的javascript视图的替代方法。