为了将面向过程的代码改造成面向对象的代码。
将现有的代码进行改造。
首先将login的逻辑进行迁移:
创建LoginController.ts
,并将代码迁移过来,先迁移具体逻辑,不管路由
class LoginController{
home(req:Request,res:Response){
const isLogin = req.session ? req.session.login : false
if(isLogin){
res.send(`
logout
getData
showData
`)
}else{
const formHtml = `
`
res.send(formHtml)
}
}
}
// LoginController.ts
- 创建一个路由的控制器,并通过原数据的方式,将路径保存在这个方法之上
//controller类的装饰器
function controller(target:any){
for(let key in target.prototype){
//打印出绑定的路径
console.log(Reflect.getMetadata('path',target.prototype,key))
// ‘/’
}
}
//路由的装饰器
function get(path:string){
return function(target:any,key:string){
Reflect.defineMetadata('path',path,target,key)
}
}
@controller
class LoginController{
@get('/')
home()
...
}
在完成基础的装饰器之后,我们需要让LoginController
通过装饰器实现路由的功能
- 根据在原数据上的路径,如果路径存在,自动生成项目的路由
export function controller(target:any){
for(let key in target.prototype){
const path = Reflect.getMetadata('path',target.prototype,key)
if(path){
const handler = target.prototype[key]
router.get(path,handler)
}
}
}
- 为了能自动生成路由,只需要引入
LoginController
这个文件,就能执行,并生成路由 - 将所有的get请求迁移过来
class LoginController{
@get('/')
home(req:Request,res:Response){
const isLogin = req.session ? req.session.login : false
if(isLogin){
res.send(`
logout
getData
showData
`)
}else{
const formHtml = `
`
res.send(formHtml)
}
}
@get('/logOut')
logOut(req:Request,res:Response){
if(req.session){
req.session.login = undefined
}
res.json(getResponseData(true));
}
}
- 接下来再迁移一下原有的post请求
//LoginController.ts
@post('/login')
login(req:Request,res:Response){
const isLogin = req.session ? req.session.login : false
if(isLogin){
res.json(getResponseData(false, '已经登陆过'));
}else{
if(req.body.password === '123' && req.session){
req.session.login = true
res.json(getResponseData(true));
}else{
res.json(getResponseData(false, 'login failed'));
}
}
}
//decorator.ts
export function post(path:string){
return function(target:any,key:string){
Reflect.defineMetadata('path',path,target,key)
}
}
- 但是原有的装饰器已满足不了新的需求,因为原有的装饰器无法辨别出post和get请求,所以,需要在元数据上绑定一个请求方法
enum Method{
get = 'get',
post = 'post',
put = 'put',
del = '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上绑定方法
router[method](path,handler)
}
}
}
export function post(path:string){
return function(target:any,key:string){
Reflect.defineMetadata('path',path,target,key)
Reflect.defineMetadata('method','post',target,key)
}
}
- 同时也可以看到,生成请求方法装饰器的函数有大量内容冗余,可以利用工厂模式优化一代码
function methodFactory(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 = methodFactory('get')
export const post = methodFactory('post')
export const put = methodFactory('put')
- 对使用了中间件的路由的装饰器
- middleware类型:
RequestHandler
- middleware类型:
//在方法的装饰器上绑定
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 middleware = Reflect.getMetadata('middleware',target.prototype,key)
const handler = target.prototype[key]
if(path&&method&&handler){
//如果有中间件就使用中间件
if(middleware){
router[method](path,middleware,handler)
}else{
router[method](path,handler)
}
}
}
}
//中间件的装饰器
export function use(middleware:RequestHandler){
return function(target:any,key:string){
Reflect.defineMetadata('middleware',middleware,target,key)
}
}
优化项目结构
- 将router从decorator中拆分出来
import {Router} from 'express';
export const router = Router()
- 按职责对decorator进行进一步拆分
- use.ts 处理中间件相关的装饰器
import {RequestHandler} from 'express'; export function use(middleware:RequestHandler){ return function(target:any,key:string){ Reflect.defineMetadata('middleware',middleware,target,key) } }
- request.ts 处理请求相关的装饰器
- use.ts 处理中间件相关的装饰器
enum Methods{
get = 'get',
post = 'post',
put = 'put',
del = 'delete'
}
function methodFactory(type:Methods){
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 = methodFactory(Methods.get)
export const post = methodFactory(Methods.post)
export const put = methodFactory(Methods.put)
- controller.ts 处理controller类的装饰器
import {Router,Request,Response, NextFunction,RequestHandler} from 'express';
import {router} from '../router'
enum Methods{
get = 'get',
post = 'post',
put = 'put',
del = 'delete'
}
export function controller(target:any){
for(let key in target.prototype){
const path = Reflect.getMetadata('path',target.prototype,key)
const method:Methods = Reflect.getMetadata('method',target.prototype,key)
const middleware = Reflect.getMetadata('middleware',target.prototype,key)
const handler = target.prototype[key]
if(path&&method&&handler){
if(middleware){
router[method](path,middleware,handler)
}else{
router[method](path,handler)
}
}
}
}
最终项目目录:
├── data
│ └── course.json
├── package-lock.json
├── package.json
├── src
│ ├── analyzer.ts
│ ├── analyzerB.ts
│ ├── controller
│ │ ├── CrowllerController.ts
│ │ ├── LoginController.ts
│ │ └── decoratorOld.ts
│ ├── crowller.ts
│ ├── customer.d.ts
│ ├── decorator
│ │ ├── controller.ts
│ │ ├── index.ts
│ │ ├── request.ts
│ │ └── use.ts
│ ├── index.ts
│ ├── responseHandler.ts
│ ├── router.ts
│ └── routerOld.ts
└── tsconfig.json