加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

有关lua,luci的介绍

发布时间:2020-12-14 22:20:15 所属栏目:大数据 来源:网络整理
导读:一颗璀璨的月光宝石——Lua Lua语言简介 1993 年在巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro in Brazil)诞生了一门编程语言,发明者是该校的三位研究人员,他们给这门语言取了个浪漫的名字——Lua,在葡萄牙语里代表美丽

一颗璀璨的月光宝石——Lua

Lua语言简介

1993
年在巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro in
Brazil)诞生了一门编程语言,发明者是该校的三位研究人员,他们给这门语言取了个浪漫的名字——Lua,在葡萄牙语里代表美丽的月亮。事实证明她没
有糟蹋这个优美的单词,Lua语言正如它名字所预示的那样成长为一门简洁、优雅且富有乐趣的语言。

Lua从一开始就是作为一门方便嵌入
(其它应用程序)并可扩展的轻量级脚本语言来设计的,因此她一直遵从着简单、小巧、可移植、快速的原则,官方实现完全采用ANSI
C编写,能以C程序库的形式嵌入到宿主程序中。Lua的每个版本都保持着开放源码的传统,不过各版采用的许可协议并不相同,自5.0版(最新版是5.1)
开始她采用的是著名的MIT许可协议。正由于上述特点,所以Lua在游戏开发、机器人控制、分布式应用、图像处理、生物信息学等各种各样的领域中得到了越
来越广泛的应用。其中尤以游戏开发为最,许多著名的游戏,比如Escape from Monkey Island、World of
Warcraft、大话西游,都采用了Lua来配合引擎完成数据描述、配置管理和逻辑控制等任务。

作为一门过程型动态语言,Lua有着如
下的特性:1、变量名没有类型,值才有类型,变量名在运行时可与任何类型的值绑定;2、语言只提供唯一一种数据结构,称为表(table),它类似key
-value关联数组,可以用任何类型的值作为key和value。提供了一致且富有表达力的表构造语法,使得Lua很适合描述复杂的数据;3、函数是一
等类型,支持匿名函数和正则尾递归(proper tail recursion);4、支持词法定界(lexical
scoping)和闭包(closure);5、提供thread类型和结构化的协程(coroutine)机制,在此基础上可方便实现协作式多任务;
6、运行期能编译字符串形式的程序文本并载入虚拟机执行;7、通过元表(metatable)和元方法(metamethod)提供动态元机制
(dynamic
meta-mechanism),从而允许程序运行时根据需要改变或扩充语法设施的内定语义;8、能方便地利用表和动态元机制实现基于原型
(prototype-based)的面向对象模型;9、从5.1版开始提供了完善的模块机制,从而更好地支持开发大型的应用程序;

Lua
的语法类似PASCAL和Modula但更加简洁,所有的语法产生式规则(EBNF)不过才60几个。熟悉C和PASCAL的程序员一般只需半个小时便可
将其完全掌握。而在语义上Lua则与Scheme极为相似,她们完全共享上述的1、3、4、6点特性,
Scheme的continuation与协程也基本相同只是自由度更高。最引人注目的是,两种语言都只提供唯一一种数据结构:Lua的表和Scheme
的列表(list)。正因为如此,有人甚至称Lua为“只用表的Scheme”。

库和工具

相比Java、Python、Perl,Lua的开源工具和库可能并不算多,但其中不乏优秀之作。以下介绍的资源均可在http://lua-users.org/wiki/LuaAddons上找到,而且绝大多数都遵循着与Lua相同的许可协议。

一、Kepler

Kepler
是一个简单且轻量的Web开发平台(但这并不意味着只能用它来开发简单的应用),支持用Lua撰写Web程序,因此相当易学易用,并且能较方便地应用在一
些资源受限的系统中。由于使用ANSI C和Lua进行开发,所以它能移植到任何支持ANSI C的平台上。

Kepler由多个Lua扩
展库组成,包括CGILua、LuaSocket、LuaFileSystem、Copas、LuaSQL、LuaLDAP、LuaExpat、
LuaXMLRPC、LuaSOAP、LuaZip、Xavante等,它们可大致分为核心库和功能支撑库两部分。其中核心是CGILua和
LuaSocket,后者负责TCP/UDP
sockets的操作,前者则可以创建动态页面并处理web表单上的输入数据。Kepler通过CGILua起动器(launcher)使得Web服务器
能执行CGILua和Web程序并与之通信。目前的版本已经包括适合CGI、FastCGI、Apache、IIS、Tomcat、Zope的
CGILua起动器,因此用Lua开发的Web程序可以在这些种类的服务器中自由迁移,只要同时安装上对应的CGILua起动器。

LuaFileSystem
是对标准Lua库中文件读写功能的补充,它提供了一种可移植的方法来访问系统的目录结构和文件属性。Copas则是一个基于协程的服务调度器。
Xavante是一个用Lua开发的支持HTTP 1.1的Web服务器,它直接支持CGILua而无需起动器。

