jj.js 0.8.4 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -7
- package/lib/db.js +19 -20
- package/lib/loader.js +0 -1
- package/lib/router.js +1 -1
- package/lib/run.js +23 -19
- package/lib/url.js +2 -1
- package/lib/utils/error.js +13 -12
- package/lib/view.js +1 -1
- package/package.json +1 -2
- package/test/app/controller/index.js +0 -250
- package/test/app/controller/not_extend_sys_controller.js +0 -32
- package/test/app/diy/diy_controller.js +0 -16
- package/test/app/middleware/index.js +0 -19
- package/test/app/middleware/middle1.js +0 -42
- package/test/app/middleware/middle2.js +0 -18
- package/test/app/model/article.js +0 -9
- package/test/app/pagination/my_pagination.js +0 -11
- package/test/app/view/index_hello.htm +0 -21
- package/test/app/view/index_index.htm +0 -18
- package/test/app/view/index_template.htm +0 -21
- package/test/app/view/index_view.htm +0 -17
- package/test/app/view/layout.htm +0 -14
- package/test/config/app.js +0 -17
- package/test/config/routes.js +0 -33
- package/test/config/view.js +0 -5
- package/test/public/favicon.ico +0 -0
- package/test/public/static/lit.css +0 -1
- package/test/test.js +0 -7
package/README.md
CHANGED
|
@@ -105,7 +105,6 @@ node server.js
|
|
|
105
105
|
- **public**:静态资源目录,主要存放css文件、js文件、图片等静态资源。在`./config/app.js`中通过`static_dir`参数可以设置或更改静态目录名字,为空时,则关闭静态访问(系统不会加载静态资源访问的逻辑,最大节省内容,也即所谓的轻量)
|
|
106
106
|
- **server.js**:应用入口文件,名字可以任意改。
|
|
107
107
|
|
|
108
|
-
>
|
|
109
108
|
### 系统类库
|
|
110
109
|
|
|
111
110
|
```javascript
|
|
@@ -146,13 +145,13 @@ module.exports = Index;
|
|
|
146
145
|
|
|
147
146
|
- 在控制器中,前缀为`$`字符的属性为特殊属性,框架首先会检测本类中即`this`实例中是否有`$db`属性,有的话,会直接调用。如果没有,会检测本类文件所在应用目录即`./app/`目录下,是否用`db`目录或文件,如果有,则`$db`即代表那个目录或文件,`this.$db.table`会继续在db目录下寻找table目录或文件。如果`db`目录或文件不存在,框架会在应用根目录`./`下找,是否有`db`目录或文件,如果有,和上面一样。如果还不存在,框架会在jj.js框架`lib`目录下找`db`文件或目录,而框架`lib`中有`db.js`文件,至此,`this.$db`成功访问到框架`db`类。
|
|
148
147
|
|
|
149
|
-
- 如果将`this.$db`赋值为给一个变量,`const db = this.$db;`,得到的将是一个`db` Class类,可以进行new操作,`const db = this.$db; const db1 = new
|
|
148
|
+
- 如果将`this.$db`赋值为给一个变量,`const db = this.$db;`,得到的将是一个`db` Class类,可以进行new操作,`const db = this.$db; const db1 = new db(this.ctx, options); const db2 = new this.$db(this.ctx, options);`创建多个实例。
|
|
150
149
|
|
|
151
150
|
- 但上面演示代码并没有new一个实例,而是直接调用`db`类的`table()`方法,这正是框架的智能之处。当调用`this.$db.table('user')`时,框架首先会检测db类是否有`table`静态属性,有的话会直接调用。没有,则会自动new一个`db`实例,而且这个实例是个单例,然后调用此`db`实例的`table`方法,`table('user')`设置数据表名后返回实例本身,然后紧接着调用`find()`方法,读取用户ID为1的数据。
|
|
152
151
|
|
|
153
152
|
> 注意:虽然系统加载很复杂, 但是基于node的常驻内存特性,上面的文件路径判断,处理一次就会被缓存下来,在下个生命周期不用重复判断,节省性能。
|
|
154
153
|
|
|
155
|
-
> 关于单例:通过`this.$xxx`调用的类实例,在单个生命周期内是单例,即不管调用几次,都是用的同一个实例,这样非常节省内存开销。如果有多个db实例需求,可以用上面的方法,自己`new
|
|
154
|
+
> 关于单例:通过`this.$xxx`调用的类实例,在单个生命周期内是单例,即不管调用几次,都是用的同一个实例,这样非常节省内存开销。如果有多个db实例需求,可以用上面的方法,自己`new`创建,自己创建时注意第一个参数需传入ctx,否则部分类库使用会出现异常。
|
|
156
155
|
|
|
157
156
|
> 生命周期:应用生命周期以url访问为单位,一次url访问到访问结束,是一个独立的生命周期,在这个周期内自动生成的单实例都是共用的。
|
|
158
157
|
|
|
@@ -300,9 +299,13 @@ module.exports = Index;
|
|
|
300
299
|
|
|
301
300
|
### Db数据库类
|
|
302
301
|
|
|
303
|
-
> 方法:**
|
|
302
|
+
> 方法:**connect(options)** 连接数据库
|
|
304
303
|
|
|
305
|
-
|
|
304
|
+
> 方法:**async close()** 关闭数据库连接
|
|
305
|
+
|
|
306
|
+
> 方法:**async startTrans(fun)** 开启事务
|
|
307
|
+
|
|
308
|
+
异步方法,如果`fun`不为空,并且是函数,则开启事务后,会自动执行此函数,并提交事务,不用再手工提交或回滚事务。`fun`为异步函数。
|
|
306
309
|
|
|
307
310
|
> 方法:**async commit()** 提交事务
|
|
308
311
|
|
|
@@ -853,7 +856,7 @@ module.exports = self;
|
|
|
853
856
|
```javascript
|
|
854
857
|
routes = [
|
|
855
858
|
{url: '/', path: 'app/index/index2'}, // 访问'/',会定位到app应用的index控制的index2方法
|
|
856
|
-
{url: '/article/:id.html', path: 'app/article/article', name: 'article'}, // 访问'/article/123.html',会定位到app应用的article控制的article方法;通过this.ctx.
|
|
859
|
+
{url: '/article/:id.html', path: 'app/article/article', name: 'article'}, // 访问'/article/123.html',会定位到app应用的article控制的article方法;通过this.ctx.params.id可以获取到参数id;通过article可以反编译网址,执行this.$url.build(':article', {id: 123}); 生成'/article/123.html'
|
|
857
860
|
{url: '/admin', path: 'app/admin/check', type: 'middleware'}, // 访问'/admin',会定位到app应用的admin中间件的check方法
|
|
858
861
|
{url: '/about', path: 'app/about/index', type: 'view'}, // 访问'/about',会定位到app应用的view模板目录about目录下的index.htm文件,并直接输出文件内容
|
|
859
862
|
{url: '/:cate/list_:page.html', path: 'cate/cate', name: 'cate_page'}, // 多参数分页示例
|
|
@@ -862,7 +865,7 @@ routes = [
|
|
|
862
865
|
|
|
863
866
|
module.exports = routes;
|
|
864
867
|
```
|
|
865
|
-
>
|
|
868
|
+
> 注意:本路由配置示例前两条规则为常规用法,后面的非常规用法,不建议使用。如果是单应用模式,可以去掉path参数里的app。
|
|
866
869
|
|
|
867
870
|
### 应用入口文件
|
|
868
871
|
|
package/lib/db.js
CHANGED
|
@@ -11,7 +11,7 @@ const nest = new Map();
|
|
|
11
11
|
|
|
12
12
|
class Db extends Context
|
|
13
13
|
{
|
|
14
|
-
constructor(ctx) {
|
|
14
|
+
constructor(ctx, options) {
|
|
15
15
|
ctx = ctx || {};
|
|
16
16
|
super(ctx);
|
|
17
17
|
this._config = null;
|
|
@@ -19,7 +19,7 @@ class Db extends Context
|
|
|
19
19
|
this._options = {};
|
|
20
20
|
this._queryStr = '';
|
|
21
21
|
this._tableField = {};
|
|
22
|
-
this.connect();
|
|
22
|
+
this.connect(options);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
reset() {
|
|
@@ -62,22 +62,21 @@ class Db extends Context
|
|
|
62
62
|
return this;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
close() {
|
|
66
|
-
|
|
67
|
-
pool.get(this._config).end(err => {
|
|
65
|
+
async close() {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
pool.has(this._config) && pool.get(this._config).end(err => {
|
|
68
68
|
if(err) {
|
|
69
|
-
const message = '连接池销毁失败:' + err
|
|
69
|
+
const message = '连接池销毁失败:' + err.message;
|
|
70
70
|
this.$logger.sql(message);
|
|
71
71
|
this.$logger.error(message);
|
|
72
|
-
|
|
72
|
+
reject(new Error('DbError: ' + message));
|
|
73
73
|
} else {
|
|
74
74
|
pool.delete(this._config);
|
|
75
75
|
this.$logger.sql(`连接池销毁成功:{poolTotal: ${pool.size}}`);
|
|
76
|
+
resolve(this);
|
|
76
77
|
}
|
|
77
78
|
});
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
return this;
|
|
79
|
+
});
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
release(conn) {
|
|
@@ -95,10 +94,10 @@ class Db extends Context
|
|
|
95
94
|
return new Promise((resolve, reject) => {
|
|
96
95
|
p.getConnection((err, connection) => {
|
|
97
96
|
if(err) {
|
|
98
|
-
const message = '获取数据库连接失败:' + err
|
|
97
|
+
const message = '获取数据库连接失败:' + err.message;
|
|
99
98
|
this.$logger.sql(message);
|
|
100
99
|
this.$logger.error(message);
|
|
101
|
-
reject(new Error(message));
|
|
100
|
+
reject(new Error('DbError: ' + message));
|
|
102
101
|
} else {
|
|
103
102
|
this.$logger.sql(`获取数据库连接:{limit: ${p.config.connectionLimit}, all: ${p._allConnections.length}, acquiring: ${p._acquiringConnections.length}, free: ${p._freeConnections.length}, queue: ${p._connectionQueue.length}}`);
|
|
104
103
|
resolve(connection);
|
|
@@ -134,10 +133,10 @@ class Db extends Context
|
|
|
134
133
|
return new Promise((resolve, reject) => {
|
|
135
134
|
conn.beginTransaction(async (err) => {
|
|
136
135
|
if(err) {
|
|
137
|
-
const message = '开启事务失败:' + err
|
|
136
|
+
const message = '开启事务失败:' + err.message;
|
|
138
137
|
this.$logger.sql(message);
|
|
139
138
|
this.$logger.error(message);
|
|
140
|
-
reject(new Error(message));
|
|
139
|
+
reject(new Error('DbError: ' + message));
|
|
141
140
|
} else {
|
|
142
141
|
const message = '开启事务成功!';
|
|
143
142
|
this.$logger.sql(message);
|
|
@@ -195,11 +194,11 @@ class Db extends Context
|
|
|
195
194
|
return new Promise((resolve, reject) => {
|
|
196
195
|
conn.commit((err) => {
|
|
197
196
|
if(err) {
|
|
198
|
-
const message = '事务提交失败:' + err
|
|
197
|
+
const message = '事务提交失败:' + err.message;
|
|
199
198
|
this.$logger.sql(message);
|
|
200
199
|
this.$logger.error(message);
|
|
201
200
|
this.rollback();
|
|
202
|
-
reject(new Error(message));
|
|
201
|
+
reject(new Error('DbError: ' + message));
|
|
203
202
|
} else {
|
|
204
203
|
trans.delete(this.ctx);
|
|
205
204
|
const message = '事务提交成功!';
|
|
@@ -220,10 +219,10 @@ class Db extends Context
|
|
|
220
219
|
return new Promise((resolve, reject) => {
|
|
221
220
|
conn.query(sql, params, (err, data) => {
|
|
222
221
|
if(err) {
|
|
223
|
-
const message = '数据操作失败,
|
|
222
|
+
const message = '数据操作失败,' + err.message + "\r\nSQL:" + this.format(sql, params);
|
|
224
223
|
this.$logger.sql(message);
|
|
225
224
|
this.$logger.error(message);
|
|
226
|
-
reject(new Error(message));
|
|
225
|
+
reject(new Error('DbError: ' + message));
|
|
227
226
|
} else {
|
|
228
227
|
this.$logger.sql('数据操作成功,SQL:' + this.format(sql, params));
|
|
229
228
|
resolve(data);
|
|
@@ -506,7 +505,7 @@ class Db extends Context
|
|
|
506
505
|
if(!where[0]) {
|
|
507
506
|
const message = 'update方法必须传入where参数';
|
|
508
507
|
this.$logger.sql(message);
|
|
509
|
-
throw new Error(message);
|
|
508
|
+
throw new Error('DbError: ' + message);
|
|
510
509
|
}
|
|
511
510
|
params = params.concat(where[1]);
|
|
512
511
|
|
|
@@ -539,7 +538,7 @@ class Db extends Context
|
|
|
539
538
|
if(!where[0]) {
|
|
540
539
|
const message = 'delete方法必须传入where参数';
|
|
541
540
|
this.$logger.sql(message);
|
|
542
|
-
throw new Error(message);
|
|
541
|
+
throw new Error('DbError: ' + message);
|
|
543
542
|
}
|
|
544
543
|
params = params.concat(where[1]);
|
|
545
544
|
|
package/lib/loader.js
CHANGED
package/lib/router.js
CHANGED
|
@@ -9,7 +9,7 @@ if (cfg_routes) {
|
|
|
9
9
|
for(let item of cfg_routes){
|
|
10
10
|
item.method || (item.method = 'all');
|
|
11
11
|
if(!~methods.indexOf(item.method)) {
|
|
12
|
-
throw new Error(
|
|
12
|
+
throw new Error(`RouteError: 未知路由方法:${item.method}`);
|
|
13
13
|
}
|
|
14
14
|
if(typeof item.path === 'function'){
|
|
15
15
|
router[item.method](item.url, item.path);
|
package/lib/run.js
CHANGED
|
@@ -7,9 +7,13 @@ const compose = require('koa-compose');
|
|
|
7
7
|
const Logger = require('./logger');
|
|
8
8
|
|
|
9
9
|
async function run(ctx, next, control_type=cfg_app.controller_folder) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
if(cfg_app.app_debug) {
|
|
11
|
+
Logger.debug(ctx.request);
|
|
12
|
+
Logger.debug(`Router(${control_type}): {APP: '${ctx.APP}', CONTROLLER: '${ctx.CONTROLLER}', ACTION: '${ctx.ACTION}'}`);
|
|
13
|
+
Object.keys(ctx.params).length && Logger.debug({Params: ctx.params});
|
|
14
|
+
Object.keys(ctx.query).length && Logger.debug({Get: ctx.query});
|
|
15
|
+
Object.keys(ctx.request.body || {}).length && Logger.debug({Post: ctx.request.body});
|
|
16
|
+
}
|
|
13
17
|
|
|
14
18
|
// 设置根加载器
|
|
15
19
|
ctx.$ = loader('./', ctx);
|
|
@@ -25,21 +29,21 @@ async function run(ctx, next, control_type=cfg_app.controller_folder) {
|
|
|
25
29
|
ctx._.config.tpl = tpl;
|
|
26
30
|
|
|
27
31
|
// 应用、控制器、方法名字验证
|
|
28
|
-
if
|
|
29
|
-
throw new Error(
|
|
32
|
+
if(~ctx.APP.indexOf('.') || ~ctx.CONTROLLER.indexOf('.') || ~ctx.ACTION.indexOf('.')) {
|
|
33
|
+
throw new Error(`RunError: 应用、控制器或方法名字不合法!`);
|
|
30
34
|
}
|
|
31
35
|
|
|
32
|
-
if
|
|
36
|
+
if(ctx.APP[0] == '_' || ctx.APP[0] == '$' || !ctx._[ctx.APP]) {
|
|
33
37
|
if(cfg_app.app_debug) {
|
|
34
|
-
throw new Error(
|
|
38
|
+
throw new Error(`RunError: 应用:${ctx.APP}不存在!`);
|
|
35
39
|
} else {
|
|
36
40
|
return false;
|
|
37
41
|
}
|
|
38
42
|
}
|
|
39
43
|
|
|
40
|
-
if
|
|
44
|
+
if(!ctx._[ctx.APP][control_type]) {
|
|
41
45
|
if(cfg_app.app_debug) {
|
|
42
|
-
throw new Error(
|
|
46
|
+
throw new Error(`RunError: 目录:${ctx.APP}/${control_type}不存在!`);
|
|
43
47
|
} else {
|
|
44
48
|
return false;
|
|
45
49
|
}
|
|
@@ -49,7 +53,7 @@ async function run(ctx, next, control_type=cfg_app.controller_folder) {
|
|
|
49
53
|
if(control_type == cfg_view.view_folder) {
|
|
50
54
|
const content = await readFile(path.join(ctx._[ctx.APP][control_type].__node.path, ctx.CONTROLLER + cfg_view.view_depr + ctx.ACTION + cfg_view.view_ext));
|
|
51
55
|
if(!content) {
|
|
52
|
-
throw new Error(
|
|
56
|
+
throw new Error(`RunError: 模板文件:${ctx.APP}/${control_type}/${ctx.CONTROLLER + cfg_view.view_depr + ctx.ACTION + cfg_view.view_ext}不存在!`);
|
|
53
57
|
}
|
|
54
58
|
ctx.body = content;
|
|
55
59
|
return;
|
|
@@ -58,22 +62,22 @@ async function run(ctx, next, control_type=cfg_app.controller_folder) {
|
|
|
58
62
|
// 控制器
|
|
59
63
|
const Controller = ctx._[ctx.APP][control_type][ctx.CONTROLLER] || ctx._[ctx.APP][control_type]['empty'];
|
|
60
64
|
|
|
61
|
-
if
|
|
65
|
+
if(ctx.CONTROLLER[0] == '_' || ctx.CONTROLLER[0] == '$' || typeof Controller != 'function') {
|
|
62
66
|
if(cfg_app.app_debug) {
|
|
63
|
-
throw new Error(`class文件:${ctx.APP}/${control_type}/${ctx.CONTROLLER}不存在!`);
|
|
67
|
+
throw new Error(`RunError: class文件:${ctx.APP}/${control_type}/${ctx.CONTROLLER}不存在!`);
|
|
64
68
|
} else {
|
|
65
69
|
return false;
|
|
66
70
|
}
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
// 控制器实例
|
|
70
|
-
$controller = new Controller(ctx, next);
|
|
74
|
+
const $controller = new Controller(ctx, next);
|
|
71
75
|
const humpAction = toHump(ctx.ACTION);
|
|
72
76
|
const action = typeof $controller[humpAction] == 'function' ? humpAction : 'empty';
|
|
73
77
|
|
|
74
|
-
if
|
|
78
|
+
if(ctx.ACTION[0] == '_' || ctx.ACTION[0] == '$' || typeof $controller[action] != 'function') {
|
|
75
79
|
if(cfg_app.app_debug) {
|
|
76
|
-
throw new Error(`class方法:${ctx.APP}/${control_type}/${ctx.CONTROLLER}/${humpAction}不存在!`);
|
|
80
|
+
throw new Error(`RunError: class方法:${ctx.APP}/${control_type}/${ctx.CONTROLLER}/${humpAction}不存在!`);
|
|
77
81
|
} else {
|
|
78
82
|
return false;
|
|
79
83
|
}
|
|
@@ -93,18 +97,18 @@ async function run(ctx, next, control_type=cfg_app.controller_folder) {
|
|
|
93
97
|
return stack.concat(async (ctx, next) => {
|
|
94
98
|
const [METHOD = action, MIDDLEWARE = ctx.CONTROLLER, APP = ctx.APP] = middle.middleware.split('/').reverse();
|
|
95
99
|
if(!ctx._[APP]) {
|
|
96
|
-
throw new Error(
|
|
100
|
+
throw new Error(`RunError: 中间件应用:${APP}不存在!`);
|
|
97
101
|
}
|
|
98
102
|
if(!ctx._[APP]['middleware']) {
|
|
99
|
-
throw new Error(
|
|
103
|
+
throw new Error(`RunError: 中间件目录:${APP}/middleware不存在!`);
|
|
100
104
|
}
|
|
101
105
|
const Middleware = ctx._[APP]['middleware'][MIDDLEWARE];
|
|
102
106
|
if(!Middleware || typeof Middleware != 'function') {
|
|
103
|
-
throw new Error(
|
|
107
|
+
throw new Error(`RunError: 中间件文件:${APP}/middleware/${MIDDLEWARE}不存在!`);
|
|
104
108
|
}
|
|
105
109
|
const $middleware = new Middleware(ctx, next);
|
|
106
110
|
if(!$middleware[METHOD] || typeof $middleware[METHOD] != 'function') {
|
|
107
|
-
throw new Error(
|
|
111
|
+
throw new Error(`RunError: 中间件方法:${APP}/middleware/${MIDDLEWARE}/${METHOD}不存在!`);
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
// 执行中间件方法
|
package/lib/url.js
CHANGED
|
@@ -12,7 +12,7 @@ const {toLine} = require('./utils/str');
|
|
|
12
12
|
class Url extends Context
|
|
13
13
|
{
|
|
14
14
|
build(url='', vars, ext='', domain='') {
|
|
15
|
-
if(typeof vars != 'object') {
|
|
15
|
+
if(vars && typeof vars != 'object') {
|
|
16
16
|
[vars, ext, domain] = [{}, vars, ext];
|
|
17
17
|
}
|
|
18
18
|
const query = {...vars};
|
|
@@ -56,6 +56,7 @@ class Url extends Context
|
|
|
56
56
|
|
|
57
57
|
if(~url.indexOf(':')) {
|
|
58
58
|
url = url.replace(/\:([^./]+)/g, (match, key) => {
|
|
59
|
+
key = key.split('(')[0];
|
|
59
60
|
if(key in query) {
|
|
60
61
|
const value = query[key];
|
|
61
62
|
delete query[key];
|
package/lib/utils/error.js
CHANGED
|
@@ -1,29 +1,33 @@
|
|
|
1
|
+
const fs = require('./fs.js');
|
|
2
|
+
|
|
1
3
|
function parseError(err) {
|
|
2
|
-
let
|
|
3
|
-
stack = stack.replace(/(\r\n)
|
|
4
|
-
|
|
5
|
-
let msg = err.name;
|
|
4
|
+
let msg = err.message;
|
|
5
|
+
let stack = err.stack.replace(/(\r\n)/g, "\n").split("\n");
|
|
6
|
+
|
|
6
7
|
if(err.name == 'TemplateError') {
|
|
7
|
-
msg = stack.pop();
|
|
8
|
+
msg = 'TemplateError: ' + stack.pop();
|
|
9
|
+
stack = [stack.shift().replace('TemplateError:', "at")];
|
|
8
10
|
} else {
|
|
9
|
-
|
|
11
|
+
stack = stack.filter(text => {return /^ at /.test(text);});
|
|
10
12
|
}
|
|
11
|
-
|
|
13
|
+
|
|
14
|
+
const file_info = stack[0].split(' ').slice(-1)[0].replace(/(\()|(\))/g, '').split(':');
|
|
12
15
|
const column = parseInt(file_info.pop());
|
|
13
16
|
const row = parseInt(file_info.pop());
|
|
14
17
|
const file_path = file_info.join(':');
|
|
15
18
|
let begin = row - 10;
|
|
16
19
|
let end = row + 10;
|
|
20
|
+
let nth = 0;
|
|
17
21
|
let code = '';
|
|
18
22
|
if(begin < 0) {
|
|
19
23
|
end -= begin;
|
|
20
24
|
begin = 0;
|
|
21
25
|
}
|
|
22
|
-
if(file_path == 'anonymous') {
|
|
26
|
+
if(file_path == 'anonymous' || !file_path || !fs.isFileSync(file_path)) {
|
|
23
27
|
code = stack;
|
|
24
28
|
} else {
|
|
25
29
|
code = require('fs').readFileSync(file_path);
|
|
26
|
-
code = code.toString().split("\n");
|
|
30
|
+
code = code.toString().replace(/(\r\n)/g, "\n").split("\n");
|
|
27
31
|
if(begin < 0) {
|
|
28
32
|
end -= begin;
|
|
29
33
|
begin = 0;
|
|
@@ -36,9 +40,6 @@ function parseError(err) {
|
|
|
36
40
|
begin = 0;
|
|
37
41
|
}
|
|
38
42
|
code = code.slice(begin, end);
|
|
39
|
-
if(err.name == 'TemplateError') {
|
|
40
|
-
stack = [stack[0]];
|
|
41
|
-
}
|
|
42
43
|
nth = row - begin;
|
|
43
44
|
}
|
|
44
45
|
|
package/lib/view.js
CHANGED
package/package.json
CHANGED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
//const {Controller} = require('jj.js');
|
|
2
|
-
const {Controller, Db, Cache, Pagination, Logger, Url, Cookie} = require('../../../jj.js');
|
|
3
|
-
|
|
4
|
-
class Index extends Controller
|
|
5
|
-
{
|
|
6
|
-
constructor(...args) {
|
|
7
|
-
super(...args);
|
|
8
|
-
this.middleware = ['middle', {middleware: 'auth', accept: 'middleTest'}];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
async index() {
|
|
12
|
-
const link_list = [
|
|
13
|
-
{title: '输出字符串内容', url: this.$url.build('show_str')},
|
|
14
|
-
{title: '加载文件显示', url: this.$url.build('load_file')},
|
|
15
|
-
{title: '中间件测试', url: this.$url.build('middle_test')},
|
|
16
|
-
{title: '数据库测试,需要先配置数据库文件', url: this.$url.build('mysql')},
|
|
17
|
-
{title: '缓存测试', url: this.$url.build('cache')},
|
|
18
|
-
{title: '日志测试', url: this.$url.build('log')},
|
|
19
|
-
{title: '路由直接输出', url: this.$url.build(':show')},
|
|
20
|
-
{title: '路由到模板文件直接输出', url: this.$url.build('template')},
|
|
21
|
-
{title: '路由到中间件(不建议这种用法)', url: this.$url.build('middleware')},
|
|
22
|
-
{title: '路由到自定义控制器层', url: this.$url.build(':diy')},
|
|
23
|
-
{title: '不继承系统控制器', url: this.$url.build('not_extend_sys_controller/index')},
|
|
24
|
-
{title: '分页测试', url: this.$url.build('/pagination')},
|
|
25
|
-
{title: 'url生成测试', url: this.$url.build('url')},
|
|
26
|
-
{title: 'Cookie测试', url: this.$url.build('cookie')},
|
|
27
|
-
{title: 'Context测试', url: this.$url.build('context')},
|
|
28
|
-
{title: 'Exception测试', url: this.$url.build('exception')},
|
|
29
|
-
{title: '成功提示', url: this.$url.build('success')},
|
|
30
|
-
{title: '错误提示', url: this.$url.build('error')},
|
|
31
|
-
{title: '302跳转', url: this.$url.build('redirect')},
|
|
32
|
-
{title: 'show object', url: this.$url.build('show')},
|
|
33
|
-
];
|
|
34
|
-
|
|
35
|
-
this.$assign('title', 'jj.js - 一个简单轻量级Node.js MVC框架');
|
|
36
|
-
this.$assign('link_list', link_list);
|
|
37
|
-
await this.$fetch();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async showStr() {
|
|
41
|
-
this.$show(`<!doctype html>
|
|
42
|
-
<html>
|
|
43
|
-
<head>
|
|
44
|
-
<meta charset="utf-8">
|
|
45
|
-
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
|
46
|
-
<title>jj.js</title>
|
|
47
|
-
<link rel="stylesheet" href="/static/lit.css">
|
|
48
|
-
<style>.c{max-width:48em;}</style>
|
|
49
|
-
</head>
|
|
50
|
-
<body style="margin:0;">
|
|
51
|
-
<div class="c">
|
|
52
|
-
<h1>jj.js</h1>
|
|
53
|
-
<hr>
|
|
54
|
-
<div>控制器输出字符串。</div>
|
|
55
|
-
<hr>
|
|
56
|
-
<div>
|
|
57
|
-
<a class="btn" href="javascript:history.go(-1);" style="display: inline-block;">返回</a>
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
60
|
-
</body>
|
|
61
|
-
</html>`);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async loadFile() {
|
|
65
|
-
let readme = await this.$view.load('/../README.md');
|
|
66
|
-
readme = readme.replace('</p>', '</p><hr>');
|
|
67
|
-
this.$assign('content', readme);
|
|
68
|
-
await this.$fetch('view');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async middleTest() {
|
|
72
|
-
this.$assign('content', '请查看控制台输出!');
|
|
73
|
-
await this.$fetch('view');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async cache() {
|
|
77
|
-
const cache = this.$cache;
|
|
78
|
-
Logger.info(Cache === cache, Cache.get === cache.get, Cache.get() === cache.get());
|
|
79
|
-
Logger.info('---------------------------');
|
|
80
|
-
Logger.info(JSON.stringify(Cache.get()), JSON.stringify(cache.get()));
|
|
81
|
-
const key1_value = Cache.get('key1');
|
|
82
|
-
Cache.set('key1', key1_value ? key1_value+1 : 1, 10000);
|
|
83
|
-
cache.set('key2', key1_value ? key1_value+100 : 100, 10000);
|
|
84
|
-
Logger.info('---------------------------');
|
|
85
|
-
Logger.info(JSON.stringify(Cache.get()), JSON.stringify(cache.get()));
|
|
86
|
-
|
|
87
|
-
this.$assign('content', '请查看控制台输出!');
|
|
88
|
-
await this.$fetch('view');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async log() {
|
|
92
|
-
this.$logger.info('logger.info');
|
|
93
|
-
Logger.error('logger.error');
|
|
94
|
-
Logger.warning('logger.warning');
|
|
95
|
-
Logger.debug('logger.debug');
|
|
96
|
-
Logger.sql('logger.sql');
|
|
97
|
-
Logger.http('logger.http');
|
|
98
|
-
Logger.log('logger.log');
|
|
99
|
-
Logger.log('logger.diy', 'diy');
|
|
100
|
-
Logger.info(1, 2, 3);
|
|
101
|
-
|
|
102
|
-
// 自定义handle
|
|
103
|
-
Logger.setHandle(function(msg, level) {
|
|
104
|
-
console.log(`[${level}] [${msg}]`)
|
|
105
|
-
});
|
|
106
|
-
Logger.info('自定义handle');
|
|
107
|
-
|
|
108
|
-
//重置系统handle
|
|
109
|
-
Logger.setHandle();
|
|
110
|
-
Logger.info('重置系统handle');
|
|
111
|
-
|
|
112
|
-
this.$assign('content', '请查看控制台输出!');
|
|
113
|
-
await this.$fetch('view');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async pagination() {
|
|
117
|
-
let html = new Pagination(this.ctx).init({key_origin: 'params', url_index: '/pagination', url_page: '/pagination/list_${page}.html'}).total(200).render();
|
|
118
|
-
|
|
119
|
-
const css = `<style>
|
|
120
|
-
.page{display:flex;}
|
|
121
|
-
.page li{list-style:none;margin:5px;}
|
|
122
|
-
.page li a{display:block;padding:5px 10px;border:1px solid blue;text-decoration:none;color:inherit;}
|
|
123
|
-
.page li.active a,.page li:hover a{background-color:blue;color:#fff;}
|
|
124
|
-
</style>`;
|
|
125
|
-
html += css;
|
|
126
|
-
|
|
127
|
-
const page2 = this.$pagination.my_pagination.render(200);
|
|
128
|
-
html += page2;
|
|
129
|
-
|
|
130
|
-
this.$assign('content', html);
|
|
131
|
-
await this.$fetch('view');
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async url() {
|
|
135
|
-
const url = new Url(this.ctx);
|
|
136
|
-
const arr = [];
|
|
137
|
-
arr.push(url.build());
|
|
138
|
-
arr.push(url.build('cate', '/'));
|
|
139
|
-
arr.push(url.build('index/cate', '.html'));
|
|
140
|
-
arr.push(url.build('index/index/cate', '.html'));
|
|
141
|
-
arr.push(url.build('app/index/index/cate', '.html'));
|
|
142
|
-
arr.push(url.build('/app/index/index/cate', '.html'));
|
|
143
|
-
arr.push(url.build('test', {var: 'test', var2: 'test2'}, '.html'));
|
|
144
|
-
arr.push(url.build('test?var3=vvv', {var: 'test', var2: 'test2'}, '.html'));
|
|
145
|
-
arr.push(url.build('test?var=vvv', {var: 'test', var2: 'test2'}, '.html'));
|
|
146
|
-
arr.push(url.build('index/cate#'));
|
|
147
|
-
arr.push(url.build('index/cate#', {var: 'test', var2: 'test2'}, '.html'));
|
|
148
|
-
arr.push(url.build('test?var=vvv#bbb', {var: 'test', var2: 'test2'}, '.html'));
|
|
149
|
-
arr.push(url.build(':test', {var1: 'test', var2: 'test2', var3: 'test3'}, '.html'));
|
|
150
|
-
arr.push(url.build(':diy'));
|
|
151
|
-
arr.push(url.build(':show'));
|
|
152
|
-
arr.push(url.build('showStr'));
|
|
153
|
-
arr.push(url.build('index/loadFile'));
|
|
154
|
-
|
|
155
|
-
this.$assign('content', arr.join('<br>'));
|
|
156
|
-
await this.$fetch('view');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async cookie() {
|
|
160
|
-
const cookie = new Cookie(this.ctx);
|
|
161
|
-
let value = cookie.get('cookie_test');
|
|
162
|
-
if(!value) {
|
|
163
|
-
value = 1;
|
|
164
|
-
} else {
|
|
165
|
-
value = parseInt(value) + 1;
|
|
166
|
-
}
|
|
167
|
-
cookie.set('cookie_test', value);
|
|
168
|
-
cookie.set('cookie_test2', 'value2', {maxAge: 1000 * 3600});
|
|
169
|
-
cookie.set('cookie_test3', 'value3', {expires: new Date('2020-07-06')});
|
|
170
|
-
|
|
171
|
-
this.$assign('content', `cookie_value: ${value}`);
|
|
172
|
-
await this.$fetch('view');
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
async context() {
|
|
176
|
-
this.$logger.info(JSON.stringify(this.$controller.__node)); // 自动定位到当前应用controller目录
|
|
177
|
-
this.$logger.info(JSON.stringify(this.$diy.__node)); // 自动定位到当前应用diy目录
|
|
178
|
-
this.$logger.info(JSON.stringify(this.$logic.__node)); // 自动定位到公共应用logic目录
|
|
179
|
-
this.$logger.info(JSON.stringify(this.$app.__node)); // 自动定位到当前应用根目录
|
|
180
|
-
this.$logger.info(JSON.stringify(this.$url.__node)); // 自动定位到系统类库url文件
|
|
181
|
-
this.$logger.info(JSON.stringify(this.$utils.__node)); // 自动定位到系统类库utils目录
|
|
182
|
-
this.$logger.info(JSON.stringify(this.$.__node)); // 强制定位到系统类库目录
|
|
183
|
-
this.$logger.info(JSON.stringify(this._.__node)); // 强制定位到项目根目录
|
|
184
|
-
this.$assign('content', '请查看控制台输出!');
|
|
185
|
-
await this.$fetch('view');
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
async exception() {
|
|
189
|
-
// throw new Error('异常测试');
|
|
190
|
-
this.$response.exception(new Error('异常测试'));
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
async success() {
|
|
194
|
-
this.$success();
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async error() {
|
|
198
|
-
this.$error();
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
async redirect() {
|
|
202
|
-
this.$redirect('/');
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async show() {
|
|
206
|
-
this.$show({data: 'object'});
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
async mysql() {
|
|
210
|
-
const db = new Db(this.ctx);
|
|
211
|
-
|
|
212
|
-
await db.startTrans();
|
|
213
|
-
await db.startTrans();
|
|
214
|
-
await db.startTrans();
|
|
215
|
-
await db.commit();
|
|
216
|
-
await db.commit();
|
|
217
|
-
await db.commit();
|
|
218
|
-
|
|
219
|
-
await this.$db.startTrans();
|
|
220
|
-
await this.$db.startTrans();
|
|
221
|
-
await this.$db.startTrans();
|
|
222
|
-
await this.$db.commit();
|
|
223
|
-
await this.$db.commit();
|
|
224
|
-
await this.$db.commit();
|
|
225
|
-
|
|
226
|
-
this.$assign('content', '请查看控制台输出!');
|
|
227
|
-
await this.$fetch('view');
|
|
228
|
-
|
|
229
|
-
// const list = await db.table('article a').field('a.title, a.id, a.click, c.c_name').join('cate c', 'c.id=a.cate_id').where({'a.click': ['in', '102,201'], source: ['=', 'me', 'or']}).where({add_time: 2, update_time: 0}, 'or').where({add_time: ['>=', 0], update_time: 0}).group('add_time').having('add_time>1').order('a.id', 'desc').limit(0, 10).select();
|
|
230
|
-
|
|
231
|
-
// const Arc = require('../model/article');
|
|
232
|
-
// const model_article = new Arc(this.ctx);
|
|
233
|
-
// const [list2, list3, list4] = await Promise.all([
|
|
234
|
-
// model_article.db.find(),
|
|
235
|
-
// this.$model.article.db.find(),
|
|
236
|
-
// this.$model.article.db.page(2, 3).select()
|
|
237
|
-
// ]);
|
|
238
|
-
//const list2 = model_article.db.find();
|
|
239
|
-
//const list3 = this.ctx.$app.model.article.db.find();
|
|
240
|
-
//const list4 = this.ctx.$app.model.article.db.page(2, 3).select();
|
|
241
|
-
//const data = {"cate_id":2,"user_id":0,"title":"测试文章","writer":"雨思","source":"me","source_link":"","click":200,"keywords":"测试,文章","description":"这是一篇测试文章","content":"测试文章测试'文章测试文章内容"};
|
|
242
|
-
//const data2 = {"cate_id":2,"user_id":0,"title":"rtrtrt","writer":"雨思","source":"me","source_link":"","click":200,"keywords":"测试,文章","description":"这是一篇测试文章","content":"test'cccccc"};
|
|
243
|
-
//Logger.info(await model_article.db.table('article').getSql().insert(data));
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
//this.ctx.body = {list, list2, list3, list4};
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
module.exports = Index;
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
class NotExtendSysController
|
|
2
|
-
{
|
|
3
|
-
constructor(ctx) {
|
|
4
|
-
this.ctx = ctx;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
async index() {
|
|
8
|
-
this.ctx.body = `<!doctype html>
|
|
9
|
-
<html>
|
|
10
|
-
<head>
|
|
11
|
-
<meta charset="utf-8">
|
|
12
|
-
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
|
13
|
-
<title>jj.js</title>
|
|
14
|
-
<link rel="stylesheet" href="/static/lit.css">
|
|
15
|
-
<style>.c{max-width:48em;}</style>
|
|
16
|
-
</head>
|
|
17
|
-
<body style="margin:0;">
|
|
18
|
-
<div class="c">
|
|
19
|
-
<h1>jj.js</h1>
|
|
20
|
-
<hr>
|
|
21
|
-
<div>不继承系统控制器。</div>
|
|
22
|
-
<hr>
|
|
23
|
-
<div>
|
|
24
|
-
<a class="btn" href="javascript:history.go(-1);" style="display: inline-block;">返回</a>
|
|
25
|
-
</div>
|
|
26
|
-
</div>
|
|
27
|
-
</body>
|
|
28
|
-
</html>`;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
module.exports = NotExtendSysController;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const {Controller, Logger} = require('../../../jj.js');
|
|
2
|
-
|
|
3
|
-
class DiyController extends Controller
|
|
4
|
-
{
|
|
5
|
-
async _init() {
|
|
6
|
-
Logger.info('_init');
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
async index() {
|
|
10
|
-
this.$assign('url_str', ':diy');
|
|
11
|
-
this.$assign('content', '自定义控制器层!');
|
|
12
|
-
await this.$fetch('index/view');
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
module.exports = DiyController;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
//const {Middleware} = require('jj.js');
|
|
2
|
-
const {Middleware, Logger} = require('../../../jj.js');
|
|
3
|
-
|
|
4
|
-
class Index extends Middleware
|
|
5
|
-
{
|
|
6
|
-
async middle() {
|
|
7
|
-
Logger.info('中间件:输出之前');
|
|
8
|
-
await this.$next();
|
|
9
|
-
Logger.info('中间件:输出之后');
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
async auth() {
|
|
13
|
-
Logger.info('auth:在这里验证登录');
|
|
14
|
-
await this.$next();
|
|
15
|
-
Logger.info('auth:业务完成时调用');
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
module.exports = Index;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
const {Logger} = require('../../../jj.js');
|
|
2
|
-
|
|
3
|
-
module.exports = class {
|
|
4
|
-
constructor(ctx, next) {
|
|
5
|
-
this.ctx = ctx;
|
|
6
|
-
this.$next = next;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
async test() {
|
|
10
|
-
Logger.info('middle1 test start');
|
|
11
|
-
this.ctx.body = `<!doctype html>
|
|
12
|
-
<html>
|
|
13
|
-
<head>
|
|
14
|
-
<meta charset="utf-8">
|
|
15
|
-
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
|
16
|
-
<title>jj.js</title>
|
|
17
|
-
<link rel="stylesheet" href="/static/lit.css">
|
|
18
|
-
<style>.c{max-width:48em;}</style>
|
|
19
|
-
</head>
|
|
20
|
-
<body style="margin:0;">
|
|
21
|
-
<div class="c">
|
|
22
|
-
<h1>jj.js</h1>
|
|
23
|
-
<hr>
|
|
24
|
-
<div>路由到中间件,中间件输出内容,实际应用中不建议这种操作。</div>
|
|
25
|
-
<hr>
|
|
26
|
-
<div>
|
|
27
|
-
<a class="btn" href="javascript:history.go(-1);" style="display: inline-block;">返回</a>
|
|
28
|
-
</div>
|
|
29
|
-
</div>
|
|
30
|
-
</body>
|
|
31
|
-
</html>`;
|
|
32
|
-
|
|
33
|
-
// 执行$next,将继续向下匹配路由
|
|
34
|
-
//await this.$next();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async end() {
|
|
38
|
-
Logger.info('middle1 end');
|
|
39
|
-
await this.$next();
|
|
40
|
-
Logger.info('middle1 end await');
|
|
41
|
-
}
|
|
42
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
const {Logger} = require('../../../jj.js');
|
|
2
|
-
|
|
3
|
-
module.exports = class {
|
|
4
|
-
constructor(ctx, next) {
|
|
5
|
-
this.ctx = ctx;
|
|
6
|
-
this.$next = next;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
async start() {
|
|
10
|
-
Logger.info('middle2 start');
|
|
11
|
-
await this.$next();
|
|
12
|
-
Logger.info('middle2 start await');
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async end() {
|
|
16
|
-
Logger.info('middle2 end');
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{{extend './layout.htm'}}
|
|
2
|
-
{{block 'title'}}
|
|
3
|
-
<title>{{title}}</title>
|
|
4
|
-
{{/block}}
|
|
5
|
-
{{block 'content'}}
|
|
6
|
-
<div class="c">
|
|
7
|
-
{{@content}}
|
|
8
|
-
<ul>
|
|
9
|
-
<li>{{url()}}</li>
|
|
10
|
-
<li>{{url('cate', '/')}}</li>
|
|
11
|
-
<li>{{url('cate/cate', '.html')}}</li>
|
|
12
|
-
<li>{{url('cate/index/cate', '.html')}}</li>
|
|
13
|
-
<li>{{url('test', {var: 'test', var2: 'test2'}, '.html')}}</li>
|
|
14
|
-
<li>{{url('test?var3=vvv', {var: 'test', var2: 'test2'}, '.html', 'http://www.baidu.com')}}</li>
|
|
15
|
-
<li>{{url('test?var=vvv', {var: 'test', var2: 'test2'}, '.html')}}</li>
|
|
16
|
-
<li>{{url('index/cate#')}}</li>
|
|
17
|
-
<li>{{url('test?var=vvv#bbb', {var: 'test', var2: 'test2'}, '.html')}}</li>
|
|
18
|
-
<li>{{url(':name', {var: 'test', var2: 'test2', var3: 'test3'}, '.html')}}</li>
|
|
19
|
-
</ul>
|
|
20
|
-
</div>
|
|
21
|
-
{{/block}}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{{extend './layout.htm'}}
|
|
2
|
-
{{block 'title'}}
|
|
3
|
-
<title>{{title}}</title>
|
|
4
|
-
{{/block}}
|
|
5
|
-
{{block 'content'}}
|
|
6
|
-
<div class="c">
|
|
7
|
-
<h1>jj.js</h1>
|
|
8
|
-
<hr>
|
|
9
|
-
<div>本页地址:{{url()}}</div>
|
|
10
|
-
<hr>
|
|
11
|
-
<div>功能测试,部分功能需在控制台查看输出。</div>
|
|
12
|
-
<ul>
|
|
13
|
-
{{each link_list}}
|
|
14
|
-
<li><a href="{{$value.url}}">{{$value.title}}</a></li>
|
|
15
|
-
{{/each}}
|
|
16
|
-
</ul>
|
|
17
|
-
</div>
|
|
18
|
-
{{/block}}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
|
6
|
-
<title>jj.js</title>
|
|
7
|
-
<link rel="stylesheet" href="/static/lit.css">
|
|
8
|
-
<style>.c{max-width:48em;}</style>
|
|
9
|
-
</head>
|
|
10
|
-
<body style="margin:0;">
|
|
11
|
-
<div class="c">
|
|
12
|
-
<h1>jj.js</h1>
|
|
13
|
-
<hr>
|
|
14
|
-
<div>路由直接输出模版文件内容。</div>
|
|
15
|
-
<hr>
|
|
16
|
-
<div>
|
|
17
|
-
<a class="btn" href="javascript:history.go(-1);" style="display: inline-block;">返回</a>
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
</body>
|
|
21
|
-
</html>
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{{extend './layout.htm'}}
|
|
2
|
-
{{block 'title'}}
|
|
3
|
-
<title>{{title}}</title>
|
|
4
|
-
{{/block}}
|
|
5
|
-
{{block 'content'}}
|
|
6
|
-
<div class="c">
|
|
7
|
-
<h1>jj.js</h1>
|
|
8
|
-
<hr>
|
|
9
|
-
<div>本页地址:{{url(url_str)}}</div>
|
|
10
|
-
<hr>
|
|
11
|
-
{{@content}}
|
|
12
|
-
<hr>
|
|
13
|
-
<div>
|
|
14
|
-
<a class="btn" href="javascript:history.go(-1);" style="display: inline-block;">返回</a>
|
|
15
|
-
</div>
|
|
16
|
-
</div>
|
|
17
|
-
{{/block}}
|
package/test/app/view/layout.htm
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
|
6
|
-
{{block 'title'}}<title>jj.js</title>{{/block}}
|
|
7
|
-
{{block 'css'}}<link rel="stylesheet" href="/static/lit.css">
|
|
8
|
-
<style>.c{max-width:48em;}</style>{{/block}}
|
|
9
|
-
</head>
|
|
10
|
-
<body style="margin:0;">
|
|
11
|
-
{{block 'content'}}{{/block}}
|
|
12
|
-
{{block 'js'}}{{/block}}
|
|
13
|
-
</body>
|
|
14
|
-
</html>
|
package/test/config/app.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
const app = {
|
|
2
|
-
app_debug: true, //调试模式
|
|
3
|
-
app_multi: false, //是否开启多应用
|
|
4
|
-
|
|
5
|
-
default_app: 'app', //默认应用
|
|
6
|
-
default_controller: 'index', //默认控制器
|
|
7
|
-
default_action: 'index', //默认方法
|
|
8
|
-
|
|
9
|
-
common_app: 'common', //公共应用,存放公共模型及逻辑
|
|
10
|
-
controller_folder: 'controller', //控制器目录名
|
|
11
|
-
|
|
12
|
-
static_dir: './public', //静态文件目录,相对于应用根目录,为空或false时,关闭静态访问
|
|
13
|
-
|
|
14
|
-
koa_body: null //koa-body配置参数,为''、null、false时,关闭koa-body
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
module.exports = app;
|
package/test/config/routes.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
routes = [
|
|
2
|
-
{url: '/hello/', path: 'index/hello', method: 'get', type: 'middleware'},
|
|
3
|
-
{url: '/show', path: async (ctx, next) => {ctx.body = `<!doctype html>
|
|
4
|
-
<html>
|
|
5
|
-
<head>
|
|
6
|
-
<meta charset="utf-8">
|
|
7
|
-
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
|
8
|
-
<title>jj.js</title>
|
|
9
|
-
<link rel="stylesheet" href="/static/lit.css">
|
|
10
|
-
<style>.c{max-width:48em;}</style>
|
|
11
|
-
</head>
|
|
12
|
-
<body style="margin:0;">
|
|
13
|
-
<div class="c">
|
|
14
|
-
<h1>jj.js</h1>
|
|
15
|
-
<hr>
|
|
16
|
-
<div>路由直接输出内容。</div>
|
|
17
|
-
<hr>
|
|
18
|
-
<div>
|
|
19
|
-
<a class="btn" href="javascript:history.go(-1);" style="display: inline-block;">返回</a>
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
22
|
-
</body>
|
|
23
|
-
</html>`;}, method: 'get', name: 'show'},
|
|
24
|
-
{url: '/index/template', path: '/index/template', type: 'view'},
|
|
25
|
-
{url: '/index/middleware', path: 'middle1/test', type: 'middleware'},
|
|
26
|
-
{url: '/diy', path: 'diy_controller/index', type: 'diy', name: 'diy'},
|
|
27
|
-
{url: '/pagination', path: 'index/pagination', method: 'get'},
|
|
28
|
-
{url: '/pagination/list_:page.html(.*)', path: 'index/pagination', method: 'get'},
|
|
29
|
-
{url: '/file', path: 'index/index', method: 'get', type: 'view'},
|
|
30
|
-
{url: '/test/:var1/:var2/:var3', path: 'index/index', method: 'get', name: 'test'},
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
module.exports = routes;
|
package/test/config/view.js
DELETED
package/test/public/favicon.ico
DELETED
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
*+*{box-sizing:border-box;margin:.5em 0}@media(min-width:35em){.col{display:table-cell}.\31{width:5%}.\33{width:22%}.\34{width:30%}.\35{width:40%}.\32{width:15%}.row{display:table;border-spacing:1em 0}}.row,.w-100{width:100%}.card:focus,hr{outline:0;border:solid #fa0}.card,pre{padding:1em;border:solid #eee}.btn:hover,a:hover{opacity:.6}.c{max-width:60em;padding:1em;margin:auto;font:1em/1.6 nunito}h6{font:300 1em nunito}h5{font:300 1.2em nunito}h3{font:300 2em nunito}h4{font:300 1.5em nunito}h2{font:300 2.2em nunito}h1{font:300 2.5em nunito}a{color:#fa0;text-decoration:none}.btn.primary{color:#fff;background:#fa0;border:solid #fa0}pre{overflow:auto}td,th{padding:1em;text-align:left;border-bottom:solid #eee}.btn{cursor:pointer;padding:1em;letter-spacing:.1em;text-transform:uppercase;background:#fff;border:solid;font:.7em nunito}
|