一、认识Luci的整体结构

Luci采用的是MVC的Web框架,即Model、View、Controller

/usr/lib/lua/luci/controller/   --控制层 
/usr/lib/lua/luci/view/ 		--视图层
/usr/lib/lua/luci/model/cbi/	--模型层

一、控制层Controller

控制层中的文件语法精简结构如下,主要为两个部分:模块声明和路由定义。

module("luci.controller.admin.network", package.seeall)
function index()
    --定义方式1
    entry({"admin", "network"}, firstchild(), _("Network") , 1)
    --定义方式2
    local page;
    page  = node("admin", "network", "vlan")
    page.target = cbi("admin_network/vlan")
    page.title  = _("Switch")
    page.order  = 20
    
    entry({"admin",'network',"tabs"},firstchild(),"Tabs",30)
    --添加三级菜单
    entry({"admin","network","tabs","tab1"},call("fun"),'Tab1',1)
    entry({"admin","network","tabs","tab4"},template("tab4_tpl"),"Tab4",4)
end
local function fun ()
    --执行fun方法
end

1、模块声明:

文件定义时需要声明其模块名称,按照其路径定义即可,比如该文件位于 /luci/controller/admin/network.lua

module(“luci.controller.admin.network”, package.seeall)

2、路由定义:

上面代码中我们可以看到使用了两种定义路由的方式,一种是直接使用entry方法来定义一个路由,并传入以下4个参数。第二种方式是使用node方法直接定义路由的路径,然后分开指定其他target,title等属性。entry方法内部也是使用node方法,所以两种方式等效。

entry(path, target, title=nil, order=nil)
  • path : 规定了此路由的访问路径,参数是一个字符串数组,比如 {“admin”, “test”, “test_view”} 这样的参数,在页面访问的时候,路径为 /admin/test/test_view ,"test" 是一级菜单。"test_view" 为二级菜单。如果使用node方法直接创建,则需要散列传参,不需要传入table。

  • target :规定访问此路径时,Luci框架执行的调用目标,根据调用目标的不同,LuCI
    也有不同的调度行为。所有的target类型,在源码文件 dispatcher.lua中可以找到。target主要使用的有aliasfirstchildcalltemplatecbiformarcombine

  • title:定义该节点在菜单上显示的名称,非必填项,如果使用了国际化配置,可以使用_(“Router”)这样的表示方式,在中文环境下显示路由,在英文环境下显示Router。如果不填title,则不会在菜单栏上面显示。但是可以通过url进行访问。

  • order:该节点在同级节点下的显示顺序。非必填项,从上至下,从左至右数值越小显示越靠前。 属性

  • target主要有如下种类:

    • firstchild() :自动指向该节点的第一个子节点(order最小的那个节点)
    • call(func_name):调用该文件下的指定函数,比如 call(“test_function”),则会在访问当前路径时,调用该文件下的test_function函数。在这些函数中,我们也可以处理一些数据。
    • template(tpl_name):根据给定的HTM模板名称访问指定的HTML页面,路径对应luci/view下面的文件。比如template(“admin_system/hello”),对应luci/view/admin_system/hello.htm 文件。
    • cbi(model,config):根据给定的model文件名,渲染一个CBI模型。路径对应luci/model/cbi下面的文件。同时可以传入一些config信息,比如 {nofooter:不显示cbi_footer,noheader:不显示cbi_header} 等等。其他用法可以在源码 dispatcher.lua 的 _cbi方法中进行查看。
    • form(model) : 与cbi()类似,不过渲染的是一个表单CBI模型。
    • arcombine(trg1,trg2):当需要访问同一个路由,而这个路由在有参和无参时的调用目标需要不一致的时候,可以使用arcombine把两个target进行组合起来(比如某个列表和其详情页分开时)。当有参数时调用trg2,无参时调用trg1.
    • alias(Path):重定向到另外一个节点上。
-- 访问/admin/test 时, 重定向到 /admin/test/test_view
entry({"admin", "test"}, alias("admin", "test", "test_view"), "重定向", 1)

节点属性:使用变量接收node方法或者entry方法返回的节点后,可以选择添加的属性。

  • i18n :定义了在请求页面时应自动加载哪个翻译文件

  • dependent :保护插件在父节点丢失时从上下文中调用

  • leaf :停止在此节点处解析请求,并且在调度树中不再进一步

  • sysauth :要求用户使用指定的帐户进行身份验证

  • sysauth_authenticator :验证时手动指定验证方法

  • setgroup :设置当前进程的组ID

  • setuser:设置当前进程的用户ID

