lua模仿java里面的模板引擎

2 篇文章 0 订阅
1 篇文章 0 订阅

由于需求的变更,以前使用的都是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 = {
    ["&"] = "&",
    ["<"] = "&lt;",
    [">"] = "&gt;",
    ['"'] = "&quot;",
    ["'"] = "&#39;",
    ["/"] = "&#47;"
}


local CODE_ENTITIES = {
    ["{"] = "&#123;",
    ["}"] = "&#125;"
}


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 context = 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值。这里需要注意一下。



















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值