Skip to content

Commit

Permalink
refactor: 使用注解注册接口
Browse files Browse the repository at this point in the history
  • Loading branch information
aooiuu committed Jul 14, 2024
1 parent 57584b1 commit cd9d198
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 19 deletions.
2 changes: 1 addition & 1 deletion packages/server/src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function createRoute(api: Api) {
const paths = path.split('@')
if (paths.length !== 2)
return
const method = paths[0] as 'post' | 'get'
const method = paths[0].toLocaleLowerCase() as 'post' | 'get'
router[method](`/${paths[1]}`, async (ctx) => {
const data = method === 'get' ? ctx.query : ctx.request.body
ctx.body = await cb(data)
Expand Down
34 changes: 17 additions & 17 deletions packages/shared/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { db } from './data-source'
import { ChapterHistory } from './controller/ChapterHistory'
import { ResourceHistory } from './controller/ResourceHistory'
import { ResourceFavorites } from './controller/ResourceFavorites'
import { mapRoute } from './decorators'

// 发现页分类
async function discoverMap(ruleId: string) {
Expand Down Expand Up @@ -275,22 +276,21 @@ export class Api {
registerApi('post@importCMS', async (data: any) => await ruleFileManager.importCMS(data))
registerApi('post@ping', async (data: any) => await ping(data))

// 章节进度记录
const chapter = new ChapterHistory(db)
registerApi('post@chapter-history/list', chapter.list.bind(chapter))
registerApi('post@chapter-history/save', chapter.save.bind(chapter))

// 历史记录
const resourceHistory = new ResourceHistory(db)
registerApi('post@resource-history/list', resourceHistory.list.bind(resourceHistory))
registerApi('post@resource-history/remove', resourceHistory.remove.bind(resourceHistory))
registerApi('post@resource-history/add', resourceHistory.create.bind(resourceHistory))
registerApi('post@resource-history/del', resourceHistory.remove.bind(resourceHistory))

// 收藏
const resourceFavorites = new ResourceFavorites(db)
registerApi('post@resource-favorites/list', resourceFavorites.list.bind(resourceFavorites))
registerApi('post@resource-favorites/star', resourceFavorites.star.bind(resourceFavorites))
registerApi('post@resource-favorites/unstar', resourceFavorites.unstar.bind(resourceFavorites))
const app = {
controllers: [
ChapterHistory,
ResourceHistory,
ResourceFavorites,
],
}

for (const controller of app.controllers) {
const routes = mapRoute(controller)
for (const route of routes) {
// eslint-disable-next-line new-cap
const Controller: any = new controller(db)
registerApi([route.method, route.route].join('@'), Controller[route.methodName].bind(Controller))
}
}
}
}
4 changes: 4 additions & 0 deletions packages/shared/src/controller/ChapterHistory.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { Controller, Post } from '../decorators'
import { BaseController } from './BaseController'

@Controller('/chapter-history')
export class ChapterHistory extends BaseController {
@Post('save')
save(data: any) {
return this.db.getChapterHistory().save(data)
}

@Post('list')
list(data: any) {
return this.db.getChapterHistory().list(data)
}
Expand Down
5 changes: 5 additions & 0 deletions packages/shared/src/controller/ResourceFavorites.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { Controller, Post } from '../decorators'
import { BaseController } from './BaseController'

@Controller('/resource-favorites')
export class ResourceFavorites extends BaseController {
// 获取列表
@Post('list')
list() {
return this.db.getResourceFavorites().list()
}

// 删除
@Post('unstar')
unstar(data: any) {
return this.db.getResourceFavorites().remove(data)
}

// 添加
@Post('star')
star(data: any) {
return this.db.getResourceFavorites().create(data)
}
Expand Down
10 changes: 10 additions & 0 deletions packages/shared/src/controller/ResourceHistory.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import { Controller, Post } from '../decorators'
import { BaseController } from './BaseController'

@Controller('/resource-history')
export class ResourceHistory extends BaseController {
// 获取列表
@Post('list')
list() {
return this.db.getResourceHistory().list()
}

// 删除一个记录
@Post('remove')
remove(data: any) {
return this.db.getResourceHistory().remove(data)
}

@Post('del')
del(data: any) {
return this.db.getResourceHistory().remove(data)
}

// 添加一个记录
@Post('add')
create(data: any) {
return this.db.getResourceHistory().create(data)
}
Expand Down
87 changes: 87 additions & 0 deletions packages/shared/src/decorators/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { isConstructor, isFunction } from '../utils/is'

const PATH_METADATA = 'path'
const METHOD_METADATA = 'method'

export enum RequestMethod {
GET = 'GET',
POST = 'POST',
}

export function Controller(path: string): ClassDecorator {
return (target) => {
Reflect.defineMetadata(PATH_METADATA, path, target)
}
}

interface RequestMappingMetadata {
path?: string | string[]
method?: RequestMethod
}

const defaultMetadata = {
[PATH_METADATA]: '/',
[METHOD_METADATA]: RequestMethod.GET,
}

function RequestMapping(metadata: RequestMappingMetadata = defaultMetadata): MethodDecorator {
const pathMetadata = metadata[PATH_METADATA]
const path = pathMetadata && pathMetadata.length ? pathMetadata : '/'
const requestMethod = metadata[METHOD_METADATA] || RequestMethod.GET

return (
target: object,
key: string | symbol,
descriptor: TypedPropertyDescriptor<any>,
) => {
Reflect.defineMetadata(PATH_METADATA, path, descriptor.value)
Reflect.defineMetadata(METHOD_METADATA, requestMethod, descriptor.value)
return descriptor
}
}

function createMappingDecorator(method: RequestMethod) {
return (path?: string | string[]): MethodDecorator => {
return RequestMapping({
[PATH_METADATA]: path,
[METHOD_METADATA]: method,
})
}
}

export const Get = createMappingDecorator(RequestMethod.GET)
export const Post = createMappingDecorator(RequestMethod.POST)

interface Route {
method: string
route: string
methodName: string
}

export function mapRoute(controller: object): Route[] {
const instance = Object.create(controller)
const prototype = instance.prototype
const basePath: string = Reflect.getMetadata(PATH_METADATA, controller)

const methodsNames = Object.getOwnPropertyNames(prototype)
.filter(
item => !isConstructor(item) && isFunction(prototype[item]),
)

return methodsNames.map((methodName) => {
const fn = prototype[methodName]
const methodPath: string = Reflect.getMetadata(PATH_METADATA, fn)
let route = basePath.replace(/^\//, '') // 移出前缀斜杠
if (methodPath.startsWith('/'))
route = methodPath // 方法定义完整路径
else
route = `${route}/${methodPath}` // 补充 controller 路径

const method = Reflect.getMetadata(METHOD_METADATA, fn)
return {
method,
route,
methodName,
}
})
}
1 change: 1 addition & 0 deletions packages/shared/src/service/ResourceFavorites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export class ResourceFavoritesService {
order: {
updateTime: 'DESC',
},
take: 100,
})
}

Expand Down
1 change: 1 addition & 0 deletions packages/shared/src/service/ResourceHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export class ResourceHistoryService {
order: {
updateTime: 'DESC',
},
take: 100,
})
}

Expand Down
2 changes: 2 additions & 0 deletions packages/shared/src/utils/is.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const isConstructor = (val: any): boolean => val === 'constructor'
export const isFunction = (val: any) => typeof val === 'function'
2 changes: 1 addition & 1 deletion packages/web/src/pages/pc/content/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const chaptersVisible = ref(false);
const contentRef = ref();
const chaptersRef = ref();
const topTarget = () => document.querySelector('#text-container');
const topTarget = () => document.querySelector('#text-container') as HTMLElement;
onClickOutside(chaptersRef, () => (chaptersVisible.value = false));
Expand Down
4 changes: 4 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"compilerOptions": {
// https://github.com/typeorm/typeorm
"emitDecoratorMetadata": true,
"experimentalDecorators": true,

"paths": {
// "@any-reader/rule-utils": ["./packages/rule-utils/src/index.ts"],
// "@any-reader/core": ["./packages/core/src/index.ts"],
Expand Down

0 comments on commit cd9d198

Please sign in to comment.