JCEF学习

news2025/1/20 5:52:19

JCEF重要概念

CEF

CEF,全称Chromium Embedded Framework ,它是基于Google Chromium的开源项目,它的目标是能够向第三方程序添加WEB浏览器功能,以及可以使用HTML、CSS和JS渲染界面。

CEF框架是由Marshall Greenblatt 在 2008 年创立的,由C/C++编写而成

而JCEF则是CEF的java接口,可以使用java调用CEF的接口。

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

其他的帮助文档:JCEF帮助文档

https://github.com/fanfeilong/cefutil/blob/master/doc/CEF%20General%20Usage-zh-cn.md

POI文档:POI中文帮助文档


Render进程

Cef3采用了多进程架构,Browser进程为主进程,负责窗口管理、界面绘制、网络交互等;Render进程负责页面渲染、V8引擎、Dom节点等。默认的进程模型中,会为每一个标签页创建一个新的Render进程。

Render进程

CEF 的渲染进程(Render Process)负责处理浏览器窗口内的内容渲染,包括 HTML、JavaScript、CSS 等。

例如,当用户在浏览器中访问一个网页时,CEF 会创建一个渲染进程来解析 HTML 代码,并根据 CSS 和 JavaScript 渲染出网页的内容。

frame render 进程

如果网页中包含了 frame 标签,CEF 会再创建一个 frame render 进程来渲染 frame 内的内容。

CEF 的 frame render 进程可以帮助开发者在应用内嵌入多个浏览器窗口,并且可以让每个浏览器窗口独立地加载和渲染网页内容,从而提升应用的性能和用户体验。


