Nest的模块Module
@Module装饰器
@Module装饰器接受一个对象参数,在Nest源码中是ModuleMetadata
接口,它有四个字段,且均是数组类型,分别是:
- imports :导入其他模块中导出的Providers,以实现共享
- providers :模块中所有用到的功能类,模块内共享实用;
- controllers:控制器
- exports:导出其他模块需要共享的Providers
通过以上四种类型的设定,Nest的IoC才能够准确识别需要组装(注入和被注入)各种依赖关系,同时实现一定程度的共享。
ts
import {Module} from "@nestjs/common"
@Module({
imports:[], // 导入模块
provider:[], // 注入服务
controller:[], // 导入控制器
exports: [], // 导出服务,这里导出后,其他模块的服务可以使用当前模块的服务。
})
export class UserModule {}
异常拦截器
创建
ts
// http-exceptopn.ts
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
} from '@nestjs/common';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
// 获取请求的上下文
const ctx = host.switchToHttp();
// 获取请求上下文的response对象
const response = ctx.getResponse();
// 获取异常的状态码
const status = exception.getStatus();
const msg = exception.message ? exception.message : '请求失败';
console.log('status:', status);
const errorResponse = {
data: null,
code: -1,
msg,
};
response.status(status);
response.header('Content-Type', 'application/json; charset=utf-8');
response.send(errorResponse);
}
}
使用
注册为全局异常拦截器。
ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './filter/http-exception';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(3001);
}
bootstrap();
MYSQL数据库
运行MYSQL
bash
# 如果尚未运行MySQL容器,使用此命令启动(推荐数据持久化)
docker run -d --name mysql-server \
-e MYSQL_ROOT_PASSWORD=your_password \
-p 3306:3306 \
-v mysql_data:/var/lib/mysql \
mysql:8.0
# 验证容器状态
docker ps | grep mysql
登录MYSQL控制台
bash
# 方式一:直接进入容器内的 MySQL 命令行
docker exec -it mysql-server mysql -u root -p
# 输入预设的密码(即your_password)
# 方式二:通过主机客户端连接(需要安装mysql-client)
mysql -h 127.0.0.1 -P 3306 -u root -p
创建数据库
在 MySQL 命令行中执行:
bash
-- 创建数据库
CREATE DATABASE demo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 验证创建结果
SHOW DATABASES;
-- 退出命令行
exit
推荐的生产环境配置
bash
docker run -d \
--name mysql-prod \
--restart always \
-p 3306:3306 \
-v /path/to/mysql_data:/var/lib/mysql \
-v /path/to/custom.cnf:/etc/mysql/conf.d/custom.cnf \
-e MYSQL_ROOT_PASSWORD=strong_password \
-e MYSQL_DATABASE=app_db \
-e MYSQL_USER=app_user \
-e MYSQL_PASSWORD=user_password \
mysql:8.0 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci
TypeORM的使用
TypeORM的两种使用方式
全局数据库实体初始化
在这一步中,无论使用下面的 那种方法,必须在这里初始化数据库,注册实体。
ts
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 { User, Role, Permission } from './user/entities/index.entity';
import { JwtModule } from '@nestjs/jwt';
import { HttpExceptionFilter } from './filters/http-exception.filter';
import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';
import { TransformInterceptor } from './interceptors/transform.interceptor';
@Module({
imports: [
// 数据库配置
TypeOrmModule.forRoot({
// 数据库类型
type: 'mysql',
// 主机地址
host: '119.96.24.5',
// 数据库端口
port: 3306,
// 用户名
username: 'root',
// 数据库连接密码
password: 'Xianyu@666',
// 连接的数据库
database: 'meetingroom_book_mysql_test',
// 是否将实体和数据库同步
synchronize: true,
// 禁用日志输出
logging: false,
// 此处的实体是作为数据库初始化的需要,不管在后面的子模块怎么引入使用,这里必须先倒入注册
entities: [User, Role, Permission],
poolSize: 10,
connectorPackage: 'mysql2',
extra: {
// 这里配置连接数据库的额外参数
authPlugins: ['sha256_password'],
},
}),
// 全局的jwt配置
JwtModule.register({
// 设置为全局模块,就不需要在每一个模块都导入了
global: true,
secret: 'chengang_test1',
signOptions: {
expiresIn: '1m',
},
}),
UserModule,
],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_FILTER,
useClass: HttpExceptionFilter,
},
{
provide: APP_INTERCEPTOR,
useClass: TransformInterceptor,
},
],
})
export class AppModule {}
只在app.module.ts中导入实体
user.service.ts
这种方法的使用特点是每次都需要this.manager.xxx方法(xxx实体, xxx参数)
来使用
ts
import { Injectable } from '@nestjs/common';
import { InjectEntityManager } from '@nestjs/typeorm';
import { EntityManager } from 'typeorm';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { User } from './entities/user.entity';
@Injectable()
export class UserService {
@InjectEntityManager()
private manager: EntityManager;
create(createUserDto: CreateUserDto) {
this.manager.save(User, createUserDto);
}
findAll() {
return this.manager.find(User)
}
findOne(id: number) {
return this.manager.findOne(User, {
where: { id }
})
}
update(id: number, updateUserDto: UpdateUserDto) {
this.manager.save(User, {
id: id,
...updateUserDto
})
}
remove(id: number) {
this.manager.delete(User, id);
}
}
在当前的模块xxx.module.ts中导入实体
1.需要现在xxx.module.ts中导入实体,示例如下:
ts
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
@Module({
imports: [
TypeOrmModule.forFeature([User])
],
controllers: [UserController],
providers: [UserService]
})
export class UserModule {}
2.1.在service文件中注入使用如下:
ts
import { Injectable } from '@nestjs/common';
import { User } from './entities/index.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateUserDto } from './dto/create-user.dto';
@Injectable()
export class UserService {
@InjectRepository(User)
private readonly userRepository: Repository<User>;
async login(loginIfo: CreateUserDto) {
const user = await this.userRepository.findOne({
where: {
username: loginIfo.username,
},
relations: {
roles: true,
},
});
if (!user) {
return '用户不存在';
}
if (user.password !== loginIfo.password) {
return '密码错误';
}
return user;
}
async createUser(createUserDto: CreateUserDto) {
const findUser = await this.userRepository.findOneBy({ username: createUserDto.username });
console.log(findUser);
return findUser;
}
}
2.2.在controller中注入使用如下:
ts
import { Repository } from 'typeorm';
import { User } from './user.entity';
import { UserService } from './user.service';
import { Body, Controller, Get, Inject, Logger, Post } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
@Controller('user')
export class UserController {
constructor(
private readonly userService: UserService,
@InjectRepository(User)
private readonly usersRepository: Repository<User>,
) { }
@Post("add")
async add(@Body() user: User) {
let result = await this.usersRepository.save(user);
Logger.debug('添加用户', result, this.constructor.name);
return "OK";
}
@Get("list")
async list() {
let result = await this.usersRepository.find();
Logger.debug('查询用户', result, this.constructor.name);
return result;
}
}
TypeORM的查询
查询指定的字段
- find 方法适合查询全部的数据
- findAndCount 方法用来查询分页分页数据和总条数数据
ts
return await this.manager.find(User, {
// 精准查询
where: { id: 1 },
});
// 给定范围的查询
return await this.manager.find(User, {
where: { id: MoreThan(10) },
});
Nestjs操作GitLab的API
Gitbeaker 是一款强大的开源项目,专为开发者设计,提供了全面的 GitLab SDK 支持,可用于浏览器、Node.js 和 Deno 环境,甚至包括命令行接口(CLI)。该项目不仅涵盖了GitLab的众多API功能,而且注重性能和可测试性,尤其对于使用TypeScript的团队来说,它的类型定义更是增添了开发的便捷性。
gitbeaker 由多个包组成,分别负责不同的任务:
- @gitbeaker/requester-utils - 提供底层HTTP请求处理的工具。
- @gitbeaker/core - 核心API,详细列出所有Gitlab资源的支持情况。
- @gitbeaker/rest - 用于Node.js、Deno和现代浏览器的SDK,基于原生fetch进行封装。
- @gitbeaker/cli - 命令行工具,方便直接与Gitbeaker交互。
具体的API演示
ts
return this.gitlabInstance.Users.create({
// 用户的邮箱,必须要
email: '13545630123@qq.com',
password: '13545630123',
username: '13545630123',
// 默认新建的都不设置为最高权限的管理员
admin: false,
name: '13545630123',
// 跳转新建用户之后的用户邮件验证确认操作
skipConfirmation: true,
});