它是一个 服务端渲染 的 MVC 框架。如果熟悉 Laravel 框架(PHP 框架),你会发现这是 Laravel 的一个 NodeJS 版本。如果你熟悉Laravel PHP框架的话,上手AdonisJS 就很容易了。它是Laravel的缩小版。
AdonisJS 文档 暂时没得中文文档
项目的结构
Http Server
Http Request
- AdonisJS 中,为了方便接收 HTTP 请求信息,所有的控制器方法和路由器闭包都会接收一个 Request 实例 。请看一下简单示例:
// 路由闭包中调用 request ,response
const Route = use('Route')
Route.get('post', function * (request, response) {
const body = request.all()
// cherry picking fields
const body = request.only('title', 'description', 'categories')
})
// 控制器中调用 request, response
class IndexController {
* index(requset, response) {
// ...
}
}
request.all()
:包括所有查询字符串和请求体:
const data = request.all()
// example.html?id=1&name=John
// <input name="gender" value="male" />
// => {"id":1, "name": "John", "gender": "male" }
request.only()
:跟 request.all() 类似,但是只包含定义的 key 值:
const data = request.only('name', 'email', 'age')
/* returns
{
'name': '..',
'email':'..',
'age':'..'
}
*/
request.input(key,[defaultValue])
:返回 input 标签对应的键值对,如果 value 为空,则返回 defaultValue:
const name = request.input('name')
const subscribe = request.input('subscribe', 'yes')
request.url()
:获取请求的 URL(出去查询字符串):
// url - http://foo.com/users?orderBy=desc&limit=10
request.url()
// returns - http://foo.com/users
request.param(key, [defaultValue])
:返回查询字符串:
// url - http://foo.com/users?orderBy=desc&limit=10
request.param('orderBy')
// returns - desc
// 返回所有的查询字符串
request.params()
request.collect(key1, key2, ...)
:转化数据格式,直接看下面例子:
<form method="POST" action="/users">
<div class="row">
<h2> User 1 </h2>
<input type="email" name="email[]" />
<input type="password" name="password[]" />
</div>
<div class="row">
<h2> User 2 </h2>
<input type="email" name="email[]" />
<input type="password" name="password[]" />
</div>
<button type="submit"> Create Users </button>
</form>
request.only('email', 'password', )
/* returns
{
email: ['bar@foo.com', 'baz@foo.com'],
password: ['secret', 'secret1']
}
*/
request.collect('email', 'password')
/* returns
[
{
email: 'bar@foo.com',
password: 'secret'
},
{
email: 'baz@foo.com',
password: 'secret1'
}
]
*/
Http Response
为了方便尽快响应 HTTP 请求,AdonisJS 提供了 response 类给我们使用。可用于渲染 nunjucks views 或者格式化数据。以下是简单的示例代码:
// Render Views
Route
.get('/', function *() {
yield response.sendView('welcome') // resources/views/welcome.njk
})
// JSON Response
Route
.get('user', function * () {
const user = yield User.all() // fetch users
response.json(users)
})
- 常用的还有重定向(Redirects)
response.location('/signup')
// or
response.location('back')
Http Middleware
中间件的使用十分常见,比如验证用户是否登录。在 AdonisJS 中,中间件放在 app/Http/Middleware 文件夹下,以下是简单示例:
'use strict'
const geoip = use('geoip-lite') // npm module
class CountryDetector {
* handle (request, response, next) {
const ip = request.ip()
request.country = geoip.lookup(ip).country
yield next // 如果想要把 req, res 传递给下个中间件或者路由行为,注意使用 yield next
}
}
MVC 设计模式
整个架构的数据流程如果下图所示:
Model
Model 是从数据库(AdonisJS 使用的是 SQL)获取数据的数据层,为了使获取数据的过程简单和安全,Adonis 使用了很好的 ORM 架构(Lucid)
Controller
控制器主要控制 HTTP 请求数据流,利用 Model 获取必要的数据(不仅数据库,第三方服务器的数据等都在控制器里边处理),并把获取的数据传递给 View 去渲染 HTML 页面。
// 引入依赖文件
const path = require('path')
// 定义控制器
class UsersController {
// 依赖注入
static get inject () {
return ['App/Model/User']
}
// 以参数形式接收依赖注入
constructor (User) {
this.User = User
}
// 自定义数据处理方法
static _processUserInfo() {
// ...
}
// 异步调用的方法
* index () {
const users = yield this.User.all()
// 传递数据给视图渲染
yield response.sendView('users',{
userName,
userInfo
})
}
}
module.exports = UserController
View
View 是整个 MVC 模式数据流的最后部分,主要是利用动态的数据(Nunjuck Template)去渲染(jinja 引擎) HTML 页面。
正如前边的数据流图所述,View 便是整个数据流程的末端,即利用前边步骤传来的数据进行页面渲染。AdonisJS 的视图引擎是建立在 nunjucks 的基础上的,所以 nunjucks 有的模板语法,在 AdonisJS 中一样可以使用。另外,AdonisJS 也提供了一些特有的 过滤器(filter)。
// Route
const Route = use('Route')
Route.get('/greet/:user', 'UserController.greet')
// Controller
class UserController {
* greet (request, response) {
const user = request.param('user') // user: "John"
yield response.sendView('greet', {user})
}
}
// View
<h2>Hello {{ user }}</h2> // <h2>John</h2>
Http Rounting
- 路由部分的代码书写在
app/Http/routes.js
中,简单的例子如下
const Route = use('Route') // 类似 include,跟 require 不同
Route.get('/', function * (request, response) {
yield response.sendView('home') // 这里使用 ES6 generator 语法达到异步请求数据的效果
})
- 路由参数:路由参数是 URL 中的动态数据段,我们可以通过自定义的 URL 接受动态数据。如下例子:
Route.get('users/:id', function * (request, response) {
const id = request.param('id')
response.send('Profile for user with id ${id}')
})
- 路由群:通常,会存在一系列路由共享同一个模块的情况,这就可能有时候需要修改这个模块的一些共同参数,我们把这些路由“集合”到一起,就方便修改了。例如下面的例子:
Route.group('version1', function () {
Route.get('users', function * (request, response) { // 路由是 /api/v1/users
// ...
})
}).prefix('api/v1').middleware('auth') // 该路由群都会加上 api/v1 的前缀,并经过用户登录中间件的检验
- 路由命名:书写完整的路径有时过于麻烦,为方便使用可以给路由命名。如下例子:
Route
.get('users/:id', '与否.show')
.as('profile')
IoC Container
依赖注入 & Service Providers 服务依赖注入
Ioc Container 主要概念就是在容器内存储/绑定依赖关系,然后从容器中取回它们,而不是手动请求它们
- IoC Container 绑定依赖关系示例代码如下:
const Ioc = require('adonis-fold').Ioc
const bugsnag = require('bugsnag')
Ioc.bind('Adonis/Src/Bugsnag', function (app) {
const Config = app.use('Adonis/Src/Config')
const bugSnagConfig = Config.get('services.bugsnag')
bugsnag.register(bugSnagConfig.apiKey, bugSnagConfig.options)
return bugsnag
})
- 绑定 Service Provider 的示例代码如下:
const ServiceProvider = require('adonis-fold').ServiceProvider
class BugSnagProvider extends ServiceProvider {
* register () {
this.app.bind('Adonis/Addons/BugSnag', (app) => {
const BugSnag = require('./BugSnag')
const Config = app.use('Adonis/Src/Config')
return new BugSnag(Config)
})
}
* boot () {
// Everything is registered do some hard work
}
}