beanshell、jcef

news2024/12/23 7:47:14

BeanShell

BeanShell是一个小型嵌入式Java源代码解释器,具有对象脚本语言特性,能够动态地执行标准JAVA语法。

BeanShell不仅仅可以通过运行其内部的脚本来处理Java应用程序,还可以在运行过程中动态执行你java应用程序执行java代码。因为BeanShell是用java写的,运行在同一个虚拟机的应用程序,因此可以自由地引用对象脚本并返回结果。

BeanShell - Introduction

1、eval()

对脚本进行反射式访问的最简单形式是通过 eval() 命令....

工程在pom.xml引入

    <dependency>
        <groupId>org.beanshell</groupId>
        <artifactId>bsh-core</artifactId>
        <version>2.0b4</version>
    </dependency>

eval返回值为Object,可以通过eval()求文本表达式的值或者运行脚本;

Object o=interpreter.eval(str);

 bsh(BeanShell)动态执行java代码

public static void main(String[] args) throws EvalError {
    Interpreter bsh = new Interpreter();
    //循环打印变量
    bsh.eval("for(int i=0; i<5; i++) { System.out.println(\"hello\"); }");
}

2、source

把刚刚的"beanshell脚本"修改一下输出,放入一个文件中

String bshPath="C:\\Users\\Administrator\\Desktop\\slenium\\demo.bsh";
Interpreter bsh = new Interpreter();
//导入并执行一个脚本文件
bsh.source(bshPath);  // or bsh.eval("source(\"myscript.bsh\")");

1


3、松类型变量

Java是强类型的语言,必须声明类型,但是 BeanShell松散类型,可以不用定义变量类型。

元类型:省略掉变量类型

foo = "Foo";
num = (2 + 3) * 10 / 2;
System.out.println(foo + " = " + num);

运行结果:

对象类型:省略掉变量类型。

button = new JButton( "My Button" );
frame = new JFrame( "My Frame" );
frame.getContentPane().add( button, "Center" );
frame.pack();
frame.setVisible(true);

运行结果


4、set()和get()

set()方法传递对象的变量参数给BeanShell

将10赋值给num

interpreter.set("num", 10);

通过get()方法去取得BeanShell中的变量

interpreter.get("num");
Interpreter interpreter = new Interpreter();
interpreter.set("num", 5);
interpreter.get("num");

5、脚本方法

可以声明和使用方法就像在Java中一样。

在main函数里执行脚本,并调用demo.bsh里的函数

 public static void main(String[] args) throws EvalError, IOException {
     String bshPath = "C:\\Users\\Administrator\\Desktop\\slenium\\demo.bsh";
     Interpreter bsh = new Interpreter();
     //导入并执行脚本
     bsh.source(bshPath);
     //调用脚本的函数
     Object eval = bsh.eval("addTwoNumbers(2,8)");
     System.out.println(eval);//10
 }

扩展:获取脚本中定义了哪些方法

getMethods() 返回 bsh.BshMethod 对象的数组,这些对象是 BeanShell 脚本方法的内部解析表示形式的包装器:

int addTwoNumbers( int a, int b ) {
    return a + b;
}
//打印此命名空间中定义的方法
System.out.println(this.namespace.getMethods()); 

java 反射 API 使用特殊的类值来表示基本类型,例如 int、char、boolean。这些类型是各自原始包装类中的静态字段。例如 Integer.TYPE、Character.TYPE、Boolean.TYPE。

要调用脚本方法,请调用其 invoke() 方法,并传递参数数组、解释器引用和“callstack”引用。

int subTwoNumbers( int a, int b ) {
	System.out.println("调用方法subTwoNumbers");
    return a - b;
}
//查找定义的方法
name="subTwoNumbers";
signature = new Class [] { Integer.TYPE, Integer.TYPE };
bshMethod = this.namespace.getMethod( name, signature );
//调用方法
bshMethod.invoke( new Object [] { new Integer(10), new Integer(2) }, 
    this.interpreter, this.callstack );

6、添加第三方jar

准备好我们的第三方jar,如:fastjson.jar

在demo.bsh脚本中使用fastjson.jar中的方法

添加第三方jar的方法如下:
interpreter.getClassManager().addClassPath(jarFile.getAbsoluteFile().toURI().toURL());