其它的组件提供了SQL数据库访问、XML解析、LDAP、SOAP、XMLRPC、ZIP文件操作等功能,用户如果只需要其中的某些功能,可以抽出相关组件(及其所依赖的组件)来使用。

二、wxLua

GUI
是开发人员花费气力比较大的一个领域,因此简化GUI程序的编写一直是广大程序员的努力方向。随着脚本语言的兴起,将动态、灵活、易用的脚本语言引入到
GUI开发中是一种非常有价值的尝试。由于复杂的GUI布局需要大量的描述信息,所以比起其它脚本来,既适合编程又适合描述数据的Lua语言在构建GUI
上就具有独特的优势。

wxWidgets是一个著名的跨平台C++
GUI库,wxLua在Lua与wxWidgets之间架起了一座桥梁,通过它Lua代码几乎可以调用wxWidgets的所有功能。wxLua基本将
wxWidgets的类体系映射到了Lua(基于原型)的对象模型中,这使得程序员能以基于对象或面向对象的风格来开发wxLua程序。一个Lua脚本的
撰写、运行、测试和修改可以非常快速,这无疑大大提高了GUI程序的开发效率,因此wxLua非常适合快速原型的构造。另外,Lua本身以及
wxWidgets良好的可移植性使得相应的Lua GUI程序在许多平台上都能顺畅地运行。

三、Pluto

虽然Lua
中的表能通过表构造器以Lua代码的形式保存到文件中从而实现持久化,但当数据之间有着复杂的引用关系,并且存在循环引用、共享引用等特殊情况时,这个任
务就变得相当困难与繁琐了。Pluto持久化库能够为用户解决这个难题。在它的帮助下程序员可以将任意复杂的表数据保存到特殊格式的二进制文件中以待将来
恢复,库会自动处理循环引用之类的情况。

除表之外,Pluto还支持函数(确切地说是闭包)、thread的持久化,这种能力非常有意
义。大家都知道程序调试中的一个基本动作就是复现bug,但很多时候bug产生的条件是非常复杂的,依赖很多因素,开发者很难精确地构建出完全一致的运行
环境。而利用Pluto对函数和thread的持久化能力,我们可以把bug发生时程序的完整运行环境保存下来,今后就可凭此方便地复现bug。另外一个
重要应用是游戏进度的保存。实现游戏逻辑的Lua脚本的运行状态能随时写入到文件中留待将来恢复,这使得在任何时间点保存游戏成了一件非常容易的事情。

四、LuaCOM

LuaCOM
是一个支持Lua与符合COM规范的组件对象(确切一点说是自动化对象)进行交互的扩展库。所谓交互包括了两个方面,首先是允许Lua程序使用COM对
象。LuaCOM支持注册在系统注册表中的COM对象的动态实例化,也支持动态访问运行中的对象。在LuaCOM的帮助下,调用COM对象方法就象调用普
通Lua函数一样,存取属性也与存取表的字段类似,同时它还负责Automation数据类型与Lua数据类型的自动转换。有了这些特性,Lua程序操作
COM对象就变得容易多了,再加上Lua天生的动态性,这无疑使其成了一门非常灵活的组件装配语言。

交互的另外一个方面就是支持用Lua
来实现(自动化)组件对象并提供给外部客户使用。LuaCOM同时支持进程内和进程外组件,它提供了一些辅助函数来处理注册、对象实例化这类事情,从而简
化了相关工作。由于LuaCOM实际上是根据Lua的表来构造一个COM对象,所以我们可以做一些非常有趣的事情:在userdata数据类型(代表不属
于Lua世界的数据结构)和动态元机制的支持下,Lua能通过表访问各种各样的外部数据,包括C++对象、C结构或者CORBA对象等等;LuaCOM可
以很方便地将代表这些数据的表包装成一个COM对象给外部使用,从而使得那些老迈的应用程序和库无需太多的努力便能跻身于COM世界。

五、tolua


接用C实现某些功能,然后将相应的函数导入到Lua中是很常见的做法。不过尽管Lua提供了与C语言交互的API,但用户必需手工进行繁琐的Lua栈(用
于与C交换数据)操作,而且还需注意两种语言数据类型的正确转换。难怪有人说使用Lua的C
API就象在使用汇编语言一样。为了减轻程序员的负担,一些C/C++ Wrapper应运而生。

tolua本身不是一个
Wrapper,但它是一个Wrapper代码自动生成器。它使用一种称为包(package)的文件来描述要导入到Lua环境中的常量、变量、函数、类
和方法,这种文件按照简化了的C++头文件格式编写。使用时首先让tolua解析包文件以生成含有相应胶水代码的C/C++源文件。然后将生成的源文件编
译并与那些具体实现功能的目标模块链接起来。

