糖果实验室杂货铺

Candy Lab

ORC索引页显示的Lapis实现

2 years ago 0

作者:糖果

ORC是是用LOR框架完成的,这次尝试实现用Lapis来实现,ORC索引页面的显示, 国为ORC是后端前端分开的, 实际上后端只要根据用输入返回按接口定义的JSON数据就好。

这个实验会涉及到几个最学用的点:

1.简单的用SQL对业务表进行left join,这个和语言平台无关。
2.OR的LUA框架返回JSON, JSON数据的编解码。
3.常规不使用ORM访问数据库。
4.Lapis模板,在模板中进行子模板渲染。
None
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
local lapis = require "lapis"
local app = lapis.Application()
local db = require("lapis.db")
app:enable("etlua")


app:get("/topics/all", function(self)
    page_no = 1
    page_size = 10
    category = 3  
    local sql = "select t.*, c.name as category_name, u.avatar as avatar from topic t " ..
                                "left join user u on t.user_id=u.id " ..
                                "left join category c on t.category_id=c.id " ..
                                "where t.category_id=1 "

    local res, err = db.query(sql)
    return { json = { data = {totalCount="54", currentPage="1",topics = res, totalPage=2}, success=true }}
end)

return app

值的注意的是,db.query(sql)返回的结果res本身就是JSON形式,不需要进入JSON编解码。 因为LORj框架是不提供ORM的,所以ORC所有返回接口几乎都是纯SQL。 因为Lapis的底层用的也是resty-mysql ,他们之间执行SQL是兼容的。

下面是节选的Lapis的Mysql库的源码:

None
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
local mysql = require("resty.mysql")
    return function(q)
      if logger then
        logger.query(q)
      end
      local db = ngx and ngx.ctx.resty_mysql_db
      if not (db) then
        local err
        db, err = assert(mysql:new())
        db:set_timeout(timeout)
        local options = {
          database = database,
          user = user,
          password = password,
          ssl = ssl,
          ssl_verify = ssl_verify
        }
        if path then
          options.path = path
        else
          options.host = host
          options.port = port
        end
        assert(db:connect(options))
        if ngx then
          ngx.ctx.resty_mysql_db = db
          after_dispatch(function()
            return db:set_keepalive(max_idle_timeout, pool_size)
          end)
        end
      end
      local start_time
      if ngx and config.measure_performance then
        ngx.update_time()
        start_time = ngx.now()
      end
      local res, err, errcode, sqlstate = assert(db:query(q))
      local result
      if err == 'again' then
        result = {
          res
        }
        while err == 'again' do
          res, err, errcode, sqlstate = assert(db:read_result())
          table.insert(result, res)
        end
      else
        result = res
      end
      if start_time then
        ngx.update_time()
        increment_perf("db_time", ngx.now() - start_time)
        increment_perf("db_count", 1)
      end
      return result
    end
  end
}

ORC的前端代码,除了其它和这个实验不相关的Layout,主要的代码如下:

meta.etlua

1
<script src="/static/js/juicer.js"></script>

图像说明文字

None
1
2
3
<% render("views.meta") %>

<script src="/static/js/index.js"></script>

这里的index.js的代码也不是很多:

None
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
(function (L) {
    var _this = null;
    L.Index = L.Index || {};
    _this = L.Index = {
        data: {
            current_category: "0"
        },

        init: function (current_category) {
            _this.data.current_category = current_category || "0";
            _this.loadTopics("default");
            //_this.loadTopics("ir-black");
            _this.initEvents();
        },

/*
        scrollTop: function () {
            $('html, body').animate({scrollTop: 0}, 0);
        },
*/

        initEvents: function () {
            $(document).on("click", "#topic-type-tab a", function () {
                $("#topic-type-tab a").each(function () {
                    $(this).removeClass("active");
                });

                $(this).addClass("active");
            });

            $("#default-topics-btn").click(function () {
                _this.loadTopics("default");
            });

            $("#recent-reply-topics-btn").click(function () {
                _this.loadTopics("recent-reply");
            });

            $("#good-topics-btn").click(function () {
                _this.loadTopics("good");
            });
            
            
            $("#noreply-topics-btn").click(function () {
                _this.loadTopics("noreply");
            });
        },

        loadTopics: function (type, pageNo) {
            pageNo = pageNo || 1;
            $.ajax({
                url: '/topics/all',
                type: 'get',
                cache: false,
                data: {
                    page_no: 1,
                    type: type,
                    category: _this.data.current_category
                },
                dataType: 'json',
                success: function (result) {
                    if (result.success) {
                        if (!result.data || (result.data && result.data.topics.length <= 0)) {
                            $("#topics-body").html('<div class="alert alert-info" role="alert">此分类下没有任何内容</div>');
                        } else {
                            _this.page(result, type, 1);
                        }
                    } else {
                        $("#topics-body").html('<div class="alert alert-danger" role="alert">' + result.msg + '</div>');
                    }
                },
                error: function () {
                    $("#topics-body").html('<div class="alert alert-danger" role="alert">error to send request.</div>');
                }
            });
        },
        page: function (result, type, pageNo) {
            var data = result.data || {};
            var $container = $("#topics-body");
            $container.empty();

            var tpl = $("#topic-item-tpl").html();
            var html = juicer(tpl, data);
            $container.html(html);

            var currentPage = data.currentPage;
            var totalPage = data.totalPage;
            var totalCount = data.totalCount;

            if (totalPage > 1) {
                $("#pagebar").show();
                $.fn.jpagebar({
                    renderTo: $("#pagebar"),
                    totalpage: totalPage,
                    totalcount: totalCount,
                    pagebarCssName: 'pagination2',
                    currentPage: currentPage,
                    onClickPage: function (pageNo) {
                        $.fn.setCurrentPage(this, pageNo);
                        $.ajax({
                            url: '/topics/all',
                            type: 'get',
                            cache: false,
                            data: {
                                page_no: pageNo,
                                type: type,
                                category: _this.data.current_category
                            },

                            dataType: 'json',
                            success: function (result) {
                                var data = result.data || {};
                                var $container = $("#topics-body");
                                $container.empty();

                                var tpl = $("#topic-item-tpl").html();
                                var html = juicer(tpl, data);
                                $container.html(html);
                               // _this.scrollTop();
                            },
                            error: function () {
                                $("#topics-body").html('<div class="alert alert-danger" role="alert">error to find topics page.</div>');
                            }
                        });
                    }
                });
            } else {
                $("#pagebar").hide();
            }
        }
    };
}(APP));

ORC并没有使用传统的框架分页器对象,结合框架模板语言来实现分页,LOR框架也暂时不提供这些功能。用的是Juicer前端模板来实现 把后端返回的JSON数据的字段,渲染到前端的Layout标签中。

None
1
2
3
var tpl = $("#topic-item-tpl").html();
var html = juicer(tpl, data);
$container.html(html);

juicer把data数据提供给了topic-item-tpl这个标签类,并在前端页面嵌入了 {@each topics as t}语法,取得JSON数据的值, t.title, t.avatar等。

上面这段代码,把后端返回JSON数据返回在前端渲染,主要靠的是juicer。按目前ORC这种写法, 前后端都是通过JSON数据建立联系,ORM,Etlua标记,分页器这种中间模块都没用到。下面的实验就是把这些功能,应用到ORC上。

PS: ORC=Openrest China

下一篇实验是对ORC的内容页进行Lapis的代码实现移植。


糖果实验室

Openresty中文编程网
IKBC经典机械键盘
机械键盘领券优惠购买

Write a Comment