luci框架相关笔记

luci架构

LuCI 架构采用了MVC(Model-View-Controller)设计模式,各个目录的作用如下:

  • model(模型): 位于 /usr/lib/lua/luci/model 下,存放了与系统配置相关的模型脚本。这些脚本负责与底层系统的交互,如读取、验证和更新配置文件。模型层封装了对系统资源的访问和业务逻辑处理。
  • view(视图): 位于 /usr/lib/lua/luci/view 下,包含了各类HTML模板文件,它们使用Lua脚本来动态生成页面内容。视图层负责将模型中的数据以合适的方式呈现给用户,如显示网络设置、系统状态等信息。
  • controller(控制器): 位于 /usr/lib/lua/luci/controller 下,包含了处理HTTP请求的Lua脚本,也就是路由和控制器脚本。控制器层接收用户的HTTP请求,调用相应的模型获取数据,然后选择合适的视图进行渲染,将处理结果返回给用户。

LuCI 将网页中的每一个菜单视作一个节点,当用户通过浏览器点击节点,向路由器发起请求,LuCI 会从 controller 目录下的 index.lua 开始组织这些节点。index.lua 中定义了根节点 root,其他所有的节点都挂在这个根节点上。

通俗来讲,可以将 LuCI 管理界面看作一棵树状结构的菜单系统。管理路由器设置的网页就像一棵大树,每一层菜单就是一个节点。

当点击网页上的任何一个菜单选项时,就像是在触摸大树上的一片叶子或枝干。这时,浏览器会发送一个请求给路由器,告诉它想访问哪个菜单节点。

LuCI 框架接收到这个请求后,会从一个叫做 controller 目录下的 index.lua 文件开始处理。这个 index.lua 文件就好比是整棵树的根部,它定义了整个菜单系统的基础结构和访问规则。

在这个根节点之下,LuCI 会根据在 index.lua 中定义的 entry 函数逐步组织起其他的子菜单节点。也就是说,每当你在 index.lua 中添加一个类似于 entry({"admin", "example", "first"}, call("first_action"), "First") 的语句时,你就相当于在菜单树上挂了一个新的子节点——"First"。

当用户点击网页上的 "First" 菜单时,LuCI 就会调用与之关联的 first_action 函数,呈现相应的页面内容或者执行相应的操作。就这样,通过一步步递归展开,整个复杂的菜单系统就被建立起来了,并能够在用户交互时动态响应用户的请求。

为界面添加节点

entry(path, callback, title, order):用于定义 LuCI 管理界面的菜单项及其关联的操作。

path 指定该节点的位置(例如 node1.node2.node3)

target 指定当该节点被调度(即用户点击)时的行为,主要有三种:call、template 和 cbi。

title:标题,即我们在网页中看到的菜单

order:同一级节点之间的顺序,越小越靠前,反之越靠后(可选)

Map (config, title, description)

config:配置文件的层级名称,比如 example 对应 /etc/config/exampl

title:配置界面的标题,即我们在网页中看到的菜单

description:配置界面的描述信息

s = m:section(TypedSection, "example_instance", "Section Title", "Section Description")

TypedSection 或 SimpleSection:Section 的类型,TypedSection 可以为区段分配类型,并支持默认配置。

example_instance:区段实例的名称,用于区分配置文件中的不同区段实例。

Section Title:区段在界面上显示的标题。

Section Description(可选):区段的描述信息。

o = s:option(Value, "option_name", "Option Label", "Option Description")

Value 或其他选项类型(如 ListValue、Flag 等):选项的数据类型。

option_name:选项在配置文件中的键名。

Option Label:选项在界面上显示的标签文本。

Option Description(可选):选项的描述信息

1.通过call

进入 /usr/lib/lua/luci/controller/ 目录下,创建 lua 脚本文件 example.lua,其内容如下

--[[module 是 LuCI 自定义的函数,用于定义一个新的模块。这里的模块名为 "luci.controller.example",
表示这是一个 LuCI 控制器模块,主要用于定义路由和处理用户请求。
package.seeall 是 Lua 标准库中的一个函数,它用于打开模块内的全局访问权限。
这意味着在这个模块内部定义的所有函数和变量都将被视为全局的,可以从外部访问]]

