entity-frame

entity-frame === 欢迎使用entity-frame框架,如果是使用过asp.net core的mvc框架的码友应该会有亲切感,本框架还在测试阶段,Bug欢迎留言反馈,给你们带来的麻烦我十分抱歉。邮箱:19815488@qq.com。

Usage no npm install needed!

<script type="module">
  import entityFrame from 'https://cdn.skypack.dev/entity-frame';
</script>

README

entity-frame

欢迎使用entity-frame框架,如果是使用过asp.net core的mvc框架的码友应该会有亲切感,本框架还在测试阶段,Bug欢迎留言反馈,给你们带来的麻烦我十分抱歉。邮箱:19815488@qq.com。

2.0 后将使用ES6的标准重新编写。

无http服务版本、http/https服务移步:https://www.npmjs.com/package/internet-information-services

Bug记录

2017.12.21 影响版本 0.8.17- 没有opt.localDB和opt.mongoDB引起的错误

2017.12.23 影响版本 0.8.24- 没有mongoDB Cursor Closed引起的错误

2018.01.09 影响版本 1.1.0- IE浏览器下mime类型的错误。

新变动

  • mongodb版本

1.1.6

mongodb使用3.0以上版本

  • 返回mongodb对象

1.1.3

如果使用mongodb的话会在context.onsuccess返回mongodb对象。

mongodb.ObjectId(id)

  • 添加mime类型的对象

1.1.0

opt.mime = {mp3: "audio/mpeg"};

  • 增加全局对象 global 可在路由方法和视图中使用

0.9.0 添加自动生成{static}/index.html,加入 测试记录.html 文件

opt.global

数据库支持

本框架支持indexeddb或mongoDB

npm install indexeddb-js sqlite3

npm install mongodb

实例

引用框架

var ef = require("entity-frame");

初始化

var context = ef.init(          //初始化
    {
        project: project,       //Object (必须)      项目主体
        // gateway: gateway,    //Function          每次网络请求都会调用此回调
        // port: 8080,          //String,Number     监听端口
        // static: "wwwroot",   //String            静态文件目录
        // mime: {mp3: "audio/mpeg"},   //Object	mime类型的对象
        // html: '{/head}\n\n{/foot}',  //String    自定义全局模板
        // shared: shared,      //Array             共享模板数组
        // global: global,      //Onject            全局对象
        // lang: "zh-cn",       //String            本地化
        // charset: "UTF-8",    //String            html编码
        // localDB: "idb"       //String            本地数据库名称
        // mongoDB: "mongodb://localhost:27017/mdb" //String    mongoDB数据库连接字符串
    }
);
context.onsuccess = function (db, mongodb) { //数据库连接成功回调,如果使用mongodb的话会返回mongodb对象。

    console.log("数据库连接成功。");
};

参数详细说明

opt.gateway

...
    gateway: function (scope) {
    
        scope.Auth          //Object    身份验证信息
        scope.global        //Object    全局对象
        scope.controller    //String    控制器名称
        scope.action        //String    方法名称
        scope.filter        //String    过滤器名称
        scope.id            //String    id值
        scope.method        //String    请求方法 get、post、put、delete
        scope.redirect      //Function  重定向方法 arg1=/*url*/
        scope.request       //Object    Node.js http的request对象
        scope.response      //Object    Node.js http的response对象
        scope.request.headers["content-length"] //Int 请求数据的大小
        
        return false;       //将拒绝该次请求
    },
...

实例

function gateway(scope) {

    if (scope.Auth.Role !== "admin" && scope.controller === "admin" && scope.action !== "login") {

        scope.redirect("/admin/login");

        return false;
    }

    if (scope.Auth.Role !== "admin"
        && (scope.controller === "user" && scope.action === "list")) {

        scope.redirect("/home");

        return false;
    }
    
    ...
    //也可以在这里编写防攻击、恶意访问逻辑,return false;将拒绝该次请求
}

opt.post 设置监听端口默认值为 80

opt.static 设置静态目录默认值为 "wwwroot"

opt.html 设置自定义全局模板

默认值为:

<!DOCTYPE html>
<html lang="{lang}">
<head>
    <meta charset="{charset}">
    <title>{controller} - {action} {filter}</title>
</head>
<body>

</body>
</html>

opt.lang 设置默认模板的本地化

opt.charset 设置默认模板的编码

opt.localDB 使用本地数据库indexeddb的数据库名称,须引用 npm install indexeddb-js sqlite3,如果不使用就不用引入。

