lua MVC框架 Orbit初探

时间:2023-03-10 04:48:43
lua MVC框架 Orbit初探

介绍

http://keplerproject.github.io/orbit/

Orbit是lua语言版本的MVC框架。

此框架完全抛弃CGILUA的脚本模型, 支持的应用, 每个应用可以卸载一个单独的文件中,当然你也可以将它拆为一个文件, 当你需要时候。

此框架运行在WSAPI协议的服务器上,所以可以工作在 Xavante和一些CGI和fastcgi程序上。

Orbit is an MVC web framework for Lua. The design is inspired by lightweight Ruby frameworks such as Camping. It completely abandons the CGILua model of "scripts" in favor of applications, where each Orbit application can fit in a single file, but you can split it into multiple files if you want. All Orbit applications follow the WSAPI protocol, so they currently work with Xavante, CGI and Fastcgi. It includes a launcher that makes it easy to launch a Xavante instance for development.

安装运行

http://keplerproject.github.io/orbit/example.html

此程序依赖 sqlite。

Depending on your configuration, you might need to install the luasql-sqlite3 and markdown rocks before running the application. Now just start Xavante, and point your browser to blog.ws, and you should see the index page of the blog. If you created a blog.db from scratch you are not going to see any posts, though. The blog application in `samples/blog' includes a blog.db filled with random posts and comments.

安装:

luarocks search sql

apt-get install sqlite3

luarocks install luasql-sqlite3 SQLITE_DIR=/usr/local

运行

root@fqs:/usr/local/lib/luarocks/rocks/orbit/2.2.4-1/samples/blog# orbit -p 8181 blog.lua
Starting Orbit server at port 8181

lua MVC框架 Orbit初探

使用firefox sqlite插件, 查看db

lua MVC框架 Orbit初探

APP接口

使用orbit.new则构造了一个APP环境, 此环境可以引用全局变量,

同时还定义了 blog应用继承了 orbit项目的接口, 例如路由的get接口  dispatch_get

local blog = setmetatable(orbit.new(), { __index = _G })
if _VERSION == "Lua 5.2" then
_ENV = blog
else
setfenv(1, blog)
end

orbit.new injects quite a lot of stuff in the blog module's namespace. The most important of these are the dispatch_get, dispatch_post, and model methods that let you define the main functionality of the application.

Creating Models

模型角色负责从数据库中查询数据, 后者新建和修改数据。

Our blog application has three kinds of objects: posts, comments, and "static" pages (things like an "About" page for the blog, for example). It's no coincidence that we also have three tables in the database, each table maps to a kind of object our application handles, and for each kind we will create a model. We first create a model object for posts:

posts = blog:model "post"
function posts:find_recent()
return self:find_all("published_at is not null",
{ order = "published_at desc",
count = recent_count })
end

Defining Controllers

对于请求的URL,执行访问什么数据, 怎么响应。 访问数据调用model对象, 响应内容可以是html, 也可以是 xml json等。

Controllers are the interface between the web and your application. With Orbit you can map the path part of your application's URLs (in http://myserver.com/myapp.ws/foo/bar the path is /foo/bar, for example) to controllers. In Lua terms, an Orbit controller is a function that receives a request/response object (usually called web) plus parameters extracted from the path, and returns text that is sent to the client (usually HTML, but can be XML, or even an image).

GET请求一个URL,调用模型获取数据

function index(web)
local ps = posts:find_recent()
local ms = posts:find_months()
local pgs = pgs or pages:find_all()
return render_index(web, { posts = ps, months = ms,
recent = ps, pages = pgs })
end blog:dispatch_get(cache(index), "/", "/index")

POST修改数据, 调用模型,保存数据 。

function add_comment(web, post_id)
local input = web.input
if string.find(input.comment, "^%s*$") then
return view_post(web, post_id, true)
else
local comment = comments:new()
comment.post_id = tonumber(post_id)
comment.body = markdown(input.comment)
if not string.find(input.author, "^%s*$") then
comment.author = input.author
end
if not string.find(input.email, "^%s*$") then
comment.email = input.email
end
if not string.find(input.url, "^%s*$") then
comment.url = input.url
end
comment:save()
local post = posts:find(tonumber(post_id))
post.n_comments = (post.n_comments or 0) + 1
post:save()
cache:invalidate("/")
cache:invalidate("/post/" .. post_id)
cache:invalidate("/archive/" .. os.date("%Y/%m", post.published_at))
return web:redirect(web:link("/post/" .. post_id))
end
end blog:dispatch_post(add_comment, "/post/(%d+)/addcomment")

Views: Generating HTML

视图定义的一个简单函数, 在函数中生成视图内容,例如HTML。

可以直接从控制器中返回,渲染的内容, 但是这里还是建议分离控制器和视图,这是一个好的编程实践。

Views are the last component of the MVC triad. For Orbit views are just simple functions that generate content (usually HTML), and are strictly optional, meaning you can return content directly from the controller. But it's still good programming practice to separate controllers and views.

你可使用concat将字符串拼接为视图结果, 也可以使用一个第三方的模板库, 将从model中获取的数据, 使用模板引擎渲染到模板中。

orbit提供了使用的 HTML和XML生成器 orbit.htmlify, 但是你也可以*选择其它的你想用的方法。

How you generate content is up to you: concatenate Lua strings, use table.concat, use a third-party template library... Orbit provides programmatic HTML/XML generation through orbit.htmlify, but you are free to use any method you want. In this tutorial we will stick with programmatic generation, though, as the other methods (straight strings, Cosmo, etc.) are thoroughly documented elsewhere.

orbit.htmlify

function layout(web, args, inner_html)
return html{
head{
title(blog_title),
meta{ ["http-equiv"] = "Content-Type",
content = "text/html; charset=utf-8" },
link{ rel = 'stylesheet', type = 'text/css',
href = web:static_link('/style.css'), media = 'screen' }
},
body{
div{ id = "container",
div{ id = "header", title = "sitename" },
div{ id = "mainnav",
_menu(web, args)
},
div{ id = "menu",
_sidebar(web, args)
},
div{ id = "contents", inner_html },
div{ id = "footer", copyright_notice }
}
}
}
end
 
 

cosmo后台模板引擎

MVC架构中一直提到数据和视图分离,

如果使用orbit.htmlify模式, 则只能写出符合DOM结构化的lua代码, 对于前端代码如果能用HTML方式书写,类似JSP格式, 也比orbit提供的这种方式好维护, 前端更加方便定制。

看看lua的后台模板引擎

http://cosmo.luaforge.net/

Overview

Cosmo is a “safe templates” engine. It allows you to fill nested templates, providing many of the advantages of Turing-complete template engines, without without the downside of allowing arbitrary code in the templates.

Simple Form Filling

Let’s start with a simple example of filling a set of scalar values into a template: Here are a few examples of Cosmo in use:

> values = { rank="Ace", suit="Spades" }
> template = "$rank of $suit"
> require("cosmo")
> = cosmo.fill(template, values)
Ace of Spades

Note that the template is a string that marks where values should go. The table provides the values. $rank will get replaced by value.rank (“Ace”) and $suit will get replaced by value.suit (“Spades”).

cosmo.fill() takes two parameters at once. Cosmo also provides a “shortcut” method f() which takes only one parameter – the template – and returns a function that then takes the second parameter. This allows for a more compact notation:

> = cosmo.f(template){ rank="Ace", suit="Spades" }
Ace of Spades