使用node+typescript搭建mvc后台(二)--使用routing-controllers搭建controller层

1,899 阅读4分钟

项目博客地址

接下来我们要routing-controllers进行controller层的搭建。
首先安装routing-controllers。这玩意在之前已经在package的依赖中了。就不介绍如何安装了。

新建环境变量获取类

这里先添加一个环境的获取方法。在后期有些我们不想暴露的或者可以根据开发生产环境区分的内容就可以卸载.evn文件里。
这里使用dotenv对环境进行一个配置(后期引用的包就不再多进行介绍安装方法
基本上就是 npm install 包命
如果需要保存到package.json文件中就加 --save 如果是开发环境才需要就加-dev
)
添加一个环境变脸配置文件。导出环境变量方法。
具体实现如下:

import * as dotenv from 'dotenv';
import * as path from 'path';
const join = path.join;

// 这行代码可以选择你拥有的后缀。选择不同的环境。
dotenv.config({ path: path.join(process.cwd(), `.env${((process.env.NODE_ENV === 'development') ? '.development' : '')}`) });

export const env={
    app:{
        routePrefix: getOsEnv('APP_ROUTE_PREFIX'),
        dirs:{
            controllers: getOsPaths('CONTROLLERS'),
            middlewares: getOsPaths('MIDDLEWARES'),
            interceptors: getOsPaths('INTERCEPTORS'),
        }
    }
}

export function getOsEnv(key: string): string {
    if (typeof process.env[key] === 'undefined') {
        throw new Error(`Environment variable ${key} is not set.`);
    }

    return process.env[key] as string;
}

export function getOsPaths(key: string): string[] {
    return getPaths(getOsEnvArray(key));
}

export function getOsEnvArray(key: string, delimiter: string = ','): string[] {
    /// @ts-ignore
    return process.env[key] && process.env[key].split(delimiter) || [];
}

export function getPath(path: string): string {
    console.log(path);
    // 不同的环境下获取的文件夹不同。如果是开发环境。那么跟文件夹就是dist。要做替换
    return (process.env.NODE_ENV === 'production')
        ? join(process.cwd(), path.replace('src/', 'dist/').slice(0, -3) + '.js')
        : join(process.cwd(), path);
}
export function getPaths(paths: string[]): string[] {
    return paths.map(p => getPath(p));
}

其中的一些方法是对获取环境的封装,比如对一个地址。我们可以拿到匹配到的文件表达式数组,这边规定了是用,来区分

而我目前来说配置的环境常量有如下:

# .evn.development
#配置controller路径
CONTROLLERS=src/api/controllers/**/*Controller.ts
#配置中间件路径
MIDDLEWARES=src/api/middlewares/**/*Middleware.ts
#配置拦截器路径
INTERCEPTORS=src/api/interceptors/**/*Interceptor.ts
# 路由base路径
APP_ROUTE_PREFIX=/api

修改expressLoader

引入routing-controllers的express,对之前生成额app进行一个包装,
首先我们也可以删除掉了原来的jade的配置。因为我们现在已经不需要jade来做一面了。准备做一个前后端分离的项目。
就是删除这三句:

// view engine setup // app.set('views', path.join(__dirname, 'views')); // app.set('view engine', 'jade');

然后之前的路由也可以不需要了直接删除

// app.use('/', indexRouter);

因为这里我们已经使用了routing-controllers  来做路由的配置

接着我们要删除原来的404和错误处理。

// catch 404 and forward to error handler
    // app.use(function (req, res, next) {
    //     res.json('error');
    //     next(createError(404));
    // });

    // // error handler
    // app.use(function (err: any, req: any, res: any, next: any) {
    //     // set locals, only providing error in development
    //     res.locals.message = err.message;
    //     res.locals.error = req.app.get('env') === 'development' ? err : {};

    //     // render the error page
    //     res.status(err.status || 500);
    //     res.json('error');
    // });

因为routing-controllers 在controller返回请求后不会终止次线程。会继续往下走。如果还保留原来的use。就会再返回一次请求。那么就会抛出一个异常。所以这里先暂时删除。此错误处理。等到后期我们再用一个错误中间件来解决这个问题。

接着我们使用useExpressServer 对我们原app服务实例进行一个封装。使他可以使用controller来处理接口
这里在配置cors的时候可能在启动服务的时候会报cors的包找不到。记得npm install下就好了
生成后代码如下

// 配置mvc服务的
    useExpressServer(app, {
        routePrefix: env.app.routePrefix, // 路由前缀
        cors: true, // 是否开启跨域请求
        classTransformer: false, // 是否开启类型转换,在获得参数的时候来决定参数形式
        controllers: env.app.dirs.controllers, // 配置controller文件。传入的是一个数组,
        middlewares: env.app.dirs.middlewares, // 配置中间件
        interceptors: env.app.dirs.interceptors, // 配置拦截器
        authorizationChecker: authorizationChecker, // 配置身份校验
        currentUserChecker: currentUserChecker, // 获取当前用户
    });

这里对一些插件的搭配可以提前先建立好环境。等到后期我们需要用到的时候可以再进行一个补充。

如我搭建的项目结构

image.png

对于权限验证和获取当前用户的插件我们先保留一个输出函数。等到后期再做实现。

export function authorizationChecker() : boolean {
    return true
}
export function currentUserChecker(){
}

添加一个controller

接下来我们来添加一个controller。在controllers下新建一个indexControllers文件。要注意。这里的文件命名要和配置的文件命名规则相符合。否者在获取的时候将会获取不到。也就是如我以上的规则。文件名则是要以Controller.ts为结尾

新建一个controllers.ts然后编写一个基础请求。

import { Get, JsonController } from "routing-controllers";

@JsonController('/')
export default class UserController {
    constructor() {
    }

    @Get()
    public find() {
        console.log('hello world');
        return "hello wrold"
    }

}

最后我们再重启服务器。浏览器输入http://localhost:3000/api
因为我们之前设置了routePrefix: env.app.routePrefix, // 路由前缀
路由的根路径。所以现在是以api为一个根路径。
然后就可以看到通过controller的返回形式了。

image.png

码云地址