likes
comments
collection
share

记录使用 Ejs + Nest + Mysql 在服务端渲染模板

作者站长头像
站长
· 阅读数 51

这篇文章将记录下使用Ejs + Nest + Mysql 在服务端渲染模板。

Ejs 是利用普通的 JavaScript 代码生成 HTML 页面的框架,它简单易懂,学习成本比较低,还可以引用公共的Layout。可以去中文官网查看,网址为:ejs.bootcss.com/

Nest,众所周知,是 Node.js 服务器端应用程序的开发框架,是一款可以创建企业级应用的框架,相对而言,比较轻量级的可以用Express、Egg、Koa等,当然据网友们说,可以和Nest相提并论的有Midway,本人没用过Midway,所以不好下结论,各位可以去尝试下。

Mysql,这个接触过后端的大家都知道,是数据库,就不多做介绍了。

首先,先安装好有关的环境和依赖,提示:本人node版本为:18.16.0。

1、在cmd里,输入下方命令,全局安装Nest 脚手架。

新建:npm install -g @nestjs/cli
更新:npm update -g @nestjs/cli

2、在cmd里,输入下方命令,新建Nest项目,本人案例项目名为demo,注意新建项目的文件路径。(大家最好看看要不要切换npm源,本人这用原npm源有点慢,新建了快10分钟,当然也可能是网络问题)

nest new demo

3、在demo项目根目录里,打开cmd,输入下方命令安装Ejs。

npm install ejs

4、安装platform-express,照例,在命令行输入下方命令。

npm install @nestjs/platform-express

5、安装typeorm操作数据库,typeorm需要详细看官网文档去学习配置,这里不做详细介绍,照例,在命令行输入下方命令。

npm install @nestjs/typeorm

6、安装Mysql,输入下方命令安装

npm install mysql2

现在,所需的依赖都安装好了,万事具备只差数据库了,本地创建数据库我用的是phpStudy,当然大家也可以用其它工具,数据库管理用的是Navicat Premium。

记录使用 Ejs + Nest + Mysql 在服务端渲染模板

记录使用 Ejs + Nest + Mysql 在服务端渲染模板

新建完即可用phpStudy的phpMyAdmin,连接数据库并管理相关数据库。

记录使用 Ejs + Nest + Mysql 在服务端渲染模板

当然,也可以用Navicat Premium去连接并管理

记录使用 Ejs + Nest + Mysql 在服务端渲染模板

在demo项目根目录里新建一个模块,Nest有个方便的地方,就是有相关命令来新建模块,输入命令:nest generate resource news,它会把news的CRUD + REST api 的代码生成出来,非常的方便。

记录使用 Ejs + Nest + Mysql 在服务端渲染模板

REST API的代码已经生成,那么先把它晾在一边,先把Ejs用起来。

在项目根目录下创建public和views文件夹,在src入口的main.ts,配置模板引擎,这样就配置的差不多了,代码如下:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

//引入
import { NestExpressApplication } from '@nestjs/platform-express'

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  // 配置静态资源目录
  // app.useStaticAssets('public', {
  //   prefix: '/static/'
  // })
  
  // 模板引擎配置
  app.useStaticAssets('public'); //静态文件
  app.setBaseViewsDir('views');  //模板引擎目录
  app.setViewEngine('ejs')       //模板渲染引擎
  app.engine('html', require('ejs').renderFile);    //改为html文件,不想改为html文件可以不用加这句,后缀则为 .ejs

  await app.listen(3000);
}
bootstrap();

目录如下:public/static/images/目录里我放了一张2222的静态图片,我这里是在views文件夹里提前新建好了公共模块header.html,和default里的index.html和news.html。

记录使用 Ejs + Nest + Mysql 在服务端渲染模板

现在我们启动项目看看,在vsCode的项目终端输入命令npm run start:dev,在文件目录里输入命令nest start:dev都可以,启动成功后,在浏览器输入localhost:3000即可访问。

记录使用 Ejs + Nest + Mysql 在服务端渲染模板

好,来试试用index.html如何输出静态文字,打开src目录下的app.controller文件,在引入Render渲染,在@Render里,引入静态模板,接收的数据类型改为Object,因为等会return出来的是Object类型,代码如下:

import { Controller, Get, Render, Param } from '@nestjs/common'; // 引入Render
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {} // 引入 AppService

  @Get()
  @Render('default/index.html')  // 使用Render方法引入静态模板
  getHello(): Object {  // 收的数据类型改为Object
    return this.appService.getHello();  // 调用app.service的getHello方法
  }
  
  // 自定义 getVersion 方法: 
  @Get('/version')
  getVersion(): Object {
    return this.appService.getVersion(); 
  }
}

这个时候再打开app.service,这个文件能看到在controller层使用的getHello方法,改为代码如下,因为return的是Object类型,所以方法定义要改为是Object,我这里写代码的顺序是反了的,应该是先写getHello方法里代码,再写controller层的代码,不过这不碍事,只是小习惯不好

import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): Object {
    let returnBody = { name: "张三", img: "/static/images/2222.jpg", nav: [{id: '1', title:'导航1'}, {id: '2', title:'导航2'}]};
    return returnBody;
  }

  // 自定义:获取版本
  getVersion(): Object {
    return {
      code: 200, 
      msg: "",
      data: {
        version:"0.0.1"
      }
    }
  }
}

接下来就是在index.html写,从上面的代码里,输出了对象,对象里包含name、img、nav三个参,所以在index.html写的代码如下,引入了公共模块header.html,给header.html传入参数nav。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><%=name%></title>
</head>
<body>
    <%- include('../public/header.html', { nav: nav }); -%>
    
    <h3>首页模板引擎</h3>
    <p>hello, <%=name%>, </p>
    <img src="<%=img%>" alt="">