tolua虽然自动产生胶水代码,但需另外撰写描述文件,所以仍然不够方便。其它一些Wrapper库则利用C++模板元编程技术来自动生成合适的连接代码,从而避免了额外的描述文件,比如使用boost库的luabind。

六、LuaJIT

Lua
非常高效,它运行得比许多其它脚本(如Perl、Python、Ruby)都快,这点在第三方的独立测评中得到了证实。尽管如此,仍然会有人不满足,他们
总觉得“嗯,还不够快!”。LuaJIT就是一个为了再榨出一点速度的尝试,它利用JIT编译技术把Lua代码编译成本地机器码后交由CPU直接执行。
LuaJIT测评报告表明,在浮点运算、循环和协程的切换等方面它的加速效果比较显著,但如果程序大量依赖C编写的函数,那么运行速度便不会有什么改进。
目前LuaJIT只支持X86 CPU。

LuaJIT中包括一个名为Coco的库,用户可以单独使用它。Coco为C函数提供了真正的协
程能力,用户能在C函数内部的任何一点将协程挂起,然后在将来用协程恢复操作返回到那一点。在标准Lua中,协程的挂起与恢复是不允许跨越C函数调用边界
的。Coco使用了一些依赖于特定系统的特性,因此在移植程序时要特别注意。

七、ChunkSpy

Lua的虚拟机字节码指令集并非语言定义的一部分,因此官方没有提供相应的文档。用户当然可以通过查看相关源代码来获取信息,但这毕竟不方便。

ChunkSpy
是一个Lua虚拟机字节码反汇编器,可以将一个二进制Lua代码块输出为非常易读的各种格式(详细或简略,带或不带源程序)的字节码汇编文件。而且它还支
持交互式的反汇编,用户在敲入一行代码后立刻就能看到对应的字节码指令。ChunkSpy的作者写过一篇详细的介绍Lua5虚拟机指令的文章,名为《A
No-Frills Introduction to Lua 5 VM
Instructions》,你在项目主页上能找到它。这篇文章现在已经针对最新的Lua5.1做了更正。另外,他还是Yueliang项目的开发者,这
个项目采用Lua语言本身来实现Lua。从项目名来看,作者应该是个华人。

八、其它

另外一些库与工具还包括
LuaEDIT、LuaEclipse、VS’05LuaLangPack(它们都是IDE或IDE插件),LuaWrapper、CaLua、CPB、
CppLua(Wrapper库),LuaProfiler(性能测量工具)等,读者可以在lua-user.org与luaforge.net网站上找
到它们以及其它有用资源。


luci框架的简介

LUCI?这个在百度上搜索除了一篇我的百度文库?luci?的介绍文章之外,前三页都是些不知所云的名词(足见百度在专业领域的搜索之烂),我却在大学毕业的大半年的大部分时间里与它纠结,由于开始的发懵到后来逐渐感觉到这家伙还很好玩的,现在就把我对?luci?的浅显认识介绍给大家。

官网:?http://luci.subsignal.org/

??有关luci?的各个方面,你几乎都可以从这里获得,当然,只是浅显的获得,?luci?的文档写的还算比较全,但是写的稍显简略,开始看的时候会有一点不知所措。

UCI??熟悉?openwrt?的人都会有所了解,就是?Uni???ed?Con???guration?Interface?的简称,而?luci?这个?openwrt上的默认?web?系统,是一个独立的由严谨的德国人开发的?web?框架,是?Lua??Con???guration?Interface?的简称,如果在您的应用里,?luci?是对?openwrt?的服务,我们就有必要做一下?uci?的简介,我这里就不说了,见链接:

http://www.google.com.hk/url?sa=t&source=web&cd=5&ved=0CEMQFjAE&url=http%3A%2F%2Fnbd.name%2Fopenwrt-fosdem-09.pdf&ei=h52iTcXvOcrMcJ-xxOwD&usg=AFQjCNGFhumCIgS5tK_mDJ2dDFU4qsskfQ

?

有的时候,我们开发的luci?是在自己的?Linux?PC?上开发,在普通的?linux?上,一般是没有?uci?命令的,为了开发方便,可以手动编译一下,方法见链接:

https://forum.openwrt.org/viewtopic.php?id=15243

OK?,之前罗里罗嗦的说了很多,现在就进入正题,进入正题的前提是你已经?make?install?正确的安装了?lua??,luci?,以及编译好链接了相关的?so?(如果你需要,比如?uci.so?nixio.so?),以及?make?install?正确?web?server,(我用的?web?server?是?thttpd?,也编译过?mongoose?,?lighttpd?,在这三个之中,?lighttpd?是功能最完善的,?mongoose?是最小巧的)。

进入正题:

一:luci?的启动

??在web?server?中的?cgi-bin?目录下,运行?luci?文件(权限一般是?755?),?luci?的代码如下:

