ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## MVC(模型-视图-控制器) `Nest` 默认使用 `Express` 库,因此,在 `Express` 中使用 `MVC` (模型 - 视图 - 控制器)模式的每一种技术同样适用于 `Nest` 。首先,让我们使用 `CLI` 工具搭建一个简单的 `Nest` 应用程序: ```bash $ npm i -g @nestjs/cli $ nest new project ``` 为了创建一个简单的 `MVC` 应用程序,我们必须安装一个[模板引擎](http://expressjs.com/en/guide/using-template-engines.html): ```bash $ npm install --save hbs ``` 我们决定使用 [hbs](https://github.com/pillarjs/hbs#readme) 引擎,但您可以使用任何符合您要求的内容。安装过程完成后,我们需要使用以下代码配置 `express` 实例: > main.ts ```typescript import { NestFactory } from '@nestjs/core'; import { NestExpressApplication } from '@nestjs/platform-express'; import { join } from 'path'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create<NestExpressApplication>(AppModule); app.useStaticAssets(join(__dirname, '..', 'public')); app.setBaseViewsDir(join(__dirname, '..', 'views')); app.setViewEngine('hbs'); await app.listen(3000); } bootstrap(); ``` 我们告诉 `express`,该 `public` 目录将用于存储静态文件, `views` 将包含模板,并且 `hbs` 应使用模板引擎来呈现 `HTML` 输出。 `app.useStaticAssets` 还支持第二个参数来设置虚拟目录。 ```typescript app.useStaticAssets(join(__dirname, '..', 'public'), { prefix: '/static', }); ``` ### 模板渲染 现在,让我们在该文件夹内创建一个 `views` 目录和一个 `index.hbs` 模板。在模板内部,我们将打印从控制器传递的 `message`: > index.hbs ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>App</title> </head> <body> {{ message }} </body> </html> ``` 然后, 打开 `app.controller` 文件, 并用以下代码替换 `root()` 方法: > app.controller.ts ```typescript import { Get, Controller, Render } from '@nestjs/common'; @Controller() export class AppController { @Get() @Render('index') root() { return { message: 'Hello world!' }; } } ``` 在这个代码中,我们指定模板使用`@Render()`装饰器,同时将路径处理器方法的返回值被传递给要渲染的模板。注意,该返回值是一个包含`message`属性的对象,和我们之前创建模板中的`message`占位符对应。 在应用程序运行时,打开浏览器访问 `http://localhost:3000/` 你应该看到这个 `Hello world!` 消息。 ### 动态模板渲染 如果应用程序逻辑必须动态决定要呈现哪个模板,那么我们应该使用 `@Res()`装饰器,并在路由处理程序中提供视图名,而不是在 `@Render()` 装饰器中: > 当 `Nest` 检测到 `@Res()` 装饰器时,它将注入特定于库的响应对象。我们可以使用这个对象来动态呈现模板。在[这里](http://expressjs.com/en/api.html)了解关于响应对象 `API` 的更多信息。 > app.controller.ts ```typescript import { Get, Controller, Render } from '@nestjs/common'; import { Response } from 'express'; import { AppService } from './app.service'; @Controller() export class AppController { constructor(private readonly appService: AppService) {} @Get() root(@Res() res: Response) { return res.render(this.appService.getViewName(), { message: 'Hello world!' }); } } ``` [这里](https://github.com/nestjs/nest/tree/master/sample/15-mvc)有一个可用的例子。 ### Fastify 如本章所述,我们可以将任何兼容的 `HTTP` 提供程序与 `Nest` 一起使用。比如 [Fastify](https://github.com/fastify/fastify) 。为了创建具有 `fastify` 的 `MVC` 应用程序,我们必须安装以下包: ```bash $ npm i --save fastify point-of-view handlebars ``` 接下来的步骤几乎涵盖了与 `express` 库相同的内容(差别很小)。安装过程完成后,我们需要打开 `main.ts` 文件并更新其内容: > main.ts ```typescript import { NestFactory } from '@nestjs/core'; import { NestFastifyApplication, FastifyAdapter } from '@nestjs/platform-fastify'; import { AppModule } from './app.module'; import { join } from 'path'; async function bootstrap() { const app = await NestFactory.create<NestFastifyApplication>(AppModule, new FastifyAdapter()); app.useStaticAssets({ root: join(__dirname, '..', 'public'), prefix: '/public/', }); app.setViewEngine({ engine: { handlebars: require('handlebars'), }, templates: join(__dirname, '..', 'views'), }); await app.listen(3000); } bootstrap(); ``` Fastify 的`API` 略有不同,但这些方法调用背后的想法保持不变。使用 Fastify 时一个明显的需要注意的区别是传递到 `@Render()` 装饰器中的模板名称包含文件扩展名。 > app.controller.ts ```typescript import { Get, Controller, Render } from '@nestjs/common'; @Controller() export class AppController { @Get() @Render('index.hbs') root() { return { message: 'Hello world!' }; } } ``` 在应用程序运行时,打开浏览器并导航至 `http://localhost:3000/` 。你应该看到这个 `Hello world!` 消息。 [这里](https://github.com/nestjs/nest/tree/master/sample/17-mvc-fastify)有一个可用的例子。