openWRT之Luci简介mvc的三层架构
Luci简介:
lua是⼀个⼩巧的脚本语⾔,容易嵌⼊其他语⾔。轻量级LUA语⾔的官⽅版本只包含⼀个精简的核⼼和最基本的库,使lua体积⼩、启动速度快,从⽽适合嵌⼊在别的程序⾥。
uci(unified configuration interface):统⼀配置接⼝。即UCI系统。
//UCI系统⽤途就是为OpenWrt提供⼀个集中控制的接⼝。OpenWrt实现的这个⼯具,能够让你的不管是Lua还是PHP程序,或者SHELL程序或C程序,只要执⾏命令传输参数就能达到修改系统参数的⽬的。
//UCI系统的优势是UCI可以视为OpenWrt系统功能设置的主要⽤户配置接⼝,通常来说这些配置与系统的功能关联性较⼤,想像⼀下我们平常所使⽤的路由器或嵌⼊式设备中的WEB界⾯中的那些配置项,就是路由器或嵌⼊式设备系统所集成了的功能。常见的例⼦如路由器的⽹络接⼝设置,⽆线参数设置,logging设置和远程登录设置等。
Luci的启动--uhttpd
uhttpd是⼀个简单的web服务器程序,主要是cgi的处理,openwrt是利⽤uhttpd作为web服务器,实现客户端web页⾯配置功能。对于request处理⽅式,采⽤的是cgi,⽽所⽤的cgi程序就是luci
LuCI
⾸先回答⼀个问题:什么是Luci?
>LuCI是OpenWrt上的Web管理界⾯,LuCI采⽤了MVC三层架构,使⽤Lua脚本开发.
简单地说,Luci就是⽤来做openwrt的页⾯的.不同于常见的html+css+javascript,Openwrt是⽤lua脚本语⾔开发的.
怎么开发⼀个页⾯呢?
要开发⼀个新的功能页⾯,开发者只要根据MVC框架写些简单的lua脚本,剩下的部分由openwrt为你⾃动完成.
说到MVC框架了,什么是MVC框架呢?
MVC是model+view+controller的简写.为了便于开发,openwrt将实现不同功能的lua脚本放在不同的⽂件夹中.
什么是controller控制器?
我们在这⾥设置功能在页⾯的位置,同时设置点击页⾯后,将要调⽤的功能.是要去Model模型读写配置数据呢?还是要呈现⼀个静态页⾯,或者是直接执⾏lua脚本函数.
什么是model模型?
这⾥我们常⽤的是,通过cbi模块和UCI(统⼀配置接⼝)进⾏交互.简单地说,就是我们在这⾥将页⾯和路由器⾥⾯的配置关联起来,从⽽将页⾯的设置写到路由器当中.
什么是view视图?
这个应该是最容易理解的,就是呈现的页⾯的样式,有点类似于传统的html页⾯.
上⾯说到了UCI(Unified Configuartion Interface),这是什么龟?
openwrt将配置⽤统⼀的格式书写,放在规定的地⽅(/etc/config/),同时提供接⼝函数进⾏读取和设置.
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,⼀种软件设计典范,⽤⼀种业务逻辑、数据、界⾯显⽰分离的⽅法组织代码,将业务逻辑聚集到⼀个部件⾥⾯,在改进和个性化定制界⾯及⽤户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来⽤于映射传统的输⼊、处理和输出功能在⼀个逻辑的图形化⽤户界⾯的结构中。
MVC 是⼀种使⽤ MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应⽤程序的模式:[1]
Model(模型)表⽰应⽤程序核⼼(⽐如数据库记录列表)。
View(视图)显⽰数据(数据库记录)。
Controller(控制器)处理输⼊(写⼊数据库记录)。
MVC 模式同时提供了对 HTML、CSS 和 JavaScript 的完全控制。
Model(模型)是应⽤程序中⽤于处理应⽤程序数据逻辑的部分。
  通常模型对象负责在数据库中存取数据。
View(视图)是应⽤程序中处理数据显⽰的部分。
  通常视图是依据模型数据创建的。
Controller(控制器)是应⽤程序中处理⽤户交互的部分。
  通常控制器负责从视图读取数据,控制⽤户输⼊,并向模型发送数据。
