# 介绍

CoolController功能继承midwayjs (opens new window)Controller (opens new window),因此它可以使用midwayjs (opens new window)控制器的所有功能:路由前缀、控制器中间件等;

CoolController特有的功能主要有:

  • 自动路由前缀
  • 快速编写CRUD接口

# 路由前缀

# 手动

/api/other

无通用CRUD设置方法

import { Provide } from '@midwayjs/decorator';
import { CoolController, BaseController } from 'midwayjs-cool-core';
import { DemoAppGoodsEntity } from '../../entity/goods';

/**
 * 商品
 */
@Provide()
@CoolController('/api')
export class DemoAppGoodsController extends BaseController {
  /**
   * 其他接口
   */
  @Get('/other')
  async other() {
    return this.ok('hello, cool-admin!!!');
  }
}

含通用CRUD设置方法

import { Get, Provide } from '@midwayjs/decorator';
import { CoolController, BaseController } from 'midwayjs-cool-core';
import { DemoAppGoodsEntity } from '../../entity/goods';

/**
 * 商品
 */
@Provide()
@CoolController({
  prefix: '/api',
  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
  entity: DemoAppGoodsEntity,
})
export class DemoAppGoodsController extends BaseController {
  /**
   * 其他接口
   */
  @Get('/other')
  async other() {
    return this.ok('hello, cool-admin!!!');
  }
}

# 自动

大多数情况下你无需指定自己的路由前缀,路由前缀将根据规则自动生成。

import { Get, Provide } from '@midwayjs/decorator';
import { CoolController, BaseController } from 'midwayjs-cool-core';
import { DemoAppGoodsEntity } from '../../entity/goods';

/**
 * 商品
 */
@Provide()
@CoolController({
  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
  entity: DemoAppGoodsEntity,
})
export class DemoAppGoodsController extends BaseController {
  /**
   * 其他接口
   */
  @Get('/other')
  async other() {
    return this.ok('hello, cool-admin!!!');
  }
}

# 规则

/controller文件夹下的文件夹名或者文件名/模块文件夹名/方法名

# 举例

 // 模块目录
 ├── modules                           
 │   └── demo(模块名)
 │   │    └── controller(api接口)
 │   │    │     └── api(参数校验)
 │   │    │     │     └── goods.ts(商品的controller)
 │   │    │     └── pay.ts(支付的controller)     
 │   │    └── config.ts(必须,模块的配置)
 │   │    └── init.sql(可选,初始化该模块的sql)
 

生成的路由前缀为: /pay/demo/xxx/api/demo/goods/xxx

# 还是看不懂怎么生成的可以查看控制台打印的日志:

WARNING

注意: cool-admin 有模块化的概念,并且接口区分前后端,默认情况下模块controller下的admin文件夹编写后台接口,会受权限控制。

# CRUD

# 参数配置(CurdOption)

通用增删改查配置参数

参数 类型 说明
prefix String 手动设置路由前缀
api Array 快速API接口可选add delete update info list page
pageQueryOp QueryOp 分页查询设置
listQueryOp QueryOp 列表查询设置
insertParam Function 请求插入参数,如新增的时候需要插入当前登录用户的ID
infoIgnoreProperty Array info接口忽略返回的参数,如用户信息不想返回密码

# 查询配置(QueryOp)

分页查询与列表查询配置参数

参数 类型 说明
keyWordLikeFields Array 支持模糊查询的字段,如一个表中的name字段需要模糊查询
where Function 其他查询条件
select Array 选择查询字段
fieldEq Array 筛选字段,字段匹配,如type=1
addOrderBy Object 排序
leftJoin LeftJoinOp[] 关联表查询

# 关联表(LeftJoinOp)

关联表查询配置参数

参数 类型 说明
entity Class 实体类
alias String 别名,如果有关联表默认主表的别名为a, 其他表一般按b、c、d...设置
condition String 关联条件

# 完整示例

import { Get, Provide } from '@midwayjs/decorator';
import { CoolController, BaseController } from 'midwayjs-cool-core';
import { BaseSysUserEntity } from '../../../base/entity/sys/user';
import { DemoAppGoodsEntity } from '../../entity/goods';

/**
 * 商品
 */
@Provide()
@CoolController({
  // 添加通用CRUD接口
  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
  // 设置表实体
  entity: DemoAppGoodsEntity,
  // 向表插入当前登录用户ID
  insertParam: (ctx => {
    return {
      // 获得当前登录的后台用户ID,需要请求头传Authorization参数
      userId: ctx.admin.userId
    }
  }),
  // 操作crud之前做的事情 midwayjs-cool-core@3.2.14 新增
  before: ctx => {
    // 将前端的数据转JSON格式存数据库
    const { data } = ctx.request.body;
    ctx.request.body.data = JSON.stringify(data);
  },
  // info接口忽略价格字段
  infoIgnoreProperty: ['price'],
  // 分页查询配置
  pageQueryOp: {
    // 让title字段支持模糊查询
    keyWordLikeFields: ['title'],
    // 让type字段支持筛选
    fieldEq: ['type'],
    // 指定返回字段
    select: ['a.*', 'b.name'],
    // 关联表用户表
    leftJoin: [{
      entity: BaseSysUserEntity,
      alias: 'b',
      condition: 'a.userId = b.id'
    }],
    // 增加其他条件
    where: async (ctx: Context) => {
      return [
        // 价格大于90
        ['a.price > :price', { price: 90.00 }],
        // 满足条件才会执行
        ['a.price > :price', { price: 90.00 }, '条件']
      ]
    },
    // 添加排序
    addOrderBy: {
      price: 'desc'
    }
  }
})
export class DemoAppGoodsController extends BaseController {
  /**
   * 其他接口
   */
  @Get('/other')
  async other() {
    return this.ok('hello, cool-admin!!!');
  }
}