[c-sharp]? view plain copy
  1. #!/usr/bin/lua??????--cgi的执行命令的路径require"luci.cacheloader"????--导入cacheloader包require"luci.sgi.cgi"?????????--导入sgi.cgi包?luci.dispatcher.indexcache?=?"/tmp/luci-indexcache"???--cache缓存路径地址??
  2. luci.sgi.cgi.run()??--执行run方法,此方法位于*/luci/sgi/cgi.lua中??

?run方法的主要任务就是在安全的环境中打开开始页面(登录页面),在?run?中,最主要的功能还是在dispatch.lua?中完成。

?运行luci?之后,就会出现登录界面:

[xhtml]? copy
    -bash-4.0#?pwd??
  1. /var/www/cgi-bin??
  2. -bash-4.0#?./luci??
  3. ??Status:?200?OK??????
  4. ??Content-Type:?text/html;???
  5. ??charset=utf-8???????
  6. ??Cache-Control:?no-cache?????
  7. ??Expires:?0??
  8. <!DOCTYPE?HTML?PUBLIC?"-//W3C//DTD?HTML?4.01//EN"???
  9. "http://www.w3.org/TR/html4/strict.dtd">??????
  10. ?<html?class="?ext-strict">??
  11. ?/*some?html?code*/??????
  12. </html>??

???
?????如果你成功的运行了luci???就说明你的?luci?框架成功的跑了起来。

二:LUCI?的?MVC

1:用户管理:

??????在luci?的官方网站说明了?luci?是一个?MVC?架构的框架,这个?MVC?做的可扩展性很好,可以完全的统一的写自己的?html?网页,而且他对?shell?的支持相当的到位,(因为?luci?是?lua?写的,?lua?是?C?的儿子嘛,???????与?shell?是兄弟)。在登录界面用户名的选择很重要,??????luci?是一个单用户框架,公用的模块放置在?*/luci/controller/?下面,各个用户的模块放置在?*/luci/controller/?下面对应的文件夹里面,比如??????????????admin?登录,最终的页面只显示?/luci/controller/admin?下面的菜单。这样既有效的管理了不同管理员的权限。

2:?controller?文件夹下的?lua?文件说明:(以?mini?用户为例)

?????在mini?目录下面,会有一个?index.lua?文件,简略的代码如下:

