Typescript爬虫实战(4) ---- 创建控制器和装饰器

为了将面向过程的代码改造成面向对象的代码。
将现有的代码进行改造。
首先将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
//在方法的装饰器上绑定
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 处理请求相关的装饰器
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

你可能感兴趣的:(Typescript爬虫实战(4) ---- 创建控制器和装饰器)