LUCI 使用其原有机制的创建新的页面

1.LUCI简介

LUCI是一个小巧的语言,诞生于2008年3月份,目的是为OpenWrt固件从 Whiterussian 到 Kamikaze实现快速配置接口。轻量级 LUA语言的官方版本只包括一个精简的核心和最基本的库。这使得LUA体积小、启动速度快,从而适合嵌入在别的程序里。UCI是OpenWrt中为实现全部系统配置的一个统一接口,英文名Unified Configuration Interface,即统一配置接口。LuCI,便是这两个项目的合体,能够实现路由的网页配置界面。[·引自百度百科https://baike.baidu.com/item/...]html

2. 我作过什么

其实我接触LUCI并不久,主要用它来为OpenWrt写UCI接口,来存取配置文件里的内容。存取有两种方式:git

  • 使用LUCI原有机制实现存取
  • 自定义界面进行存取

这两种我都会介绍。本文主要介绍一些LUCI的基本内容和一种方式的应用。web

3. LUCI的基本架构

LUCI能够归属为web开发行列。由于它的内容都是直接在浏览器里体现出来的。它的基本架构跟不少WEB开发语言的框架同样,都是MVC架构。如下给出一些简单的解释:
M(Model): 模型层,路径是/usr/lib/lua/luci/model/。这个是数据处理的具体代码的层。该层中有一个cbi文件夹,那里面是预约义的一些的逻辑文件。
V(View): 视图层,路径是/usr/lib/lua/luci/view/。这个很容易理解,就是存放视图文件的地方。LUCI里的视图文件是.htm文件。
C(Controller): 控制层,路径是/usr/lib/lua/luci/controller/admin/。这个层最主要的功能是设定路由;它还有一个功能跟模型层一致——处理数据。
根目录: /usr/lib/lua/luci
资源文件存放目录: /www/luci-static/vim

4. 开始创建新页面

以配置network文件为例,实现一个testnet模块须要完成下面的步骤。
步骤:浏览器

  1. 创建一个配置文件
  2. 定义控制层
  3. 定义模型层
1> 创建一个配置文件

以前介绍的时候有说到,LUCI是用于存取配置文件的信息,因此咱们的若要新建一个模块,须要一个配置文件。配置文件的路径通常是在/etc/config/。因为如今咱们是须要配置network文件,而这个是系统必备文件,它已经存在,因此咱们不须要新建,但咱们要了解一下里面的结构是怎么样的:架构

config interface 'loopback'
        option ifname 'lo'
        option proto 'static'
        option ipaddr '127.0.0.1'
        option netmask '255.0.0.0'

config interface 'lan'
        option type 'bridge'
        option ifname 'eth1'
        option proto 'static'
        option ipaddr '192.168.1.1'
        option netmask '255.255.255.0'
        option ip6assign '60'

这个是配置里有内容,而其余配置文件内容格式也是差很少:框架

-- 编辑配置文件
root@openWrt:~# vim /etc/config/<config name>
-- 配置文件格式
config <section type> <section name>
    option <option name> <option value>
    option <option name> <option value>
    option <option name> <option value>

那么咱们创建一个新的配置给testnet模块使用函数

config interface testnets
    option ifname 'testnets'
    option type 'test'
    option ipaddr '192.168.1.1'
    option net '192.168.251.1'
2> 定义控制层

控制层中,咱们主要定义访问的路由。每个模块的控制都是独立的,那样才能方便控制。路由的定义是在控制器的index()函数里。控制器里还能够定义其余的函数用于处理处理,相信这一点有过WEB开发经验的童鞋们都知道。
接下来咱们创建一个能以/admin/testnet访问的路由
话很少说,直接上代码:oop

-- /controller/admin/testnet.lua
module("luci.controller.admin.testnet")
function index()
    entry({"admin", "testnet", "index"}, cbi("admin_test/net"), translate("Test Net"), 10)
end

function test()
    return 'This is a test function.'
end

module("luci.controller.admin.testnet"): 这一句是命名空间的声明,luci指的是/usr/lib/lua/luci这个的文件夹,也就是LUCI的根目录
entry({"admin", "testnet", "index"}, cbi("admin_test/net"), translate("Test Net"), 10): 这一句必须写在控制器文件的index()函数里。它的格式定义是这样子的:post

entry(path, target[[, title][, order]])
  • path: 即路由规则,格式是{"admin","testnet","index"[[,"..."][,"..."]]}基本上能够无限延伸,但通常不建议这么干,到五六层已经很深了,再潜就很差了。
  • target: 即页面指向,格式是cbi("admin_test/net")。这里的cbi的函数指的是调用/luci/model/cbi/里的admin_test/里的net.lua文件。它还有其余的使用方法:

    1. cbi("..."):调用/luci/model/cbi/文件夹中的指定lua文件,这里指向的文件至关于指向一个处理函数。使用的是LUCI自带逻辑的处理方法,本文就是使用这种方法来生成的页面。
    2. template("..."):调用/luci/view/文件夹里指定的.htm视图文件。这个方法是直接调用视图。在视图里咱们也能够嵌入代码读取配置。
    3. alias("..."): 这个是重定向函数, 通常用于顶级菜单上,使其重定向到指定的子菜单。
    4. call("..."): 这个函数的做用是将该路由指向控制下的某个函数,通常用于处理数据,做用与指向模型层的cbi("...")函数相似,只是一个指向到其余文件,一个还是存在于控制层文件内。
    5. post("..."): 这个函数在openwrt里的其余模块有使用过,本人研究了一下,其做用于call方法相似,但在使用的时候彷佛没有成功,如果有成功使用过的猿友,欢迎交流探讨。

* title: 即标题展现,这个是设置在菜单里显示的内容项。格式有_("Test Net")translate("Test Net"),前一个使用我也没有成功(有点摸不清楚),后一个是调用translate('...')函数,用于与后期的语言包进行适配。该项能够用nil代替,表示为不在菜单栏显示。

  • order: 这个是排序,为子菜单进行排序,序号以1开始,最大不限。该项也能够忽略,表示为不在菜单栏显示。

* 若想让某项隐藏,能够写成如下格式:

entry({"admin", "testnet", "index"}, cbi("admin_test/net"), nil)
3> 定义模型层

OK,说了那么多,终于到了咱们最关键的模型层。在模型层,LUCI拥有一套自动生成机制,接下来让咱们一一介绍。先上代码再解释——

-- /model/cbi/admin_test/net.lua
m = Map("network", translate("Test Net"))

s = m:section(NamedSection, "testnets", "interface", translate("Net Configuration")
s.addremove = true
s.anonymouse = true

ifname = s:option(Value, "ifname", translate("Ifname: "))
ifname.datatype = 'string'

itype = s:option(Value, "type", translate("Type: "))
itype.datatype = 'string'

ipaddr = s:option(Value, "ipaddr", translate("Ipaddr: "))
ipaddr.datatype = 'ipaddr'

net = s:option(Value, "net", translate("Net:"))
net.datatype = 'ipaddr'

return m
  • m = Map("network", translate("Test Net")):这一句是链接配置文件,是以LUCI机制的必不可少的语句。第一个参数是配置文件的名称,第二个参数页面的大标题。
  • s = m:section(NamedSection, "testnets", "interface", translate("Net Configuration"):这一句是以section`的name名链接到指定的section

    1. 第一个参数是指定存取section的方法,本文用的是以section的name名进行查找的方式NamedSecton。其余还有几种方式:

      • TypedName: 根据section的type来进行存取
      • SimpleSection:(这个没用过,就很少说了)
      • Table:以表格的形式体现section
      • Tab:以标签的形式体现section
    2. 第二个参数是section的名字
    3. 第三个参数是section的类型
    4. 第四个参数是模块标题的名称

其余类型的代码示例分别以下:

-- TypedSection
s = m:section(TypedSection, "interface", translate("Net Configuration")

-- SimpleSection
s = m:section(SimpleSection, "interface", translate("Net Configuration")

-- Table
s = m:section(TypedSection, "interface", translate("Net Configuration")--也能够用NamedSection
s.Table(Table, "Table Title")

-- Tab
s = m:section(TypedSection, "interface", translate("Net Configuration")--也能够用NamedSection
s.Table(Tab, "Tab Title")
  • s.addremove = false:打开/关闭添加删除按钮,这个为true时,会在页面上添加一个添加和一个删除按钮,这样就可以在页面快速进行增减项了。不过有一点要注意的是,那样的页面比较丑……
  • s.anonymouse = true:这一句是不显示section的名字在页面上。还能够加上s.template = 'admin_test/net'这样的语句
  • net = s:option(Value, "net", translate("Net:")):这一句是链接具体的option。

    1. 第一个参数是显示类型。经常使用的显示类型有:

      • Value(普通文本框)、ListValue(下拉列表)、Flag(复选框)、MultiValue(文本域)、DummyValue(纯文本)、TextValue(多行input)、Button(按钮)、StaticList(静态列表)、DynamicList(动态列表)
    2. 第二个参数是option的名称
    3. 第三个参数是显示项的说明
  • net.datatype = 'ipaddr':这一句是指定option的类型。这里的是ip地址类型,其余还有不少类型:

    • neg、list、bool(布尔类型)、uinteger、integer(整型)、ufloat、float(浮点型)、ipaddr(IP地址)、ip4addr(IP4型IP地址)、ip4prefix(IP4前缀)、ip6addr、ip6prefix、port、portrange、macaddr、hostname、host、network、wpakey、wepkey、string、directory、file、device、uciname、range、min、max、rangelength、minlength、maxlength、phonedigit

这时访问/admin/testnet便可以看到页面了。

clipboard.png
参考连接:

相关文章
相关标签/搜索