想要给openwrt开发应用,虽然直接可执行程序也可以运行,但是没有UI会很不方便,想要开发UI就要用openwrt的那一套,自然就是LuCI,LuCI又用了一套MVC框架,今天就讲讲这是个什么东西。
OpenWrt LuCI 界面开发中的 MVC 架构
在 OpenWrt 的 LuCI Web 界面开发中,采用了 MVC(Model-View-Controller)架构,但它和传统的 MVC 框架有所不同,主要依赖 Lua + UCI + JavaScript(Vue 风格) 来实现 Web UI 交互。
1. OpenWrt LuCI 的 MVC 架构
在 LuCI 开发中:
- Model(模型):负责数据处理(通常基于 UCI 配置)。
- View(视图):负责 UI 展示(使用 Lua Template (
.htm
) 或现代 JavaScript (.js
))。 - Controller(控制器):负责业务逻辑和路由(通常是 Lua (
.lua
) 脚本)。
🔹 架构示意图
用户请求 (Web)↓
Controller (Lua) - 处理请求,调用 Model↓
Model (UCI) - 读取/写入配置数据↓
View (HTML/JS) - 渲染页面↓
用户交互 (表单提交,RPC 调用)
2. LuCI 的三大核心组件
组件 | 作用 | 代码位置 |
---|---|---|
Model(模型) | 处理 UCI 配置数据 | /usr/lib/lua/luci/model/cbi/ |
View(视图) | 生成 HTML/JS 页面 | /usr/lib/lua/luci/view/ 或 /www/luci-static/resources/view/ |
Controller(控制器) | 处理请求逻辑和路由 | /usr/lib/lua/luci/controller/ |
3. Model(模型) - 处理 UCI 配置
在 LuCI 开发中,Model 层主要用于 操作 OpenWrt 的 UCI(Unified Configuration Interface)。
📌 示例:定义 Model 处理 UCI
文件:/usr/lib/lua/luci/model/cbi/admin_network/wol.lua
m = Map("wol", "Wake on LAN") -- 绑定到 UCI "wol" 配置
s = m:section(NamedSection, "main", "wol", "WOL 配置")mac = s:option(Value, "macaddr", "MAC 地址") -- 用户输入的 MAC 地址
mac.datatype = "macaddr"iface = s:option(ListValue, "interface", "网络接口")
iface:value("br-lan", "LAN")
iface:value("wan", "WAN")return m
🔹 解释
Map("wol", "Wake on LAN")
绑定到/etc/config/wol
UCI 配置文件。s:option(Value, "macaddr", "MAC 地址")
定义了MAC 地址
输入框,并限制为macaddr
数据类型。iface:value("br-lan", "LAN")
提供了接口选择。
4. View(视图) - 生成 UI 页面
LuCI 视图有两种方式:
- 传统 Lua 模板 (
.htm
) - 现代 JavaScript (
.js
)
📌 示例 1:Lua 方式渲染 HTML
文件:/usr/lib/lua/luci/view/admin_network/wol.htm
<%+cbi/header%>
<h2>Wake on LAN</h2>
<%+cbi/apply_cb%>
<form method="post"><input type="text" name="macaddr" placeholder="输入 MAC 地址"/><button type="submit">发送 WOL</button>
</form>
<%+cbi/footer%>
🔹 解释
cbi/header
和cbi/footer
负责引入 LuCI 标准框架。<input type="text" name="macaddr">
让用户输入 MAC 地址。<button>
让用户提交 WOL 请求。
📌 示例 2:JavaScript (.js
) 动态渲染
文件:/www/luci-static/resources/view/wol.js
return view.extend({render: function() {return E([CBI.form.Value.extend({name: "macaddr",label: _("MAC 地址"),datatype: "macaddr",}),CBI.form.ListValue.extend({name: "interface",label: _("网络接口"),values: {"br-lan": _("LAN"),"wan": _("WAN")}})]);}
});
🔹 解释
CBI.form.Value
创建一个 MAC 地址输入框。CBI.form.ListValue
创建一个 接口选择下拉框。- 视图是动态生成的,没有固定 HTML 代码。
5. Controller(控制器) - 处理请求
LuCI 的 Controller 层主要用于:
- 定义 Web UI 的 URL 路由
- 调用 Model(UCI 读取/写入)
- 返回 View(HTML/JS 渲染)
📌 示例:控制器定义 WOL 页面
文件:/usr/lib/lua/luci/controller/admin/wol.lua
module("luci.controller.admin.wol", package.seeall)function index()entry({"admin", "network", "wol"}, cbi("admin_network/wol"), "Wake on LAN", 30)entry({"admin", "network", "wol_send"}, call("send_wol"), nil).leaf = true
endfunction send_wol()local mac = luci.http.formvalue("macaddr")os.execute("etherwake " .. mac)luci.http.redirect(luci.dispatcher.build_url("admin", "network", "wol"))
end
🔹 解释
entry({"admin", "network", "wol"})
创建 Web UI 菜单项。cbi("admin_network/wol")
调用 Model (wol.lua
) 处理 UCI 配置。function send_wol()
处理用户提交的 WOL 请求,然后执行etherwake
命令。
6. 组件之间如何协作?
组件 | 作用 | 代码 |
---|---|---|
Controller (Lua) | 处理请求,调用 Model | luci.controller.admin.wol |
Model (Lua/UCI) | 读取/写入配置 | luci.model.cbi.admin_network.wol |
View (HTML/JS) | 渲染 Web UI | luci-static/resources/view/wol.js |
后端进程 (C/命令行) | 执行 WOL | etherwake |
🔹 交互流程
- 用户打开 WOL 页面(Controller 解析请求)
- Controller 调用 Model 读取 UCI 配置
- View 生成 UI,用户输入 MAC 地址
- 用户点击 "发送 WOL",Controller 处理请求
- Controller 调用
etherwake
发送 WOL - 返回到 Web UI,显示成功消息
7. 结论
✅ LuCI 使用 MVC 架构,但 Controller 是 Lua,View 现在更多用 JavaScript。
✅ 现代 OpenWrt 主要基于 rpcd
和 ubus
进行数据交互,而不只是传统的 Lua cbi()
。
✅ 如果你要修改 luci-app-wol
,需要改动 controller/wol.lua
(后端)、view/wol.js
(前端)、以及 rpcd
相关部分。