opt.mongoDB 使用mongoDB的连接字符串,须引用npm install mongodb@2.2.33,暂时支持2.2.33,还需打开mongoDB服务,移步http://www.runoob.com/mongodb/mongodb-window-install.html,如果不使用就不用引入。

  • 重要参数

opt.shared 共享模板目录

引用结构:{/{path}/{file}}

模板文件将自动生成在views下shared文件夹中

opt.shared = ["head", "foot", "user/head", "user/foot", "templet/partial/page"];

自动生成的文件结构

views ─ shared ┬ head.html
               ├ foot.html
               ├ user ─────┬ head.html
               │           └ foot.html
               └ templet ─── partial ── page.html

实例

<html>
{/user/head}
<div>内容1</div>
{/templet/partial/page}
<div>内容2</div>
{/foor}
</html>

opt.project 项目的主要重要结构和逻辑处理中心

路由结构:://{domain}/{controller}/{action}/{filter}/{id}

var project = {
    controller1: {
        action1: {
            filter1: ...,
            filter2: ...,
            ...
        },
        action2: ...,
        ...
    },
    controller2: ...,
    ...
};

视图文件将自动生成在views文件夹中

views ┬ controller1 ┬ action1 ┬ filter1
      │             │         ├ filter2
      │             │         └ ...
      │             ├ action2
      │             │
      │             └ ...
      ├ controller2
      │
      └ ...

实例1

