一:luci 的启动

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

#!/usr/bin/lua      --cgi的执行命令的路径

require"luci.cacheloader"    --导入cacheloader包

require"luci.sgi.cgi"         --导入sgi.cgi包

luci.dispatcher.indexcache = "/tmp/luci-indexcache"   --cache缓存路径地址

luci.sgi.cgi.run()  --执行run方法,此方法位于*/luci/sgi/cgi.lua中

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

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

-bash-4.0# pwd

/var/www/cgi-bin

-bash-4.0# ./luci

Status: 200 OK

Content-Type: text/html;

charset=utf-8

Cache-Control: no-cache

Expires: 0

HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"

"http://www.w3.org/TR/html4/strict.dtd">

二: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 文件,简略的代码如下:

module("luci.controller.mini.index", package.seeall)

17

18  function index()

19      luci.i18n.loadc("admin-core")

20      local i18n = luci.i18n.translate

21

22      local root = node()

23      if not root.lock then

24          root.target = alias("mini")

25          root.index = true

26      end

27

28      entry({"about"}, template("about")).i18n = "admin-core"

29

30      local page   = entry({"mini"}, alias("mini", "index"), i18n("essentials", "Essentials"), 10)

31      page.i18n    = "admin-core"

32      page.sysauth = "root"

33      page.sysauth_authenticator = "htmlauth"

34      page.index = true

35

36      entry({"mini", "index"}, alias("mini", "index", "index"), i18n("overview"), 10).index = true

37      entry({"mini", "index", "index"}, form("mini/index"), i18n("general"), 1).ignoreindex = true

38      entry({"mini", "index", "luci"}, cbi("mini/luci", {autoapply=true}), i18n("settings"), 10)

39      entry({"mini", "index", "logout"}, call("action_logout"), i18n("logout"))

40  end

41

42  function action_logout()

43      luci.http.header("Set-Cookie", "sysauth=; path=/")

44      luci.http.redirect(luci.dispatcher.build_url())

45  end

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

例如 system.lua 文件

function index()

19      luci.i18n.loadc("admin-core")

20      local i18n = luci.i18n.translate

21

22      entry({"mini", "system"}, alias("mini", "system", "index"), i18n("system"), 40).index = true

23      entry({"mini", "system", "index"}, cbi("mini/system", {autoapply=true}), i18n("general"), 1)

24      entry({"mini", "system", "passwd"}, form("mini/passwd"), i18n("a_s_changepw"), 10)

25      entry({"mini", "system", "backup"}, call("action_backup"), i18n("a_s_backup"), 80)

26      entry({"mini", "system", "upgrade"}, call("action_upgrade"), i18n("a_s_flash"), 90)

27      entry({"mini", "system", "reboot"}, call("action_reboot"), i18n("reboot"), 100)

28  end

mudel是对应文件的, function index 定义了菜单,比如这一句entry({"mini", "system", "reboot"}, call("action_reboot"), i18n("reboot"), 100)

第1 项为菜单入口:

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