调用bsh脚本并执行

String bshPath = "C:\\Users\\Administrator\\Desktop\\slenium\\demo.bsh";
Interpreter bsh = new Interpreter();
//最关键的一步,添加第三方jar
File jarFile = new File("E:\\tmp\\fastjson-1.2.29.jar");
bsh.getClassManager().addClassPath(jarFile.getAbsoluteFile().toURI().toURL());
//接着就可以在脚本中引入并使用了
bsh.source(bshPath);

运行结果如下


JCEF

JCEF的官方网站(chromiumembedded / java-cef / wiki / Home — Bitbucket)

Java Chromium嵌入式框架(JCEF)。 一个简单的框架,用于使用Java编程语言在其他应用程序中嵌入基于Chromium的浏览器

进程模型

Browser被定义为主进程,负责窗口管理,界面绘制和网络交互Blink的渲染和Js的执行被放在一个独立的Render 进程中;除此之外,Render进程还负责Js Binding和对Dom节点的访问 默认的进程模型中,会为每个标签页创建一个新的Render进程

Browser和Render进程可以通过发送异步消息进行双向通信

一个从Browser进程发送到Render进程的消息将会在CefRenderProcessHandler::OnProcessMessageReceived()方法里被接收。一个从Render进程发送到Browser进程的消息将会在CefClient::OnProcessMessageReceived()方法里被接收。

JavaScript被集成在Render进程,但是需要频繁和Browser进程交互。 JavaScript API应该被设计成可使用闭包异步执行。


入门案例

初始化JCEF:在应用程序启动时,必须先初始化JCEF

import org.cef.CefApp;
import org.cef.CefClient;
import org.cef.CefSettings;
import org.cef.OS;
import org.cef.browser.CefBrowser;
import org.cef.handler.CefAppHandlerAdapter;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class TestFrame extends JFrame {

    private static final long serialVersionUID = -7410082787754606408L;

    public static void main(String[] args) {
        new TestFrame();
    }

    public TestFrame() {
        //是否Linux系统
        boolean useOSR = OS.isLinux();
        //是否透明
        boolean isTransparent = false;
        //添加Handler,在CEFAPP状态为终止时退出程序
        CefApp.addAppHandler(new CefAppHandlerAdapter(null) {
            @Override
            public void stateHasChanged(org.cef.CefApp.CefAppState state) {
                // Shutdown the app if the native CEF part is terminated
                if (state == CefApp.CefAppState.TERMINATED) System.exit(0);
            }
        });

        //--------------------------初始化JCEF---------------------------
        CefSettings settings = new CefSettings();
        settings.windowless_rendering_enabled = useOSR;
        //获取CefApp实例
        CefApp cefApp = CefApp.getInstance(settings);
        //创建客户端实例
        CefClient cefClient = cefApp.createClient();

        //-----------------------------创建浏览器实例-------------------------------
        //创建一个新的浏览器实例,并打开指定的URL
        CefBrowser cefBrowser = cefClient.createBrowser("http://hao.fly63.com/", useOSR, isTransparent);
        //将浏览器UI添加到窗口中
        getContentPane().add(cefBrowser.getUIComponent(), BorderLayout.CENTER);

        pack();
        setTitle("JCEF打开极简导航");
        setSize(800, 600);
        setVisible(true);
        //添加一个窗口关闭监听事件
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                CefApp.getInstance().dispose();
                dispose();
            }
        });
    }
}

CefSettings

CefSettings结构体允许定义全局的CEF配置,经常用到的配置项如下

single_process 设置为true时,Browser和Renderer使用一个进程。

locale 此设置项将传递给Blink。如果此项为空,将使用默认值“en-US”。

log_file 此项设置的文件夹和文件名将用于输出debug日志。如果此项为空,默认的日志文件名为debug.log,位于应用程序所在的目录

log_severity 此项设置日志级别。只有此等级、或者比此等级高的日志的才会被记录。此项可以通过命令行参数“log-severity”配置,可以设置的值为“verbose”,“info”,“warning”,“error”,“error-report”,“disable”。

emote_debugging_port 此项可以设置1024-65535之间的值,用于在指定端口开启远程调试。例如,如果设置的值为8080,远程调试的URL为http://localhost:8080。CEF或者Chrome浏览器能够调试CEF