var project = { //大小写不敏感
    LOG: {
        Add: function (scrop) { // todo },
        list: function (scrop) { // todo }
    },
    admin: function (scrop) { // todo },
    user: {
        index: null,
        login: function (scrop) { // todo },
        logon: function (scrop) { // todo },
        logout: function (scrop) { // todo },
        vip: {
            index: null,
            logout: null
        },
        svip: {
            index: null,
            logout: function (scrop) { // todo }
        }
    }
};

自动生成的文件结构

views ┬ log ──┬─── add.html
      │       └── list.html
      ├ admin ── index.html
      └ user ─┬─ index.html
              ├─ login.html
              ├─ logon.html
              ├ logout.html
              ├ vip ────────┬─ index.html
              │             └ logout.html
              └ svip ───────┬─ index.html
                            └ logout.html

请求(实例1)

参数方式1:filter, id;

://domain/log/list/user/201712

路由到方法 project.log.list(scope)

方法中使用:

scope.where(l => l.filter === scope.filter && l.data >= scope.id).onsuccess = function (list) {
    list.forEach(log) { //todo };
};

页面内使用

<html>
<body>
<h2>{filter}</h2>
日期:{id}
...
</body>
</html>

参数方式2:querystring;

://domain/log/list?filter=user&date=201712

路由到方法 project.log.list(scope)

方法中使用:

scope.where(l => l.filter === scope.query.filter && l.data >= scope.query.date).onsuccess = function (list) {
    list.forEach(log) { //todo };
};

页面内使用

<html>
<body>
<h2>{query.filter}</h2>
日期:{query.date}
...
</body>
</html>

参数方式3:data; //post,put,delete

://domain/log/list

路由到方法 project.log.list(scope)

方法中使用:

scope.where(l => l.filter === scope.data.filter && l.data >= scope.data.date).onsuccess = function (list) {
    list.forEach(log) { //todo };
};

//文件上传处理
scope.data.file1.save("file", "f1.jpg");//异步处理
//scope.data.file1.save("file", "f1.jpg", true);//同步处理

//参数缺省,如:<input type="file" name="i1" /> //type: image/jpeg
//scope.data.file1.save("file"); 等价 scope.data.file1.save("file", "i1.jpeg");

页面内使用

<html>
<body>
<h2>{data.filter}</h2>
日期:{data.date}
...
</body>
</html>

参数方式4:混合使用

://domain/log/list/user?date=201712

路由到方法 project.log.list(scope)

方法中使用:

scope.where(l => l.filter === scope.filter && l.data >= scope.query.date).onsuccess = function (list) {
    list.forEach(log) { //todo };
};

//文件上传处理
scope.data.file1.save("file", "f1.jpg");//异步处理
//scope.data.file1.save("file", "f1.jpg", true);//同步处理

//参数缺省,如:<input type="file" name="i1" /> //type: image/jpeg
//scope.data.file1.save("file"); 等价 scope.data.file1.save("file", "i1.jpeg");

页面内使用

<html>
<body>
<h2>{filter}</h2>
日期:{data.date}
...
</body>
</html>

服务器端脚本

<script server>

    // todo
    
</script>

循环5个div

1、//不推荐

<script server>

    for (var i = 0; i < 5; i++)
    
        <div>{id}</div>
    
</script>

2、//推荐

<script server>

    for (var i = 0; i < 5; i++)
    
        '<div>{0}</div>'.format(i);
    
</script>

3、

<script server>

    for (var i = 0; i < 5; i++)
    
        document.write('<div>{0}</div>'.format(i));
    
</script>

可以使用路由到的方法传递过来的数据,默认为scope的数据

<script server>

    "" + scope.method;
    
    "name: {query.name}, age: {query.age}.".format(scope);
    
    if (!scope.Auth.user)
    
        scope.redirect("/user/login");
        
    else
    
        '<h4>登录成功,正在跳转</h4><meta http-equiv="Refresh" content="1; url=/home" />';
    
</script>

数据库使用

如果配置了数据库context.onsuccess会返回一个数据库context实例,数据库自动按照控制器生成对应的数据表,context里面就有相应的表实体。

如 实例1:

context.user
context.admin
context.log
context.log.add({title: "Login", date: Date.now()}).onsuccess = function (ev) {};
context.log.add([{title: "Logon", date: Date.now()}, {title: "Login", date: Date.now()}]).onsuccess = function (ev) {};

//在controller对应的action中
scope.add({title: "Login", date: Date.now()}).onsuccess = function (ev) {};
scope.add([{title: "Logon", date: Date.now()}, {title: "Login", date: Date.now()}]).onsuccess = function (ev) {};

查一个

context.user.default(u => u.uid === Uid && u.pwd === Pwd).onsuccess = function (result) {
    if (result === null)
        ;// todo
    else
        ;// todo 
}
//在controller对应的action中
scope.default(u => u.uid === scope.data.uid && u.pwd === scope.data.pwd).onsuccess = function (result) {
    if (result === null)
        ;// todo
    else
        ;// todo 
}

查多个

context.log.where(l => l.title === "Login").onsuccess = function (arr) {
    arr.forEach(function (l) { // todo });
}
//在controller对应的action中
scope.where(l => l.title === "Login").onsuccess = function (arr) {
    arr.forEach(function (l) { // todo });
}

分页

context.log.page(1, 10).onsuccess = function (arr, count) {
    arr.forEach(function (l) { // todo });
}
//在controller对应的action中
scope.page(1, 10).onsuccess = function (arr, count) {
    arr.forEach(function (l) { // todo });
}

总条数

context.log.count().onsuccess = function (count) {
    // todo
}
//在controller对应的action中
scope.count().onsuccess = function (count) {
    // todo
}
context.log.default(l => l.date === "201712").onsuccess = function (result) {
    if (result === null)
        ;// todo
    else {
        result.remark = "remark";
        result.update();
    }
}
context.log.where(l => l.title === "Login").onsuccess = function (arr) {
    arr.forEach(function (l) {
        l.remark = "login";
        l.update();
    });
}
//在controller对应的action中
scope.default(l => l.date === "201712").onsuccess = function (result) {
    if (result === null)
        ;// todo
    else {
        result.remark = "remark";
        result.update();
    }
}
scope.where(l => l.title === "Login").onsuccess = function (arr) {
    arr.forEach(function (l) {
        l.remark = "login";
        l.update();
    });
}
context.log.default(l => l.date === "201712").onsuccess = function (result) {
    if (result === null)
        ;// todo
    else
        result.delete();
}
context.log.where(l => l.title === "Login").onsuccess = function (arr) {
    arr.forEach(function (l) {
        l.delete();
    });
}
//在controller对应的action中
scope.default(l => l.date === "201712").onsuccess = function (result) {
    if (result === null)
        ;// todo
    else
        result.delete();
}
scope.where(l => l.title === "Login").onsuccess = function (arr) {
    arr.forEach(function (l) {
        l.delete();
    });
}

身份验证

action中

scope.Auth.User     //String
scope.Auth.Role     //String
scope.Auth.set      //Function arg: user, role, expiredays;
scope.Auth.clear    //Function

重定向

action中

scope.redirect  //Function arg: url;

等待异步处理完成

action中

setTimeout(function () {
    scope.date = Date.now();
    scope.async();
}, 1000);
context.user.default(u => u.uid === scope.query.uid).onsuccess = function (resault) {
    if (resault === null) {
        scope.msg = {rc: 1, rm: "用户不存在"};
        scope.async();
    } else
        scope.async({rc: 0, rm: "用户已存在"});
};
return false;//异步标志,任务被挂起,直到scope.async被执行。