Nest 实战 (一)
配置项
配置项
- 就是把那些数据库配置、端口配置、日志配置、缓存配置、文件上传配置、邮件配置、第三方配置等,这些配置项,统一放到一个文件中,方便管理。
两种方式 1.env 文件 2. yml 配置
安装
bash
pnpm i @nestjs/config -S
pnpm i cross-env -S
pnpm i dotenv -S
根目录
在根目录,不在 src 目录下
- 创建
.env
文件
bash
DATABASE_USER=root
DATABASE_PASSWORD=123456
DATABASE_NAME=testnest1
DATABASE_HOST=localhost
DATABASE_PORT=3306
DATA="EVN或者PRO没用的配置"
- 创建
.env.development
bash
DATABASE_USER=root
DATABASE_PASSWORD=123456
DATABASE_NAME=testnest1
DATABASE_HOST=localhost
DATABASE_PORT=3306
DATA="测试服"
- 创建
.env.production
bash
DATABASE_USER=root
DATABASE_PASSWORD=123456
DATABASE_NAME=testnest1
DATABASE_HOST=localhost
DATABASE_PORT=3306
DATA="正式服"
找到 package.json 文件
bash
"start:dev": "cross-env NODE_ENV=development nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "cross-env NODE_ENV=production node dist/main",
基础版
- 找到根目录 app.module.ts 模块
ts
import { Module } from "@nestjs/common";
import { LoginModule } from "./Login/login.module";
import { UserModule } from "./User/user.module";
// 配置文件
import { ConfigModule } from "@nestjs/config";
import * as dotenv from "dotenv";
const envPath = `.env.${process.env.NODE_ENV || "development"}`;
@Module({
imports: [
UserModule,
LoginModule,
// 修改配置
ConfigModule.forRoot({
isGlobal: true,
envFilePath: envPath,
// 这里新增.env的文件解析
load: [() => dotenv.config({ path: ".env" })],
}),
],
controllers: [],
providers: [],
})
export class AppModule {}
- 使用
ts
import { Inject, Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
@Injectable()
export class LoginService {
constructor() {}
@Inject()
private ConfigService: ConfigService;
async login(): Promise<string> {
return this.ConfigService.get("DATABASE_USER");
}
}
高级版本
测试用例
ts
import { TypeOrmCrudService } from "@nestjsx/crud-typeorm";
import { Inject, Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import UserEntity from "../model/User.entity";
import { ConfigService } from "@nestjs/config";
@Injectable()
export class UserService extends TypeOrmCrudService<UserEntity> {
constructor(@InjectRepository(UserEntity) repo) {
super(repo);
}
@Inject()
private ConfigService: ConfigService;
async createUser(username: string) {
console.log(this.ConfigService.get("DATABASE_NAME"));
// const user = new UserEntity();
// user.username = username;
// return await this.repo.save(user);
}
}
修改数据库配置
- src 目录下面新建一个 config 文件夹里面 新建一个 orm.config.ts
ts
import { TypeOrmModuleOptions } from "@nestjs/typeorm";
import * as fs from "fs";
import * as dotenv from "dotenv";
import * as path from "path";
// 匹配所有实体
const entitiesDir = [path.join(__dirname, "../**/*.entity{.ts,.js}")];
// 通过环境变量读取不同的.env文件
function getEnv(env: string): Record<string, string> {
if (fs.existsSync(env)) {
return dotenv.parse(fs.readFileSync(env));
}
return {};
}
// 通过dotENV来解析不同的配置
function buildConnectionOptions() {
const defaultConfig = getEnv(".env");
const envConfig = getEnv(`.env.${process.env.NODE_ENV || "development"}`);
const config = {
...defaultConfig,
...envConfig,
};
return {
type: "mysql",
host: config.DATABASE_HOST,
port: config.DATABASE_PORT,
username: config.DATABASE_USER,
password: config.DATABASE_PASSWORD,
database: config.DATABASE_NAME,
entities: entitiesDir,
synchronize: false, //同步本地的schema与数据库 ->初始化的时候使用
logging: ["error"], //日志等级
};
}
export const connectionOptions =
buildConnectionOptions() as TypeOrmModuleOptions;
找到连接数据库的模块文件
xxxx.module.ts
ts
import { Global, Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import User from "./model/User.entity";
import { UserController } from "./controller/user.controller";
import { UserService } from "./service/user.service";
import { ConfigModule } from "@nestjs/config";
import * as dotenv from "dotenv";
// 修改数据库配置
import { connectionOptions } from "../config/orm.config";
const envPath = `.env.${process.env.NODE_ENV || "development"}`;
@Global()
@Module({
imports: [
TypeOrmModule.forRoot(connectionOptions),
TypeOrmModule.forFeature([User]),
// 修改配置
ConfigModule.forRoot({
isGlobal: true,
envFilePath: envPath,
// 这里新增.env的文件解析
load: [() => dotenv.config({ path: ".env" })],
}),
],
controllers: [UserController],
providers: [UserService],
})
export class CoreModule {}
使用 yaml 方式配置
安装依赖
安装 js-yaml 包和类型
ts
npm i js-yaml -S
npm i @types/js-yaml -D
pnpm i @nestjs/config -S
pnpm i cross-env -S
在 src
文件夹下创建一个 config
目录来放各个环境的配置,这里创建 3 个环境 dev/prod/test
ts
── src
│ ├── app.module.ts
│ ├── config
│ │ ├── dev.yml
│ │ ├── index.ts
│ │ ├── prod.yml
│ │ └── test.yml
│ ├── main.ts
│ └── user
│ ├── dto
│ │ ├── create-user.dto.ts
│ │ └── update-user.dto.ts
│ ├── entities
│ │ └── user.entity.ts
│ ├── user.controller.ts
│ ├── user.module.ts
│ └── user.service.ts
├── tsconfig.build.json
└── tsconfig.json
config/index.ts
是动态加载所有配置的入口页,代码如下
ts
import { readFileSync } from "fs";
import * as yaml from "js-yaml";
import { join } from "path";
const configFileNameObj = {
development: "dev",
test: "test",
production: "prod",
};
const env = process.env.NODE_ENV;
export default () => {
return yaml.load(
readFileSync(join(__dirname, `./${configFileNameObj[env]}.yml`), "utf8")
) as Record<string, any>;
};
这里有个需要注意的地方导入 js-yaml
的时候一定要用\* as yaml
或者 require()
不然的话会报错 load
方法不存在,当然你也可以单独导入方法,看你喜好。
还需要注意的是导出必须是个函数,以为配置包的 load
方法只接受函数数组
yml
格式的配置文件比如dev.yml
ts
# 开发环境配置
app:
prefix: ''
port: 8080
logger:
# 项目日志存储路径,相对路径(相对本项目根目录)或绝对路径
dir: '../logs'
# 文件相关
file:
# 是否为本地文件服务或cos
isLocal: true
# location 文件上传后存储目录,相对路径(相对本项目根目录)或绝对路径
location: '../upload'
# 文件服务器地址,这是开发环境的配置 生产环境请自行配置成可访问域名
domain: 'http://localhost:8080'
# 文件虚拟路径, 必须以 / 开头, 如 http://localhost:8080/profile/****.jpg , 如果不需要则 设置 ''
serveRoot: '/profile'
# 文件大小限制,单位M
maxSize: 10
# 腾讯云cos配置
cos:
secretId: ''
secretKey: ''
bucket: ''
region: ''
domain: ''
location: ''
# 数据库配置
db:
mysql:
host: 'xxxxx'
username: 'NestAdmin'
password: 'xxxxx'
database: 'nestadmin'
port: 3306
charset: 'utf8mb4'
logger: 'file'
logging: true
multipleStatements: true
dropSchema: false
synchronize: true
supportBigNumbers: true
bigNumberStrings: true
# redis 配置
redis:
host: 'xxxxx'
password: 'xxxxx'
port: 6379
db: 2
keyPrefix: ''
# jwt 配置
jwt:
secretkey: 'you_secretkey'
expiresin: '1h'
refreshExpiresIn: '2h'
# 权限 白名单配置
perm:
router:
whitelist:
[
{ path: '/captchaImage', method: 'GET' },
{ path: '/registerUser', method: 'GET' },
{ path: '/register', method: 'POST' },
{ path: '/login', method: 'POST' },
{ path: '/logout', method: 'POST' },
{ path: '/perm/{id}', method: 'GET' },
{ path: '/upload', method: 'POST' },
]
# 用户相关
# 初始密码, 重置密码
user:
initialPassword: '123456'
然后在 app.module.ts
中配置导入 yml
配置
ts
import { Module, Global } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
import configuration from "./config/index";
@Global()
@Module({
imports: [
// 配置模块
ConfigModule.forRoot({
cache: true,
load: [configuration],
isGlobal: true,
}),
],
controllers: [],
providers: [],
})
export class AppModule {}
现在如果启动项目的话,大概率 yml
文件会找不到而报错,此时还需要去配置下 cli
的配置文件 nest-cli.json
ts
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": ["**/*.yml"],
"deleteOutDir": true,
"watchAssets": true
},
"generateOptions": {
"spec": false
}
}
特别注意的就是这个打包配置 compilerOptions
中的 assets
,这个要配置成所有的 yml
文件,这样才能在 dist 中找到配置的配置文件
ts
dist
│ ├── app.module.d.ts
│ ├── app.module.js
│ ├── app.module.js.map
│ ├── config
│ │ ├── dev.yml
│ │ ├── index.d.ts
│ │ ├── index.js
│ │ ├── index.js.map
│ │ ├── prod.yml
│ │ └── test.yml
接下来还需要去修改一下 npm
的 script
命令,加上环境变量来运行对应的环境配置,先安装一个 cross-env
ts
npm i cross-env -D
然后修改对应环境的脚本命令
ts
"start:dev": "cross-env NODE_ENV=development nest start --watch",
"start:debug": "cross-env NODE_ENV=development nest start --debug --watch",
"start:test": "cross-env NODE_ENV=test node dist/main",
"start:prod": "cross-env NODE_ENV=production node dist/main",
使用配置
使用配置的话,需要导入@nestjs/config
提供的服务来获取配置信息,比如在 user 模块使用配置
因为配置已经设置为全局可用,所以不再需要在 user
模块中导入了,可以直接使用
ts
import { ConfigService } from '@nestjs/config';
@Controller('user')
export class UserController {
constructor(
private readonly userService: UserService,
private configService: ConfigService,
) {}
@Get()
findAll() {
console.log('configService===', this.configService.get('db'));
return this.userService.findAll();
}