执行JavaScript代码

一旦有了浏览器实例,就可以使用CefBrowser类提供的方法与网页进行交互。例如,你可以执行JavaScript代码、发送消息给网页等

执行JavaScript代码

cefBrowser.executeJavaScript("document.getElementById('myElement').innerHTML = 'Hello, JCEF!';", "",0);

----


发送消息给网页

发送消息给网页:

CefProcessMessage message = CefProcessMessage.create("myMessage");
message.getArgumentList().setString(0, "Hello, JCEF!"); cefBrowser.sendProcessMessage(CefProcessId.BROWSER, message);


处理网页发送的消息

render进程和browser进程之间是通两端的消息路由传递消息的,

创建了一个CefMessageRouterHandlerAdapter的子类,重写了onQuery方法来处理来自JavaScript的查询。

import org.cef.browser.CefBrowser;
import org.cef.browser.CefFrame;
import org.cef.callback.CefQueryCallback;
import org.cef.handler.CefMessageRouterHandlerAdapter;

public class JCEFMessageRouterHandler extends CefMessageRouterHandlerAdapter {
    
    //重写了onQuery方法来处理来自JavaScript的查询
    @Override
    public boolean onQuery(CefBrowser browser, CefFrame frame, long query_id, String request, boolean persistent,
                           CefQueryCallback callback) {
        if (request.equals("getJavaData")) {
            String javaData = "This data is from Java";
            callback.success(javaData);
            return true;
        }
        return false;
    }
}

JCEF使得在Java应用程序中嵌入Chromium引擎成为可能,并且通过使用CefMessageRouter,您可以在Java和JavaScript之间实现双向的交互。

将这个JCEFMessageRouterHandler注册到CefMessageRouter中。这样,您就可以在JavaScript中使用cefQuery来与Java进行交互了

//配置一个查询路由,html页面可使用 window.java({}) 和 window.javaCancel({}) 来调用此方法
CefMessageRouter.CefMessageRouterConfig cmrc = new CefMessageRouter.CefMessageRouterConfig("java", "javaCancel");
//创建查询路由
CefMessageRouter router = CefMessageRouter.create(cmrc);
router.addHandler(new JCEFMessageRouterHandler(), true);
cefClient.addMessageRouter(router);

当JavaScript代码中调用cefQuery并传递"getJavaData"时,Java代码会返回一段数据。

// 在JavaScript中调用Java方法并获取返回值
cefQuery({
  request: "getJavaData",
  onSuccess: function (response) {
    console.log("Data from Java: " + response);
  },
  onFailure: function (errorCode, errorMessage) {
    console.error("Java query failed: " + errorCode + " - " + errorMessage);
  },
});

举例: 用js去打开文件选择对话框

    //打开文件选择器
    public static void openFileChooser(CefBrowser browser, final CefQueryCallback callback) {
        CefRunFileDialogCallback dialogCallBack = new CefRunFileDialogCallback() {

            @Override
            public void onFileDialogDismissed(int selectedAcceptFilter, Vector<String> filePaths) {
                if (filePaths.size() == 0) {
                    return;
                }
                File selectedFile = new File(filePaths.get(0));
                if (selectedFile != null) {
                    String selectedPath = selectedFile.getAbsolutePath();
                    System.out.println(selectedPath);
                    callback.success(selectedPath);
                }
            }
        };
        browser.runFileDialog(CefDialogHandler.FileDialogMode.FILE_DIALOG_OPEN, "文件选择器", null, null, 0, dialogCallBack);
    }

弹出窗口处理

CefLifeSpanHandlerAdapter:弹出窗口创建一个处理的Handler

当我们点击target值为_blank的链接时,JCEF默认以弹出窗口的形式打开新页面。创建一个实现CefLifeSpanHandlerAdapter的类,重写onBeforePopup方法:根据url创建一个CefBrowser对象。

Browser生命周期(Browser Life Span)

public class LifeSpanHandler extends CefLifeSpanHandlerAdapter {
     
    private TabbedPaneTestFrame frame;
     
    public LifeSpanHandler(TabbedPaneTestFrame frame) {
        this.frame=frame;
    }
     