Browser进程

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:在应用程序启动时,必须先初始化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) {
                //CefApp.CefAppState TERMINATED:CefApp已终止,无法再使用。您现在可以安全地关闭应用程序
                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


JCEF重要API

CefSettings

CefSettings定义了Cef的全局配置信息,比如指定单进程模式、指定渲染子进程路径、设置localstorage路径、设置日志等级、Cef资源文件路径。其中对于项目最重要的字段是single_process、multi_threaded_message_loop、windowless_rendering_enabled,分别用于指定单进程模式、多线程渲染模式、离屏渲染模式。
经常用到的配置项如下:

  1. single_process 设置为true时,Browser和Render使用一个进程。此项也可以通过命令行参数”single-process”配置。
  2. browser_subprocess_path 设置用于启动子进程单独执行的路径。
  3. cache_path 设置存放缓存数据的位置。如果此项为空,某些功能使用内存缓存,多数功能使用临时的磁盘缓存。
  4. locale 此设置项将传递给Blink。如果此项为空,将使用默认值”en-US”。在Linux平台下此项被忽略,使用环境变量中的值,解析的依次顺序为:LANGUAE,LC_ALL,LC_MESSAGES和LANG。此项也可以通过命令行参数”lang”配置。
  5. log_file 此项设置文件路径用于输出debug日志,如果此项为空,默认的日志文件名为debug.log,位于应用程序所在的目录。此项也可以通过命令参数”log-file”配置。
  6. log_severity 此项设置日志级别,只有当前等级、或者更高等级的日志才会被记录。此项可以通过命令行参数”log-severity”配置,可以设置的值为”verbose”,”info”,”warning”,”error”,”error-report”,”disable”。
  7. resources_dir_path 此项设置资源文件夹的位置。如果此项为空,Windows平台下cef.pak、Linux平台下devtools_resourcs.pak、Mac OS X下的app bundle Resources目录必须位于组件目录。此项也可以通过命令行参数”resource-dir-path”配置。
  8. locales_dir_path 此项设置locale文件夹位置。如果此项为空,locale文件夹必须位于组件目录,在Mac OS X平台下此项被忽略,pak文件从app bundle Resources目录。此项也可以通过命令行参数”locales-dir-path”配置。
  9. remote_debugging_port 此项可以设置1024-65535之间的值,用于在指定端口开启远程调试。此项也可以通过命令行参数”remote-debugging-port”配置。
  10. command_line_args_disabled 用于禁用Cef进程命令行参数功能,只能通过CefSettings方式进行设置。

1


CefApp

CefApp接口提供了不同进程的可定制回调函数,每一个进程对应一个CefApp接口

 CefApp:公开用于管理全局 CEF 上下文的静态方法

1、addAppHandler(CefAppHandler appHandler)

//将一个AppHandler分配给CefApp,必须在初始化CefApp之前调用此方法
public static void addAppHandler(CefAppHandler appHandler) throws java.lang.IllegalStateException

2、createClient()

//创建一个新的客户端实例并将其返回给调用者
public CefClient createClient()

3、getInstance(

//CefApp已启动并正在运行。至少创建了一个CefClient,并且消息循环正在运行。您现在可以使用JCEF的所有类和方法。
public static final CefApp.CefAppState INITIALIZED

//CefApp正在进行初始化过程。请等待初始化完成
public static final CefApp.CefAppState INITIALIZING


//(CefApp是新创建的,但尚未初始化。到目前为止,还没有CefClient和CefBrowser被创建
public static final CefApp.CefAppState NEW

 settings)

//获取CefApp类的实例
public static CefApp getInstance(CefSettings settings) throws java.lang.UnsatisfiedLinkError

4、dispose()

//调用此方法将关闭所有客户端实例以及每个客户端拥有的所有浏览器实例。此后,消息循环终止并且CEF关闭
public final void dispose()

CefApp.CefAppState 枚举常量

总共有6个

//CefApp已启动并正在运行。至少创建了一个CefClient,并且消息循环正在运行。您现在可以使用JCEF的所有类和方法
public static final CefApp.CefAppState INITIALIZED


//CefApp已终止,无法再使用。您现在可以安全地关闭应用程序
public static final CefApp.CefAppState TERMINATED

CefClient

Client that owns a browser and renderer.:拥有浏览器和渲染器的客户端

每一个CefBrowser对象会对应一个CefClient接口,用于处理浏览器页面的各种回调信息,包括了Browser的生命周期,右键菜单,对话框,状态通知显示,下载事件,拖曳事件,焦点事件,键盘事件,离屏渲染事件等。

public CefBrowser createBrowser(java.lang.String url,
                                boolean isOffscreenRendered,
                                boolean isTransparent)


//返回所有浏览器实例的列表
protected java.lang.Object[] getAllBrowser()

CefClient: 提供了一些获取Handler的方法。

  • CefDisplayHandler: 回调类,用来处理与页面状态相关的事件,如页面加载情况的变化,地址栏变化,标题变化等。
  • CefLifeSpanHandler: 回调类,主要用来处理与浏览器生命周期相关的事件,和浏览器对象的创建、销毁以及弹出框的管理。
  • CefLoadHandler: 回调类,主要用来处理浏览器页面加载状态的变化,如页面加载开始,完成,出错等。

CefBrowser

Interface representing a browser. (代表浏览器的界面)

//获取与此浏览器关联的客户端
CefClient getClient()


//要求关闭浏览器。 close表示是否强制关闭
void close(boolean force)

//返回唯一的浏览器标识符
int getIdentifier()

//在此框架中执行一串JavaScript代码
void executeJavaScript(java.lang.String code,
                       java.lang.String url,
                       int line)

//返回浏览器窗口的框架
CefFrame getFocusedFrame()

//返回浏览器窗口的顶层框架
CefFrame getMainFrame()

//如果窗口是弹出窗口,则为true
boolean isPopup()

//重新加载当前页面
void reload()

//如果document已加载到浏览器中,则为true
boolean hasDocument()

关于Frame的

//返回当前存在的Frame个数
int getFrameCount()

//返回所有现有的框架的标识符
java.util.Vector<java.lang.Long> getFrameIdentifiers()

//返回所有现有的框架的名称
java.util.Vector<java.lang.String> getFrameNames()


-----------------------------------------

//返回具有指定标识符的Frame;如果未找到,则返回NULL
CefFrame getFrame(long identifier)

//返回具有指定名称的框架,如果找不到,则返回NULL。
CefFrame getFrame(java.lang.String name)

CefFrame

//返回此框架的名称。如果框架具有分配的名称(例如,通过iframe的“名称”属性设置),则将返回该值。
//否则,将基于框架父级层次结构构造一个唯一的名称。
java.lang.String getName()

//返回此框架的父级;如果这是主要(顶级)框架,则返回NULL
CefFrame getParent()

//如果此框架是顶级,则为True,否则为false
boolean isMain()


//发出当前加载到该框架中的 URL
java.lang.String getURL()


//在此框架中执行一串JavaScript代码
void executeJavaScript(java.lang.String code,
                       java.lang.String url,
                       int line)

code -要执行的代码
url -可以找到相关脚本的网址
line -用于错误报告的基线号

CefLifeSpanHandler

CefBrowser对象的生命周期事件的回调接口。

//创建浏览器对象后会立马触发这个回调
void onAfterCreated(CefBrowser browser)


//当浏览器对象即将销毁时会触发这个回调
void onBeforeClose(CefBrowser browser)

//在浏览器收到关闭请求时调用
boolean doClose(CefBrowser browser)


//当单击了网页中会弹出新窗口的链接时,会触发这个回调,要取消创建弹出窗口,请返回true
boolean onBeforePopup(CefBrowser browser,
                      CefFrame frame,
                      java.lang.String target_url,
                      java.lang.String target_frame_name)

1


CefQueryCallback

Interface representing a query callback. (表示查询回调的接口

//通知关联的 JavaScript onFailure 回调查询失败
void failure(int error_code,
             java.lang.String error_message)

error_code  -错误代码传递给JavaScript
error_message -错误消息传递给JavaScript


//通知关联的JavaScript onSuccess回调查询已成功完成
void success(java.lang.String response)
response - 传递给JavaScript的响应

CefMessageRouter

//使用默认配置创建一个新路由器
public static final CefMessageRouter create()


//创建具有指定配置的新路由器
public static final CefMessageRouter create(CefMessageRouter.CefMessageRouterConfig config)


//添加一个新的查询处理程序
public abstract boolean addHandler(CefMessageRouterHandler handler,
                                   boolean first)
handler-要添加的处理程序
first -如果为true,则将处理程序添加为第一个处理程序,否则将添加为最后一个处理程序

//删除现有的查询处理程序,成功删除则返回为True。
public abstract boolean removeHandler(CefMessageRouterHandler handler)

//如果不再使用CefMessageRouter实例,则必须调用
public abstract void dispose()

1


CefMessageRouterHandler

onQuery

  • 返回如果为True,则处理查询;
  • 返回如果为false,则将查询传播到其他注册的处理程序(如果有)。

如果没有处理程序从此方法返回true,则查询将被自动取消,并向JavaScript onFailure回调传递错误代码-1

//当浏览器收到JavaScript查询时调用
boolean onQuery(CefBrowser browser,
                CefFrame frame,
                long queryId,
                java.lang.String request,
                boolean persistent,
                CefQueryCallback callback)

browser -相应的浏览器
frame -生成事件的框架。实例仅在此方法的范围内有效
queryId -查询的唯一ID
persistent -如果查询是持久的,则为true
callback -用于异步继续或取消查询的对象

1

//(取消待处理的JavaScript查询时调用
void onQueryCanceled(CefBrowser browser,
                     CefFrame frame,
                     long queryId)

browser -相应的浏览器
frame -生成事件的框架。实例仅在此方法的范围内有效
queryId -查询的唯一ID

CefMessageRouterHandlerAdapter用于接收消息路由器事件的抽象适配器类。此类中的方法为空。此类的存在是为了方便创建处理程序对象


JCEF应用举例

执行JavaScript代码

CEF使用的V8 JavaScript 引擎用于内部JavaScript实现,每一个frame都有JS上下文(context),为JS代码执行提供范围和安全。CEF暴露了很多JS特性可以和客户端程序进行交互。

CefBrowser:一个普通的浏览器页面(HTML)
CefFrame:每一个页面都由至少一个frame组成,最顶层的为mainframe
context:JS执行环境,每个frame都有自己独立的context,CEF中使用V8 JavaScriptEngine解析和执行JS代码

执行JavaScript代码

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

CEF有专门的调用js方法的函数:executeJavaScript,它是一个属于CefFrame类的方法。所以我们想要调用js的方法,只需要获取到页面的frame,然后调用executeJavaScript就可以了。

//在此框架中执行一串JavaScript代码
void executeJavaScript(java.lang.String code,
                       java.lang.String url,
                       int line)

参数一是要执行的js语句;

参数二是可以找到问题脚本(如果有的话)的URL。渲染器可能会请求这个URL来向开发人员显示错误的来源;

第三个参数是用于错误报告的基线编号。


发送消息给网页

发送消息给网页:

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


处理网页发送的消息

当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);
  },
});

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

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);

