Typescript node starter 3. App Router Controller

Request

request对象表示HTTP请求,并具有请求query字符串、参数、body、HTTP headers等的属性。除了添加新的属性和方法外,还包含原型的属性和方法。

随着系列文章的发布,我们将继续研究使用request对象;

Response

response对象表示程序在接收到HTTP请求时发送HTTP响应。它最重要的方法就是send,它发送HTTP响应,所以客户端能够接收到它。send函数接受不同类型的数据,例如string,object,数组或缓冲区。send使用数据结束响应过程,也可以使用end函数结束响应过程。

与request对象一样,我们将继续深入研究和使用它。

app.get('/', (request, response) => {
  response.send({
    hostname: request.hostname,
    path: request.path,
    method: request.method,
  });
});

Controllers

创建一个Express应用的常见方法叫做mvc。controller是mvc的关键组件,它包含了应用程序中处理客户端请求的主要逻辑。为了使项目具有良好的可读性,我创建了一个app类,并且使用外置路由挂载相应的controller函数。

在server脚本中加载应用,监听端口。 src/server.ts

app.listen(process.env.PORT || 3001, () => {
    logger.info(`Server running at http://localhost:${process.env.PORT} in ${process.env.NODE_ENV}`);
});

下面代码定义了app类,通过构造函数创建express应用,注册中间件,初始化路由器,连接数据库。src/app.ts:

class App {
    app: express.Application = express();
    private _routes: Router;

    constructor(mongoUrl: string) {
        this.app = express();
        this.initializeStaticFolder(this.app);
        this.initializeMiddlewares(this.app);

        this._routes = new Router();
        this._routes.initializeRouter(this.app);

        this.mongoSetup(mongoUrl);
        this.app.use((request: Request, response: Response) => {
            return response.status(404).json({ code: -1, data: null, msg: "Notfound" })
        });
    }
	//初始化中间件
    private initializeMiddlewares = (app: express.Application): void =>{
        app.use(express.json());
        app.use(bodyParser.json());
        app.use(bodyParser.urlencoded({ extended: false }));
    }
	//初始化静态文件夹
    private initializeStaticFolder = (app: express.Application): void =>{
        const folder = "assets";
        const fileFolder = path.resolve(folder);
        app.use(express.static(fileFolder))
    }
	//连接数据库
    private mongoSetup = (connStr: string): void => {
        mongoose.connect(connStr, { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true, useFindAndModify: false }).then(
            () => { logger.info("MongoDB connection success!"); }
        ).catch(
            (err) => { logger.error("MongoDB connection error. Please make sure MongoDB is running. " + err); }
        );
    }
}

export default new App(MONGODB_URI).app;

  下面代码定义了应用程序的总路由器类,通过构造函数实例化外置路由和控制器;定义初始化路由函数,将express应用程序传递给外置路由器。src/router.ts:

export class Router {
    private _clientRouter: ClientRouter;

    constructor() {
        const clientController = new ClientController();
        this._clientRouter = new ClientRouter(clientController);
    }

    //registered routing.
    initializeRouter = (app): void => {
        this._clientRouter.router(app);
    }
}

下面的代码定义了client的外置路由器,涉及到了client的增删改查功能。src/auth/client/clientRouter.ts

export class ClientRouter {
    private _clientController: ClientController;
    private _router: Router;

    constructor(clientController: ClientController) {
        this._clientController = clientController;
        this._router = Router();//创建一个express的外置路由
        this.initRouter(this._router);
    }

    //配置路由与controller.
    private initRouter = (router: Router): void => {

        router.route("")
            .get(this._clientController.getClients)
            .post(this._clientController.create);

        router.route("/:id")
            .patch(this._clientController.update)
            .delete(this._clientController.delete);
    }

    //将外置路由配置给express应用程序
    router = (app: express.Application): void => {
        app.use("/api/v1/admin/clients", this._router);
    }
}

下列代码定义了client的控制器类,该类中的函数要被传递给clientRouter使用,上下文发生了变化,所以采用箭头函数保证this的指向正确。src/auth/client/clientController.ts

export class ClientController
{
    private _iclientRepository: IClientRepository;
    constructor(iClientRepository: IClientRepository)
    {
        this._iclientRepository = iClientRepository;
    }

    create = async(req: Request, res: Response, next: NextFunction): Promise<void | Response>=>{
        try
        {
            const { clientId, clientName, grants } = req.body;
            const body = { clientId, clientName, grants };
            const client = await this._iclientRepository.create(body);
            if(client){
                return this.responseSuccess(201, client, "Created.", res);
            }
            else{
                return this.responseWarn(200, {code: ErrCode.CLIENTID_OR_CLIENTNAME_EXISTS}, "ClientName or clientId field is already exists.", res);
            }
        }
        catch (e)
        {
            logger.error(e);
            next(e);
        }
        
    }

    getClients = async(req: Request, res: Response, next: NextFunction): Promise<void | Response>=>{
        try
        {
            let pageSize = req.query.pageSize || 5;
            let page = req.query.page || 1;
    
            pageSize = (Number)(pageSize);
            page = (Number)(page);
            const clients = await this._iclientRepository.getClients(page, pageSize);
            if(clients){
                return this.responseSuccess(200, clients, `${clients.length} client.`, res);
            }
            else{
                return this.responseWarn(200, {code: ErrCode.CLIENT_NOCONTENT}, "0 client.", res);
            }
        }
        catch (e)
        {
            logger.error(e);
            next(e);
        }
    }

    update = async(req: Request, res: Response, next: NextFunction): Promise<void | Response>=>{
        try
        {
            const { id } = req.params;
            const body = req.body;
            const clientName = body.clientName;
    
            if (body.clientId || body.clientId === "") {
                delete body.clientId;
            }
            if (body.clientSecret || body.clientSecret === "") {
                delete body.clientSecret;
            }

            const client = await this._iclientRepository.update(id, clientName, body);
            if(client){
                return this.responseSuccess(200, client, `${client.clientName} has been updated.`, res);
            }
            else{
                return this.responseWarn(200, {code: ErrCode.INVALID_CLIENT}, "The client is notfound or clientName/clientId field is already exists.", res);
            }
        }
        catch (e)
        {
            logger.error(e);
            next(e);
        }
    }

    delete = async(req: Request, res: Response, next: NextFunction): Promise<void | Response>=>{
        try
        {
            const { id } = req.params;
            const client = await this._iclientRepository.delete(id);
            if(client){
                return this.responseSuccess(204, null, "deleted.", res);
            }
            else{
                return this.responseWarn(200, {code: ErrCode.CLIENT_NOTFOUND}, "The client is notfound.", res);
            }
        }
        catch (e)
        {
            logger.error(e);
            next(e);
        }
    }

    private responseSuccess = (statusCode: number, data: object, msg: string, res: Response): void =>{
        res.status(statusCode).json({
            code: 0,
            data,
            msg
        });
    }

    private responseWarn = (statusCode: number, data: object, msg: string, res: Response): void =>{
        res.status(statusCode).json({
            code: 1,
            data,
            msg
        });
    }
}

  

posted @ 2020-07-03 22:24  冷风冷雨  阅读(178)  评论(0)    收藏  举报