    /* (non-Javadoc)
     * @see org.cef.handler.CefLifeSpanHandlerAdapter#onBeforePopup(org.cef.browser.CefBrowser, org.cef.browser.CefFrame, java.lang.String, java.lang.String)
     */
    @Override
    public boolean onBeforePopup(CefBrowser browser, CefFrame frame, String target_url, String target_frame_name) {
        this.frame.createBrowser(target_url);
        //返回true表示取消弹出窗口
        return true;
    }
}

设置onBeforePopup方法的返回值为true,取消弹出窗口


Java SPI 机制

SPI(Service Provider Interface),是JDK内置的一种服务提供发现机制,可以用来启用框架扩展和替换组件。Java的SPI机制可以为某个接口寻找服务实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1309044.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络传输层(期末、考研)

计算机网络总复习链接&#x1f517; 目录 传输层的功能端口UDP协议UDP数据报UDP的首部格式UDP校验 TCP协议&#xff08;必考&#xff09;TCP报文段TCP连接的建立TCP连接的释放TCP的可靠传输TCP的流量控制零窗口探测报文段 TCP的拥塞控制慢开始和拥塞控制快重传和快恢复 TCP和U…

【网络编程之初出茅庐】

前言&#xff1a;本章主要先讲解一些基本的网络知识&#xff0c;先把基本的知识用起来&#xff0c;后续会更深入的讲解底层原理。 网络编程的概念 网络编程&#xff0c;指网络上的主机&#xff0c;通过不同的进程&#xff0c;以编程的方式实现网络通信&#xff08;或称为网络数…

SAP 标准GUI 中增加按钮时报错:EC181

今天在打一个note的时候&#xff0c;需要做一些手动的调整&#xff0c;其中的步骤就需要我去在标准的GUI STATUS 增加按钮 我在进入编辑模式的时候&#xff0c;直接去插入的时候&#xff0c;始终报错如下&#xff1a; Function code xxxx has not been assigned to a functio…

数据结构与算法:插入排序

原理 保证区间内排好顺序&#xff0c;逐渐将区间外数据插入到该区间中。 从局部扩散到整体。 第一次&#xff1a;保证0-1范围内有序 arr[0]和arr[1]对比&#xff0c;若arr[0] 大于 arr[1] &#xff0c;交换两个值&#xff0c; 0-1范围内有序。 第二次&#xff1a;保证 0-2 …

蓝牙物联网全屋智能系统解决方案

#蓝牙物联网# 蓝牙物联网全屋智能系统解决方案是一种通过低功耗蓝牙技术将家中的各种设备连接到一起&#xff0c;实现家居物联智能操控的方案。 全屋智能系统解决方案是一种将智能家居设备、传感器、照明、安防等系统集成在一起&#xff0c;实现全屋智能化控制的方案。 蓝牙物…

如何用python编写抢票软件,python爬虫小程序抢购

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python小程序抢购脚本怎么写&#xff0c;如何用python编写抢票软件&#xff0c;现在让我们一起来看看吧&#xff01; 大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python小程序抢购脚本怎么写&#xff0c;如…

【剑指offer|图解|二分查找】点名 + 统计目标成绩的出现次数

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;数据结构、剑指offer每日一练 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 一. ⛳️点名1.1 题目1.2 示例1.3 限制1.4 解题思路一c代码 1.5 解题思路二c代码 二. ⛳️统…

ARM I2C通信

1.概念 I2C总线是PHLIPS公司在八十年代初推出的一种串行的半双工同步总线&#xff0c;主要用于连接整体电路2.IIC总线硬件连接 1.IIC总线支持多主机多从机&#xff0c;但是在实际开发过程中&#xff0c;大多数采用单主机多从机模式 2.挂接到IIC总线上&#xff0c;每个从机设备都…

leetcode--1004 最大连续1的个数 III[滑动窗口c++]

原题链接&#xff1a; 3. 无重复字符的最长子串 - 力扣&#xff08;LeetCode&#xff09; 题目解析&#xff1a; 题目的翻转0&#xff0c;意思就是把0变成1&#xff1b; 将题的 最多可翻转k个0 操作看成 限定范围内最多可有k个0&#xff08;等价转换&#xff09; 因为实…

js 时间字符串截掉微秒后面的内容及加1秒