entry({"mini", "system", "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 语句)。

问价查找对应简介:

entry({"mini", "system", "reboot"}, call("action_reboot"), i18n("reboot"), 100)  :对应此文件的action_reboot function

entry({"mini", "system", "index"}, cbi("mini/system", {autoapply=true}), i18n("general"), 1):对应*/model/cbi/mini/system.lua  {autoapply=true}   这个失传的参数。

。。。。。

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

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

现在说一下这些文件的解析是怎么解析的呢?你当然是说dispatch.lua中,你说对了,但是真正解析成菜单的递归算法确实在header.htm中 位置:*/view/themes/openwrt/

代码如下:

require("luci.sys")

local load1, load5, load15 = luci.sys.loadavg()

local request  = require("luci.dispatcher").context.path

local category = request[1]

local tree     = luci.dispatcher.node()

local cattree  = category and luci.dispatcher.node(category)

local node     = luci.dispatcher.context.dispatched

local hostname = luci.sys.hostname()

local c = tree

for i,r in ipairs(request) do

if c.nodes and c.nodes[r] then

c = c.nodes[r]

c._menu_selected = true

end

end

require("luci.i18n").loadc("default")

require("luci.http").prepare_content("application/xhtml+xml")

-%>

html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

" lang="">

/cascade.css" />

/" />

- LuCI

:

:

local function submenu(prefix, node)

if not node.nodes or node.hidden then

return false

end

local index = {}

local count = 0

for k, n in pairs(node.nodes) do

if n.title and n.target then

table.insert(index, {name=k, order=n.order or 100})

count = count + 1

end

end

table.sort(index, function(a, b) return a.order

if count > 0 then

%>

  • ">

for j, v in pairs(index) do

if #v.name > 0 then

local nnode = node.nodes[v.name]

local href = controller .. prefix .. v.name .. "/"

href = (nnode.query) and href .. luci.http.build_querystring(nnode.query) or href

if nnode.nodes then

for k1, n1 in pairs(nnode.nodes) do

href = "#"

end

end

%>

class="active" href="">

submenu(prefix .. v.name .. "/", nnode)

%>

end

end

%>

end

end

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", column2 = "xxx", .... },

row3 = {column1 = "xxx", column2 = "xxx", .... },

row4 = {column1 = "xxx", column2 = "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", "system", "version_manage", "upload"))

95 end

ps:只有当 Value 的 rmempty == false 时, Value 输入为空也会触发 write 函数 ,  需要对 rmemtpy 显示赋值为false ( xx.rmempty = false)

4: view 下面的 html 简介

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

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

if c and next(c) then

-%>

end

if not reboot then

-%>

/admin/system/reboot?reboot=1">

加载公用的头部和尾部

luci网页shell_Luci框架-LUA的一个web框架使用相关推荐

  1. luci框架-LUA的一个web框架使用

    转自:http://blog.csdn.net/initphp/article/details/17527639 LUCI 这个在百度上搜索除了一篇我的百度文库 luci 的介绍文章之外,前三页都是些 ...

  2. asp.net web开发框架_用Python开发一个Web框架

    一.Web框架 首先我们今天要做的事是开发一个Web框架.可能听到这你就会想.是不是很难啊?这东西自己能写出来? 如果你有这种疑惑的话,那就继续看下去吧.相信看完今天的内容你也能写出一个自己的Web框 ...

  3. 如何从零开始写一个 web 框架?

    ‍ 作为一线开发 Web 服务的工程师,我用过不少语言的不少框架,尤其近几年轮子层出不穷,每次刚用熟练一个,就有更新.更好的出现了.日常疲于奔命学习新框架,一次次陷入"死循环". ...

  4. 2、基于wsgiref模块DIY一个web框架

    一 web框架 Web框架(Web framework)是一种开发框架,用来支持动态网站.网络应用和网络服务的开发.这大多数的web框架提供了一套开发和部署网站的方式,也为web行为提供了一套通用的方 ...

  5. Spring - Java/J2EE Application Framework 应用框架 第 12 章 Web框架

    第 12 章 Web框架 12.1. Web框架介绍 Spring的web框架是围绕分发器(DispatcherServlet)设计的,DispatcherServlet将请求分发到不同的处理器,框架 ...

  6. html5 网页便利贴,HTML5 – 创建一个Web网页便利贴

    当你在看我前面所写的HTML 5例子时,我正在思考创建一个简单但又适用的例子.以一种更新奇的方式来演练这些HTML5新特性.我的目标并不是想单纯的展示这些HTML 5 API,而是想用例子来告诉开发人 ...

  7. python数据处理框架_python 最快 web 框架 Sanci 快速入门

    简介 Sanic 是一个和类Flask 的基于Python3.5+的web框架,它编写的代码速度特别快. 除了像Flask 以外,Sanic 还支持以异步请求的方式处理请求.这意味着你可以使用新的 a ...

  8. python有哪些web框架_python五大主流web框架

    Django Python框架虽然说是百花齐放,但仍然有那么一家是最大的,它就是Django.要说Django是Python框架里最好的,有人同意也有人 坚决反对,但说Django的文档最完善.市场占 ...

  9. python十大框架_python 十大web框架排名总结

    0 引言 python在web开发方面有着广泛的应用.鉴于各种各样的框架,对于开发者来说如何选择将成为一个问题.为此,我特此对比较常见的几种框架从性能.使用感受以及应用情况进行一个粗略的分析. 1 D ...

  10. 使用Yii 1.1框架搭建第一个web应用程序

    我已经安装好了WampServer,web项目根目录是 D:\wamp\www. 1.下载Yii 1.1的源码 yii-1.1.14.f0fee9.tar.gz: 2.解压源码包,放在web项目的根目 ...

最新文章

  1. 文件系统与NoSQL分布式存储技术对比
  2. iOS开发系列--并行开发其实很容易
  3. ubuntu9.10升级成功
  4. Apache CXF 3.0:CDI 1.1支持替代Spring
  5. java高端架构_Java高端架构师
  6. 如何从SQL Server中的SELECT更新?
  7. 动态绑定dropdownlist --开始拣.NET
  8. 收集了一些容易出错的题,可能大家也不会注意到的基础知识(js)
  9. 如何在Mac上创建和移除替身
  10. [设计模式] 15 解释器模式 Interpreter
  11. 蓝桥杯题目常用API (JAVA)
  12. TBSchedule调度平台疑难解答
  13. 初学Spring Cloud踩得坑之Caused by: org.springframework.context.ApplicationContextException
  14. 计算机应用软件弹窗消除,去除电脑弹窗广告的4种方法
  15. deepin efi 启动u盘_用Deepin Linux ISO镜像启动或U盘引导只显示一个光标的解决
  16. 扩展欧几里得算法、乘法逆元与中国剩余定理
  17. 报错:“export ‘default‘ (imported as ‘mui)‘ was not fount in ‘../lib/mui/js/mui-min.js‘
  18. 开机、重启和用户登录注销
  19. FFmpeg+SDL视频播放器
  20. Android天气开源项目之添加城市

热门文章

  1. 东子破解jms7月2号
  2. Dell R730xd 安装显卡后风扇转速高 解决方法
  3. java 单体测试_单体测试指南
  4. 数据中心常说的IDC,EDC,ODC,DC分别指什么类型机房?
  5. dns服务器地址为空,dns服务器地址为空
  6. 笔记本未指定打印机服务器,打印机未指定怎么办_win10打印机未指定设备的解决方法...
  7. 笔记本怎么自己装系统?u盘装系统windows7教程图解
  8. HTTPS之SNI介绍与Nginx多域名支持
  9. java+poodle漏洞修复_如何修复 POODLE SSLv3 安全漏洞 (CVE-2014-3566)
  10. c# 中文转换为拼音或者拼音首字母