lua模仿java里面的模板引擎
2014-11-24 15:10
363 查看
由于需求的变更,以前使用的都是java的模板引擎,现在api都采用lua来开发,所以以前的那套只能重新写了,在网上找了很久类似的例子,总算到找了一个比较不错的类似模板引擎,lua-resty-template 。
原程序的地址如下:
https://github.com/bungle/lua-resty-template
我的需求如下:
1、前端提供多种(4种)不同版式的专题页面
2、每次访问的时候专题页版式要随机选取
3、方便前端人员配置
前端会不定期的做一些专题;相关信息数据来源其实固定不变,(当然这只是相对时间,可能过一些时间会取自不同的专题数据,所以这里还是要比较灵活)
我的思路大概如下。
1、将所需要的专题数据存入redis里面,定期刷新redis.确保有新数据录入的时候能及时获取(我这里大概是30分钟更新一次)
2、获数据的时候先从redis里面取,如果没有就查一次表。确定redis出现问题时也能及时的获取数据。
3、用lua生静态模板并将数据写入到页面当。
4、测试上线。
相关的代码如下:
fileUtils.lua
-----------------------------------------------
module(...,package.seeall)
--读文件
function readFile(filepath)
local path = filepath[1]
--ngx.say(filepath)
local f = assert(io.open(path,'r'))
local str = f:read("*a")
f:close()
return str
end
--写文件
function writeFile(srcFilePath,contentStr )
local f = assert(io.open(srcFilePath,'w'))
f:write(contentStr)
f:close()
end
--------------------------------
dataUtil.lua
--------------------------------
module(..., package.seeall)
--联连redis
function getRedis()
local redis = (require "resty.redis"):new()
redis:set_timeout(10000)
redis:set_keepalive(10000, 3000)
if not redis:connect("127.0.0.1", 6379) then
ngx.log(ngx.ERR, "failed to connect to redis")
return false, nil
end
return true,redis
end
--关闭redis
function closeRedis(red)
local ok, err = red:close()
if not ok then
ngx.say("failed to close: ", err)
return
end
end
--打开mysql连接
function getMySQL()
-- if not ngx.ctx.my_sql then
local mysql = require "resty.mysql"
local db, err = mysql:new()
if not db then
ngx.log(ngx.ERR, "failed to instantiate mysql: ", err)
return false, nil
end
db:set_timeout(60000) -- 1 sec
local ok, err = db:set_keepalive(10000, 3000)
local ok, err, errno, sqlstate = db:connect{
host = "127.0.0.1",
port = 3306,
database = "TestTaginfo",
user = "root",
password = "root",
max_packet_size = 1024 * 1024 }
if not ok then
ngx.log(ngx.ERR, "failed to connect: ", err, ": ", errno, " ", sqlstate)
return false, nil
end
return true, db
end
--关闭连接
function closeDB(db)
local ok, err = db:close()
if not ok then
ngx.say("failed to close: ", err)
return
end
end
-----------------------------------------------
template.lua
-------------------------------------------------
local setmetatable = setmetatable
local tostring = tostring
local setfenv = setfenv
local concat = table.concat
local assert = assert
local open = io.open
local load = load
local type = type
local HTML_ENTITIES = {
["&"] = "&",
["<"] = "<",
[">"] = ">",
['"'] = """,
["'"] = "'",
["/"] = "/"
}
local CODE_ENTITIES = {
["{"] = "{",
["}"] = "}"
}
local caching, ngx_var, ngx_capture, ngx_null = true
local template = { _VERSION = "1.3", cache = {}, concat = concat }
local function read_file(path)
local file = open(path, "rb")
if not file then return nil end
local content = file:read("*a")
file:close()
return content
end
local function load_lua(path)
return read_file(path) or path
end
local function load_ngx(path)
local file, location = path, ngx_var.template_location
if file:sub(1) == "/" then file = file:sub(2) end
if location and location ~= "" then
if location:sub(-1) == "/" then location = location:sub(1, -2) end
local res = ngx_capture(location .. '/' .. file)
if res.status == 200 then return res.body end
end
local root = ngx_var.template_root or ngx_var.document_root
if root:sub(-1) == "/" then root = root:sub(1, -2) end
return read_file(root .. "/" .. file) or path
end
if ngx then
template.print = ngx.print or print
template.load = load_ngx
ngx_var, ngx_capture, ngx_null = ngx.var, ngx.location.capture, ngx.null
else
template.print = print
template.load = load_lua
end
local load_chunk
if _VERSION == "Lua 5.1" then
local context = { __index = function(t, k)
return t.context[k] or t.template[k] or _G[k]
end }
if jit then
load_chunk = function(view)
return assert(load(view, nil, "tb", setmetatable({ template = template }, context)))
end
else
load_chunk = function(view)
local func = assert(loadstring(view))
setfenv(func, setmetatable({ template = template }, context))
return func
end
end
else
local context = { __index = function(t, k)
return t.context[k] or t.template[k] or _ENV[k]
end }
load_chunk = function(view)
return assert(load(view, nil, "tb", setmetatable({ template = template }, context)))
end
end
function template.caching(enable)
if enable ~= nil then caching = enable == true end
return caching
end
function template.output(s)
if s == nil or s == ngx_null then return "" end
if type(s) == "function" then return template.output(s()) end
return tostring(s)
end
function template.escape(s, c)
if type(s) == "string" then
if c then s = s:gsub("[}{]", CODE_ENTITIES) end
return s:gsub("[\">/<'&]", HTML_ENTITIES)
end
return template.output(s)
end
function template.new(view, layout)
assert(view, "view was not provided for template.new(view, layout).")
local render, compile = template.render, template.compile
if layout then
return setmetatable({ render = function(self, context)
local context = context or self
context.view = compile(view)(context)
render(layout, context)
end }, { __tostring = function(self)
local co
4000
ntext = context or self
context.view = compile(view)(context)
return compile(layout)(context)
end })
end
return setmetatable({ render = function(self, context)
render(view, context or self)
end }, { __tostring = function(self)
return compile(view)(context or self)
end })
end
function template.precompile(view, path, strip)
local chunk = string.dump(template.compile(view), strip ~= false)
if path then
local file = io.open(path, "wb")
file:write(chunk)
file:close()
end
return chunk
end
function template.compile(view, key, plain)
assert(view, "view was not provided for template.compile(view, key, plain).")
if key == "no-cache" then
return load_chunk(template.parse(view, plain)), false
end
key = key or view
local cache = template.cache
if cache[key] then return cache[key], true end
local func = load_chunk(template.parse(view, plain))
if caching then cache[key] = func end
return func, false
end
function template.parse(view, plain)
assert(view, "view was not provided for template.parse(view, plain).")
if not plain then
view = template.load(view)
if view:sub(1, 1):byte() == 27 then return view end
end
local c = {
"context=... or {}",
"local ___,blocks,layout={},blocks or {}"
}
local i, j, s, e = 0, 0, view:find("{", 1, true)
while s do
local t = view:sub(s, e + 1)
if t == "{{" then
local x, y = view:find("}}", e + 2, true)
if x then
if j ~= s then c[#c+1] = "___[#___+1]=[=[" .. view:sub(j, s - 1) .. "]=]" end
c[#c+1] = "___[#___+1]=template.escape(" .. view:sub(e + 2, x - 1) .. ")"
i, j = y, y + 1
end
elseif t == "{*" then
local x, y = view:find("*}", e + 2, true)
if x then
if j ~= s then c[#c+1] = "___[#___+1]=[=[" .. view:sub(j, s - 1) .. "]=]" end
c[#c+1] = "___[#___+1]=template.output(" .. view:sub(e + 2, x - 1) .. ")"
i, j = y, y + 1
end
elseif t == "{%" then
local x, y = view:find("%}", e + 2, true)
if x then
if j ~= s then c[#c+1] = "___[#___+1]=[=[" .. view:sub(j, s - 1) .. "]=]" end
c[#c+1] = view:sub(e + 2, x - 1)
if view:sub(y + 1, y + 1) == "\n" then
i, j = y + 1, y + 2
else
i, j = y, y + 1
end
end
elseif t == "{(" then
local x, y = view:find(")}", e + 2, true)
if x then
if j ~= s then c[#c+1] = "___[#___+1]=[=[" .. view:sub(j, s - 1) .. "]=]" end
local file = view:sub(e + 2, x - 1)
local a, b = file:find(',', 2, true)
if a then
c[#c+1] = '___[#___+1]=template.compile([=[' .. file:sub(1, a - 1) .. ']=])(' .. file:sub(b + 1) .. ')'
else
c[#c+1] = '___[#___+1]=template.compile([=[' .. file .. ']=])(context)'
end
i, j = y, y + 1
end
elseif t == "{-" then
local x, y = view:find("-}", e + 2, true)
if x then
local a, b = view:find(view:sub(e, y), y, true)
if a then
if j ~= s then c[#c+1] = "___[#___+1]=[=[" .. view:sub(j, s - 1) .. "]=]" end
c[#c+1] = 'blocks["' .. view:sub(e + 2, x - 1) .. '"]=template.compile([=[' .. view:sub(y + 1, a - 1) .. ']=], "no-cache", true)(context)'
i, j = b, b + 1
end
end
elseif t == "{#" then
local x, y = view:find("#}", e + 2, true)
if x then
if j ~= s then c[#c+1] = "___[#___+1]=[=[" .. view:sub(j, s - 1) .. "]=]" end
i, j = y, y + 1
end
end
i = i + 1
s, e = view:find("{", i, true)
end
c[#c+1] = "___[#___+1]=[=[" .. view:sub(j) .. "]=]"
c[#c+1] = "return layout and template.compile(layout)(setmetatable({view=template.concat(___),blocks=blocks},{__index=context})) or template.concat(___)"
return concat(c, "\n")
end
function template.render(view, context, key, plain)
assert(view, "view was not provided for template.render(view, context, key, plain).")
return template.print(template.compile(view, key, plain)(context))
end
return template
---------------------------
test-temp.lua
---------------------------
local template = require "resty.template"
local file = require("fileUtils")
local re = require("dataUtil")
local math = require("math")
local cjson = require "cjson"
local path1 = "/data/template/view.html"
local path2 = "/data/template/view_2.html"
local path3 = "/data/template/view_3.html"
local path4 = "/data/template/view_4.html"
local x = {}
local paths = {}
table.insert(x,path1)
table.insert(x,path2)
table.insert(x,path3)
table.insert(x,path4)
ngx.say("rnd=" ..math.random(1,table.getn(x)))
local srcpath = x[math.random(1,table.getn(x))]
table.insert(paths,srcpath)
local str = file.readFile(paths)
-- Using template.new
local view = template.new(str)
view.names = { "James", "Jack", "Anne" }
view.message = "Hello, World!"
local flag,db = re:getMySQL()
local res, err, errno, sqlstate =
db:query("SELECT `Name`,TagDesc,BigPics,Rank FROM Tag WHERE Id = 1")
if not res then
ngx.say("bad result: ", err, ": ", errno, ": ", sqlstate, ".")
return
end
--[[]]--
--查询专题应用数据
local hql = "SELECT p.Id,p. NAME,p.LogoUrl,p.Version,p.Catalog,p.SubCatalog FROM Tag m INNER JOIN App p ON m.AppId = p.Id WHERE m.TagId = 1"
local contion = " ORDER BY m.Rank DESC"
local sqls = hql ..contion
--ngx.say(sqls)
local rest, errt, errnot, sqlstatet = db:query(sqls)
if not rest then
ngx.say("bad result: ", errt, ": ", errnot, ": ", sqlstatet, ".")
return
end
view.app = rest
view.tag = res
view:render()
re.closeDB(db);
ngx.say("hello kity~~~")
--[[
--另一种页面传参方式
local x = template.render(str, {params = res,message = "Hello, World!",names = {"James", "Jack", "Anne" }})
ngx.say(x)
]]--
静态页面大概是:
<h1>{{message}}</h1>
<hr/>
<br/>
<ul>
{% for _, name in ipairs(names) do %}
<li>{{name}}</li>
{% end %}
</ul>
<hr/>
<ul>
{% for k, v in ipairs(tag) do %}
<li>{{v.NAME}}</li>
<li>{{v.TagDesc}}</li>
<li>{{v.Rank}}</li>
<li>{{v.BigPics}}</li>
{% end %}
</ul>
================================
<br/>
应用
------
{% if not app==nil then %} {% end %}
<table>
{% for k, v in pairs(app) do %}
<tr>
<td>{{v.Id}}</td>
<td>{{v.NAME}}</td>
<td>{{v.LogoUrl}}</td>
<td>{{v.Version}}</td>
<td>{{v.Catalog}}</td>
</tr>
{% end %}
</table>
</body>
</html>
写到这里基本就完成了,这里大家需要注意一点的是lua在不文件之间调用方法的时候,传入的参数要是table类型的,不像我们的java那样直接传String,int类型这样,不然会提示错误 nil值。这里需要注意一下。
原程序的地址如下:
https://github.com/bungle/lua-resty-template
我的需求如下:
1、前端提供多种(4种)不同版式的专题页面
2、每次访问的时候专题页版式要随机选取
3、方便前端人员配置
前端会不定期的做一些专题;相关信息数据来源其实固定不变,(当然这只是相对时间,可能过一些时间会取自不同的专题数据,所以这里还是要比较灵活)
我的思路大概如下。
1、将所需要的专题数据存入redis里面,定期刷新redis.确保有新数据录入的时候能及时获取(我这里大概是30分钟更新一次)
2、获数据的时候先从redis里面取,如果没有就查一次表。确定redis出现问题时也能及时的获取数据。
3、用lua生静态模板并将数据写入到页面当。
4、测试上线。
相关的代码如下:
fileUtils.lua
-----------------------------------------------
module(...,package.seeall)
--读文件
function readFile(filepath)
local path = filepath[1]
--ngx.say(filepath)
local f = assert(io.open(path,'r'))
local str = f:read("*a")
f:close()
return str
end
--写文件
function writeFile(srcFilePath,contentStr )
local f = assert(io.open(srcFilePath,'w'))
f:write(contentStr)
f:close()
end
--------------------------------
dataUtil.lua
--------------------------------
module(..., package.seeall)
--联连redis
function getRedis()
local redis = (require "resty.redis"):new()
redis:set_timeout(10000)
redis:set_keepalive(10000, 3000)
if not redis:connect("127.0.0.1", 6379) then
ngx.log(ngx.ERR, "failed to connect to redis")
return false, nil
end
return true,redis
end
--关闭redis
function closeRedis(red)
local ok, err = red:close()
if not ok then
ngx.say("failed to close: ", err)
return
end
end
--打开mysql连接
function getMySQL()
-- if not ngx.ctx.my_sql then
local mysql = require "resty.mysql"
local db, err = mysql:new()
if not db then
ngx.log(ngx.ERR, "failed to instantiate mysql: ", err)
return false, nil
end
db:set_timeout(60000) -- 1 sec
local ok, err = db:set_keepalive(10000, 3000)
local ok, err, errno, sqlstate = db:connect{
host = "127.0.0.1",
port = 3306,
database = "TestTaginfo",
user = "root",
password = "root",
max_packet_size = 1024 * 1024 }
if not ok then
ngx.log(ngx.ERR, "failed to connect: ", err, ": ", errno, " ", sqlstate)
return false, nil
end
return true, db
end
--关闭连接
function closeDB(db)
local ok, err = db:close()
if not ok then
ngx.say("failed to close: ", err)
return
end
end
-----------------------------------------------
template.lua
-------------------------------------------------
local setmetatable = setmetatable
local tostring = tostring
local setfenv = setfenv
local concat = table.concat
local assert = assert
local open = io.open
local load = load
local type = type
local HTML_ENTITIES = {
["&"] = "&",
["<"] = "<",
[">"] = ">",
['"'] = """,
["'"] = "'",
["/"] = "/"
}
local CODE_ENTITIES = {
["{"] = "{",
["}"] = "}"
}
local caching, ngx_var, ngx_capture, ngx_null = true
local template = { _VERSION = "1.3", cache = {}, concat = concat }
local function read_file(path)
local file = open(path, "rb")
if not file then return nil end
local content = file:read("*a")
file:close()
return content
end
local function load_lua(path)
return read_file(path) or path
end
local function load_ngx(path)
local file, location = path, ngx_var.template_location
if file:sub(1) == "/" then file = file:sub(2) end
if location and location ~= "" then
if location:sub(-1) == "/" then location = location:sub(1, -2) end
local res = ngx_capture(location .. '/' .. file)
if res.status == 200 then return res.body end
end
local root = ngx_var.template_root or ngx_var.document_root
if root:sub(-1) == "/" then root = root:sub(1, -2) end
return read_file(root .. "/" .. file) or path
end
if ngx then
template.print = ngx.print or print
template.load = load_ngx
ngx_var, ngx_capture, ngx_null = ngx.var, ngx.location.capture, ngx.null
else
template.print = print
template.load = load_lua
end
local load_chunk
if _VERSION == "Lua 5.1" then
local context = { __index = function(t, k)
return t.context[k] or t.template[k] or _G[k]
end }
if jit then
load_chunk = function(view)
return assert(load(view, nil, "tb", setmetatable({ template = template }, context)))
end
else
load_chunk = function(view)
local func = assert(loadstring(view))
setfenv(func, setmetatable({ template = template }, context))
return func
end
end
else
local context = { __index = function(t, k)
return t.context[k] or t.template[k] or _ENV[k]
end }
load_chunk = function(view)
return assert(load(view, nil, "tb", setmetatable({ template = template }, context)))
end
end
function template.caching(enable)
if enable ~= nil then caching = enable == true end
return caching
end
function template.output(s)
if s == nil or s == ngx_null then return "" end
if type(s) == "function" then return template.output(s()) end
return tostring(s)
end
function template.escape(s, c)
if type(s) == "string" then
if c then s = s:gsub("[}{]", CODE_ENTITIES) end
return s:gsub("[\">/<'&]", HTML_ENTITIES)
end
return template.output(s)
end
function template.new(view, layout)
assert(view, "view was not provided for template.new(view, layout).")
local render, compile = template.render, template.compile
if layout then
return setmetatable({ render = function(self, context)
local context = context or self
context.view = compile(view)(context)
render(layout, context)
end }, { __tostring = function(self)
local co
4000
ntext = context or self
context.view = compile(view)(context)
return compile(layout)(context)
end })
end
return setmetatable({ render = function(self, context)
render(view, context or self)
end }, { __tostring = function(self)
return compile(view)(context or self)
end })
end
function template.precompile(view, path, strip)
local chunk = string.dump(template.compile(view), strip ~= false)
if path then
local file = io.open(path, "wb")
file:write(chunk)
file:close()
end
return chunk
end
function template.compile(view, key, plain)
assert(view, "view was not provided for template.compile(view, key, plain).")
if key == "no-cache" then
return load_chunk(template.parse(view, plain)), false
end
key = key or view
local cache = template.cache
if cache[key] then return cache[key], true end
local func = load_chunk(template.parse(view, plain))
if caching then cache[key] = func end
return func, false
end
function template.parse(view, plain)
assert(view, "view was not provided for template.parse(view, plain).")
if not plain then
view = template.load(view)
if view:sub(1, 1):byte() == 27 then return view end
end
local c = {
"context=... or {}",
"local ___,blocks,layout={},blocks or {}"
}
local i, j, s, e = 0, 0, view:find("{", 1, true)
while s do
local t = view:sub(s, e + 1)
if t == "{{" then
local x, y = view:find("}}", e + 2, true)
if x then
if j ~= s then c[#c+1] = "___[#___+1]=[=[" .. view:sub(j, s - 1) .. "]=]" end
c[#c+1] = "___[#___+1]=template.escape(" .. view:sub(e + 2, x - 1) .. ")"
i, j = y, y + 1
end
elseif t == "{*" then
local x, y = view:find("*}", e + 2, true)
if x then
if j ~= s then c[#c+1] = "___[#___+1]=[=[" .. view:sub(j, s - 1) .. "]=]" end
c[#c+1] = "___[#___+1]=template.output(" .. view:sub(e + 2, x - 1) .. ")"
i, j = y, y + 1
end
elseif t == "{%" then
local x, y = view:find("%}", e + 2, true)
if x then
if j ~= s then c[#c+1] = "___[#___+1]=[=[" .. view:sub(j, s - 1) .. "]=]" end
c[#c+1] = view:sub(e + 2, x - 1)
if view:sub(y + 1, y + 1) == "\n" then
i, j = y + 1, y + 2
else
i, j = y, y + 1
end
end
elseif t == "{(" then
local x, y = view:find(")}", e + 2, true)
if x then
if j ~= s then c[#c+1] = "___[#___+1]=[=[" .. view:sub(j, s - 1) .. "]=]" end
local file = view:sub(e + 2, x - 1)
local a, b = file:find(',', 2, true)
if a then
c[#c+1] = '___[#___+1]=template.compile([=[' .. file:sub(1, a - 1) .. ']=])(' .. file:sub(b + 1) .. ')'
else
c[#c+1] = '___[#___+1]=template.compile([=[' .. file .. ']=])(context)'
end
i, j = y, y + 1
end
elseif t == "{-" then
local x, y = view:find("-}", e + 2, true)
if x then
local a, b = view:find(view:sub(e, y), y, true)
if a then
if j ~= s then c[#c+1] = "___[#___+1]=[=[" .. view:sub(j, s - 1) .. "]=]" end
c[#c+1] = 'blocks["' .. view:sub(e + 2, x - 1) .. '"]=template.compile([=[' .. view:sub(y + 1, a - 1) .. ']=], "no-cache", true)(context)'
i, j = b, b + 1
end
end
elseif t == "{#" then
local x, y = view:find("#}", e + 2, true)
if x then
if j ~= s then c[#c+1] = "___[#___+1]=[=[" .. view:sub(j, s - 1) .. "]=]" end
i, j = y, y + 1
end
end
i = i + 1
s, e = view:find("{", i, true)
end
c[#c+1] = "___[#___+1]=[=[" .. view:sub(j) .. "]=]"
c[#c+1] = "return layout and template.compile(layout)(setmetatable({view=template.concat(___),blocks=blocks},{__index=context})) or template.concat(___)"
return concat(c, "\n")
end
function template.render(view, context, key, plain)
assert(view, "view was not provided for template.render(view, context, key, plain).")
return template.print(template.compile(view, key, plain)(context))
end
return template
---------------------------
test-temp.lua
---------------------------
local template = require "resty.template"
local file = require("fileUtils")
local re = require("dataUtil")
local math = require("math")
local cjson = require "cjson"
local path1 = "/data/template/view.html"
local path2 = "/data/template/view_2.html"
local path3 = "/data/template/view_3.html"
local path4 = "/data/template/view_4.html"
local x = {}
local paths = {}
table.insert(x,path1)
table.insert(x,path2)
table.insert(x,path3)
table.insert(x,path4)
ngx.say("rnd=" ..math.random(1,table.getn(x)))
local srcpath = x[math.random(1,table.getn(x))]
table.insert(paths,srcpath)
local str = file.readFile(paths)
-- Using template.new
local view = template.new(str)
view.names = { "James", "Jack", "Anne" }
view.message = "Hello, World!"
local flag,db = re:getMySQL()
local res, err, errno, sqlstate =
db:query("SELECT `Name`,TagDesc,BigPics,Rank FROM Tag WHERE Id = 1")
if not res then
ngx.say("bad result: ", err, ": ", errno, ": ", sqlstate, ".")
return
end
--[[]]--
--查询专题应用数据
local hql = "SELECT p.Id,p. NAME,p.LogoUrl,p.Version,p.Catalog,p.SubCatalog FROM Tag m INNER JOIN App p ON m.AppId = p.Id WHERE m.TagId = 1"
local contion = " ORDER BY m.Rank DESC"
local sqls = hql ..contion
--ngx.say(sqls)
local rest, errt, errnot, sqlstatet = db:query(sqls)
if not rest then
ngx.say("bad result: ", errt, ": ", errnot, ": ", sqlstatet, ".")
return
end
view.app = rest
view.tag = res
view:render()
re.closeDB(db);
ngx.say("hello kity~~~")
--[[
--另一种页面传参方式
local x = template.render(str, {params = res,message = "Hello, World!",names = {"James", "Jack", "Anne" }})
ngx.say(x)
]]--
静态页面大概是:
<h1>{{message}}</h1>
<hr/>
<br/>
<ul>
{% for _, name in ipairs(names) do %}
<li>{{name}}</li>
{% end %}
</ul>
<hr/>
<ul>
{% for k, v in ipairs(tag) do %}
<li>{{v.NAME}}</li>
<li>{{v.TagDesc}}</li>
<li>{{v.Rank}}</li>
<li>{{v.BigPics}}</li>
{% end %}
</ul>
================================
<br/>
应用
------
{% if not app==nil then %} {% end %}
<table>
{% for k, v in pairs(app) do %}
<tr>
<td>{{v.Id}}</td>
<td>{{v.NAME}}</td>
<td>{{v.LogoUrl}}</td>
<td>{{v.Version}}</td>
<td>{{v.Catalog}}</td>
</tr>
{% end %}
</table>
</body>
</html>
写到这里基本就完成了,这里大家需要注意一点的是lua在不文件之间调用方法的时候,传入的参数要是table类型的,不像我们的java那样直接传String,int类型这样,不然会提示错误 nil值。这里需要注意一下。
相关文章推荐
- Java的模板引擎Velocity初体验
- Java语言介绍(04)开源项目(04)模板引擎(01)Velocity
- 初识Java模板引擎Beetl之简单示例
- 一种基于java语言的模板引擎velocity的使用
- 新一代Java模板引擎 jetbrick-template 1.1.2 发布
- Java的模板引擎Velocity初体验 (1)-2
- Java模板引擎 FreeMarker
- Beetl 1.25 发布,java模板引擎
- 在winform里面如何使用razor模板引擎?
- Java 模板引擎 jetbrick-template
- Java的模板引擎Velocity初体验-Java基础-Java-编程开发
- Thymeleaf:面向Java的XML/HTML模板引擎
- NVelocity是Java模板引擎Velocity的.Net版本
- Java模板引擎 FreeMarker
- Java模板引擎 FreeMarker介绍
- Java模板引擎Velocity 2007年3月底
- Java模板引擎 FreeMarker
- 开源 Java 模板引擎 HTTL 1.0.0 发布
- Java模板引擎 FreeMarker
- JAVA velocity模板引擎使用实例