

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
12345# 控制器(Controller)67为了实现`快速CRUD`与`自动路由`功能,框架基于[midwayjs controller](mdc:https:/www.midwayjs.org/docs/controller),进行改造加强89完全继承[midwayjs controller](mdc:https:/www.midwayjs.org/docs/controller)的所有功能1011`快速CRUD`与`自动路由`,大大提高编码效率与编码量1213## 路由前缀1415虽然可以手动设置,但是我们并不推荐,cool-admin 在全局权限校验包含一定的规则,1617如果你没有很了解框架原理手动设置可能产生部分功能失效的问题1819### 手动2021`/api/other`2223无通用 CRUD 设置方法2425```ts26import { CoolController, BaseController } from "@cool-midway/core";2728/**29 * 商品30 */31@CoolController("/api")32export class AppDemoGoodsController extends BaseController {33 /**34 * 其他接口35 */36 @Get("/other")37 async other() {38 return this.ok("hello, cool-admin!!!");39 }40}41```4243含通用 CRUD 配置方法4445```ts46import { Get } from "@midwayjs/core";47import { CoolController, BaseController } from "@cool-midway/core";48import { DemoGoodsEntity } from "../../entity/goods";4950/**51 * 商品52 */53@CoolController({54 prefix: "/api",55 api: ["add", "delete", "update", "info", "list", "page"],56 entity: DemoGoodsEntity,57})58export class AppDemoGoodsController extends BaseController {59 /**60 * 其他接口61 */62 @Get("/other")63 async other() {64 return this.ok("hello, cool-admin!!!");65 }66}67```6869### 自动7071大多数情况下你无需指定自己的路由前缀,路由前缀将根据规则自动生成。7273::: warning 警告74自动路由只影响模块中的 controller,其他位置建议不要使用75:::7677`src/modules/demo/controller/app/goods.ts`7879路由前缀是根据文件目录文件名按照[规则](mdc:src/guide/core/controller.html#规则)生成的,上述示例生成的路由为8081`http://127.0.0.1:8001/app/demo/goods/xxx`8283`xxx`代表具体的方法,如: `add`、`page`、`other`8485```ts86import { Get } from "@midwayjs/core";87import { CoolController, BaseController } from "@cool-midway/core";88import { DemoGoodsEntity } from "../../entity/goods";8990/**91 * 商品92 */93@CoolController({94 api: ["add", "delete", "update", "info", "list", "page"],95 entity: DemoGoodsEntity,96})97export class AppDemoGoodsController extends BaseController {98 /**99 * 其他接口100 */101 @Get("/other")102 async other() {103 return this.ok("hello, cool-admin!!!");104 }105}106```107108### 规则109110/controller 文件夹下的文件夹名或者文件名/模块文件夹名/方法名111112#### 举例113114```ts115 // 模块目录116 ├── modules117 │ └── demo(模块名)118 │ │ └── controller(api接口)119 │ │ │ └── app(参数校验)120 │ │ │ │ └── goods.ts(商品的controller)121 │ │ │ └── pay.ts(支付的controller)122 │ │ └── config.ts(必须,模块的配置)123 │ │ └── init.sql(可选,初始化该模块的sql)124125```126127生成的路由前缀为:128`/pay/demo/xxx(具体的方法)`与`/app/demo/goods/xxx(具体的方法)`129130## CRUD131132### 参数配置(CurdOption)133134通用增删改查配置参数135136| 参数 | 类型 | 说明 | 备注 |137| ------------------ | -------- | ------------------------------------------------------------- | ---- |138| prefix | String | 手动设置路由前缀 | |139| api | Array | 快速 API 接口可选`add` `delete` `update` `info` `list` `page` | |140| serviceApis | Array | 将 service 方法注册为 api,通过 post 请求,直接调用 service 方法 | |141| pageQueryOp | QueryOp | 分页查询设置 | |142| listQueryOp | QueryOp | 列表查询设置 | |143| insertParam | Function | 请求插入参数,如新增的时候需要插入当前登录用户的 ID | |144| infoIgnoreProperty | Array | `info`接口忽略返回的参数,如用户信息不想返回密码 | |145146### 查询配置(QueryOp)147148分页查询与列表查询配置参数149150| 参数 | 类型 | 说明 | 备注 |151| ----------------- | -------- | ----------------------------------------------------------------------------------- | ---- |152| keyWordLikeFields | Array | 支持模糊查询的字段,如一个表中的`name`字段需要模糊查询 | |153| where | Function | 其他查询条件 | |154| select | Array | 选择查询字段 | |155| fieldEq | Array | 筛选字段,字符串数组或者对象数组{ column: string, requestParam: string },如 type=1 | |156| fieldLike | Array | 模糊查询字段,字符串数组或者对象数组{ column: string, requestParam: string },如 title | |157| addOrderBy | Object | 排序 | |158| join | JoinOp[] | 关联表查询 | |159160### 关联表(JoinOp)161162关联表查询配置参数163164| 参数 | 类型 | 说明 |165| --------- | ------ | ------------------------------------------------------------------ |166| entity | Class | 实体类,注意不能写表名 |167| alias | String | 别名,如果有关联表默认主表的别名为`a`, 其他表一般按 b、c、d...设置 |168| condition | String | 关联条件 |169| type | String | 内关联: 'innerJoin', 左关联:'leftJoin' |170171### 完整示例172173```ts174import { Get } from "@midwayjs/core";175import { CoolController, BaseController } from "@cool-midway/core";176import { BaseSysUserEntity } from "../../../base/entity/sys/user";177import { DemoAppGoodsEntity } from "../../entity/goods";178179/**180 * 商品181 */182@CoolController({183 // 添加通用CRUD接口184 api: ["add", "delete", "update", "info", "list", "page"],185 // 8.x新增,将service方法注册为api,通过post请求,直接调用service方法186 serviceApis: [187 'use',188 {189 method: 'test1',190 summary: '不使用多租户', // 接口描述191 },192 'test2', // 也可以不设置summary193 ]194 // 设置表实体195 entity: DemoAppGoodsEntity,196 // 向表插入当前登录用户ID197 insertParam: (ctx) => {198 return {199 // 获得当前登录的后台用户ID,需要请求头传Authorization参数200 userId: ctx.admin.userId,201 };202 },203 // 操作crud之前做的事情 @cool-midway/core@3.2.14 新增204 before: (ctx) => {205 // 将前端的数据转JSON格式存数据库206 const { data } = ctx.request.body;207 ctx.request.body.data = JSON.stringify(data);208 },209 // info接口忽略价格字段210 infoIgnoreProperty: ["price"],211 // 分页查询配置212 pageQueryOp: {213 // 让title字段支持模糊查询214 keyWordLikeFields: ["title"],215 // 让type字段支持筛选,请求筛选字段与表字段一致是情况216 fieldEq: ["type"],217 // 多表关联,请求筛选字段与表字段不一致的情况218 fieldEq: [{ column: "a.id", requestParam: "id" }],219 // 让title字段支持模糊查询,请求参数为title220 fieldLike: ['a.title'],221 // 让title字段支持模糊查询,请求筛选字段与表字段不一致的情况222 fieldLike: [{ column: "a.title", requestParam: "title" }],223 // 指定返回字段,注意多表查询这个是必要的,否则会出现重复字段的问题224 select: ["a.*", "b.name", "a.name AS userName"],225 // 4.x置为过时 改用 join 关联表用户表226 leftJoin: [227 {228 entity: BaseSysUserEntity,229 alias: "b",230 condition: "a.userId = b.id",231 },232 ],233 // 4.x新增234 join: [235 {236 entity: BaseSysUserEntity,237 alias: "b",238 condition: "a.userId = b.id",239 type: "innerJoin",240 },241 ],242 // 4.x 新增 追加其他条件243 extend: async (find: SelectQueryBuilder<DemoGoodsEntity>) => {244 find.groupBy("a.id");245 },246 // 增加其他条件247 where: async (ctx) => {248 // 获取body参数249 const { a } = ctx.request.body;250 return [251 // 价格大于90252 ["a.price > :price", { price: 90.0 }],253 // 满足条件才会执行254 ["a.price > :price", { price: 90.0 }, "条件"],255 // 多个条件一起256 [257 "(a.price = :price or a.userId = :userId)",258 { price: 90.0, userId: ctx.admin.userId },259 ],260 ];261 },262 // 添加排序263 addOrderBy: {264 price: "desc",265 },266 },267})268export class DemoAppGoodsController extends BaseController {269 /**270 * 其他接口271 */272 @Get("/other")273 async other() {274 return this.ok("hello, cool-admin!!!");275 }276}277```278279::: warning280如果是多表查询,必须设置 select 参数,否则会出现重复字段的错误,因为每个表都继承了 BaseEntity,至少都有 id、createTime、updateTime 三个相同的字段。281:::282283通过这一波操作之后,我们的商品接口的功能已经很强大了,除了通用的 CRUD,我们的接口还支持多种方式的数据筛选284285### 获得 ctx 对象286287```ts288@CoolController(289 {290 api: ['add', 'delete', 'update', 'info', 'list', 'page'],291 entity: DemoAppGoodsEntity,292 // 获得ctx对象293 listQueryOp: ctx => {294 return new Promise<QueryOp>(res => {295 res({296 fieldEq: [],297 });298 });299 },300 // 获得ctx对象301 pageQueryOp: ctx => {302 return new Promise<QueryOp>(res => {303 res({304 fieldEq: [],305 });306 });307 },308 },309 {310 middleware: [],311 }312)313```314315### 接口调用316317`add` `delete` `update` `info` 等接口可以用法[参照快速开始](mdc:src/guide/quick.html#接口调用)318319这里详细说明下`page` `list`两个接口的调用方式,这两个接口调用方式差不多,一个是分页一个是非分页。320以`page`接口为例321322#### 分页323324POST `/admin/demo/goods/page` 分页数据325326**请求**327Url: http://127.0.0.1:8001/admin/demo/goods/page328329Method: POST330331#### Body332333```json334{335 "keyWord": "商品标题", // 模糊搜索,搜索的字段对应keyWordLikeFields336 "type": 1, // 全等于筛选,对应fieldEq337 "page": 2, // 第几页338 "size": 1, // 每页返回个数339 "sort": "desc", // 排序方向340 "order": "id" // 排序字段341}342```343344**返回**345346```json347{348 "code": 1000,349 "message": "success",350 "data": {351 "list": [352 {353 "id": 4,354 "createTime": "2021-03-12 16:23:46",355 "updateTime": "2021-03-12 16:23:46",356 "title": "这是一个商品2",357 "pic": "https://show.cool-admin.com/uploads/20210311/2e393000-8226-11eb-abcf-fd7ae6caeb70.png",358 "price": "99.00",359 "userId": 1,360 "type": 1,361 "name": "超级管理员"362 }363 ],364 "pagination": {365 "page": 2,366 "size": 1,367 "total": 4368 }369 }370}371```372373### 服务注册成 Api374375很多情况下,我们在`Controller`层并不想过多地操作,而是想直接调用`Service`层的方法,这个时候我们可以将`Service`层的方法注册成`Api`,那么你的某个`Service`方法就变成了`Api`。376377#### 示例:378379在 Controller 中380381```ts382import { CoolController, BaseController } from "@cool-midway/core";383import { DemoGoodsEntity } from "../../entity/goods";384import { DemoTenantService } from "../../service/tenant";385386/**387 * 示例388 */389@CoolController({390 serviceApis: [391 "use",392 {393 method: "test1",394 summary: "不使用多租户", // 接口描述395 },396 "test2", // 也可以不设置summary397 ],398 entity: DemoGoodsEntity,399 service: DemoXxxService,400})401export class AdminDemoTenantController extends BaseController {}402```403404在 Service 中405406```ts407/**408 * 示例服务409 */410@Provide()411export class DemoXxxService extends BaseService {412 /**413 * 示例方法1414 */415 async test1(params) {416 console.log(params);417 return "test1";418 }419420 /**421 * 示例方法2422 */423 async test2() {424 return "test2";425 }426}427```428429::: warning 注意430`serviceApis` 注册为`Api`的请求方法是`POST`,所以`Service`层的方法参数需要通过`body`传递431:::432433### 重写 CRUD 实现434435在实际开发过程中,除了这些通用的接口可以满足大部分的需求,但是也有一些特殊的需求无法满足用户要求,这个时候也可以重写`add` `delete` `update` `info` `list` `page` 的实现436437#### 编写 service438439在模块新建 service 文件夹(名称非强制性),再新建一个`service`实现,继承框架的`BaseService`440441```ts442import { Inject, Provide } from "@midwayjs/core";443import { BaseService } from "@cool-midway/core";444import { InjectEntityModel } from "@midwayjs/orm";445import { Repository } from "typeorm";446import { BaseSysMenuEntity } from "../../entity/sys/menu";447import * as _ from "lodash";448import { BaseSysPermsService } from "./perms";449450/**451 * 菜单452 */453@Provide()454export class BaseSysMenuService extends BaseService {455 @Inject()456 ctx;457458 @InjectEntityModel(BaseSysMenuEntity)459 baseSysMenuEntity: Repository<BaseSysMenuEntity>;460461 @Inject()462 baseSysPermsService: BaseSysPermsService;463464 /**465 * 重写list实现466 */467 async list() {468 const menus = await this.getMenus(469 this.ctx.admin.roleIds,470 this.ctx.admin.username === "admin"471 );472 if (!_.isEmpty(menus)) {473 menus.forEach((e) => {474 const parentMenu = menus.filter((m) => {475 e.parentId = parseInt(e.parentId);476 if (e.parentId == m.id) {477 return m.name;478 }479 });480 if (!_.isEmpty(parentMenu)) {481 e.parentName = parentMenu[0].name;482 }483 });484 }485 return menus;486 }487}488```489490#### 设置服务实现491492`CoolController`设置自己的服务实现493494```ts495import { Inject } from "@midwayjs/core";496import { CoolController, BaseController } from "@cool-midway/core";497import { BaseSysMenuEntity } from "../../../entity/sys/menu";498import { BaseSysMenuService } from "../../../service/sys/menu";499500/**501 * 菜单502 */503@CoolController({504 api: ["add", "delete", "update", "info", "list", "page"],505 entity: BaseSysMenuEntity,506 service: BaseSysMenuService,507})508export class BaseSysMenuController extends BaseController {509 @Inject()510 baseSysMenuService: BaseSysMenuService;511}512```513514## 路由标签515516我们经常有这样的需求:给某个请求地址打上标记,如忽略 token,忽略签名等。517518```ts519import { Get, Inject } from "@midwayjs/core";520import {521 CoolController,522 BaseController,523 CoolUrlTag,524 TagTypes,525 CoolUrlTagData,526} from "@cool-midway/core";527528/**529 * 测试给URL打标签530 */531@CoolController({532 api: [],533 entity: "",534 pageQueryOp: () => {},535})536// add 接口忽略token537@CoolUrlTag({538 key: TagTypes.IGNORE_TOKEN,539 value: ["add"],540})541export class DemoAppTagController extends BaseController {542 @Inject()543 tag: CoolUrlTagData;544545 /**546 * 获得标签数据, 如可以标记忽略token的url,然后在中间件判断547 * @returns548 */549 // 这是6.x支持的,可以直接标记这个接口忽略token,更加灵活优雅,但是记得配合@CoolUrlTag()一起使用,也就是Controller上要有这个注解,@CoolTag才会生效550 @CoolTag(TagTypes.IGNORE_TOKEN)551 @Get("/data")552 async data() {553 return this.ok(this.tag.byKey(TagTypes.IGNORE_TOKEN));554 }555}556```557558#### 中间件559560```ts561import { CoolUrlTagData, TagTypes } from "@cool-midway/core";562import { IMiddleware } from "@midwayjs/core";563import { Inject, Middleware } from "@midwayjs/core";564import { NextFunction, Context } from "@midwayjs/koa";565566@Middleware()567export class DemoMiddleware implements IMiddleware<Context, NextFunction> {568 @Inject()569 tag: CoolUrlTagData;570571 resolve() {572 return async (ctx: Context, next: NextFunction) => {573 const urls = this.tag.byKey(TagTypes.IGNORE_TOKEN);574 console.log("忽略token的URL数组", urls);575 // 这里可以拿到下一个中间件或者控制器的返回值576 const result = await next();577 // 控制器之后执行的逻辑578 // 返回给上一个中间件的结果579 return result;580 };581 }582}583```584585
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| cool-team-official/cool-admin-midway.cursor/rules/authority.mdc · 3.3k | Cursor rules | security | 54/100 | today | |
| cool-team-official/cool-admin-midway.cursor/rules/cache.mdc · 3.3k | Cursor rules | no sections | 58/100 | today | |
| cool-team-official/cool-admin-midway.cursor/rules/db.mdc · 3.3k | Cursor rules | setupdatabase | 62/100 | today | |
| cool-team-official/cool-admin-midway.cursor/rules/event.mdc · 3.3k | Cursor rules | no sections | 45/100 | today | |
| cool-team-official/cool-admin-midway.cursor/rules/module.mdc · 3.3k | Cursor rules | no sections | 50/100 | today | |
| cool-team-official/cool-admin-midway.cursor/rules/service.mdc · 3.3k | Cursor rules | database | 54/100 | today | |
| cool-team-official/cool-admin-midway.cursor/rules/socket.mdc · 3.3k | Cursor rules | no sections | 58/100 | today | |
| cool-team-official/cool-admin-midway.cursor/rules/task.mdc · 3.3k | Cursor rules | style | 58/100 | today | |
| cool-team-official/cool-admin-midway.cursor/rules/tenant.mdc · 3.3k | Cursor rules | no sections | 50/100 | today | |
| cool-team-official/cool-admin-midway.cursorrules · 3.3k | .cursorrules | no sections | 39/100 | today |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 46 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 14 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 14 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 46 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 14 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/cool-team-official-cool-admin-midway-cursor-rules-controller)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.