[python]? copy
    module("luci.controller.mini.index",?package.seeall)??
  1. 17????
  2. 18??function?index()??
  3. 19??????luci.i18n.loadc("admin-core")??
  4. 20??????local?i18n?=?luci.i18n.translate??
  5. 21????
  6. 22??????local?root?=?node()??
  7. 23??????if?not?root.lock?then??
  8. 24??????????root.target?=?alias("mini")??
  9. 25??????????root.index?=?true??
  10. 26??????end??
  11. 27???????
  12. 28??????entry({"about"},?template("about")).i18n?=?"admin-core"??
  13. 29???????
  14. 30??????local?page???=?entry({"mini"},?alias("mini",?"index"),?i18n("essentials",?"Essentials"),?10)??
  15. 31??????page.i18n????=?"admin-core"??
  16. 32??????page.sysauth?=?"root"??
  17. 33??????page.sysauth_authenticator?=?"htmlauth"??
  18. 34??????page.index?=?true??
  19. 35???????
  20. 36??????entry({"mini",?"index"},?"index",?i18n("overview"),?10).index?=?true??
  21. 37??????entry({"mini",?form("mini/index"),?i18n("general"),?1).ignoreindex?=?true??
  22. 38??????entry({"mini",?"luci"},?cbi("mini/luci",?{autoapply=true}),?i18n("settings"),248); line-height:18px"> 39??????entry({"mini",?"logout"},?call("action_logout"),?i18n("logout"))??
  23. 40??end??
  24. 41????
  25. 42??function?action_logout()??
  26. 43??????luci.http.header("Set-Cookie",?"sysauth=;?path=/")??
  27. 44??????luci.http.redirect(luci.dispatcher.build_url())??
  28. 45??end??

这个文件定义了node?,最外面的节点,最上层菜单的显示等等。在其他的?lua?文件里,定义了其他菜单的显示和html?以及业务处理路径。每个文件对应一个菜单相。

例如?system.lua?文件

copy
function?index()??
  • 19??????luci.i18n.loadc("admin-core")??
  • 20??????local?i18n?=?luci.i18n.translate??
  • 21????
  • 22??????entry({"mini",?"system"},?"system",?i18n("system"),?40).index?=?true??
  • 23??????entry({"mini",?cbi("mini/system",?{autoapply=true}),?1)??
  • 24??????entry({"mini",?"passwd"},?form("mini/passwd"),?i18n("a_s_changepw"),?10)??
  • 25??????entry({"mini",?"backup"},?call("action_backup"),?i18n("a_s_backup"),?80)??
  • 26??????entry({"mini",?"upgrade"},?call("action_upgrade"),?i18n("a_s_flash"),?90)??
  • 27??????entry({"mini",?"reboot"},?call("action_reboot"),?i18n("reboot"),?100)??
  • 28??end??
  • mudel是对应文件的,?function?index?定义了菜单,比如这一句entry({"mini",?"system",?"reboot"},?call("action_reboot"),?i18n("reboot"),?100)

    1?项为菜单入口:

    {"mini",?"reboot"},?mini?是最上层的菜单,即为用户项,?system?为一个具体的菜单,?reboot?为这个菜单的子菜单,如果?reboot?还需要加上子菜单的话,可以这样写:

    entry({"mini",?"reboot",?"chreboot"},?call("action_chreboot"),?i18n("chreboot"),?1),?这样就会在reboot?上产生一个新的子菜单,以此类推,可以产生?N?层菜单。

    第二项为菜单对应的页面,可以是lua?的源代码文件,也可以是?html?页面。

    alias?cgi?form?call?等定义了此菜单相应的处理方式,?form?和?cgi?对应到?model/cbi?相应的目录下面,那里面是对应的定制好的?html?和?lua?业务处理。

    alias是等同于别的链接,?call?调用了相应的?action_function?。还有一种调用,是?template?,是直接链接到view?相应目录下面的?htm?页面。(说明:?luci?框架下面的?htm?都是可以嵌入?lua?语句的,做业务处理,相当于?jsp?页面的内部的?Java?语句)。

    问价查找对应简介:

    action_reboot?function

    */model/cbi/mini/system.lua??{autoapply=true}???这个失传的参数。

    。。。。。

    第三项为i18n?显示,比如entry({"mini",?100),菜单的名字为admin-core?文件内的对应显示。此处也可以这样写,??i18n("reboot","?重启?")?,即直接做了国际化。菜单上显示的就是“重启”。

    第四项为现实的顺序,这个数字越小,显示越靠前,靠上。

    ?

    现在说一下这些文件的解析是怎么解析的呢?你当然是说dispatch.lua中,你说对了,但是真正解析成菜单的递归算法确实在header.htm中 ?位置:*/view/themes/openwrt/
    代码如下:
    [php]? view plain copy
      <%??
    1. require("luci.sys")??
    2. local?load1,?load5,?load15?=?luci.sys.loadavg()??
    3. local?request??=?require("luci.dispatcher").context.path??
    4. local?category?=?request[1]??
    5. local?tree?????=?luci.dispatcher.node()??
    6. local?cattree??=?category?and?luci.dispatcher.node(category)??
    7. local?node?????=?luci.dispatcher.context.dispatched??
    8. local?hostname?=?luci.sys.hostname()??
    9. local?c?=?tree??
    10. for?i,r?in?ipairs(request)?do??
    11. ?????if?c.nodes?and?c.nodes[r]?then??
    12. ??????????c?=?c.nodes[r]??
    13. ??????????c._menu_selected?=?true??
    14. ?????end??
    15. end??
    16. require("luci.i18n").loadc("default")??
    17. require("luci.http").prepare_content("application/xhtml+xml")??
    18. -%>??
    19. <?xml?version="1.0"?encoding="utf-8"?>??
    20. <!DOCTYPE?html?PUBLIC?"-//W3C//DTD?XHTML?1.0?Strict//EN"?"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">??
    21. <html?xmlns="http://www.w3.org/1999/xhtml"?xml:lang="<%=luci.i18n.context.lang%>"?lang="<%=luci.i18n.context.lang%>">??
    22. <head>??
    23. <meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"?/>??
    24. <meta?http-equiv="Content-Script-Type"?content="text/javascript"?/>??
    25. <link?rel="stylesheet"?type="text/css"?media="screen"?href="<%=media%>/cascade.css"?/>??
    26. <!--[if?lt?IE?7]><link?rel="stylesheet"?type="text/css"?media="screen"?href="<%=media%>/ie6.css"?/><![endif]-->??
    27. <!--[if?IE?7]><link?rel="stylesheet"?type="text/css"?media="screen"?href="<%=media%>/ie7.css"?/><![endif]-->??
    28. <%?if?node?and?node.css?then?%><link?rel="stylesheet"?type="text/css"?media="screen"?href="<%=resource%>/<%=node.css%>"?/>??
    29. <%?end?-%>??
    30. <mce:script?type="text/javascript"?src="<%=resource%><!--??
    31. /VarType.js">??
    32. //?--></mce:script>??
    33. <mce:script?type="text/javascript"?src="<%=resource%><!--??
    34. /XHTML1.js">??
    35. //?--></mce:script>??
    36. /Dropdowns.js">??
    37. <title><%=striptags(?hostname?..?(?(node?and?node.title)?and?'?-?'?..?node.title?or?''))?%>?-?LuCI</title>??
    38. </head>??
    39. <body?class="lang_<%=luci.i18n.context.lang%>">??
    40. <p?class="skiplink">??
    41. <span?id="skiplink1"><a?href="#navigation"?mce_href="#navigation"><%:skiplink1?Skip?to?navigation%></a></span>??
    42. <span?id="skiplink2"><a?href="#content"?mce_href="#content"><%:skiplink2?Skip?to?content%></a></span>??
    43. </p>??
    44. <div?id="header">??
    45. <h1><%=luci.version.distname%></h1>??
    46. <p>??
    47. <%=luci.version.distversion%><br?/>??
    48. <%:load%>:?<%="%.2f"?%?load1%>?<%="%.2f"?%?load5%>?<%="%.2f"?%?load15%><br?/>??
    49. <%:hostname%>:?<%=hostname%>??
    50. </p>??
    51. </div>??
    52. <div?id="menubar">??
    53. <h2?class="navigation"><a?id="navigation"?name="navigation"><%:navigation?Navigation%></a></h2>??
    54. <ul?id="mainmenu"?class="dropdowns">??
    55. <%-??
    56. local?function?submenu(prefix,?node)??
    57. if?not?node.nodes?or?node.hidden?then??
    58. ??????????return?false??
    59. ?????end??
    60. ?????local?index?=?{}??
    61. ?????local?count?=?0??
    62. ?????for?k,?n?in?pairs(node.nodes)? ??????????if?n.title?and?n.target?then??
    63. ???????????????table.insert(index,?{name=k,?order=n.order?or?100})??
    64. ???????????????count?=?count?+?1??
    65. ??????????end??
    66. ?????table.sort(index,?function(a,?b)?return?a.order?<?b.order?end)??
    67. if?count?>?0?then??
    68. %>??
    69. <ul?id="submenu_<%=string.gsub(string.gsub(prefix,?"/",?"_"),?"^_(.-)_$",?"%1")%>">??
    70. <%-??
    71. for?j,?v?in?pairs(index)?do??
    72. ???????????????if?#v.name?>?0?then??
    73. ????????????????????local?nnode?=?node.nodes[v.name]??
    74. ????????????????????local?href?=?controller?..?prefix?..?v.name?..?"/"??
    75. ????????????????????href?=?(nnode.query)?and?href?..?luci.http.build_querystring(nnode.query)?or?href??
    76. ??????????????????????
    77. ????????????????????if?nnode.nodes?then??
    78. ?????????????????????????for?k1,?n1?in?pairs(nnode.nodes)? ??????????????????????????????href?=?"#"??
    79. ???????????????????????????
    80. ?????????????????????????end??
    81. ????????????????????end???????
    82. %>??
    83. <li><a<%?if?nnode._menu_selected?then?%>?class="active"<%end%>?href="<%=luci.util.pcdata(href)%>"><%=nnode.title%></a><%-??
    84. submenu(prefix?..?v.name?..?"/",?nnode)??
    85. %></li>??
    86. ???????????????end??
    87. ??????????end??
    88. </ul>??
    89. <%??
    90. end??
    91. if?cattree?and?cattree.nodes?then??
    92. ??????????table.insert(index,?order=node.order? ??????????node?=?cattree.nodes[k.name]??
    93. if?node.title?and?node.target?and?not?node.hidden?then??
    94. ???????????????local?href?=?controller.."/"..category.."/"..k.name.."/"??
    95. ???????????????href?=?(k.query)?and?href?..?luci.http.build_querystring(k.query)? ?????????????????
    96. ??????????????? ????????????????????if?n1.title?and?n1.target?then??
    97. ?????????????????????????href?=?"?#"??
    98. ????????????????????end??
    99. ???????????????end???????
    100. if?node._menu_selected?then?%>?class="preactive"<%end%>?href="<%=href%>"><%=node.title%></a><%??
    101. submenu("/"?..?category?..?"/"?..?k.name?..?"/",?node)??
    102. %></li><%?end??
    103. </ul>??
    104. <ul?id="modemenu"><%??
    105. and?not?node.hidden?then?%>??
    106. if?request[1]?==?k?then?%>?class="active"<%end%>?href="<%=controller%>/<%=k%>/"><%=node.title%></a></li><%??
    107. <%??
    108. if?tree.nodes[category]?and?tree.nodes[category].ucidata?then??
    109. ?????local?ucic?=?0??
    110. require("luci.model.uci").cursor():changes())?for?m,?n?in?pairs(l)? ????????????????????ucic?=?ucic?+?1;??
    111. -%>??
    112. <ul?id="savemenu"? <li><%?if?ucic?>?0?then?%><a?class="warning"?href="<%=controller%>/<%=category%>/uci/changes/"><%:unsavedchanges%>:?<%=ucic%></a><%??
    113. submenu("/"?..?category?..?"/uci/",?tree.nodes[category].nodes["uci"])??
    114. else?-%>??
    115. <a?href="#"?mce_href="#"><%:changes%>:?0</a><%?end?-%>??
    116. </li>??
    117. </ul><%?end?%>??
    118. <div?class="clear"></div>??
    119. </div>??
    120. <div?id="maincontent">??

    3:?model?业务处理和页面生成简介

    ????我认为model?的业务处理和?html?生成,是?luci?框架的精华,但是想用好它,最终扩展定义自己的页面也是最难的,但是一旦定义好了,后面的工作就会轻松高效简介统一,不失为一种好的解决方案。但是它又有缺点,就是写页面虽然统一,但是不够灵活。

    下面以?SimpleForm为例,讲解一下。

    具体文件?*/luci/model/cbi/passwd.lua

    f?=?SimpleForm("password",?translate("a_s_changepw"),?translate("a_s_changepw1"))??--调用SimpleForm?页面??当然还是?I18N?从中捣乱,看上去没那么直观,不理他?
    pw1=f:field(Value,"pw1",translate("password"))?--??SimpleForm?里面加一个?field???至于?SimpleForm??和?fiemd?是什么,一会去看?SimpleForm?页面去?
    pw1.rmempty=false?--?把?SimpleForm的?rmempty?为不显示??后面就不做注释了?应该看得懂了?
    pw2?=?f:field(Value,?"pw2",?translate("confirmation"))?
    pw2.rmempty?=?false?
    function?pw2.validate(self,?value,?section)?
    ?????return?pw1:formvalue(section)?==?value?and?value?
    end?
    function?f.handle(self,?state,?data)?
    ?????if???state?==?FORM_VALID???then?????--这个就是业务处理了??你懂得??呵呵?
    ??????????local?stat?=?luci.sys.user.setpasswd("admin",?data.pw1)?==?0??--?root?-->?admin?????
    ??????????if?stat?then?
    ???????????????f.message?=?translate("a_s_changepw_changed")?
    ??????????else?
    ???????????????f.errmessage?=?translate("unknownerror")?
    ??????????end?
    ??????????
    ??????????data.pw1?=?nil?
    ??????????data.pw2?=?nil?
    ?????end?
    ?????return?true?
    end?
    return?f

    说明:(?simpleForm??位于?view/cbi???下面,可以研究一下,各个元素是如何定义的?)

    现在在给一个小例子:

    .*/luci/model?/cbi/admin_system/version_manage.lua?为例,介绍一下?luci?中?web?页面?lua?代码?
    ??6?local?h?=?loadfile("/usr/local/luci/help.lua")?
    ??7?if?h?then?
    ??8?????h()?
    ??9?end?
    10?local?help_txt?=?help_info?and??help_info.version?
    加载帮助帮助文件help.lua,?关于?loadfile()?的用法可以查看?lua?的手册?(?我还没完全弄明白,先用了?)?
    help_txt?是一个全局变量?

    12?appadmin_path?=?"/usr/local/appadmin/bin/"?
    定义一个全局变量,其实跟功能跟宏一样,定义appadmin?的绝对路径?

    14?versionlist?=?{}?
    15?
    16?function?getline?(s)?
    .........?
    32?end?
    33?
    34?function?get_versionlist()?
    .........?
    68?end?
    69?
    70?versionlist?=?get_versionlist()?

    定义一个全局变量和两个函数,并初始化此变量?

    接下来就是和最终展现的Web?页面直接相关的代码了,大部分都是对?luci?封装好的一些?html?控件(代码)的使用和扩展。?luci??封装好的?html?控件?

    类可以在以下文件查看:./host/usr/lib/lua/luci/cbi.lua?
    71?m?=?SimpleForm("version",?translate("版本管理?"))?
    72?m.submit?=?false?
    73?m.reset?=?false?
    74?m.help?=?help_txt?and?true?or?false?
    75?m.helptxt?=?help_txt?or?""?
    使用了一个SimpleForm?的控件,?SimpleForm?实际上对应一个?html?表单,是整个页面最大的?"?容器?"?,本页面内的绝大部分控件都处于?SimpleForm?内?

    ,是它的子控件?。我知道的可以做>?页面最大?"?容器?"?的控件还有一个?Map,?但它需要?./host/etc/config/?目录下的一个配置文件,我没有使用。?
    submit?reset是?luci?默认就封装好的一个属性,分别控制?html?表单的?"?提交?""?重置?"?按钮?;help?helptxt?是我扩充的表单属性,分别控制?web?页面的?

    "帮助?"?功能和帮助内容。关于控件属?
    性的意义、实现和扩充可以按以下步骤进行:?
    ????在文件./host/usr/lib/lua/luci/cbi.lua?中查找控件名?SimpleForm,??然后可以找到以下行?664?????self.template?=?"cbi/simpleform"?这?

    表明SimpleForm?的?html?模版文件为?./host/usr/lib/lua/luci/view/cbi?/simpleform.htm?,通过研究?simpleform.htm?文件内容可以知道各属性的?

    功能以及模版中使用lua?代码的方法,然后可以按类似的方法添加自定义的?
    属性。?
    77?s?=?m:section(Table,?versionlist)?
    新建了一个section,section?内定义了一个表格类,?versionlist?是与其相关的变量(?lua?的所有变量都可归类于?table?类型?)?
    Table?关联的?table?变量应该是这种结构的:?
    t?=?{?
    ????row1?=?{column1?=?"xxx",?column2?=?"xxx",?....?},?
    ????row2?=?{column1?=?"xxx",?
    ????row3?=?{column1?=?"xxx",?
    ????row4?=?{column1?=?"xxx",?
    }?
    然后定义Table?的列控件?
    79?enable?=?s:option(DummyValue,?"_enabled",?translate("软件状态?"))?
    83?appid??=?s:option(DummyValue,?"_appid",?translate("软件版本?"))?
    84?appname?=?s:option(DummyValue,?"_appname",?translate("软件名称?"))?
    DummyValue是只读的文本框,只输出不输入。?Value?是单行文本框,可输出也可输入。?Flag?是一个?checkbox,值为?"1"?时被选中,为?"0"?时未选中。?

    ListValue是列表框?...?具体的用法可?
    以看./host/usr/lib/lua/luci?/model/cbi/?下的文件(?find?./host/usr/lib/lua/luci/model/cbi/?-name?"*.lua"?|xargs?grep?

    "ListValue")?
    对于table?内普通的字符串类的值,只需要把列控件的?id?(括号内第二个值,如?"_appid"?)定义为?table?内对应的变量名(比如?column1?)?
    对于非变通字符串类的值,或者为字符串但需要进行一定的处理然后再显示的值,可以按以下方法显示:定义该控件的cfgvalue?函数属性?
    127?????newinfo?=?up_s:option(TextValue,?"_newifo",?translate("新版本信息?"))?
    128?????newinfo.readonly?=?true?
    129?????newinfo.rows?=?11?
    130?????newinfo.cfgvalue?=?function(self,?section)?
    131?????????local?t?=?string.gsub(info,?"Archive:[^/n]*",?"")?
    132?????????return?t?
    133?????end?
    定义cfgvalue?后,?luci?的处理函数会调用此函数为此控件赋值,(传入的?section?参数值为?row1/row2/row3等,当处理到?row?几时值就为?row?几?)?
    对于DummyValue?等只输出不输入的类,还有一种赋值方法:?控件实例名(如?enable).value?=?xxx?
    对于有输入的控件Value?等,??.value?方法赋值在处理输入里会有一些问题,有什么问题以及如何解决可以做实验试试??,?也许是我使用方法不对造?
    成的?
    对有输入控件的处理有两种方法:?
    1?定义控件的?.write?属性?
    ????这种方法对处理比较独立的输入(与其它控件输入关系不大)比较适用?
    88?up_s?=?m:section(SimpleSection)?
    89?up_version?=?up_s:option(Button,?"_up_version",?translate("上传新版本?"))?
    90?up_version.onlybutton?=?true?
    91?up_version.align?=?"right"?
    92?up_version.inputstyle?=?"save"?
    93?up_version.write?=?function(self,?section)?
    94?????luci.http.redirect(luci.dispatcher.build_url("admin",?"version_manage",?"upload"))
    95?end?
    ps:只有当?Value?的?rmempty?==?false?时,?Value?输入为空也会触发?write?函数?,??需要对?rmemtpy?显示赋值为false?(?xx.rmempty?=?false)?

    4:?view?下面的?html?简介

    这个是最好理解的??例:passwd.htm

    <%+header%>

    <h2><a?id="content"?name="content"><%:system%></a></h2>

    <h3><%:reboot%></h3>

    <p><%:a_s_reboot1%></p>

    <%-

    local?c?=?require("luci.model.uci").cursor():changes()

    if?c?and?next(c)?then

    -%>

    ???????<p?class="warning"><%:a_s_reboot_u%></p>

    end

    if?not?reboot?then

    <p><a?href="<%=controller%>/admin/system/reboot?reboot=1"><%:a_s_reboot_do%></a></p>

    <%-?else?-%>

    <p><%:a_s_reboot_running%></p>

    <script?type="text/javascript">setTimeout("location='<%=controller%>/admin'",?60000)</script>

    <%-?end?-%>

    <%+footer%>


    <%+header%>?<%+footer%>??加载公用的头部和尾部

    <%?lua?code%>

    <%:i18n%>

    <%lua?code%>

    <%=lua?变量?%>

    (编辑:李大同)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

      推荐文章
        热点阅读