module("luci.controller.example", package.seeall)

--[[定义了 LuCI 控制器的入口点(entry points)。
entry({"admin", "example"}, firstchild(), "Example", 60) 表示注册一个路由。
当用户在 Web 管理界面访问 /admin/example 时,LuCI 将会调用 firstchild() 函数来决定下一步跳转的位置。
这里 firstchild() 通常是指导航菜单的第一个子页面,即指向 "admin", "example", "first" 的路由。
'模板', 60 分别表示在菜单中显示的标题("模板")和菜单排序优先级(60)。]]
--[[这里的 firstchild() 是一种特殊的回调函数引用。
当LuCI接收到匹配到该路由 "admin", "example" 的请求时,它不会直接执行某个特定的动作函数,
而是查找该路由下第一个有效的子节点(即 "admin", "example", * 中的 * 部分),
并将控制权传递给这个子节点对应的处理函数]]
--
function index()
	entry({"admin", "example"},  firstchild(),"模板", 60)
	entry({"admin", "example", "first"}, call("first_action"), "第一")
	entry({"admin", "example", "second"}, call("second_action"), "第二")
end

--[[当用户访问 /admin/example/first 时,LuCI 将调用 first_action() 函数进行处理。
luci.template.render("header") 表示渲染一个名为 "header" 的模板文件,
通常这个模板文件包含了页面的头部元素,如导航栏、样式表引用等。
这个模板文件位于 /usr/lib/lua/luci/view,如果在其他目录下则更改参数为header.htm路径
luci.http.write("<h1>Hello World</h1>") 用于直接向客户端发送 HTML 数据,
这里是发送一个 <h1> 标签,显示 "Hello World",即页面的主要内容。]]

function first_action()
	luci.template.render("header")
	luci.http.write("<h1> 一级标题 hello</h1>")
	luci.http.write("<h2> 二级标题 hello</h2>")
end

function second_action()
	luci.template.render("header")
	luci.http.write("<h1> 一级标题 hello</h1>")
	luci.http.write("<h2> 二级标题 hello</h2>")
end

刷新网页

2.通过template

更改example.lua文件

module("luci.controller.example", package.seeall)

--[[更改call为template 在view目录下直接调用html页面
添加order参数为子菜单排序
order参数加不加引号系统都会识别为数字]]
function index()
	entry({"admin", "example"},  firstchild(),"模板", 60)
	entry({ "admin", "example", "third" }, template("example/third"), "第三","30")
	entry({ "admin", "example", "fourth" }, template("example/fourth"), "第四","35")
	entry({"admin", "example", "first"}, call("first_action"), "第一","10")
	entry({"admin", "example", "second"}, call("second_action"), "第二","20")

end
function first_action()
	luci.template.render("header")
	luci.http.write("<h1> 一级标题 hello</h1>")
	luci.http.write("<h2> 二级标题 hello</h2>")
end

function second_action()
	luci.template.render("header")
	luci.http.write("<h1> 一级标题 hello</h1>")
	luci.http.write("<h2> 二级标题 hello</h2>")
end

创建模板目录 /usr/lib/lua/luci/view/example/在模板目录下创建文件 third.htm/fourth.htm其内容如下

--third
<%+header%>
<h1>Hello World</h1>
--fourth
<%+header%>
<h1>Hello World</h1>

刷新网页

3.通过cbi

更改example.lua文件

module("luci.controller.example", package.seeall)

function index()
	entry({ "admin", "example" }, firstchild(), "模板", 60)
	entry({ "admin", "example", "third" }, template("example/third"), "第三", "30")
	entry({ "admin", "example", "fourth" }, template("example/fourth"), "第四", "35")
	entry({ "admin", "example", "first" }, call("first_action"), "第一", "10")
	entry({ "admin", "example", "second" }, call("second_action"), "第二", "20")
  --[[
如果配置文件/etc/config/example 存在,则创建 Example 的子节点,
当节点被调度时,LuCI 会将
/usr/lib/lua/luci/model/cbi/example/fifth.lua 这个脚本转换成 html 页面
发给客户端。
--]]
	if nixio.fs.access("/etc/config/example") 
	then
		entry({ "admin", "example", "fifth" }, cbi("example/fifth"), "第五", 40)
	end
