Service Provider

adonisJS 要实现 Controller 和 Service 的分离,这里用到 Service Provider。

  1. 将 Provider 注入到 adonis 中

    bash
    1touch providers/ServiceProvider.ts

    在配置文件.adonisrc.json中注入这个 Provider。

    js
    1  "providers": [
    2    "./providers/ServiceProvider",
    3    ...
    4  ]
  2. 创建一个接口并用一个 class implement 它,这个 class 里写 service 代码

    bash
    1touch Service/Login.ts
    js
    1export interface Login_Interface {
    2  signup: () => Promise<any>;
    3}
    4
    5export default class Login implements Login_Interface {
    6  public database;
    7  constructor(database: typeof Database) {
    8    this.database = database;
    9  }
    10  public async signup() {
    11  	...
    12  }
    13}

    注意:由于注入的 Service 的实例方法中不能直接使用import Database from @ioc:Adonis/Lucid/Database,所以这里在 constructor 时传递 database 过去。

  3. 在 ServiceProvider 中注册 Service

    js
    1import { ApplicationContract } from "@ioc:Adonis/Core/Application";
    2import Login from "../Service/Login";
    3
    4export default class ServiceProvider {
    5  constructor(protected app: ApplicationContract) {}
    6  public register() {
    7    this.app.container.singleton("Loc/Signup", () => {
    8      const database = this.app.container.use("Adonis/Lucid/Database");
    9      return new Login(database);
    10    });
    11  }
    12  public async boot() {
    13    // IoC container is ready
    14  }
    15
    16  public async ready() {
    17    // App is ready
    18  }
    19
    20  public async shutdown() {
    21    // Cleanup, since app is going down
    22  }
    23}

    这个 Provider 的注册周期内,用单例模式注册一个 Login 实例。

    由于 Provider 中也不能直接引入Database,所以这里使用this.app.container.use("Adonis/Lucid/Database")将 database 对象传递过去,这里就接上了第一步中的constructor

  4. 暴露出这个实例的方法

    bash
    1touch contracts/login.ts
    js
    1declare module "@ioc:Loc/Signup" {
    2  import { Login_Interface } from "Service/Login";
    3  const login: Login_Interface;
    4  export default login;
    5}

    这样在 Typescript 下,就会有语法提示。

  5. Controller 中调用 Service 的代码

    js
    1import loginInstance from "@ioc:Loc/Signup";
    2
    3export default class LoginController {
    4  public async signup() {
    5    return loginInstance.signup();
    6  }
    7  ...
    8}
  6. 补充 service 方法,这里的示例是调用数据库查询

    js
    1  public async signup() {
    2    const { default: Users } = await import("App/Models/User");
    3    const dbRes = await this.database.from("users").where("user", "邱彦兮");
    4    const ormRes = await Users.query().select("*").where("user", "邱彦兮");
    5    console.log("🚀🚀🚀🚀🚀 - res:", [...dbRes, ...ormRes]);
    6    return [...dbRes, ...ormRes];
    7  }

    在 service 中,不管是用 database 还是 orm 都不能直接import xxx from xxx

    这里的细节在于:

    1. constructor后的 database 对象来查询数据库
    2. 使用await import("App/Models/User")获取 orm 版本的数据库查询对象来查询数据库

现在你已经实现了 Controller 和 Service 的分离。