Adonis.js

一、初始化

版本要求:Node.js v14

创建项目
yarn create adonis-ts-app hello-adonis
1
2
3
4
5
6

CUSTOMIZE PROJECT
> Select the project structure · api   
> Enter the project name · hello-adonis
> Setup eslint? (y/N) · true
> Setup prettier? (y/N) » false
启动开发服务器
node ace serve --watch
为生产编译
node ace build --production

cd build

node server.js

二、路由

网站或 Web 应用程序的用户可以访问不同的 URL,例如/,/about或/posts/1. 要使这些 URL 起作用,必须将它们定义为路由。

默认路由路径:start/routes.ts

列出路由

node ace list:routes

嵌套路由&路由域

1
2
3
4
5
6
7
8

Route.group(() => {
  Route.group(() => {
    Route.get('/users', 'UsersController.index') // /api/v1/users
    Route.get('/posts', 'PostsController.index') // /api/v1/posts
  }).prefix('/v1') // 路由前缀(可选)
}).prefix('/api') // 路由前缀(可选)
.domain('blog.adonisjs.com') // 路由域(可选)

三、控制器

控制器是处理路由的实际方式。通过将所有内联路由处理程序移动到其专用控制器文件来处理路由文件。

默认控制器路径:app/Controllers/Http

1. 自动生成控制器类

node ace make:controller Post

2. 编辑控制器

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class PostsController {
  public async index(ctx: HttpContextContract) {
    return [
      {
        id: 1,
        title: 'Hello world',
      },
      {
        id: 2,
        title: 'Hello universe',
      },
    ]
  }
}

3. 路由调用控制器

import Route from '@ioc:Adonis/Core/Route'

Route.get('/posts', async (ctx) => {
  const { default: PostsController } = await import(
    'App/Controllers/Http/PostsController'
  )
  return new PostsController().index(ctx)
})

四、中间件

将中间件编写为内联函数对于一些快速测试来说是很好的。但是,建议将中间件逻辑提取到它自己的文件中。
默认路径:app/Middleware

1. 自动生成中间件类

node ace make:middleware Auth

2. 编辑中间件

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class Auth {
  public async handle(
    { request, response }: HttpContextContract,
    next: () => Promise<void>
  ) {
    if (notAuthenticated) {
      response.unauthorized({ error: 'Must be logged in' })
      return
    }

    await next()
  }
}

3. 注册中间件

要使中间件生效,必须在文件内注册为全局中间件或命名中间件。

路径:start/kernel.ts

全局中间件

全局中间件按照与注册时相同的顺序为所有 HTTP 请求执行。

Server.middleware.register([
  () => import('@ioc:Adonis/Core/BodyParser'),
  () => import('App/Middleware/LogRequest')
])
命名中间件

有选择地在路由/路由组上应用中间件。

Server.middleware.registerNamed({
  auth: () => import('App/Middleware/Auth')
})
1
2
3
4

Route
  .get('dashboard', 'DashboardController.index')
  .middleware('auth') // 👈

五、数据库

Lucid

Lucid 为框架的数据层提供支持。

1. 安装

yarn add @adonisjs/lucid

2. 自动生成配置文件

node ace configure @adonisjs/lucid

3. 验证配置环境变量

.env 文件中

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15

// 根据使用的数据库驱动程序,必须验证定义的环境变量。

// 以下是 MySQL 的示例。
PORT=3333
HOST=0.0.0.0
NODE_ENV=development
APP_KEY=yZNA8Mcjy4XRwijH8Uz924aSjt5M2x92
DRIVE_DISK=local
DB_CONNECTION=mysql
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD=123456
MYSQL_DB_NAME=world

所有数据库驱动程序的配置都存储在 config/database.ts 文件中。

 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

import Env from '@ioc:Adonis/Core/Env'
import { DatabaseConfig } from '@ioc:Adonis/Lucid/Database'

const databaseConfig: DatabaseConfig = {
  // Default connection
  connection: Env.get('DB_CONNECTION'),

  // List of available connections
  connections: {
    mysql: {
      client: 'mysql',
      connection: {
        host: Env.get('MYSQL_HOST'),
        port: Env.get('MYSQL_PORT'),
        user: Env.get('MYSQL_USER'),
        password: Env.get('MYSQL_PASSWORD'),
        database: Env.get('MYSQL_DB_NAME'),
      },
      migrations: {
        naturalSort: true,
      },
      healthCheck: false,
      debug: false,
    }
  }
}

export default databaseConfig

4. 使用

在控制器 app/Controllers/Http/HelloWorldsController.ts 中使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16

import Database from '@ioc:Adonis/Lucid/Database'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class HelloWorldsController {
  public async index(ctx: HttpContextContract) {
    // return { hello: 'world' }
    const limit = 20
    const page = ctx.request.input('page', 1)
    return Database
      .from('city') // 数据表 city
      .select('*')
      .orderBy('id', 'desc')
      .paginate(page, limit)
  }
}