end

function first_action()
	luci.template.render("header")
	luci.http.write("<h1> 一级标题 hello</h1>")
	luci.http.write("<h2> 二级标题 hello</h2>")
end

function second_action()
	luci.template.render("header")
	luci.http.write("<h1> 一级标题 hello</h1>")
	luci.http.write("<h2> 二级标题 hello</h2>")
end

创建配置文件/etc/config/example

新建 lua 脚本文件:/usr/lib/lua/luci/model/cbi/example/fifth.lua,内容如下

--[[
  Map (config, title, description)
]]
m = Map("example", "cbi示例", "这是cbi的一个非常简单的例子")
return m

刷新网页

修改/usr/lib/lua/luci/model/cbi/example/fifth.lua

m = Map("example", "cbi示例", "这是cbi的一个非常简单的例子")
--[[
在 Map 对象 m 中创建一个名为 s 的 Section(配置区段),类型为 TypedSection。
第一个参数 TypedSection 表示这是一个带有类型属性的配置区段;
第二个参数 是区段的名称,这也将成为 /etc/config/example 文件中区段的标识;
第三个参数 是区段的标题;
第四个参数 是区段的描述信息。
]]
s = m:section(TypedSection, "example", "模板", "此部分为模板")

--[[
设置 Section 对象 s 允许用户在界面上添加和移除区段实例。
]]
s.addremove = true

--[[
设置 Section 对象 s 不是匿名区段,意味着每个实例都需要在配置文件中拥有一个唯一的标识(id)。
]]
s.anonymous = false

--[[
在 Section 对象 s 中创建一个名为 n 的 Option(选项),类型为 Value(值类型)。
第一个参数 Value 表示这是一个可以输入任意值的选项;
第二个参数 "num" 是选项在配置文件中的键名;
第三个参数 "Number" 是选项在界面上显示的标签文本。
]]
n = s:option(Value, "num", "Number")

--[[
设置 Option 对象 n 允许用户清空其值,如果用户在界面上删除了输入值,保存时也会将配置文件中的相应值清空。
]]
n.rmempty = true
return m

刷新网页

在文本框中输入 first,然后单击 Add,如下所示

在 Number 后面随便输入一个数字,比如 12,然后单击 Save & Apply,如下所示

在路由器开发板上查看一些配置文件

n.rmempty = true表示当用户对该选项的输入值为空值时,LuCI 会将该选项从配置文件中移除。

将 Number 的值删除,再单击 Save & Apply

现在再来查看配置文件

添加启动脚本

在 OpenWrt系统中,LuCI 作为 Web 管理界面,允许用户通过网页图形界面编辑系统的各项配置。当用户在 LuCI 中修改了配置,并单击“Save & Apply”按钮后,会发生以下过程:

LuCI 会首先将用户在网页上所做的更改保存到对应的配置文件中。例如,网络相关的配置会保存到 /etc/config/network 文件。(上述保存到创建的配置文件/etc/config/example)

保存完成后,LuCI 通常会调用相应的 UCI(Unified Configuration Interface)命令行工具(如 ubus 或 uci)来通知系统配置已更改,并触发重新加载配置

系统收到配置更改通知后,会根据配置文件的变化情况,调用相应的启动脚本执行配置更新操作。这些启动脚本通常位于 /etc/init.d/ 目录下,例如对于网络配置,对应的启动脚本就是 /etc/init.d/network,如果为上述示例在/etc/init.d/目录下新建启动脚本文件,当示例的配置文件变化后,在/etc/init.d/目录下新建的启动脚本也会运行。

启动脚本接收到诸如 reload 的参数后,会停止当前的相关服务,应用新的配置,然后再启动这些服务,从而使更改生效。