上面的属性的使用,在dispatcher.lua文件中的dispatch方法中有体现。

二、视图层 View

在controller中提到,target 可以使用 template 可以指定对应的htm文件作为界面显示。同样,在使用cbi,form等方法指定target时,最后也会根据htm文件来渲染界面。具体流程在后续解释。这个htm文件所属范畴就是View中,浏览器界面主要由两种途径产生,使用CBI模型进行生成,或者是自定义htm显示。CBI模型是使用Luci预定义的一些CBI组件来生成常用的表单。如果需要制作一些CBI文件满足不了的页面,可以自己定义htm文件来满足需求。
htm文件中通常由三大部分构成:Lua代码、HTML代码、JavaScript代码。

--lua代码
<%
    local sys = require "luci.sys"
-%>
--JavaScript代码
<script>
    function(){
        console.log('This is JavaScript Code')    
    }
</script>
--HTML代码
<%+header%>
    <h1><%: HelloWorld %></h1>
    <h1><%= sys.hostname() %></h1>
<%+footer%>

语法解释
在htm文件中,可以在HTML代码和JavaScript代码中插入lua代码,使用下面的语法格式标志代码为Lua代码。可以嵌套进行使用。具体实例在后续CBI模型渲染过程的解析中。
1、 包含Lua代码块:

<% code %>
<%- code -%>

2、 输出变量和函数值:

<% write(value) %>
<%=value%>

3、 引用另一个模板:

<% include(templatesName) %>
<%+ templatesName %>

4、 翻译转换:

<%= translate(“Text to translate”) %>
<%:Text to translate%>

5、 注释:

<%# comment %>

三、模型层 Model

controller中提到。target 使用 cbi可以根据给出的文件创建一个CBI模型进行界面渲染。官方的说,CBI模型是Lua文件描述UCI配置文件的结构和由此参生的HTML表单来评估CBI解析器。通俗的说就是CBI模型通常由LuCI预定义的一些CBI控件组成,不同的CBI控件根据其对应的模板生成页面上可见的表单元素。这些控件可以执行大部分的UCI配置的获取或者设置的处理工作。我们也可以覆盖其本来的行为来达到我们满足项目需求的目的。

在我们定义的CBI文件中,与UCI的配置息息相关,UCI配置暂时可以理解为系统的各个应用程序的配置的统一接口。后面再详细介绍UCI。CBI模型文件定义在 /model/cbi/ 目录下

简单介绍一下CBI模型中的语法结构。后面对CBI控件进行详细介绍。以下面的代码为例。

m = Map("sn_file", translate("产品序列号")) 
d = m:section(TypedSection, "gateway_sn",nil,nil) 
a = d:option(Value, "sn", translate("序列号"));
return m
-------------------------------
1、表示生成一个map对象,对/etc/config/sn_file 文件进行映射
2、添加TypedSection 对type为"gateway_sn"的配置进行映射
3、添加一个Value输入框,对"gateway_sn"下的选项"sn"进行映射
    对应的 /etc/config/sn_file 文件的UCI配置为
    config gateway_sn
        option sn "sn"

所有CBI luci.cbi.Map类型的模型文件必须返回一个map对象。

m = Map(config, title,description)
-- 第一个参数,代表 cbi 基于某个配置文件 config 建立Map, 
-- 比如'system'对应配置文件 /etc/config/system
-- 第二个参数, 映射页面的标题,第三个参数, 描述信息

d = m:section(sectionClass,...)
--section是Map实例上的一个方法,作用是
--为map对象添加一个sectionClass类。
--section方法接收的参数只会使用到第一个,剩余的参数
--全部传递给sectionClass类使用。
--常用的sectionClass类有TypedSection NameSection两种
--比如 m:section(TypedSection, type, title, description)
--表示为Map对象增添一个TypedSection类,
-- type, title, description 参数会传递给 TypedSection
-- type 表示对 /etc/config/system 下类型为 type 的配置进行映射。

a = d:option(optionClass,...)
-- option是TypedSection实例的一个方法,作用是
-- 添加一个选项,对TypedSection所定义的某个type下的option进行映射。
-- 第一个参数为optionClass,比如Value、ListValue等等,
-- 同样,传递给option方法的参数都会传递到optionClass中
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值