JavaFX 8 WebEngine:如何从 javascript 获取 console.log() 到 java 中的 System.out?

Posted

技术标签:

【中文标题】JavaFX 8 WebEngine:如何从 javascript 获取 console.log() 到 java 中的 System.out?【英文标题】:JavaFX 8 WebEngine: How to get console.log() from javascript to System.out in java? 【发布时间】:2015-04-25 14:16:12 【问题描述】:

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

【问题讨论】:

【参考方案1】:

以下代码将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 调用之前已被垃圾收集(另请参阅 ***.com/a/41903154 了解有关 setMember 和垃圾收集的详细信息) @AndrewHead 我修正了答案。谢谢你指出他!【参考方案2】:

您只需添加消息侦听器即可查看输出中发生的情况。您不必为每个加载的页面注入带有 console.log 等函数的重新定义的 js 桥

WebConsoleListener.setDefaultListener((webView, message, lineNumber, sourceId) -> 
    System.out.println(message + "[at " + lineNumber + "]");
);

【讨论】:

是的,但是您无法像从调试器控制台获得的那样扩展和查看传递给控制台方法的参数或跳转到源代码。 他只是询问了从 console.log 获取输出的问题,所以它是绿人答案的更好选择。专用调试工具属于另一种情况,它并不总是有帮助 - 例如,如果我们想在最终的分布式应用程序中捕获输出。 遗憾的是,WebConsoleListener 在 Java 的最新版本中不可用。【参考方案3】:

我喜欢另辟蹊径。我们使用 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 视图的替代方案。

【讨论】:

以上是关于JavaFX 8 WebEngine:如何从 javascript 获取 console.log() 到 java 中的 System.out?的主要内容,如果未能解决你的问题,请参考以下文章

附加文本WebEngine - JavaFX

JavaFX WebEngine上的UserAgent实现方法

JavaFx Webview JDK 8 无法加载自签名证书

我可以在 JavaFX 中将自签名证书添加到我的 WebEngine 以连接到 https Web 服务器吗?

尝试将本地页面加载到 JavaFX webEngine

JavaFX 2.0+ WebView /WebEngine 将网页呈现为图像