</body>
</html>

header.html

<div>
    我是头部公共模块 <%=name%> 下面是从index.html传过来的参数nav数组
    <% for(var i=0; i<nav.length; i++) {%>
        <div key="<%= nav[i].id %>">
            <%= nav[i].title %> <br>
        </div>
    <% } %>
</div>

刷新页面即可看到刚刚代码输出的静态内容

记录使用 Ejs + Nest + Mysql 在服务端渲染模板

这个时候来渲染从数据库获取的数据,用刚刚CRUD生成的news模块来输出,打开src目录下的app.module文件,引入TypeOrm,链接数据库,代码如下:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserModule } from './user/user.module';
import { NewsModule } from './news/news.module';
import { User } from './user/entities/user.entity';
import { News } from './news/entities/news.entity';

@Module({
  imports: [UserModule, NewsModule,
    TypeOrmModule.forRoot({
      type: "mysql",
      host: "localhost", // 数据库地址
      port: 3306,
      username: "用户名",
      password: "数据库密码",
      database: "数据库名称",
      synchronize: true,
      logging: true,
      entities: [User, News], // 需要使用数据库的模块实体
      poolSize: 10, // 最大链接数
      connectorPackage: 'mysql2',
      extra: {
          authPlugin: 'sha256_password',
      }
    }),],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

再打开刚刚CRUD生成的news模块目录,打开里面的news.service,里面有个findAll的方法,写入代码如下:(需要注意的是要引入news实体和typeorm,并使用@InjectEntityManager,把EntityManager注入)

import { Injectable } from '@nestjs/common';
import { InjectEntityManager } from '@nestjs/typeorm'; // typeorm实体管理
import { EntityManager } from 'typeorm'; // typeorm实体管理方法
import { CreateNewsDto } from './dto/create-news.dto';
import { UpdateNewsDto } from './dto/update-news.dto';
import { News } from './entities/news.entity'; // news实体

@Injectable()
export class NewsService {

  @InjectEntityManager()
  private manager: EntityManager; // 注入EntityManager

  create(createNewsDto: CreateNewsDto) {
    this.manager.save(News, createNewsDto);
  }

  async findAll() {
    const [users, count] = await this.manager.findAndCount(News); // 调用EntityManager的方法

    let data = {
      rows: users,  // rows数组
      total: count  // 总共几条
    }
    return data;
  }

  findOne(id: number) {
    return `This action returns a #${id} news`;
  }

  update(id: number, updateNewsDto: UpdateNewsDto) {
    return `This action updates a #${id} news`;
  }

  remove(id: number) {
    return `This action removes a #${id} news`;
  }
}

typeorm具体的 EntityManager的方法大概有这些,我用的是findAndCount这个方法,可去看typeorm相关文档

  • save:新增或者修改 Entity,如果传入了 id 会先 select 再决定修改还新增
  • update:直接修改 Entity,不会先 select
  • insert:直接插入 Entity
  • delete:删除 Entity,通过 id
  • remove:删除 Entity,通过对象
  • find:查找多条记录,可以指定 where、order by 等条件
  • findBy:查找多条记录,第二个参数直接指定 where 条件,更简便一点
  • findAndCount:查找多条记录,并返回总数量
  • findAndCountBy:根据条件查找多条记录,并返回总数量
  • findOne:查找单条记录,可以指定 where、order by 等条件
  • findOneBy:查找单条记录,第二个参数直接指定 where 条件,更简便一点
  • findOneOrFail:查找失败会抛 EntityNotFoundError 的异常
  • query:直接执行 sql 语句
  • createQueryBuilder:创建复杂 sql 语句,比如 join 多个 Entity 的查询
  • transaction:包裹一层事务的 sql
  • getRepository:拿到对单个 Entity 操作的类,方法同 EntityManager

再打开news.controller文件,写入代码如下:

import { Controller, Get, Post, Body, Patch, Param, Delete, Render } from '@nestjs/common';
import { NewsService } from './news.service';
import { CreateNewsDto } from './dto/create-news.dto';
import { UpdateNewsDto } from './dto/update-news.dto';

@Controller('news')
export class NewsController {
  constructor(private readonly newsService: NewsService) {} // 引入 NewsService

  @Post()
  async create(@Body() createNewsDto: CreateNewsDto) {
    await this.newsService.create(createNewsDto);
    let returnBody = {
      code: 200,
      message: '创建成功',
      data: true
    }
    return returnBody
  }

  @Get() // 页面链接带参数请在这里定义,形成伪静态
  @Render('default/news.html') // 注意引入模板引擎!
  findAll() {
    return this.newsService.findAll(); // 调用service层的方法
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.newsService.findOne(+id);
  }

  @Patch(':id')
  update(@Param('id') id: string, @Body() updateNewsDto: UpdateNewsDto) {
    return this.newsService.update(+id, updateNewsDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.newsService.remove(+id);
  }
}

在刚才新建好的views/default/news.html写入代码,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>新闻页面</title>
</head>
<body>
    总共有新闻<%=total%>条
    <br>
    ----------------------------------------
    <br>
    <% rows.forEach(function(item) {%>
        <div class="cece">
            <%= item.title %> <br>
            <%= item.descption %>
        </div>
    <% }); %>
</body>
</html>

然后打开localhost:3000/news,打开的页面如下图:

记录使用 Ejs + Nest + Mysql 在服务端渲染模板

再打开数据库,看看数据对不对,

记录使用 Ejs + Nest + Mysql 在服务端渲染模板

渲染的视图数据和数据库的数据是一模一样的,那么就是正常了。

本文记录到这里,大家一起共勉学习进步。

转载自:https://juejin.cn/post/7280740613891424275
评论
请登录