为配置文件 example 创建一个启动脚本/etc/init.d/example,同时为其添加可执行权限。其内容如下:

#!/bin/sh /etc/rc.common 
START=50 
start() 
{ 
 echo "start example" > /dev/ttyS0 
} 
reload()
{ 
 echo "reload example" > /dev/ttyS0 
}

LuCI 通过以配置文件名作为参数调用/sbin/luci-reload 来使配置生效,而 luci-reload 会解析另一个配置文件 /etc/config/ucitrack,需要将 example 添加进去。用vi打开/etc/config/ucitrack,在最后添加如下内容:

config example

option init example

当用户在 LuCI 管理界面单击 "Save & Apply" 保存并应用配置变更后,LuCI 通常会执行 /sbin/luci-reload 命令,并传入对应的配置模块名称(即执行/sbin/luci-reload example)。luci-reload 会识别出与该模块相关的启动脚本,并调用其 reload 函数来重新加载配置并应用更改。

这里,example表示要跟踪的配置文件,init 选项指定了与该配置文件关联的启动脚本名称(即 /etc/init.d/example)

当 /etc/config/example 文件发生变化时,ucitrack 会监测到变化并调用 /etc/init.d/example 脚本的 reload 函数(如果存在),以重新加载并应用新的配置。这样就能确保当用户通过 LuCI 管理界面单击 "Save & Apply" 后,配置变更能够被系统及时识别并应用。

为了确保 /etc/init.d/example 脚本在系统启动时被自动运行,以及能够响应 luci-reload 命令,需要执行以下命令启用该服务:

chmod +x /etc/init.d/example  #首先确保有执行权限 否则报错Permission denied
root@OpenWrt:/# /etc/init.d/example enable

这条命令会创建一个符号链接,将 /etc/init.d/example 链接到 /etc/rc.d/S50example(这里的数字 50 可能根据实际的 START 变量值有所不同),这样每次启动或执行 reload 时,系统都会自动运行 /etc/init.d/example 脚本中的相应函数。

当使用 reload 参数调用启动脚本时,其目的是让系统在不完全重启服务的情况下,仅重新加载并应用新的配置。这对于许多服务来说是十分重要的,因为它可以在不影响服务整体运行的前提下实现配置的热更新。例如,在网络配置变更时,调用 /etc/init.d/network reload 就可以让系统在不关闭网络连接的前提下,重新读取 /etc/config/network 配置文件并按照新配置调整网络设置。这样做的好处是可以避免因服务重启带来的短暂网络中断。相比之下,如果是使用其他参数(如 start 或 stop),它们分别代表启动或停止服务,这会导致服务状态的显著改变,很可能会影响到依赖于该服务的其他功能。而 reload 参数提供了更平滑的配置过渡方式,更适合于实时生效的配置更新场景。

现在单击网页中的 Save & Apply,打开串口助手可以看到开发板中输出了如下内容:(配置更改才会执行,即填入不同数字才会输出reload example )

reload example

说明确实执行了/etc/init.d/example 中的 reload 函数。

将软件包添加到路由器(以dtu程序为例)

dtu文件夹下Makefile

include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/package.mk #引入全局变量规则和包构建规则

PKG_NAME:=dtu
PKG_VERSION:=1.0
define Package/$(PKG_NAME)
	CATEGORY:=My Package
	#DEPENDS:= 如果需要依赖其他软件包,在这里添加
	TITLE:=DTU program
endef                           #定义包的基本信息,包括名称 版本号 类别 标题