MVC 分层有助于管理复杂的应⽤程序,因为您可以在⼀个时间内专门关注⼀个⽅⾯。例如,您可以在不依赖业务逻辑的情况下专注于视图设计。同时也让应⽤程序的测试更加容易。
MVC 分层同时也简化了分组开发。不同的开发⼈员可同时开发视图、控制器逻辑和业务逻辑。
------------------------------------------------------------------------------------
------------------------------------------------------------------------------------
Luci
轻量级LUA语⾔的官⽅版本只包括⼀个精简核⼼和最基库。这使得LUA体积⼩、启动速度快,从⽽适合嵌⼊在别的程序⾥。
UCI是Openwrt中为实现所有系统配置的⼀个接⼝,英⽂名 Unified Configuration Interface,即统⼀配置接⼝。
LuCI即是这两个项⽬的合体,可以实现路由⽹页配置界⾯。
先学习LUA脚本编程.
LuCI使⽤ MVC(模型 /视图 /控制)模型,在/usr/lib/lua/luci/下有三个⽬录 model、view、controller,它们分别对应 M、V、C。我们要做的主⼯作就是基于 LuCI框架编写LUA脚本、在html页⾯中嵌⼊LUA脚本。
LuCI将⽹页中的每⼀个菜单视作节点,如下图1:
这⾥有⼀级节点Status、System、Network、Logout,⼆级节点 System、Administration、Software、Startup等。我们使⽤浏览器向路由发起请求时, LuCI会从controller⽬录下的 index.lua开始组织这些节点。index.lua中定义了根节点 root,其他所有的节点都挂在这个根节点上。
我们可以将controller⽬录下的这些.lua⽂件叫做模块,这样的模块⽂件第⼀⾏必须是如下格式:
module("xx",package.seeall)
上⾯的xx表⽰该⽂件的路径luci. controller表⽰ /usr/lib/lua/luci/controller/,⽐如上⾯的index.lua其第⼀⾏为:
module("ller.admin.index", package.seeall),表⽰其路径为: /usr/lib/lua/luci/controller/admin/index.lua
接着是定义⼀个index⽅法,其主要⼯作是调⽤entry⽅法创建节点,可以多次调⽤创建多个节点。其调⽤⽅式如下:
entry (path, target, title, order)
a.path指定该节点的位置(例如 de3)
b.target指定当该节点被调度(即⽤户点击)时的⾏为主要有三种:
call、template和 cbi,后⾯有3个实例。
c.title:标题,即我们在⽹页中看到的菜单
LuCI默认开启了缓存机制,这样当我们修改了代码后,不会⽴即⽣效除⾮删缓存操作如下:
root@OpenWrt:/# rm -rf /tmp/luci-*
为了便于调试,我们可以直接关闭缓存,修改配置⽂件 /etc/config/luci,操作如下:操作如下:
root@OpenWrt:/# uci able=0
root@OpenWrt:/# uci commit
eg1: call
root@OpenWrt:/# cat /usr/lib/lua/luci/controller/example.lua
module("ample",package.seeall)
function index()
entry({"admin","example"},firstchild(),"Example",60)
entry({"admin","example","first"},call("first_action"),"First")
end
function first_action() --加载 /usr/lib/lua/luci/view/header.htm
luci.http.write("<h1>hello world_call</h1>")
end
说明:
创建⼀级菜单example,firstchild()表⽰链接到其第⼀个⼦节点,即当我们单击菜Example时,LuCI将调度其第⼀个⼦节点。"Example"即在⽹页中显⽰的菜单。
60表⽰其顺序,LuCI⾃带的模块顺序为:
Administration(10),Status(20),System(30),Network(50),Logout(90)。
call("first_action")表⽰当⼦节点被调度时将执⾏下⾯定义的⽅法first_action()
在lua脚本中,使⽤ --表⽰单⾏注释,--[[ --]]表⽰多⾏注释。
eg2: template
效果call⼀样,不同的是上节使⽤call调度执⾏⼀个函数,本节直接⽤html页⾯。
root@OpenWrt:/# cat /usr/lib/lua/luci/controller/example.lua
module("ample",package.seeall)
function index()
entry({"admin","example"},firstchild(),"Example",60)
entry({"admin","example","first"},template("example/example"),"First")
end
root@OpenWrt:/# mkdir /usr/lib/lua/luci/view/example/
root@OpenWrt:/# cat /usr/lib/lua/luci/view/example/example.htm
<%+header%>
<h1>hello world_template</h1>
说明:
创建⼀级菜单example,firstchild()表⽰链接到其第⼀个⼦节点,即当我们单击菜当我们单击菜Example时,LuCI将调度其第⼀个⼦节点。"Example"即
在⽹页中显⽰的菜单。
60表⽰其顺序,LuCI⾃带的模块顺序为:
Administration(10),Status(20),System(30),Network(50),Logout(90)
template ("example/example")表⽰当⼦节点被调度时LuCI将使⽤我们指定的html页⾯ /usr/lib/lua/luci/view/example/example.htm来⽣成页⾯。
eg3: cbi
该⽅法与UCI配置息相关,主要⽤来修改UCI配置⽂件以及使配置⽣效。
root@OpenWrt:/# cat /usr/lib/lua/luci/controller/example.lua
module("ample",package.seeall)
function index()
entry({"admin","example"},firstchild(),"Example",60)
entry({"admin","example","first"},template("example/example"),"First",1)
现在刷新⽹页,看下效果:
没有出现Second这个节点,是因为还没创建配置⽂件 /etc/config/example,touch命令创建这个⽂件:
root@OpenWrt:/# touch /etc/config/example
现在还没添加具体的业务功能,只是⼀个模型下⾯继续修改 /usr/lib/lua/luci/model/cbi/example/example.lua,内容如下:
root@OpenWrt:/# cat /usr/lib/lua/luci/model/cbi/example/example.lua
m=Map("example","Example for cbi","This is very simple example for cbi")
s=m:section(TypedSection,"example","Example","The section of type is example")
s.addremove=true
s.anonymous=false
n=s:option(Value,"num","Number")
return m
----------------图2705
----------------图2706
现在在路由器开发板上查看⼀些配置⽂件:
root@OpenWrt:/# cat /etc/config/example
config example 'first'
option num '12'
root@OpenWrt:/# uci export example
package example
config example 'first'
option num '12'
重点说明:
⼀般情况下,⼀个配置⽂件与启动脚本对应,⽐如/etc/config/network和/etc/init.d/network,当我们在页⾯上单击Save & Apply时,LuCI⾸先保存配置⽂件,然后就以 reload为参数调⽤配置⽂件对应的启动脚本。
为配置⽂件example创建⼀个启动脚本/etc/init.d/example,同时为其添加可执⾏权限。其内容如下:
root@OpenWrt:/# cat /etc/init.d/example
#!/bin/sh /etc/rcmon
#example
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,在最后添加如下内容:
root@OpenWrt:/# vim /etc/config/ucitrack
root@OpenWrt:/# tail -2 /etc/config/ucitrack
config example
option init example
当我们单击⽹页中的Save&Apply后,LuCI将会调⽤/sbin/luci-reload example,最终调⽤到/etc/rc.d/example中的函数,因此还需要执⾏如下操作:
root@OpenWrt:/# /etc/init.d/example enable
现在单击⽹页中的Save & Apply,可以看到开发板中输出了如下内容:
reload example
说明确实执⾏了/etc/init.d/example中的reload函数。
---------------------------------------------------------
CBI参考⼿册:
1. Map
Map (config, title, description)
//映射⼀个配置⽂件,返回⼀个Map对象。其中description可以省略。
m = Map("example", "Example for cbi"), "This is very simple example for cbi")
2. section
s = m:section(TypedSection, type, title, description)
/
/根据section类型解析section
s = m:section(NamedSection, name, type, title, description)
//根据section类型和名称解析section,其中m为Map返回的对象,s为Map类的成员函数 section返回的section对象。
section对象有⼀些属性如下:
template: html模板,默认为 "cbi/tsection"
addremove:是否可以增加和删除,默认为 false
anonymous:是否为匿名section,默认为 false
3. option
o = s:option(type, name, title, description)
//调⽤section对象的成员函数option,返回⼀个option对象。其中 type有多个取值:有多个取值:Value、DynamicList、Flag、ListValue。option对象的⼀些属性如下:
rmempty:如果为空值则删除该选项,默认为true
default:默认值,如果为空值,则设置该默认值
datatype:限制输⼊类型。例如 "and(uinteger,min(1))"限制输⼊⽆符号整形⽽且⼤于 0,"ip4addr"限制输⼊IPv4地址,"port"限制输⼊类型为端⼝,更多参考/usr/lib/lua/luci/cbi/datatypes.lua
placeholder:占位符(html5才⽀持)
4. Tab
s:tab(tabname, title)
//调⽤section的tab函数创建⼀个名称为tabname,标题为title的Tab标签。
对应的option则使⽤taboption
s:taboption(tabname, type, name, title)
在指定的tabname下创建⼀个option。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。