1.19.0 • Published 2 years ago

maishu-nws-mvc v1.19.0

Weekly downloads
49
License
-
Repository
-
Last release
2 years ago

Node MVC

Node Web Server 的 MVC 插件。使用 typescript 开发,需要配合 typescript 和 Node Web Server 使用。

为什么要开发这个类库?

作者使用过的 mvc 框架包括:asp.net mvc,spring boot。后来在 nodejs 下做开发,使用过 node.js express,后来听别人介绍,也了解过 egg.js 等框架,但是 nodejs 的这些 web 开发框架,都不是作者想要的。于是开发 node-mvc ,作者在开发 node-mvc 的时候,充分借鉴了 asp.net mvc 的设计,甚至起名都借鉴了 ^_^ 。

安装

  1. Node MVC 是 Node Web Server 的一个插件,依赖于 Node Web Server,所以使用前先要安装 Node Web Server。

    npm i maishu-node-web-server -g
  2. 创建项目文件夹,在项目文件夹内进行安装

    npm i maishu-nws-mvc

    项目文件夹如下:

    demo
    ├── controllers
    ├── node_modules
    ├── static
    |   ├── index.html
    |   └── index.ts
    └── package.json

    其中 controllers 用于放置控制器文件,public 用于放置静态文件。

NODE-WEB-SERVER 配置

let w = new WebServer({
  websiteDirectory: 'your-website-path'
})

控制器的路径

控制器的路径默认为 websiteDirectory 文件夹的子文件夹 controllers。可以通过配置修改该路径。

例如:

下面的示例中把控制器的路径改为 my-controllers 。

let w = new WebServer({
  websiteDirectory: 'your-website-path',
  requestProcessorTypes: [
    MVCRequestProcessor,
    ...WebServer.defaultRequestProcessorTypes
  ],
  requestProcessorConfigs: {
    MVC: {
      controllersPath: 'my-controllers'
    }
  }
})

一分钟上手

  1. 创建 nodejs 项目文件夹,安装 node-mvc

    npm i maishu-node-mvc

    文件夹结构如下

    根目录
    ├── controllers
    |   └── home.ts
    ├── index.ts
    └── package.json
  2. 创建 index.ts 文件

    import { startServer } from 'maishu-node-mvc'
    startServer({
      port: 1234,
      rootPath: __dirname
    })
  3. 创建 controllers 文件夹

    在 controllers 文件夹下创建 home.ts 文件

    import { Controller } from 'maishu-node-mvc'
    
    export class Home extends Controller {
      @action('/')
      index () {
        return 'node mvc'
      }
    }
  4. 启动程序

    把 ts 文件转换为 js 文件,输入命令启动程序

    node index.js
  5. 在浏览器输入

    在浏览器输入 http://localhost:1234/ 显示

    node mvc

使用手册

服务器启动

使用 startServer 启动一个 node mvc 服务。例如:

const { startServer } = require('maishu-node-mvc')
startServer({
  port: 1234,
  rootPath: __dirname
})

完整的参数定义为:

 {
    port: number;
    rootPath: string;
    bindIP?: string;
    proxy?: {
        [path_pattern: string]: string | ProxyItem;
    };
    controllerDirectory?: string | string[];
    staticRootDirectory?: string;
    authenticate?: (req: http.IncomingMessage, res: http.ServerResponse) => Promise<{
        errorResult: ActionResult;
    }>;
    actionFilters?: ((req: http.IncomingMessage, res: http.ServerResponse) => Promise<ActionResult>)[];
    /** 设置默认的 Http Header */
    headers?: {
        [name: string]: string;
    };
    virtualPaths?: {
        [virtualPath: string]: string;
    };
}

参数有点多,我们先来看几个经常用到的:

参数名解释
port服务器监听的端口必填
rootPath文件件的根目录,必须为绝对路径必填
bindIP服务器绑定 IP,可为空可选
controllerDirectory控制器文件夹,绝对路径或者相对路径,如果是相对路径,则为 rootPath 的相对路径,默认值为 controllers选填
staticRootDirectory静态文件放置的路径,绝对路径或者相对路径,如果是相对路径,则为 rootPath 的相对路径,默认值为 public选填
proxy用于把请求转发到其他服务器选填
authenticate用于对用户身份进行认证选填
actionFiltersaction 过滤器,用于对 action 进行拦截选填

注册控制器

所有的控制器,都必须放在控制器文件夹或者其子文件内。注册控制器需要注意的是, 控制器类,必须继承于 Controller 或者使用 controller 装饰器标记。例如:

import { Controller } from 'maishu-node-mvc'

export class Home extends Controller {
  @action('/')
  index () {
    return 'node mvc'
  }
}
import { controller, Controller } from 'maishu-node-mvc'

@controller()
export class Home extends Controller {
  @action('/')
  index () {
    return 'node mvc'
  }
}

控制器的路径

controller 路径,在使用 controller 装饰器时,可以指定 controller 的路径。如果不指定,则为控制器的类名。例如:

import { Controller } from 'maishu-node-mvc'

@controller()
export class Home {}

controller 的路径名为 Home

import { Controller } from 'maishu-node-mvc'

@controller('/distributor/home')
export class Home {}

controller 的路径名为 /distributor/home

action 的路径

action 路径,在使用 action 装饰器时,可以指定 action 路径,action 装饰器的路径可以使用绝对路径(已/开头)和相对路径

* 使用绝对路径访问路径则为 action 设定的绝对路径。