#编译前执行
define Build/Prepare
	mkdir -p $(PKG_BUILD_DIR)   
	$(CP) ./src/* $(PKG_BUILD_DIR)/
endef                          #在编译前运行 将src源文件复制到编译目录PKG_BUILD_DIR下

#安装时执行
define Package/$(PKG_NAME)/install
	$(INSTALL_DIR) $(1)/bin     
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/dtu $(1)/bin/
endef                         #创建bin目录,将PKG_BUILD_DIR下可执行文件安装到/bin下


$(eval $(call BuildPackage,dtu))

将源文件放入src文件并在src下创建Makefile文件

all:
	$(CC) dtu.c -o dtu

make menuconfig勾选dtu,M生成单独软件包,*包含进固件

运行 make ./package/dtu/compile V=s后在/bin/packages/mipsel_24kc/base下生成dtu_1.0_mipsel_24kc.ipk 运行scp dtu_1.0_mipsel_24kc.ipk root@192.168.1.1:/root 将软件包拷贝到root目录下

运行opkg install dtu_1.0_mipsel_24kc.ipk安装软件包 在/bin下生成dtu可执行程序

实现软件包开机自启

在路由器上实现

在/etc/init.d下创建脚本server_init

#!/bin/sh /etc/rc.common
START=99
STOP=10
start()
{
        /bin/dtu &      
}
stop()
{
        killall dtu
}

添加执行权限

chmod +x server_init

在/etc/rc.d/rc*.d下创建链接 系统开机后会按照预定的优先级依次启动

./server_init enable

reboot重启ps查看

在软件包上实现

在package/dtu下创建files文件夹储存启动脚本文件server_init

在dtu目录下的Makefile文件中添加代码,将files下的启动脚本文件拷贝到/etc/init.d下

并启动开机启动

#安装时执行
define Package/$(PKG_NAME)/install
	$(INSTALL_DIR) $(1)/bin $(1)/etc/init.d/         
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/dtu $(1)/bin/
	$(INSTALL_BIN) ./files/server_init $(1)/etc/init.d/
endef    									
            #创建bin目录和/etc/init.d/目录,将PKG_BUILD_DIR下可执行文件安装到/bin下  
            #将server_init脚本安装到/etc/init.d/下

#安装后执行 					
define Package/$(PKG_NAME)/postinst
#!/bin/sh
# check if we are on real system
if [ -z "$${IPKG_INSTROOT}" ]; then
	echo "Enabling rc.d symlink for dtu"
if [ -e /etc/rc.d/S??dtu ];then
	rm /etc/rc.d/S??dtu
fi
if [ -e /etc/rc.d/K??dtu ];then
	rm /etc/rc.d/K??dtu
fi
	/etc/init.d/server_init enable
fi
exit 0
endef                       #设置开机自启动,检查是否存在S启动脚本和K关闭脚本
                            #存在则关闭,并创建新的服务

#卸载前执行 
define Package/$(PKG_NAME)/prerm
	#!/bin/sh
	# check if we are on real system
	if [ -z "$${IPKG_INSTROOT}" ]; then
	echo "Removing rc.d symlink for dtu"
	/etc/init.d/server_init disable
fi
exit 0
endef                     #判断是否为真实的系统环境(非临时安装环境)
                          #并禁用server_init服务

相关资料

hostname():获取主机名。

loadavg():获取系统负载平均值。

luci.model.uci模块:

cursor():创建一个UCI数据库游标。

changes():获取最近的UCI更改。

apply():应用UCI配置更改。

游标对象的 get、set、add、delete 等方法用于操作UCI配置。

luci.template模块:

render(template, ...):渲染指定的Lua模板文件。

process(template, context):处理模板并输出内容。

luci.util模块:

split(str, sep):分割字符串。

trim(s):去除字符串两侧的空白字符。

ip.IPv4(ipstr):IP地址解析。

ip.IPv6(ipstr):IPv6地址解析。

软件包:

PKG_NAME - 用于指定软件包的名称,通常是唯一标识该软件包的关键字符串。

PKG_VERSION - 表示软件包的版本号,这是构建系统用来区分不同版本软件的重要信息。

PKG_RELEASE - 这是编译发布的版本信息,可能反映了软件包在同一个版本基础上的不同编译版本或修订版本,比如补丁级别。

PKG_BUILD_DIR - 指定编译该软件包的工作目录,默认情况下,会在构建系统的临时目录(如$(BUILD_DIR))下为每个软件包创建一个单独的子目录,子目录名由软件包名和版本号组成。

PKG_SOURCE - 指定要下载的源代码包的文件名,构建系统会根据这个信息从指定位置下载源代码。

PKG_SOURCE_URL - 提供源代码包的下载地址,构建系统会从这个URL下载指定的源码包。

PKG_MD5SUM - 源代码包的MD5校验和,用于验证下载的源代码包是否完整无误。

PKG_CAT - 指定解压源代码包的方式,比如使用zcat解压.gz文件,bzcat解压.bz2文件,或者unzip解压.zip文件。

PKG_BUILD_DEPENDS - 指定该软件包在编译过程中依赖的其他软件包,这些依赖的软件包必须先于当前软件包被成功编译。这通常用于编译时依赖关系,与运行时依赖(DEPENDS)有所区别,尽管两者语法可能相似。

SECTION - 软件包分类,目前未使用,未来可能会引入分类功能。

CATEGORY - 指定软件包在menuconfig菜单中的位置,如果这个类别之前未被使用过,menuconfig会自动创建一个新的菜单来容纳该类别的软件包。

TITLE - 软件包的简短描述,用于在menuconfig中显示软件包的基本信息。

URL - 提供软件包源代码的官方网站或仓库地址,方便开发者获取更多信息。

MAINTAINER - 软件包的维护者联系信息,便于用户报告问题或寻求帮助。

DEPENDS - 定义软件包在编译和安装时所需的依赖关系。具体语法包括:

- DEPENDS:=+foo:当前软件包和foo软件包一起联动,一荣俱荣,一损俱损,如果当前软件包被选中或取消选中,foo软件包的状态也会随之同步改变。

- DEPENDS:=foo:当前软件包依赖于foo软件包,只有当foo软件包被选中时,当前软件包才会出现在menuconfig中。

- DEPENDS:=@FOO:当前软件包依赖于全局配置项CONFIG_FOO,只有当CONFIG_FOO被启用时,当前软件包才会出现在menuconfig中。

- DEPENDS:=+FOO:bar:当前软件包和bar软件包联动,同时取决于全局配置项CONFIG_FOO,当CONFIG_FOO被启用时,当前软件包依赖于bar软件包。

- DEPENDS:=@FOO:bar:当前软件包是否依赖bar软件包取决于全局配置项CONFIG_FOO,只有当CONFIG_FOO被启用且bar软件包被选中时,当前软件包才会出现在menuconfig中。

o:value("wan","WAN")

在 OpenWrt/LEDE LuCI 的上下文中,o:value("wan","WAN") 这行代码的作用是在表单选项 o 中添加一个选项值。这里的 o 是一个 Value 类型的表单选项对象。

  • "wan" 是选项的值,即当用户选择这个选项时,表单提交时实际存储的数据值。
  • "WAN" 是选项的显示文本,即用户在界面上看到的文字描述。

固件的etc的文件受源代码哪些文件的影响?

OpenWrt固件中/etc目录下的文件受到源代码树中多个位置的影响:

  1. 基础系统配置文件:
    • /package/base-files/files/etc/:这个目录包含了OpenWrt的基本系统配置文件,如/etc/config/*系列的网络配置文件、防火墙规则文件、系统启动脚本等。
  1. 特定软件包的配置文件:
    • 各个软件包目录下的files/etc/子目录:例如,当编译安装某个软件包时,该软件包的源代码目录中可能包含files/etc文件夹,其中的配置文件会在编译打包阶段被复制到固件的/etc目录下。

feeds是软件包仓库的目录,那package是什么

在OpenWRT环境中,feeds 和 package 目录都与软件包管理有关,它们的作用有所不同:

  1. feeds
    • 是一个或多个软件包仓库的集合,这些仓库通常位于远程服务器上或者本地文件系统中,并且通过版本控制系统(如Git)维护。feeds中包含了一系列预编译的软件包定义,它们提供了扩展OpenWRT功能的各种附加软件包。当执行./scripts/feeds update和./scripts/feeds install命令时,feeds中的软件包信息会被下载到本地的feeds目录中,但实际的源代码并不会直接放置在feeds目录下。
  1. package
    • 位于OpenWRT源代码树的顶级目录或其子目录中,它存储的是OpenWRT系统本身自带的软件包源代码以及由feeds安装后提取出来的第三方软件包源代码。当你通过feeds安装了某个软件包后,相应的源代码将会被解压并放入到package目录下相应的位置,以便在编译OpenWRT固件时能够将这些软件包一同编译进去。

简而言之,在OpenWRT编译流程中,feeds是软件包仓库列表和软件包元数据的来源,而package则是实际存放编译时所需软件包源代码的地方。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

cmd输入mysql -u root -p无法启动

问题分析&#xff1a;cmd输入mysql -u root -p无法启动 解决方法&#xff1a;配置系统环境变量 1.找到mysql安装文件下的bin文件&#xff1a;&#xff08;复制改文件地址,如下图所示&#xff09; 2.电脑桌面下方直接搜索环境变量并进入&#xff0c;如下图 3.点击环境变量&a…

读取打包到JAR中的文件:常见问题与解决方案(文件在但是报错not find)

读取打包到JAR中的文件&#xff1a;常见问题与解决方案 喝淡酒的时候&#xff0c;宜读李清照&#xff1b;喝甜酒时&#xff0c;宜读柳永&#xff1b;喝烈酒则大歌东坡词。其他如辛弃疾&#xff0c;应饮高梁小口&#xff1b;读放翁&#xff0c;应大口喝大曲&#xff1b;读李后主…

Python数据清洗与可视化实践:国际旅游收入数据分析

文章目录 概要整体流程名词解释NumPyPandasMatplotlibre 技术细节数据清洗可视化 小结 概要 在本篇博客中&#xff0c;我们将通过一个实际的案例&#xff0c;演示如何使用Python进行数据清洗和可视化&#xff0c;以分析国际旅游收入数据。我们将使用Python中的Pandas库来进行数…

04-25 周四 FastBuild重构实践-TLS、全局捕获异常、一键配置

04-25 周四 FastBuild重构实践 时间版本修改人描述04-25V0.1宋全恒新建文档2024年5月6日14:33:16V1.0宋全恒完成文档撰写 简介 由于 04-22 周日 阿里云-瑶光上部署FastBuild过程(配置TLS、自定义辅助命令)描述了重新部署一个FastBuild实例的过程&#xff0c;通过阅读这个&…

线性表的概念与结构,以及顺序表和链表的简单概念

1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线…

JS hook cookie

JS hook cookie cookie 的值是V&#xff0c;v是动态变化的 可以看到D中生成了cookie的值n 尝试使用RPC定位到cookie。 替换内容&#xff0c;下断点。 将写好的RPC代码直接插入 加入代码&#xff0c;file.virjar.com/sekiro_web_client.js?_123 这个地址是在前端创建客户端…

开源模型应用落地-CodeQwen模型小试-小试牛刀(一)

一、前言 代码专家模型是基于人工智能的先进技术&#xff0c;它能够自动分析和理解大量的代码库&#xff0c;并从中学习常见的编码模式和最佳实践。这种模型可以提供准确而高效的代码建议&#xff0c;帮助开发人员在编写代码时避免常见的错误和陷阱。 通过学习代码专家模型&…

【网络知识】光猫、路由器 和 交换机 的作用和区别?

数字信号&#xff1a;是指自变量是离散的、因变量也是离散的信号&#xff0c;这种信号的自变量用整数表示&#xff0c;因变量用有限数字中的一个数字来表示。在计算机中&#xff0c;数字信号的大小常用有限位的二进制数表示。 模拟信号&#xff1a;模拟信号是指用连续变化的物…

学习c#第26天 面向对象基础之类与对象

1.类 1.什么是类? 俗话说&#xff0c;“物以类聚&#xff0c;人以群分”。意思是同类的东西经常聚在一起&#xff0c;志同道合 的人相聚成群。前者说物&#xff0c;后者说人。这里以物来进行举例说明[见图]&#xff1a; 水果超市&#xff0c;所有同类的水果摆放在一起&#xf…

【机器学习与实现】线性回归分析

目录 一、相关和回归的概念&#xff08;一&#xff09;变量间的关系&#xff08;二&#xff09;Pearson&#xff08;皮尔逊&#xff09;相关系数 二、线性回归的概念和方程&#xff08;一&#xff09;回归分析概述&#xff08;二&#xff09;线性回归方程 三、线性回归模型的损…

vivado刷题笔记46

题目&#xff1a; Design a 1-12 counter with the following inputs and outputs: Reset Synchronous active-high reset that forces the counter to 1 Enable Set high for the counter to run Clk Positive edge-triggered clock input Q[3:0] The output of the counter c…

场外个股期权和场内个股期权的优缺点是什么?

场外个股期权和场内个股期权的优缺点 场外个股期权是指在沪深交易所之外交易的个股期权&#xff0c;其本质是一种金融衍生品&#xff0c;允许投资者在股票交易场所外以特定价格买进或卖出证券。场内个股期权是以单只股票作为标的资产的期权合约&#xff0c;其内在价值是基于标…

金融业开源软件应用 管理指南

金融业开源软件应用 管理指南 1 范围 本文件提供了金融机构在应用开源软件时的全流程管理指南&#xff0c;对开源软件的使用和管理提供了配套 组织架构、配套管理规章制度、生命周期流程管理、风险管理、存量管理、工具化管理等方面的指导。 本文件适用于金融机构规范自身对开…

工业物联网技术在生产流程中的应用及优势与挑战——青创智通

工业物联网解决方案-工业IOT-青创智通 随着科技的不断发展&#xff0c;物联网技术逐渐渗透到各个行业中&#xff0c;尤其是在工业领域&#xff0c;工业物联网的应用正在逐步重塑生产流程。本文将探讨工业物联网如何影响生产流程&#xff0c;并分析其带来的优势和挑战。 一、工…

Amazon Bedrock的进化:更多选择与新特性,助力生成式AI应用更快落地

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

leetcode-没有重复项的全排列-97

题目要求 思路 1.递归&#xff0c;如果num和n的元素个数一样就可以插入res中了&#xff0c;这个作为递归的结束条件 2.因为这个题是属于排列&#xff0c;并非组合&#xff0c;两者的区别是排列需要把之前插入的元素在回退会去&#xff0c;而组合不需要&#xff0c;因此会存在一…

YPay源支付Mini Pro免授权使用版v1.0

YPay源支付Mini Pro免授权使用版v1.0 &#xff0c;修改host屏蔽Pro授权站&#xff0c;可有效防止因用户操作不当导致免授权程序无法执行时 执行授权官方的盗版入库代码&#xff0c;尽可能保证网站安全 1.安装SG14组件 注&#xff1a;仅防止二次开发添加授权 2.”/etc/host”文…

尊享面试100题(314.二叉树的垂直遍历python)

题目关键词&#xff0c;从左到右&#xff0c;从上到下&#xff0c;那么使用bfs宽度优先算法。 使用字典v保存每一列的值。 class Solution:def verticalOrder(self, root: Optional[TreeNode]) -> List[List[int]]:if not root: return []v defaultdict(list)qu deque()…

淘宝扭蛋机小程序开发:开启你的惊喜之旅

一、扭出新世界&#xff0c;惊喜不断 在这个充满无限可能的数字时代&#xff0c;淘宝扭蛋机小程序为你带来了一种全新的购物与娱乐体验。扭蛋机&#xff0c;这个充满童趣和惊喜的玩具&#xff0c;如今在我们的小程序中焕发出新的活力&#xff0c;为你带来一波又一波的惊喜与快…

WES-100B液晶数显式液压万能试验机

一、简介 主机为两立柱、两丝杠、油缸下置式&#xff0c;拉伸空间位于主机的上方&#xff0c;压缩、弯曲试验空间位于主机下横梁和工作台之间。测力仪表采用高清液晶显示屏&#xff0c;实验数据方便直观。 二、 传动系统 下横梁升降采用电机经减速器、链传动机构、丝杠副传动…