通过这一波操作之后,我们的商品接口的功能已经很强大了,除了通用的CRUD,我们的接口还支持多种方式的数据筛选

# 获得ctx对象

@CoolController(
  {
    api: ['add', 'delete', 'update', 'info', 'list', 'page'],
    entity: DemoAppGoodsEntity,
    // 获得ctx对象
    listQueryOp: ctx => {
      return new Promise<QueryOp>(res => {
        res({
          fieldEq: [],
        });
      });
    },
    // 获得ctx对象
    pageQueryOp: ctx => {
      return new Promise<QueryOp>(res => {
        res({
          fieldEq: [],
        });
      });
    },
  },
  {
    middleware: [],
  }
)

# 接口调用

add delete update info 等接口可以用法参照快速开始

这里详细说明下page list两个接口的调用方式,这两个接口调用方式差不多,一个是分页一个是非分页。 以page接口为例

# 分页

POST /admin/demo/goods/page 分页数据

请求 Url: http://localhost:8001/admin/demo/goods/page

Method: POST

# Body

{
    "keyWord": "商品标题", // 模糊搜索,搜索的字段对应keyWordLikeFields
    "type": 1, // 全等于筛选,对应fieldEq
    "page": 2, // 第几页
    "size": 1, // 每页返回个数
    "sort": "desc", // 排序方向
    "order": "id" // 排序字段
}

返回

{
    "code": 1000,
    "message": "success",
    "data": {
        "list": [
            {
                "id": 4,
                "createTime": "2021-03-12 16:23:46",
                "updateTime": "2021-03-12 16:23:46",
                "title": "这是一个商品2",
                "pic": "https://show.cool-admin.com/uploads/20210311/2e393000-8226-11eb-abcf-fd7ae6caeb70.png",
                "price": "99.00",
                "userId": 1,
                "type": 1,
                "name": "超级管理员"
            }
        ],
        "pagination": {
            "page": 2,
            "size": 1,
            "total": 4
        }
    }
}

# 重写CRUD实现

在实际开发过程中,除了这些通用的接口可以满足大部分的需求,但是也有一些特殊的需求无法满足用户要求,这个时候也可以重写add delete update info list page 的实现

# 编写service

在模块新建service文件夹(名称非强制性),再新建一个service实现,继承框架的BaseService

import { Inject, Provide } from '@midwayjs/decorator';
import { BaseService } from 'midwayjs-cool-core';
import { InjectEntityModel } from '@midwayjs/orm';
import { Repository } from 'typeorm';
import { BaseSysMenuEntity } from '../../entity/sys/menu';
import * as _ from 'lodash';
import { Context } from 'egg';
import { BaseSysPermsService } from './perms';

/**
 * 菜单
 */
@Provide()
export class BaseSysMenuService extends BaseService {
  @Inject()
  ctx: Context;

  @InjectEntityModel(BaseSysMenuEntity)
  baseSysMenuEntity: Repository<BaseSysMenuEntity>;

  @Inject()
  baseSysPermsService: BaseSysPermsService;

  /**
   * 重写list实现
   */
  async list() {
    const menus = await this.getMenus(
      this.ctx.admin.roleIds,
      this.ctx.admin.username === 'admin'
    );
    if (!_.isEmpty(menus)) {
      menus.forEach(e => {
        const parentMenu = menus.filter(m => {
          e.parentId = parseInt(e.parentId);
          if (e.parentId == m.id) {
            return m.name;
          }
        });
        if (!_.isEmpty(parentMenu)) {
          e.parentName = parentMenu[0].name;
        }
      });
    }
    return menus;
  }
}

# 设置服务实现

CoolController设置自己的服务实现

import { Inject, Provide } from '@midwayjs/decorator';
import { CoolController, BaseController } from 'midwayjs-cool-core';
import { BaseSysMenuEntity } from '../../../entity/sys/menu';
import { BaseSysMenuService } from '../../../service/sys/menu';

/**
 * 菜单
 */
@Provide()
@CoolController({
  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
  entity: BaseSysMenuEntity,
  service: BaseSysMenuService,
})
export class BaseSysMenuController extends BaseController {
  @Inject()
  baseSysMenuService: BaseSysMenuService;
}

# 参数校验

参数校验写法规则跟参数校验一样

只是写的地方有点不同

通用CRUD的参数校验可以写在实体类上,如:

import { EntityModel } from '@midwayjs/orm';
import { BaseEntity } from 'midwayjs-cool-core';
import { Column } from 'typeorm';
import { Rule, RuleType } from "@midwayjs/decorator";

/**
 * 文件空间信息
 */
@EntityModel('base_app_space_info')
export class BaseAppSpaceInfoEntity extends BaseEntity {

  @Rule(RuleType.number().required())
  @Column({ comment: '地址' })
  url: string;

  @Column({ comment: '类型' })
  type: string;

  @Column({ comment: '分类ID', type: 'bigint', nullable: true })
  classifyId: number;
}