本文未全部完成,后续会继续更新,请大家监督!同时在此也祝大家新春快乐!虎年大吉!虎虎生威!
Node 框架对比
Express
Express 是一个保持最小规模的灵活的 Node.js Web 应用程序开发框架,为 Web 和移动应用程序提供一组强大的功能。
github:github.com/expressjs/e…
中文官网:www.expressjs.com.cn/
Koa
koa 是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。
koa 是一个拥有洋葱模型中间件的 http 处理库,一个请求,经过一系列的中间件,最后生成响应。
Koa的大致实现原理:context 上下文的保存和传递,中间件的管理和 next 方法的实现。
中文官网:www.koajs.com.cn/
Egg
阿里团队基于 Koa 来做的。Egg 奉行『约定优于配置』,按照一套统一的约定进行应用开发。
对于开发者来说,Egg 因为是国产,所以文档比较好理解,也比较齐全。但是 EggJS 有2个问题。
一个是依赖注入的问题,导致所有的代码文件是按照功能来归类的,比如所有的控制器代码都会放置在同一个目录下,所有的服务代码也全部放置在 service 目录下,在模块众多的情况下,开发时需要来回切换分散在不同目录下的文件,给开发带来了不便。
另一个是对 TS 的支持天生残缺(egg-ts-helpers),各种第三方库的支持也不受控制。
为了解决这些问题,阿里新出了 Midway 框架。
Midway
Midway 是 Egg 的新一代版本。
midwayjs 一个面向未来的云端一体 Node.js 框架。
Midway 是一个适用于构建 Serverless 服务,传统应用、微服务,小程序后端的 Node.js 框架。
Midway 对于依赖采用了自动扫描的机制,连手动注册依赖的一步都可以省去。
Midway 内部使用了自动扫描的机制,在应用初始化之前,会扫描所有的文件,包含装饰器的文件会自动绑定到容器。
同时使用 TypeScript 开发。但是也有人说 midway 是为了 ts 而 ts。
Nest
Nest.js 背后是国外的 Trilon 团队。Nestjs 是基于 Express 开发的, Koa.js 是 Express.js 原班人马用新理念重新创作的框架,相信是有一定的先进性的,而 Express.js 因为产生历史早,而有更好的生态基础,周边的插件、中间件什么的可能更丰富。
Nest 属于前端 ts 大趋势下深度使用注解特性并提供各种增强开发体验的框架,它提供了一套完整的解决方案,包含了认证、数据库、路由、http 状态码、安全、配置、请求等开箱即用的技术。
内置并完全支持 TypeScript(但仍然允许开发人员使用纯 JavaScript 编写代码)。
Nestjs 采用命令行工具生成相应的文件,比如 provider, module, controller, filter 等等,所以无需手动添加相应的文件。
Nestjs 毕竟是国外的框架,他的生态会比 Midway 的生态更好,这也是我为什么选择 Nestjs 的原因。
中文官网:docs.nestjs.cn/
Nest 最基础的几个概念
控制器(controller)
控制器负责处理传入的请求和向客户端返回响应。
要使用 CLI 创建控制器,只需执行 $ nest g controller cats
命令。
介绍 路由,Request, 状态码,Headers, 重定向,路由参数
Nest 为所有标准的 HTTP 方法提供了相应的装饰器:@Put()
、@Delete()
、@Patch()
、@Options()
、以及 @Head()
。
注册控制器。
/* cats.controller.ts */
import { Controller, Get, Query, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { CreateCatDto, UpdateCatDto, ListAllEntities } from './dto';
@Controller('cats')
export class CatsController {
@Post()
create(@Body() createCatDto: CreateCatDto) {
return 'This action adds a new cat';
}
@Get()
findAll(@Query() query: ListAllEntities) {
return `This action returns all cats (limit: ${query.limit} items)`;
}
@Get(':id')
findOne(@Param('id') id: string) {
return `This action returns a #${id} cat`;
}
@Put(':id')
update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto) {
return `This action updates a #${id} cat`;
}
@Delete(':id')
remove(@Param('id') id: string) {
return `This action removes a #${id} cat`;
}
}
提供者(Providers)
Provider 只是一个用 @Injectable()
装饰器注释的类。可以理解为 Model。
控制器应处理 HTTP
请求并将更复杂的任务委托给 providers。
要使用 CLI
创建服务类,只需执行 $ nest g service cats
命令。
注册提供者。
import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
import { CatsService } from './cats/cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class AppModule {}
模块(Module)
模块是具有 @Module()
装饰器的类。
nest g module cats
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ProjectController } from './project.controller';
import { ProjectService } from './project.service';
import { ProjectEntities } from '../shared/entity/project.entities';
@Module({
imports: [TypeOrmModule.forFeature([ProjectEntities])],
controllers: [ProjectController],
providers: [ProjectService],
})
export class ProjectModule {}
Nest 的第一个 demo
nest new project-name
cd first-nest
npm run start:dev
创建 controller, module, service
nest g controller user
nest g service user
nest g module user
迁移 controller, service
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './user/user.module';
@Module({
imports: [UserModule], // 这里
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
// user.module.ts
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
@Module({
controllers: [UserController],
providers: [UserService],
})
export class UserModule {}
// user.service.ts
import { Injectable } from '@nestjs/common';
import { User } from '../mock/user';
import { MockUser } from '../mock/MockUser';
@Injectable()
export class UserService {
private mockUser = new MockUser();
public findAll(): Array<User> {
return this.mockUser.data;
}
public add(user: User): User {
this.mockUser.data.push(user);
return user;
}
public update(user: User): User {
this.remove(user.id);
this.mockUser.data.push(user);
return user;
}
public remove(id: number): void {
this.mockUser.data = this.mockUser.data.filter((v) => v.id != id);
}
public findOne(id: number): User {
return this.mockUser.data.find((v) => v.id == id);
}
}
// user.controller.ts
import {
Controller,
Get,
Post,
Body,
Patch,
HttpCode,
Param,
Delete,
} from '@nestjs/common';
import { User } from '../mock/user';
import { UserService } from './user.service';
import { InputUser } from '../mock/input';
import { UpdateUser } from '../mock/update';
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}
/**
* findAll
*/
@Get()
@HttpCode(200)
public findAll(): Array<User> {
return this.userService.findAll();
}
@Post()
@HttpCode(201)
public add(@Body() input: InputUser): User {
if (input.id === undefined) {
throw new Error('未带入ID');
}
const user: User = {
...input,
};
return this.userService.add(user);
}
@Patch(':id')
@HttpCode(203)
public update(@Param() param, @Body() update: UpdateUser): User {
const userInfo = this.userService.findOne(param.id);
if (!userInfo) {
throw new Error('该用户不存在');
}
userInfo.no = update.no;
userInfo.name = update.name;
return this.userService.update(userInfo);
}
@Delete(':id')
@HttpCode(204)
public remove(@Param() param): void {
this.userService.remove(param.id);
}
@Get(':id')
@HttpCode(200)
public findOne(@Param() param): User {
return this.userService.findOne(param.id);
}
}
接口验证
1、获取所有的用户信息 http://localhost:3000/user
2、新增用户信息 post http://localhost:3000/user?id=1&no=test1&name=zhangsan
3、修改用户信息 patch http://localhost:3000/user/1
no: test2
name: lisi
4、根据id 获取用户信息get http://localhost:3000/user/1
5、删除某条用户信息 delete http://localhost:3000/user/1
参数区别
Query: Query Params中获取
Body: body中获取
Param: url中获取
Nest 数据库连接
创建数据库表
1、SQL语句创建
验证数据库的安装
mysqladmin --version
// 显示的结果
mysqladmin Ver 8.0.25 for macos11.3 on x86_64 (Homebrew)
链接数据库
// mysql -h 主机名 -u 用户名 -p
mysql -h 127.0.0.1 -u root -p
// 输入密码
Enter password: 123456
管理数据库的命令
// SHOW DATABASES: 列出 MySQL 数据库管理系统的数据库列表。
SHOW DATABASES;
// USE 数据库名 : 选择要操作的Mysql数据库,使用该命令后所有Mysql命令都只针对该数据库。
USE demo;
// SHOW TABLES: 显示指定数据库的所有表,使用该命令前需要使用 use 命令来选择要操作的数据库。
SHOW tables;
// SHOW COLUMNS FROM 数据表: 显示数据表的属性,属性类型,主键信息 ,是否为 NULL,默认值等其他信息。
SHOW COLUMNS FROM users;
// SHOW INDEX FROM 数据表: 显示数据表的详细索引信息,包括PRIMARY KEY(主键)
SHOW INDEX FROM users;
创建数据库,删除数据库
// CREATE DATABASE 数据库名;
CREATE DATABASE name_database;
// DROP DATABASE <数据库名>;
DROP DATABASE name_database;
创建数据库表,删除数据库表
// CREATE TABLE table_name (column_name column_type): 创建数据库表
CREATE TABLE IF NOT EXISTS `runoob_tbl`(
`id` INT UNSIGNED AUTO_INCREMENT,
`no` VARCHAR(225) NOT NULL,
`number` VARCHAR(225) NOT NULL,
`submission_date` DATE,
PRIMARY KEY ( `id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
// DROP TABLE table_name :删除数据库表:
2、navicat操作
新建数据库,新建表
TypeORM 集成
TypeORM 框架是对象关系映射框架。通常,对象部分是指应用程序中的域/模型,关系部分是关系数据库管理系统中的表之间的关系(例如Oracle, MYSQL等),最后,映射部分是指桥接模型和表格的行为。
ORM 是一种将实体与数据库表进行映射的工具。
nest js TypeORM 文档:docs.nestjs.cn/8/technique…
TypeORM 中文文档:typeorm.biunav.com/zh/
TypeORM 英文文档:typeorm.io/#/connectio…
1、安装依赖
npm install --save @nestjs/typeorm typeorm mysql2
2、将 TypeOrmModule 导入 AppModule
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './user/user.module';
import { UsersqlModule } from './usersql/usersql.module';
// TypeOrmModule导入
import { TypeOrmModule } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
import { UserEntity } from './shared/entity/user.entity';
@Module({
imports: [
// TypeOrmModule 导入
TypeOrmModule.forRoot({
type: 'mysql',
host: '127.0.0.1',
port: 3306,
username: 'root',
password: '123456',
database: 'nest_user',
entities: [], // 添加entity
synchronize: true, // 这里这个真实环境不能是true
}),
UserModule,
UsersqlModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
// 链接上
constructor(private readonly connection: Connection) {}
}
3、修改entity实体
1)新增entity实体
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity({ name: 'user' })
export class UserEntity {
@PrimaryGeneratedColumn()
id: number;
@Column()
no: string;
@Column()
name: string;
}
2)导入userEntity到app.module中
entities: [UserEntity]
3)修改usersql.module.ts
import { Module } from '@nestjs/common';
import { UsersqlController } from './usersql.controller';
import { UsersqlService } from './usersql.service';
import { UserEntity } from 'src/shared/entity/user.entity';
// 新增
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
// 新增
imports: [TypeOrmModule.forFeature([UserEntity])],
controllers: [UsersqlController],
providers: [UsersqlService],
})
@Module({})
export class UsersqlModule {}
4)修改usersql.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { UserEntity } from 'src/shared/entity/user.entity';
import { Repository } from 'typeorm';
import { User } from '../mock/user';
@Injectable()
export class UsersqlService {
constructor(
@InjectRepository(UserEntity)
private userRepository: Repository<UserEntity>,
) {}
async findAll(): Promise<UserEntity[]> {
return await this.userRepository.find();
}
async add(user: UserEntity): Promise<any> {
await this.userRepository.save(user);
}
async update(user: User): Promise<UserEntity> {
const currentUser = await this.userRepository.findOne(user.id);
currentUser.no = user.no;
currentUser.name = user.name;
await this.userRepository.save(currentUser);
return currentUser;
}
async findOne(id: number): Promise<UserEntity> {
return await this.userRepository.findOne(id);
}
async remove(id: number): Promise<void> {
await this.userRepository.delete(id);
}
}
5) 修改usersql.controller.ts
import {
Body,
Controller,
Delete,
Get,
HttpCode,
Param,
Patch,
Post,
} from '@nestjs/common';
import { InputUser } from 'src/mock/input';
import { UpdateUser } from 'src/mock/update';
import { UsersqlService } from 'src/usersql/usersql.service';
import { User } from '../mock/user';
@Controller('usersql')
export class UsersqlController {
constructor(private readonly UsersqlService: UsersqlService) {}
@Get()
@HttpCode(200)
async findAll(): Promise<User[]> {
return await this.UsersqlService.findAll();
}
@Post()
@HttpCode(200)
async add(@Body() input: InputUser) {
if (input.id === undefined) {
throw new Error('未带入ID');
}
const user: User = {
...input,
};
return await this.UsersqlService.add(user);
}
@Patch(':id')
@HttpCode(203)
async update(@Param() param, @Body() update: UpdateUser) {
const userInfo = await this.UsersqlService.findOne(param.id);
if (!userInfo) {
throw new Error('该用户不存在');
}
userInfo.no = update.no;
userInfo.name = update.name;
return await this.UsersqlService.update(userInfo);
}
@Delete(':id')
@HttpCode(204)
async remove(@Param() param) {
await this.UsersqlService.remove(param.id);
}
@Get(':id')
@HttpCode(200)
async findOne(@Param() param) {
return await this.UsersqlService.findOne(param.id);
}
}
备注:其他entity
import {
Entity,
Column,
PrimaryGeneratedColumn,
CreateDateColumn,
UpdateDateColumn,
} from 'typeorm';
@Entity({ name: 'platform_user_version' })
export class UserVersionEntities {
// 主键装饰器
@PrimaryGeneratedColumn({ comment: '用户自增ID' })
id: number;
@Column({ name: 'project_id', comment: '项目id' })
project_id: number;
@Column({ name: 'version', comment: '版本号' })
version: string;
// @Column({ name: 'create_at', type: 'timestamp', comment: '创建时间' })
// create_at: string;
// @Column({ name: 'update_at', type: 'timestamp', comment: '更新时间' })
// update_at: string;
@CreateDateColumn({ name: 'create_at', comment: '创建时间' }) // 自动生成列
create_at: string;
@UpdateDateColumn({ name: 'update_at', comment: '更新时间' }) // 自动生成并自动更新列
update_at: string;
@Column({ name: 'uid', default: 0, comment: '用户id' })
uid: string;
}
Query builder
QueryBuilder
是 TypeORM 最强大的功能之一 ,它允许你使用优雅便捷的语法构建 SQL 查询,执行并获得自动转换的实体。
中文文档:typeorm.biunav.com/zh/select-q…
使用 repository:
import { getRepository } from "typeorm";
const user = await getRepository(User)
.createQueryBuilder("user")
.where("user.id = :id", { id: 1 })
.getOne();
有 5 种不同的QueryBuilder
类型可用:
SelectQueryBuilder
- 用于构建和执行SELECT
查询。 例如:
import { getConnection } from "typeorm";
const user = await getConnection()
.createQueryBuilder()
.select("user")
.from(User, "user")
.where("user.id = :id", { id: 1 })
.getOne();
InsertQueryBuilder
- 用于构建和执行INSERT
查询。 例如:
import { getConnection } from "typeorm";
await getConnection()
.createQueryBuilder()
.insert()
.into(User)
.values([{ firstName: "Timber", lastName: "Saw" }, { firstName: "Phantom", lastName: "Lancer" }])
.execute();
UpdateQueryBuilder
- 用于构建和执行UPDATE
查询。 例如:
import { getConnection } from "typeorm";
await getConnection()
.createQueryBuilder()
.update(User)
.set({ firstName: "Timber", lastName: "Saw" })
.where("id = :id", { id: 1 })
.execute();
DeleteQueryBuilder
- 用于构建和执行DELETE
查询。 例如:
import { getConnection } from "typeorm";
await getConnection()
.createQueryBuilder()
.delete()
.from(User)
.where("id = :id", { id: 1 })
.execute();
RelationQueryBuilder
- 用于构建和执行特定于关系的操作[TBD]。
使用QueryBuilder
获取值
const timber = await getRepository(User)
.createQueryBuilder("user")
.where("user.id = :id OR user.name = :name", { id: 1, name: "Timber" })
.getOne();
const users = await getRepository(User)
.createQueryBuilder("user")
.getMany();