老规矩先上效果图: 一、js 时间字符串截掉微秒后面的内容&#xff0c;保留前面的 let str 2023-11-27 19:08:34.733; let index str.lastIndexOf(".") str str.substring(0, index); console.log(str) // 2023-11-27 19:08:34 二、转成时间戳&#xff0c;加1秒的…

人机融合与意图理解

人机融合本质上是人类智能与机器自动化之间的协同。 人机融合的目标是利用人类智能和机器自动化的优势&#xff0c;使二者相互补充、相互支持&#xff0c;共同实现更高效、更智能的工作和生活方式。 人类智能和机器自动化具有不同的特点和优势。人类智能具有创造性、灵活性、推…

VS Code串口监视插件Serial Monitor

文章目录 初步使用参数设置VS Code插件 初步使用 Serial Monitor&#xff0c;即串行监视器&#xff0c;提供串口和TCP协议的通信监控功能。在插件栏搜索安装之后&#xff0c;按下Ctrl打开终端&#xff0c;终端界面会多出一个串行监视器选项卡&#xff0c;进入之后&#xff0c;…

基于vue实现的疫情数据可视化分析及预测系统-计算机毕业设计推荐 django

本疫情数据可视化分析及预测系统 开发&#xff0c;用小巧灵活的MySQL数据库做完后台存储解释。本系统不仅主要实现了注册登录&#xff0c;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;全国实时数据管理&#xff0c;每日实时数据管理&#xff0c;国内实时动态…

KUKA机器人如何在程序中编辑等待时间?

KUKA机器人如何在程序中编辑等待时间&#xff1f; 如下图所示&#xff0c;如何实现在P1点和P2点之间等待设定的时间&#xff1f; 如下图所示&#xff0c;可以直接输入wait sec 2&#xff08;等待2秒&#xff09;&#xff0c; 如下图所示&#xff0c;再次选中该程序后&#…

ZLMediaKit中的线程

EventLoop的线程模型 服务器通用的IO模型event-loop 非阻塞IO。线程模型可以是单线程&#xff0c;可以是多线程。对于已经普及了的多核环境&#xff0c;通常都是采用多线程。 通常一个线程中有一个EventLoop&#xff0c;比如accept是一个专门线程&#xff0c;accept后的fd分…

I.MX RT1170双核学习(2):双核相互激活和启动流程

RT1170这个芯片带有双核&#xff1a;Cortex-M7和Corterx-M4&#xff0c;两个核都可以独立地运行&#xff0c;当然双核也可以同时运行。在上一篇文章中&#xff0c;介绍了一下在RT1170中消息模块MU的使用&#xff1a;双核通信之MU消息单元详解&#xff0c;因为这是双核之间用来通…

基于Dockerfile创建LNMP

实验组件 172.111.0.10&#xff1a;nginx docker-nginx 172.111.0.20&#xff1a;mysql docker-mysql 172.111.0.30&#xff1a;php docker-php 实验步骤 1.建立nginx-lnmp镜像及容器 cd /opt mkdir nginx cd nginx/ --上传nginx-1.22.0.tar.gz和wordpress-6.4.2-zh_C…

JOSEF 约瑟 时间继电器 DHC6A AC/DC100-240V 面板安装

特点 DIN&#xff08;4848mm&#xff09;标准面板尺寸 9 种工作模式可任意设定&#xff0c;简化外围线路,增强可靠性 带背光源 LCD 显示&#xff0c;在阳光或黑夜都能清晰显示 键保护可按要求锁定相关的按键,保护部分或全部的设定数据不受更 改&#xff0c;有效的防止误操…

02-详解请求路由的实现和常见的断言工厂

请求路由 路由转发 第一步: 新建一个SpringBoot工程如gateway模块, 引入网关依赖和nacos服务发现依赖 <!--网关依赖--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId&…

【免费神器】一键转换PDF文件,轻松解决你的烦恼!

你是否曾经因为PDF文件的格式问题而感到困扰&#xff1f;是否曾经因为无法快速转换PDF文件而感到烦恼&#xff1f; 现在&#xff0c;这些问题都可以迎刃而解了&#xff01;下面这个在线PDF转换网站&#xff0c;就是你的解决方案。 目前5M以下文件免费转换&#xff0c;赶紧来看…