Express项目改良
创建控制器和装饰器
npm install reflect-metadata --save
|-- src
| |-- controller
| | |-- decorators.ts
| | |-- LoginController.ts
// LoginController.ts
import 'reflect-metadata';
import { Request, Response, response } from 'express';
import { controller, get } from './decorators';
import { getResponseData } from '../utils/util';
interface BodyRequest extends Request {
body: { [key: string]: string | undefined };
}
@controller
class LoginController {
@get('/logout')
loginout(req: BodyRequest, res: Response) {
if (req.session) {
req.session.login = undefined;
}
res.json(getResponseData(true));
}
@get('/')
home(req: BodyRequest, res: Response) {
const isLogin = req.session ? req.session.login : false;
if (isLogin) {
res.send(`
<html>
<body>
<a href='/getData'>爬取内容</a>
<a href='/showData'>展示内容</a>
<a href='/logout'>退出</a>
</body>
</html>
`);
} else {
res.send(`
<html>
<body>
<form method="post" action="/login">
<input type="password" name="password" />
<button>登陆</button>
</form>
</body>
</html>
`);
}
}
}
export function controller(target: any) {
for (let key in target.prototype) {
// 获取'path',从target.prototype中的key上获取
console.log(Reflect.getMetadata('path', target.prototype, key));
}
}
export function get(path: string) {
return function(target: any, key: string) {
// 存的key是'path',值是传入的path,存到target的key上
Reflect.defineMetadata('path', path, target, key);
};
}
"scripts": {
"test": "tsc && node ./build/controller/LoginController.js"
}
- 将方法所对应的路径,使用get这个方法装饰器,通过reflect-metadata绑定到方法上;
- 在LoginController这个类上添加controller类装饰器,获取到对应方法的path元数据值;
装饰器实现项目路由
在装饰器内添加生成路由的逻辑
import { Router } from 'express'; // 导出路由 export const router = Router(); export function controller(target: any) { for (let key in target.prototype) { const path = Reflect.getMetadata('path', target.prototype, key); // 拿到对应的方法 const handler = target.prototype[key]; if (path) { // 生成路由,放到了router下面 router.get(path, handler); } } } export function get(path: string) { return function(target: any, key: string) { Reflect.defineMetadata('path', path, target, key); }; }
引入LoginController类生成路由
// index.ts import './controller/LoginController'; // 生成路由 import { router } from './controller/decorators'; // 导出路由
在index.ts中引入LoginController类,装饰器在类声明时执行,相当于执行了这个装饰器,得到了router
运行
npm run dev
访问根路径(’/‘)和(’login‘)正常返回
多种请求方法装饰器
- 增加method元数据区分各类请求方法
- Method枚举类型解决method的any报错
- getRequestDecorator工厂函数生成各种方法装饰器
// decorators.ts
import { Router } from 'express';
export const router = Router();
enum Method {
get = 'get',
post = 'post',
put = 'put',
delete = 'delete'
}
export function controller(target: any) {
for (let key in target.prototype) {
const path = Reflect.getMetadata('path', target.prototype, key);
const method: Method = Reflect.getMetadata('method', target.prototype, key);
const handler = target.prototype[key];
if (path && method && handler) {
router[method](path, handler);
}
}
}
function getRequestDecorator(type: string) {
return function(path: string) {
return function(target: any, key: string) {
Reflect.defineMetadata('path', path, target, key);
Reflect.defineMetadata('method', type, target, key);
};
};
}
export const get = getRequestDecorator('get');
export const post = getRequestDecorator('post');
export const put = getRequestDecorator('put');
export const del = getRequestDecorator('delete'); // delete是关键字用del
// LoginController.ts
import 'reflect-metadata';
import { Request, Response } from 'express';
import { controller, get, post } from './decorators';
import { getResponseData } from '../utils/util';
interface BodyRequest extends Request {
body: { [key: string]: string | undefined };
}
@controller
class LoginController {
@post('/login')
login(req: BodyRequest, res: Response) {
const { password } = req.body;
const isLogin = req.session ? req.session.login : false;
if (isLogin) {
res.json(getResponseData(false, '已经登陆过'));
} else {
if (password === '123' && req.session) {
req.session.login = true;
res.json(getResponseData(true));
} else {
res.json(getResponseData(false, '登陆失败'));
}
}
}
@get('/logout')
logout(req: BodyRequest, res: Response) {
...
}
@get('/')
home(req: BodyRequest, res: Response) {
...
}
}