创建了一个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;
    }
}

文件选择对话框

举例: 用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

//onBeforePopup 在接口中  CefLifeSpanHandler
public boolean onBeforePopup(CefBrowser browser,
                             CefFrame frame,
                             java.lang.String target_url,
                             java.lang.String target_frame_name)


browser - 弹出请求的来源
frame - 弹出请求的来源。实例仅在此方法的范围内有效
target_url -如果请求中未指定任何内容,则可以为空
target_frame_name -如果请求中未指定任何内容,则可以为空

返回:如果为True,则取消创建弹出窗口;如果为false,则继续进行。)

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


开发者工具

public class DevToolsDialog extends JDialog {
    /**
	 * 
	 */
	private static final long serialVersionUID = 4115973232808017898L;
	
	private final CefBrowser devTools_;
    public DevToolsDialog(Frame owner, String title, CefBrowser browser) {
        this(owner, title, browser, null);
    }

    public DevToolsDialog(Frame owner, String title, CefBrowser browser, Point inspectAt) {
        super(owner, title, false);

        setLayout(new BorderLayout());
        setSize(1000, 800);
        setLocation(owner.getLocation().x + 20, owner.getLocation().y + 20);

        devTools_ = browser.getDevTools(inspectAt);
        add(devTools_.getUIComponent());

        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentHidden(ComponentEvent e) {
                dispose();
            }
        });
    }

    @Override
    public void dispose() {
        devTools_.close(true);
        super.dispose();
    }
}

