1 import express, {Request, Response} from 'express'
2 const app = express();
3 const router = express.Router();
4
5 // 随便写一个get请求的接口
6 router.get('/api/login/loginByPhone', (req:Request, res:Response) => {
7 //...
8 })
9 // 在将路由注册到app中
10 app.use(router)
但如果有N多个路由,不同的路由肯定会按照需求的情况写在不同的ts文件中,例如:
先将router放在单独的一个中间件文件中进行导出,其他路由文件引入的都是这一个router对象
// middleware/router.ts
const express = require('express')
// 创建路由对象
const router = express.Router()
// 导出的路由对象专门用于创建不同的路由: router.post('/api/...')
export default router;
然后新建路由
//LoginRouter.ts
import router from './middleware/router'
router.get('/api/login/loginByPhone', (req:Request, res:Response) => {
//...
})
router.post('/api/login/selectxxx', (req:Request, res:Response) => {
//...
})
//...
// 最后导出LoginRouter
export default LoginRouter;
//UserRouter.ts
import router from './middleware/router'
router.get('/api/user/selectUserInformation', (req:Request, res:Response) => {
//...
})
router.post('/api/user/saveInformation', (req:Request, res:Response) => {
//...
})
// 导出UserRouter路由
export default UserRouter;
最后再统一引入到一个文件中进行注册:
import LoginRouter from './Router/LoginRouter'
import UserRouter from './Router/UserRouter'
import express from 'express'
const app = express()
// 注册路由
app.use(LoginRouter);
app.use(UserRouter);
但是如果路由文件特别多的话(假如有100个),那是不是得在一个文件里面引入100个路由文件挨个进行注册...
import xxx1 from './Router/xxx1'
import xxx2 from './Router/xxx2'
import xxx3 from './Router/xxx3'
//...
import xxx100 from './Router/xxx100'
app.use(xxx1)
app.use(xxx2)
app.use(xxx3)
//...
app.use(xxx100)
这也太麻烦了,那我岂不是成跪着敲代码的了么? 所以必须想到一个偷懒的办法!经过深思熟虑反复斟酌,再凭借着我对Java的一丝经验,总算是有了一些思路,于是顺着思路马上开写:
1)首先就是修改路由文件中导出的内容,不再导出router对象,而是导出一个类
// ./router/LoginRouter.ts
import router from './middle/router';
export default class LoginRouter{
// 类对象中的属性用来存放router路由
selectInforByPhone = router.post('/api/login/loginByPassWord', (req: Request, resp: Response) => {
//...
})
registerByPhone = router.post('/api/register/registerByPhone', (req: Request, resp: Response) => {
//...
})
}
2)第二步就是利用typescript写一个@controller装饰器放在路由类上,装饰器的功能很简单,就是获取到类对象中的路由
// ./decorators/controller.ts
// 专门保存类对象中路由的数组
const routerArray:any = [];
function Controller(target: any): void {
// 实例化当前类
let obj = new target();
// 然后将对象中的每一个router变量保存到routerArray数组中
for (let route in obj) {
routerArray.push(obj[route]);
}
}
// Controller装饰器, 保存路由的数组
export {Controller, routerArray};
现在的路由类就变成了这样
import {Controller} from './decorators/controller'
import router from './middleware/router'
// 现在路由类不叫xxxRouter了,改叫xxxController
@Controller // 加上装饰器
export default class LoginController{
// 类对象中的变量用来存放router路由
selectInforByPhone = router.post('/api/login/loginByPassWord', (req: Request, resp: Response) => {
//...
})
registerByPhone = router.post('/api/register/registerByPhone', (req: Request, resp: Response) => {
//...
})
}
接下来每次实例化这个类时,就会执行装饰器函数,将类对象中的路由变量存入到routerArray数组中。然后只需要对数组进行遍历,就可以注册所有的路由。但是相比于最开始的引入 + 注册,现在好像更麻烦了。。。不仅要引入路由类,还得实例化路由类,最后需要遍历数组才能进行注册。因此接下来才是改变一切的关键:
const path = require('path');
const fs = require('fs');
export default class routerConfig {
// 1.1 获取controller文件夹的绝对路径
filePath = `${path.resolve()}\\src\\controller`;
registerRouters(app: any) {
return new Promise((resolve, reject) => {
//1.2 读取到controller文件夹下的文件名
fs.readdir(this.filePath, (err: any, files: any) => {
if(err){
reject('Controller file path error!');
}
files.forEach((file: any) => {
// 2. 引入当前文件中的类对象
const nowClass = require(this.filePath + "\\" + file);
if(typeof nowClass === 'object'){
// 3. 每次new当前类时,都会触发controller装饰器
new nowClass['default']();
}
})
// 4.1 获取到存放路由的数组
const { routerArray } = require('../decorators/controller');
//4.2 遍历数组,将路由注册到app中
routerArray.forEach((route: string) => {
app.use(route);
})
resolve(true);
})
})
}
}
上面的类中的registerRouters()方法的作用就是:
-
获取到src文件夹下的controller文件夹下的每一个文件名
-
通过const xx = require(path)的方式引入controller文件夹下的文件中导出的类对象
-
实例化xx类,在这个过程中,就会触发@Controller装饰器,将当前类中的路由存到同一个数组中
-
循环完每一个路由文件后,再将数组中的路由遍历一遍,注册到app中。
我们最后在index.ts中执行这个操作
// index.ts
const express = require('express');
const app = express();
// 引入关键的那个类
import RouteConfig from './src/config/routerConfig'
let routerConfig = new RouteConfig();
// 调用routerConfig对象下的registerRouters()方法,并将app对象传入,路由注册完毕之后再对8888端口进行监听
routerConfig.registerRouters(app).then(_ => {
app.listen(8888, () => {
console.log('note-station Server running at http://127.0.0.1');
})
}).catch(err => {
console.log(err);
});
测试:
先启动服务端,通过nodemon执行以下index.ts文件
然后随便启动一个React项目,随便访问一下已有的router,看一下注册是否成功
即将被访问的router

访问/api/user/selectUser


再看看服务端控制台是否有前端传来的数据

可以看到数据交互完全没问题,因此路由的注册肯定也是成功了的!!
总结:
通过@Controller装饰器和RouterConfig对象的registerRouters()方法对controller文件夹下的类对象进行处理后,我们不需要再每次新建一个router后都要进行路由的引入和注册操作。后续只需要在新建的xxxController类上加一个@Controller,那么最后在启动服务时就会将这个类中的路由自动注册到app中。
对于以上方法,若有觉得方法有不足之处或是值得改进的地方,又或者有更好的方式,欢迎随时指出。各位的批评与指点就是在下进步的良药。
浙公网安备 33010602011771号