OPENWRT-LUCI开发总结-LUCI添加新页面总结

前言

在《LUCI启动流程介绍》里,我们介绍了LUCI的启动主体是dispatcher.lua的dispatch()函数,他通过解析controller目录下的lua文件,定义node节点,构建node-tree来进行页面管理。本节将详细介绍M(model)、V(view)、C(controller)各个文件的功能以及如果添加新的node节点。

  1. controller目录
  2. model目录
  3. view目录
  4. 新页面添加流程
  5. 官方及参考网址
controller目录

因为dispatch()函数通过解析controller目录下的lua文件构建node-tree,所以我们优先看一下这个目录的lua脚本是如何定义的。以controller/admin/status.lua的部分代码为例。

module("luci.controller.admin.status", package.seeall)

function index()
	entry({"admin", "status"}, alias("admin", "status", "overview"), _("Status"), 20).index = true
	entry({"admin", "status", "overview"}, template("admin_status/index"), _("Overview"), 1)
	entry({"admin", "status", "iptables"}, call("action_iptables"), _("Firewall"), 2).leaf = true
	entry({"admin", "status", "processes"}, cbi("admin_status/processes"), _("Processes"), 6)
end

function action_iptables()
	......
end

1、定义模块入口---> module("luci.controller.admin.status", package.seeall)

此行说明了程序和模块的路径名称,比如在controller/admin目录创建一个status.lua,那么就可以写成“luci.controller.admin.status”

2、添加index()函数,在index()函数中定义node节点属性

createtree()函数调用lua文件中的index()函数创建node-tree,同时index()引用entry函数定义node节点

3、entry (path, target, title, order)函数

(1)path:地址栏访问路径,通常也定义菜单分配,如:“{"admin", "一级菜单名", "菜单项名"}”

-- 定义菜单栏的一级菜单名
entry({"admin", "status"}, alias("admin", "status", "overview"), _("Status"), 20).index = true
-- 定义status下的overview菜单项
entry({"admin", "status", "overview"}, template("admin_status/index"), _("Overview"), 1)

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

  • alias:别名,指向别的entry函数
  • call:调用指定函数,例如上述代码直接调用action_iptables函数
  • template:调用指定页面,例如 template(“admin_status/index”)表示调用/usr/lib/lua/luci/view/admin_status/index.htm页面
  • cbi:调用指定lua文件,这个页面的生成与LUA脚本及UCI配置文件息息相关,具体联系后文介绍。此时命令cbi(“admin_status/processes”)表示调用/usr/lib/lua/luci/model/cbi/admin_status/processes.lua文件。

(3)title:标题,即我们在网页中看到的菜单名(可选)

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

model目录

在entry函数中,使用cbi方式调用model下的lua文件。在这部分主要介绍model目录的lua脚本是如何定义的,他与UCI配置文件到底有何联系,保存生效如何能连接启动脚本。

1、model页面

model的页面是通过其目录下的LUA脚本与配置文件一起生成的。在LUA脚本的开头,通过 Map("配置文件文件名", "配置页面标题", "配置页面说明") 函数连接相应的配置文件;然后使用类型或者名称查找对应的section及option;最后根据页面需求,将option转换成HTML元素。以上操作就完成了model页面的配置,LUA脚本的详细介绍可以参考下列网址,这里只贴部分代码进行说明。

https://blog.csdn.net/qq_19004627/article/details/80364099
(1)/etc/config/example配置文件内容如下

config interface 'test'
	option enable '1'
	option addr '192.168.1.1'

(2)model目录的lua脚本内容如下,因为页面内容是由配置文件生成的,所以当修改完页面点击保存按钮时,修改的值也会同步到底层配置文件中。

--m = Map("配置文件文件名", "配置页面标题", "配置页面说明")
--第一个参数为配置文件存储的文件名,不包含路径,默认在/etc/config目录下
--第二个参数为页面的标题
--第三个参数为页面的描述
m = Map("example", translate("LUA Example"))

--创建与配置文件中对应的section
--section的创建分为两种:NamedSection和TypedSection
--s = m:section(NamedSection, name, type, title, description) 
--s = m:section(TypedSection, type, title, description) 
--前者根据配置文件中的section名,例如上述配置文件中的test
--后者根据配置文件中的section类型,例如上述配置文件中的interface
s = m:section(TypedSection, "interface", translate("Example Info"))
s.anonymous = true 

--获取section对应的option,并转换成HTML元素
addr = s:option(Value, "addr", translate("Address"))
enable = s:option(Flag, "enable", translate("Enable"))

--一定要记得return,才会有页面显示,否则是空页面
return m

(3)保存生效按钮与脚本的关联方法有二,一是捕获保存生效按钮,如果发现用户点击保存生效按钮,则调用底层脚本;

local apply = luci.http.formvalue("cbi.apply")
if apply then
	luci.sys.call("/etc/init.d/example restart")
end

二是底层脚本监听配置文件是否有修改,如果发现有改动,脚本重新启动。具体操作可以参考下列网址:
https://www.cnblogs.com/mayswind/p/3468124.html

view目录

在entry函数中,主要通过template方式调用view下的HTML文件。在这部分主要介绍页面框架是如何搭建的。注:view目录下的文件虽然是HTML文件,但是文件尾缀必须要写成.htm形式

1、顶部<%- 内容 -%>: 此部分主要包含lua脚本的调用,在这里获取的变量可以直接在后文HTML中进行引用。

2、中部:此部分完成CGI post及get的处理,主要使用JS语言进行编写

<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<script type="text/javascript"..></script>

3、html部分:此部分完成页面内容的显示,与常规HTML编写相同

新页面添加流程

例:在状态菜单下添加测试页面

1、在controller目录下定义node节点

entry({"admin", "status", "example"}, cbi("admin_status/example"), _("Example"), 6)

2、在/etc/config下添加配置文件example

config interface 'test'
	option enable '1'
	option addr '192.168.1.1'

3、在model目录下添加example.lua脚本

m = Map("example", translate("LUA Example"))
s = m:section(TypedSection, "interface", translate("Example Info"))
s.anonymous = true 
addr = s:option(Value, "addr", translate("Address"))
enable = s:option(Flag, "enable", translate("Enable"))
return m

4、生成页面如下:
在这里插入图片描述

官方及参考网址

1、开发OpenWrt路由器上LuCI的模块(https://www.cnblogs.com/mayswind/p/3468124.html)
2、luci cbi 模块函数详解(https://blog.csdn.net/qq_19004627/article/details/80364099)
3、openWRT官网,保存生效调用脚本(https://oldwiki.archive.openwrt.org/doc/devel/config-scripting)
4、LUCI简单说明教程(https://wenku.baidu.com/view/7cfb0d17e518964bcf847c76.html)
5、OpenWrt自定义luci页面来修改配置文件(https://blog.csdn.net/lvshaorong/article/details/53939138)
6、LUA的详细总结(https://www.cnblogs.com/rohens-hbg/category/743186.html)