怎么打开devtools呢

DevToolsDialog devToolsDlg = new DevToolsDialog(CefManager.getInstance().getFrame(), "开发者工具-"+browser.getMainFrame().getName(), browser);
devToolsDlg.setVisible(true);

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

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

相关文章

vue项目如何实现运行完项目就跳转到浏览器

在package.json中的启动命令中添加--open参数可以实现在Vue项目编译后自动打开浏览器的功能。 通过这样的设置&#xff0c;在运行npm run dev时&#xff0c;Vue项目编译完成后会自动打开默认浏览器并加载应用程序。

【问题解决】java-word转pdf踩坑

问题情境&#xff1a; 项目中采用word转pdf&#xff0c;最开始使用的pdf相关的apache的pdfbox和itextpdf&#xff0c;后面发现对于有图片背景的word转pdf的情景&#xff0c;word中的背景图会直接占用位置&#xff0c;导致正文不会正确落在背景图上。 解决方案&#xff1a; 采…

计算机网络——虚拟局域网+交换机基本配置实验

1.实验题目 虚拟局域网交换机基本配置实验 2.实验目的 1.了解交换机的作用 2.熟悉交换机的基本配置方法 3.熟悉Packet Tracer 7.0交换机模拟软件的使用 4.掌握在交换机上划分局域网&#xff0c;并且使用局域网与端口连接&#xff0c;检测信号传输 3.实验任务 1.了解交换…

C 变量

目录 1. C变量 2. C变量定义 2.1 变量初始化 2.2 C中的变量声明 3. C中的左值&#xff08;Lvalues&#xff09;和右值&#xff08;Rvalues&#xff09; 1. C变量 在C语言中&#xff0c;变量可以根据其类型分为以下几种基本类型&#xff1a; 整型变量&#xff1a;用…

蓝桥小白赛4 乘飞机 抽屉原理 枚举

&#x1f468;‍&#x1f3eb; 乘飞机 &#x1f437; 抽屉原理 import java.util.Scanner;public class Main {static int N 100010;static int[] a new int[N];public static void main(String[] args){Scanner sc new Scanner(System.in);int n sc.nextInt();int q s…

(南京观海微电子)——OLED驱动与调试

一、OLED DDIC分类 OLED DDIC的技术方向可以分为3类&#xff1a;带Ram【内存】的IC、Ram-less IC和TDDI【显示&触控集成的IC】 1、带Ram的OLED DDIC OLED DDIC有两个Ram&#xff0c;分别是Demura Ram和Display Ram。 1、带Ram的OLED DDIC 1-1&#xff09;Demura Ram&a…

取消Vscode在输入符号时自动补全

取消Vscode在输入符号时自动补全 取消Vscode在输入符号时自动补全问题演示解决方法 取消Vscode在输入符号时自动补全 问题演示 在此状态下输入/会直接自动补全, 如下图 笔者想要达到的效果为可以正常输入/而不进行补全, 如下图 解决方法 在设置->文本编辑器->建议, 取消…

C语言第十一弹---函数(下)

​ ✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 函数 1、嵌套调用和链式访问 1.1、嵌套调用 1.2、链式访问 2、函数的声明和定义 2.1、单个文件 2.2、多个文件 2.3、static 和 extern 2.3.1、static…

STM32+ESP8266 实现物联网设备节点