* 使用相对路径则为 controller 路径 + action 路径。
  • action,controller 都不指定路径,访问路径为控制器的默认路径加上 action 的默认路径,例如:

    export class Home extends Controller {
      @action()
      index () {
        return 'node mvc'
      }
    
      @action()
      productList () {
        return 'product list'
      }
    }

    控制的默认路径为类名 Home ,index action 的默认路径名为方法名 index ,所以 index action 的访问路径,为 Home/index ;productList action 的默认路径为方法名 productList ,所以 productList action 的访问路径为 Home/productList

  • action 路径参数为绝对路径(已/开头),那么访问的路径则为指定的绝对路径,例如:

    import { controller, Controller } from 'maishu-node-mvc'
    
    @controller()
    export class Home extends Controller {
      @action('/')
      index () {
        return 'node mvc'
      }
    
      @action('/distributor/product/list')
      productList () {
        return 'product list'
      }
    }

    其中的 index,productList action 的访问路径分别为 //distributor/product/list

  • action 路径参数为为相对路径(不已/开头),例如:

    import { controller, Controller } from 'maishu-node-mvc'
    
    @controller('/distributor')
    export class Home extends Controller {
      @action()
      index () {
        return 'node mvc'
      }
    
      @action('product/list')
      productList () {
        return 'product list'
      }
    }

    其中的 index,productList action 的访问路径分别为 /distributor/index/distributor/product/list

action 返回的结果

默认情况情况下,action 返回给浏览器的结果可以分为两种情况:

  • 字符串,返回给浏览器的类型为 text/plain; charset=UTF-8

  • 对象,返回给浏览器的类型为 application/json; charset=UTF-8

例如:

export class Test extends Controller {
  @action()
  index () {
    return 'Hello World'
  }

  @action('/j')
  j () {
    return { a: 10, b: 10 }
  }
}

我们在来看一个例子:

export class Test extends Controller {
  @action()
  index () {
    return '<html><body><h1>Hello World</h1><body><html>'
  }
}

我们在浏览器看到的结果是:

<html>
  <body>
    Hello World
  </body>
</html>

这是因为返回给浏览器的类型为 text/plain; charset=UTF-8,我们都知道,要浏览器识别为 html ,需要制定 content-type 类型为 text/html; charset=UTF-8

使用 Controller 类中的 content 方法即可指定 content-type 类型。例如:

export class Test extends Controller {
  @action()
  index () {
    return this.content(
      '<html><body><h1>Hello World</h1><body><html>',
      'text/html; charset=UTF-8'
    )
  }
}

Controller 类方法:

名称含义
content指定返回给浏览器内容的类型
json指定返回给浏览器内容的类型为 json
redirect重定向到指定的链接
proxy请求转发

使用路由

node-mvc 内置了路由功能,使用的是 url-pattern ,该类库网址是 https://github.com/snd/url-pattern

关于路由的使用,我们先来看一个例子:

export class Test extends Controller {
  @action('/product/:id')
  product (@routeData { id }) {
    return id
  }
}

在浏览器输入:http://localhost:1234/product/1122 ,可以看到浏览器输出结果为:

1122

其中的 routeData 装饰器,除了用来获取路由解释的结果。还可以获取 url 参数和表单参数。

例如:

export class Test extends Controller {
  @action('/product/:id')
  product (@routeData { id, name }) {
    return `id: ${id}, name: ${name}`
  }
}

在浏览器输入:http://localhost:1234/product/1122?name=apple ,可以看到浏览器输出结果为:

id: 1122, name: apple

其中的 name 来自 url 参数

参数注入

在了解 node-mvc 的参数注入前,先来对比一下这两段代码,为什么要使用参数注入。

代码一:

import * as mysql from 'mysql'
import * as settings from './settings'
export class UserController {
  @action()
  async getUser () {
    let conn = mysql.createConnection(settings.conn.auth)
    try {
      // 查询数据库等操作
    } finally {
      conn.end()
    }
  }
}

代码二,使用参数注入方法:

export class UserController {
  @action()
  async getUser (@connection conn: Connection) {
    // 查询数据库等操作
  }
}

对比上面这两段代码,可以发现,代码二更为简洁,因为没有 try finally 这些代码。为什么通过参数注入的方式,不需要处理连接的关闭呢,这是因为,conn 是函数外传进来给函数使用的,由外部创建,也由外部销毁。

通过调用 createParameterDecorator 方法创建装饰器,然后在参数前面加上该装饰器,就可以把参数注入到函数中了。例如 @connection 的创建:

import * as mysql from 'mysql'
import * as settings from './settings'
import { createParameterDecorator } from 'maishu-node-mvc'
export let connection = createParameterDecorator(
  async () => {
    let conn = mysql.createConnection(settings.conn.auth)
    return conn
  },
  conn => {
    console.assert(conn != null)
    conn.end()
  }
)

createParameterDecorator 方法的第一个参数,为创建要注入的对象,第二个参数为销毁该对象的函数。第二个参数的函数,在 action 执行完成后进行调用。注意:进行数据库操作,要返回一个 Promise 对象。

1.19.0

2 years ago

1.18.0

2 years ago

1.17.0

2 years ago

1.15.0

3 years ago

1.14.0

3 years ago

1.13.0

3 years ago

1.12.0

3 years ago

1.11.0

3 years ago

1.10.2

3 years ago

1.10.0

3 years ago

1.9.0

3 years ago

1.8.0

3 years ago

1.7.4

3 years ago

1.7.3

3 years ago

1.7.2

3 years ago

1.7.0

3 years ago

1.6.0

3 years ago

1.5.0

3 years ago

1.4.0

3 years ago

1.3.2

3 years ago

1.3.1

3 years ago

1.2.4

3 years ago

1.2.3

3 years ago