目录 一、硬件准备 二、编译环境 三、源代码地址 四、说明 五、测试方法 六、所有测试工具和文档 本项目使用stm32F103ZEesp8266实现一个物联网的通信节点&#xff0c;目前支持的协议有mqtt&#xff0c;tcp。后续会持续更新&#xff0c;增加JSON&#xff0c;传感器&#…

MySQL 聚集与非聚集索引

文章目录 1.聚集索引1.1 介绍1.2 优点1.3 缺点 2.非聚集索引3.区别参考文献 MySQL 中&#xff0c;根据索引树叶结点存放数据行还是数据行的地址&#xff0c;可以将索引分为两类&#xff1a; 存放数据行&#xff1a;聚集索引存放数据行地址&#xff1a;非聚集索引 InnoDB 使用聚…

VSCode 1.85.0更新的3个实用功能

1、单个文件可直接拖拽为独立窗口 当单文件过长&#xff0c;直接分成两个视图就不用上下频繁滚动 2、将终端移动到编辑器区域 此时&#xff0c;终端也可像文件一样拖拽为独立窗口 3、文件夹目录粘性头部 默认关闭&#xff0c;需要设置 "workbench.tree.enableStickyScro…

【Linux】编写第一个小程序:进度条

文章目录 1. 预备知识1.1 简单认识几个函数1.1.1 sleep()1.1.2 fflush()1.1.3 usleep()1.1.4 memset() 1.2 缓冲区1.3 回车与换行 2. 编写入门版的进度条2.1 基本逻辑2.2 美化效果2.3 代码实现2.4 执行效果 3. 编写升级版的进度条3.1 代码实现3.2 执行效果 1. 预备知识 1.1 简…

php项目中laravel框架下用postman调用接口实战总结

一.项目接口实战总结: 1.传参赋值错乱问题&#xff0c;如下&#xff1a; SQLSTATE[HY093]: Invalid parameter number (SQL: select count(*) as aggregate from cars where company_id 3345 and status ! 7 and user_id in (2148, 2060, 2061, 2432, 2136, 1970, 1987, 202…

Spark Exchange节点和Partitioning

​Exchange 在explain时&#xff0c;常看到Exchange节点&#xff0c;这个节点其实就是发生了数据交换 此图片来自于网络截取 BroadcastExchangeExec 主要是用来广播的 ShuffleExchangeExec 里面决定了数据分布的方式和采用哪种shuffle 在这里可以看到好几种不同的分区器 shuf…

shell 脚本 点菜啦

#!/bin/bash sum0 PS3"请输入(1-6):" MENU" 宫保鸡丁 酸菜鱼 鱼香肉丝 佛跳墙 水煮肉片 点菜结束 "select menu in $MENU do case $REPLY in 1) echo $menu 价格是20 let sum20 ;; 2) echo $menu 价格是60 let sum60 ;;3) echo $menu 价格是25 let sum25 ;…

在linux上进行编译调试

1.相关疑问 1. 为什么在代码里使用了一个未定义过的函数&#xff08;如add()&#xff09;&#xff0c;在编译阶段不会报错&#xff0c;在链接阶段会报错呢&#xff1f; 答&#xff1a;先说几个代码编译的结论&#xff1a; 单个\.c源文件文件被编译成机器码文件时&#xff0c…

如何把openwrt的ipk软件包安装到ubuntu上

前提&#xff1a;都是arm64的架构的软件包。 下载openwrt的ipk软件包 1. 从https://pkgs.org/ 查找下载软件包&#xff1a; 本文以swconfig软件包为例&#xff0c;下载swconfig和相关的依赖软件包&#xff1a; swconfig_12_aarch64_cortex-a72.ipk libuci20130104_2021-10-2…

认识与探索大模型时代的RPA应用及进化(上)

AI Agent当前仍然处于技术爬坡与实验阶段&#xff0c;特别是在企业领域&#xff0c;真正的成熟应用还处于广泛探索与原型验证阶段&#xff0c;离成熟还尚待时日。而同时另外一种在最近几年广受欢迎的自动化解决方案-RPA&#xff08;机器人流程自动化&#xff09;也在LLM时代不断…

python使用迭代生成器yield减少内存占用的方法

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 在python编码中for循环处理任务时&#xff0c;会将所有的待遍历参量加载到内存中。 其实这本没有必要&#xff0c;因为这些参量很有可能是一次性使用的&#xff0c; 甚至很多场景下这些参量是不需要同时存储在内存中的&…

IM-CNN

SHAP means ‘Shapley additive explanation’ 辅助信息 作者未提供代码