NestJS
eslint报错 'cr'
eslintrc.js
rules:[
...
"prettier/prettier": ["error", { "endOfLine": "auto" }]
]
1.ioc 依赖注入
// 依赖注入
class A {
name: string
constructor(name: string) {
this.name = name
}
}
/*
// 传统方式 获取 new A 耦合度太高
// 当引入别的库时,不太适合再次封装
class B{
a:any
constructor(){
this.a = new A().name
}
}
*/
// 定义一个B类,给类中的mo对象,给对象添加class
class B {
mo: any
constructor() {
this.mo = {}
}
provide(key: string, mo: any) {
this.mo[key] = mo
}
get(key: string) {
return this.mo[key]
}
}
const b = new B()
b.provide('A', new A("陆小杭"))
b.provide('B', new A("陆大杭"))
class C {
a: any
b: any
constructor(b: B) {
this.a = b.get("A")
this.b = b.get("B")
}
get() {
console.log(this.a);
}
}
new C(b).get()
2.修饰器
// 1.类装饰器 ClassDecorator
// 2.方法装饰器 MethodDecorator(参数1:原型对象,参数2:函数名称,参数3:PropertyDescriptor)
// 3.参数装饰器 ParameterDecorator 参数修饰器比方法修饰器更早执行
// 4.属性装饰器 PropertyDecorator
// 5.装饰器工厂
// 6.import "reflect-metadata"
// 7.axios
// 8.Reflect.metadata 元数据
/*
元数据的添加 Reflect.metadata
Reflect.metadata(参数1:对象上添加的key,参数2:对象添加的值,参数3:添加元数据的类) //给参数3的类,添加 key:value 元数据
Reflect.metadata(a,"123",obj) // obj{a:"123"}
Reflect.metadata(参数1:对象上添加的key,参数2:对象添加的值,参数3:添加元数据的类,参数4:添加元数据的属性) //给参数3的类的参数4属性,添加 key:value 元数据
Reflect.metadata(a,"123",obj,a) // obj{ a:{ a:"123"}}
元数据获取 Reflect.getMethod
Reflect.getMethod(参数1:对象上的key,参数2:元数据的类) //获取 参数2类 挂载的元数据
Reflect.getMethod(参数1:对象上的key,参数2:元数据的类,参数3:元数据参数2类的属性) //获取 参数2类.参数3 的元数据
*/
import axios from 'axios';
import 'reflect-metadata'
// 1.类装饰器 ClassDecorator
const create:ClassDecorator = (target) =>{
target.prototype.lu = "luxiaohang"
target.prototype.fn = ()=>{
console.log("桀桀桀");
}
}
// 有了装饰器后,可以不破坏原本class结构去添加属性
@create
class People{
}
const man = new People() as any
console.log(man.lu);
// 通过函数科里化,用装饰器给工厂直接传参
const create2 = (name:string)=>{
const fn:ClassDecorator = (target:any)=>{
// 类原型上挂载属性
target.prototype.name = name
target.prototype.fn =()=>{
console.log('base2 装饰器');
}
}
return fn
}
@create2("lxh")
class People2 {
}
// 实例化装饰器对象,需要类型断言因为类型默认为:ClassDecorator
const man2 = new People2() as any
console.log(man2.name);
//===================下面方法在一个类中使用=======================
//类装饰器
const Base = (name:string)=>{
// target 传进来的是 class
const fn:ClassDecorator = (target)=>{
target.prototype.name = "张三干掉" + name
target.prototype.fn = ()=>{
console.log("我是base fn()");
}
}
return fn
}
// 2.方法装饰器
const get = (url:string)=>{
/*
// 装饰器形参
fn:MethodDecorator =(
target:"获得class中所有方法", // { getList: [Function (anonymous)], create: [Function (anonymous)] }
propertyKey:"获得当前方法名", // getList
descriptor:"获得一个对象 .value给方法回传的内容"{value: [Function (anonymous)],writable: true,enumerable: true,configurable: true}
)
*/
//descriptor需要给定PropertyDescriptor 属性,不然参数不可用
const fn:MethodDecorator =(target,propertyKey,descriptor:PropertyDescriptor)=>{
// 获取到字符串 list
const key = Reflect.getMetadata('getList', target)
axios.get(url)
.then(res => {
// 通过 descriptor 回传成功的回调.返回元数据 value
descriptor.value(res.data[key])
})
}
return fn
}
// 3.参数装饰器
const List = ()=>{
// 参数修饰器需要加类型 ParameterDecorator 。参数修饰器
const fn:ParameterDecorator = (target,key,index)=>{
//设置一个 getList 值为 list 供元数据获取
Reflect.defineMetadata("getList","list",target)
}
return fn
}
// 4.属性修饰器
const Name:PropertyDecorator = (target,propertyKey)=>{
console.log(target, propertyKey); //{},name
}
@Base('LXH')
class Http{
// 4.属性修饰器
@Name
name:string
constructor(){
this.name = "张三"
}
// 2.指定一个方法修饰器
@get('http://localhost:8080')
// 3.指定一个参数修饰器
getList(@List() data:any){
console.log("我收到了后端请求",data);
}
create(){
}
}
3.nest.js 指令
//安装全局环境
pnpm i -g @nestjs/cli
//nest指令创建项目
nest new 项目名
//创建一个 module.ts 模块
nest g mo 模块名称
//创建一个 service.ts 模块
nest g s 模块名称
//直接生成一个 crud
nest g resource 模块名称
4.nest 路由
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { UserService } from './user.service';
import {
Controller,
Get,
Request,
Response,
Query,
Post,
Body,
Patch,
Param,
Delete,
} from '@nestjs/common';
@Controller('user')
export class UserController {
//这里相当于 new userService
constructor(private readonly userService: UserService) {}
@Get()
// 获取Query中的单个属性
findAll(@Query('name') query) {
console.log(query);
return {
code: 200,
};
}
// 读取动态路由
@Get(':id')
finduserId(@Request() req) {
console.log(req.params);
return {
code: 200,
data: req.params,
};
}
// 创建 post请求
@Post()
creat(@Request() req) {
console.log(req.body);
if (req.query.name !== '张三') {
return {
code: '200',
};
}
}
}
//添加全局路由前缀 在main文件中
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 添加全局路由前缀 api
app.setGlobalPrefix('api');
await app.listen(3000);
}
5.依赖注入
//依赖 providers 用法 module 层
import { Module } from '@nestjs/common';
import { GirlController } from './girl.controller';
import { GirlService } from './girl.service';
@Module({
controllers: [GirlController],
providers: [
GirlService,
// 定义类
{
provide: 'getgirl',
useClass: GirlService,
},
// 定义值
{
provide: 'getnumber',
useValue: '123456',
},
// 定义工厂
{
provide: 'MyFactory',
useFactory() {
console.log('Factory');
return 'fact func()';
},
},
],
})
export class GirlModule {}
//依赖 providers 用法 controller 层
import { Controller, Get, Inject, Post, Req, Res } from '@nestjs/common';
import { GirlService } from './girl.service';
@Controller('girl')
export class GirlController {
constructor(
// 服务层挂载
private girlService: GirlService,
// 通过inject 挂载
@Inject('getnumber') private nb: string,
@Inject('getgirl') private girl: GirlService,
@Inject('MyFactory') private factory: string,
) {}
@Get(':id')
getGrils(@Req() req) {
const id: number = parseInt(req.params.id);
return this.girlService.getInfo(id);
}
@Get('/u/info')
getInfo(@Req() req) {
//通过依赖注入获取 server
return this.girl.getInfo(1);
}
@Get('/u/number')
getNumber(@Res() res) {
// 获取注入工厂
console.log(this.factory);
// 获取注入number
res.send(this.nb);
}
@Post('')
postlove() {
return {
code: 200,
msg: '我是girl',
};
}
}
6.数据库连接
nest.js连接数据库
1.安装@nestjs/typeorm
安装nest.js提供的typeorm包,因为它是可用于Typescript的最成熟的对象关系映射器(ORM),由于他是Typescript编写的,因此可以很好的和Nest框架集成。
$ pnpm install --save @nestjs/typeorm typeorm
2.TypeOrmModule导入AppModule
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql', // 数据库类型
host: 'localhost', // 域名
port: '3306', // 端口
username: 'root', // 数据库名字
password: '123456', // 数据库密码
database: 'test', // 库名
entities: [User], // 导入的实体(数据库模型)
synchronize: true,
retryAttempts: 100,
// 重试连接数据库的次数,默认为10次
retryDelay: 2000,
// 两次重试连接的间隔(ms),默认为3000
autoLoadEntities: false
// 如果为true,将自动加载实体(默认:false)
})
]
})
forRoot()方法支持TypeORM包中createConnection()函数暴露出的配置属性
7.中间件
1.局部中间件
/**
局部中间件的使用
1.创建中间件文件
2.module层导入中间件
3.拦截操作
4.拦截某一类型路由
*/
// 1.中间件文件创建
nest g mi '创建名'
//init.middlexxxware.ts 中间件内容
import { Injectable, NestMiddleware } from '@nestjs/common';
//局部中间件
@Injectable()
export class InitMiddleware implements NestMiddleware {
use(req: any, res: any, next: () => void) {
//使用中间件
console.log('局部中间件Init');
next();
}
}
//拦截中间件
@Injectable()
export class InterCept implements NestMiddleware {
use(req: any, res: any, next: () => void) {
//使用中间件
console.log('USER的所有get被我拦截中间件承包了 桀桀桀');
res.send('USER的所有get被我拦截中间件承包了 桀桀桀');
}
}
//2.module层导入中间件
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
// 引入局部中间件
import { InitMiddleware } from '../init/init.middleware';
@Module({
controllers: [UserController],
providers: [UserService],
})
// 实现 NestModule 接口
export class UserModule implements NestModule {
//中间件实例化
configure(consumer: MiddlewareConsumer) {
//consumer.apply(添加的中间件).forRoutes(路由名)
consumer.apply(InitMiddleware).forRoutes('user/jack');
consumer.apply(InitMiddleware).forRoutes('user/g2/jntm');
}
}
2.全局中间件
/*
全局中间件使用
1.外部创建中间件函数 或 定义中间件方法
2.main中注册全局中间件
*/
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
//定义全局中间件 middleAll
function middleAll(req, res, next) {
console.log(`全局中间件`);
next();
}
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 注册全局中间件 middleAll
app.use(middleAll);
await app.listen(3000);
}
bootstrap();
8.模块化
1.单个模块的使用
//在 boy.module.ts 中导出单个模块
import { Global, Module } from '@nestjs/common';
import { BoyService } from './boy.service';
import { BoyController } from './boy.controller';
@Module({
controllers: [BoyController],
providers: [BoyService],
// 导出模块
exports: [BoyService],
})
export class BoyModule {}
//在 girl.module.ts 中导入 boy 模块
import { Module } from '@nestjs/common';
import { GirlService } from './girl.service';
import { GirlController } from './girl.controller';
import { BoyService } from '../boy/boy.service';
@Module({
controllers: [GirlController],
providers: [
GirlService,
// 导入boy模块
BoyService,
{
provide: 'girl',
useClass: GirlService,
},
],
})
export class GirlModule {}
//在 girl.controller.ts 中使用 boy 模块方法
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
Inject,
} from '@nestjs/common';
import { GirlService } from './girl.service';
// 引入boy模块
import { BoyService } from '../boy/boy.service';
import { CreateGirlDto } from './dto/create-girl.dto';
import { UpdateGirlDto } from './dto/update-girl.dto';
@Controller('girl')
export class GirlController {
constructor(
//使用 Girl 模块
@Inject('girl') private readonly girl: string,
//使用 Girl 模块
private readonly girlService: GirlService,
private boyService: BoyService,
) {}
@Get()
findAll() {
console.log(this.configName?.name);
return this.boyService.findAll();
}
}
2.全局模块的使用
//1.config.module声明模块并且导出
import { Module, Global } from '@nestjs/common';
//声明全局模块
@Global()
@Module({
providers: [
{
provide: 'Config',
useValue: { name: '张三' },
},
],
//导出模块
exports: [
{
provide: 'Config',
useValue: {
configName: 'global',
},
},
],
})
export class ConfigModule {}
//2.app.module.ts 引入全局模块
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { BoyModule } from './boy/boy.module';
import { GirlModule } from './girl/girl.module';
// 引入config
import { ConfigModule } from './config/config.module';
@Module({
// 全局手动引入Config模块
imports: [BoyModule, GirlModule, ConfigModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
//3.全局模块在 girl 模块 control层的使用
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
Inject,
} from '@nestjs/common';
import { GirlService } from './girl.service';
// 引入boy模块
import { BoyService } from '../boy/boy.service';
import { CreateGirlDto } from './dto/create-girl.dto';
import { UpdateGirlDto } from './dto/update-girl.dto';
// 给定全局模块类型
type Con = {
name: string;
configName: string;
};
@Controller('girl')
export class GirlController {
constructor(
// 注入全局模块
@Inject('Config') private configModule: Con,
) {}
@Get()
findAll() {
//使用全局模块
console.log(this.configModule?.configName);
return this.boyService.findAll();
}
}
9.文件处理
1.包安装
// nest上传图片用到的两个包
//multer @nestjs/platform-express nestJs自带了
//multer @types/multer 这两个需要安装
2.文件上传
2.配置上传module
import { Module } from '@nestjs/common';
import { UploadService } from './upload.service';
import { UploadController } from './upload.controller';
// 引入文件上传
import { MulterModule } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { join, extname } from 'path';
@Module({
imports: [
MulterModule.register({
// 存放位置
storage: diskStorage({
// 存放地址
destination: join(__dirname, '../Images'),
filename(_, file, callback) {
const filename = `${
// 拼接文件名
new Date().getTime() + extname(file.originalname)
}`;
return callback(null, filename);
},
}),
}),
],
controllers: [UploadController],
providers: [UploadService],
})
export class UploadModule {}
3.上传 controller
import {
Controller,
Post,
Body,
UploadedFile,
UseInterceptors,
} from '@nestjs/common';
import { UploadService } from './upload.service';
import { CreateUploadDto } from './dto/create-upload.dto';
// 读取文件
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
@Controller('upload')
export class UploadController {
constructor(private readonly uploadService: UploadService) {}
@Post('img')
// 拦截器中间件
@UseInterceptors(FileInterceptor('file'))
// 上传图片
create(@UploadedFile() file) {
console.log(file, 'file');
return 'file';
}
}
4.配置静态资源 main
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
// 配置静态资源访问路径. prefix 浏览器请求地址
app.useStaticAssets(join(__dirname, 'Images'), { prefix: '/static/img' });
await app.listen(3000);
}
bootstrap();
3.文件下载
import { UploadService } from './upload.service';
import { CreateUploadDto } from './dto/create-upload.dto';
// 读取文件
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
// 配置express代码提示
import type { Response } from 'express';
import { join } from 'path';
// 压缩文件
import { zip } from 'compressing';
// 下载接口
@Get('export')
downLoad(@Res() res: Response) {
// 拼接路径
const url = join(__dirname, '../Images/1685439451315.jpg');
// 下载
res.download(url);
}
@Get('stream')
async downzip(@Res() res: Response) {
const url = join(__dirname, '../Images/1685439451315.jpg');
//图片生成zip形式
const tarStream = new zip.Stream();
await tarStream.addEntry(url);
res.setHeader('Content-Type', 'application/octet-stream');
res.setHeader('Content-Disposition', `attachment;filename=lxh`);
tarStream.pipe(res);
}
1.前端获取stream流
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<button class="upload">下载</button>
</body>
<script >
const btn = document.querySelector('.upload')
const useFetch = async(url)=>{
const res = await fetch(url).then(res=>res.arrayBuffer())
var a = document.createElement('el')
a.href = URL.createObjectURL(new Blob([res],{
type:"image/png"
}))
a.download ='lxh.zip'
console.log(a.download);
a.click()
}
btn.onclick = (e)=>{
useFetch('http://127.0.0.1:3000/upload/stream')
// window.open('http://127.0.0.1:3000/upload/export')
}
</script>
</html>
10.Rx.js
1.引入rx js
//引入 Rx.js
$ npm i rxjs
import { of, Observable, interval, take } from 'rxjs';
import { map, filter, findIndex, reduce, retry } from 'rxjs/operators';
import { of, Observable, interval, take } from 'rxjs';
import { map, filter, findIndex, reduce, retry } from 'rxjs/operators';
// 类似迭代器对象
const observable = new Observable((subscribe) => {
subscribe.next(1);
subscribe.next(2);
subscribe.next(3);
setTimeout(() => {
subscribe.next(4);
// 结束
subscribe.complete();
}, 3000);
subscribe.next(5);
});
// 获取返回值
observable.subscribe({
next: (cb) => {
console.log(cb); //1 2 3 5 4
},
});
// 间隔多少毫秒执行
interval(1)
//到多少数字结束
.pipe(take(309))
//回调
.subscribe((e) => {
console.log(e);
});
const sub = interval(20)
.pipe(
map((v) => ({
num: v,
})),
)
//手动停止
.subscribe((e) => {
console.log(e);
if (e.num == 100) {
sub.unsubscribe(); // 1,2,3,...,98,99,100
}
});
//指定数据
of(1, 2, 3, 4, 5, 6)
.pipe(
retry(3),
map((v) => ({
num: v,
})),
// 过滤
filter((v) => v.num % 2 == 0),
)
.subscribe((e) => {
console.log(e); //2,4,6
});
11.拦截器
1.全局拦截
//common 文件夹创建一个拦截器 request.ts
import { Injectable, NestInterceptor, CallHandler } from '@nestjs/common';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
interface Data<T> {
data: T;
}
//创建一个注入
@Injectable()
export class Response<T> implements NestInterceptor {
// 返回的 Data 类型的数据
intercept(context, next: CallHandler): Observable<Data<T>> {
// 返回拦截器
return next.handle().pipe(
map((data) => {
return {
data,
status: 0,
message: '666',
success: '登录成功',
};
}),
);
}
}
// main.ts 中全局注册拦截器
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
// 引入全局拦截器
import { Response } from './common/response';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 注册全局拦截器
app.useGlobalInterceptors(new Response());
await app.listen(3000);
}
bootstrap();
2.异常拦截
// 异常拦截器
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
} from '@nestjs/common';
import { Request, response, Response } from 'express';
//异常拦截这里是catch
@Catch()
export class HttpFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
//获取 req res
const ctx = host.switchToHttp();
const req = ctx.getRequest<Request>();
const res = ctx.getResponse<Response>();
console.log(req, res);
// 接口状态信息
const status = exception.getStatus();
// const next = ctx.getNext();
//返回的数据
res.status(status).json({
success: false,
code: status,
time: new Date(),
data: exception.message,
// 报错的接口
path: req.url,
});
}
}
//main中的异常拦截器
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
// 引入异常拦截器
import { HttpFilter } from './common/filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 注册异常拦截
app.useGlobalFilters(new HttpFilter());
await app.listen(3000);
}
bootstrap();
12.管道
1.管道pipe
//管道
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
ParseIntPipe,
ParseUUIDPipe,
} from '@nestjs/common';
import { PService } from './p.service';
import { CreatePDto } from './dto/create-p.dto';
import { UpdatePDto } from './dto/update-p.dto';
@Controller('p')
export class PController {
constructor(private readonly pService: PService) {}
@Post()
create(@Body() createPDto: CreatePDto) {
return this.pService.create(createPDto);
}
@Get()
findAll() {
return this.pService.findAll();
}
@Get(':id')
//接收一个 ParseUUIDPipe 类型的参数
findOne(@Param('id', ParseUUIDPipe) id: string) {
console.log(typeof id, '---------------');
return this.pService.findOne(+id);
}
}
2.验证validate
1.安装两个插件
$ pnpm i --save class-validator class-transformer
2.校验模块
校验规则
//规则检验模块 login.service.ts
import { IsNotEmpty, IsString, Length, IsNumber } from 'class-validator';
//规则校验
export class CreateLoginDto {
@IsNotEmpty()
@IsString()
@Length(2, 10, {
message: 'name长度不能小于或,超过10个字符',
})
name: string;
@IsNumber({}, { message: 'age请输入number类型' })
age: number;
}
校验验证模块
//配置Body模块验证文件 login.pipe.ts
import {
ArgumentMetadata,
HttpException,
HttpStatus,
Injectable,
PipeTransform,
} from '@nestjs/common';
import { plainToInstance } from 'class-transformer';
// 引入验证模块
import { validate } from 'class-validator';
@Injectable()
export class LoginPipe implements PipeTransform {
// 获取数据原信息 //value = {name:xxx,age:xxx,xxx} ,metadata = {}
async transform(value: any, metadata: ArgumentMetadata) {
// console.log(value, metadata);
// plainToInstance 将值反射到类上面
const DTO = plainToInstance(metadata.metatype, value);
// 失败校验 返回的失败类型的数组 信息,类型是:promise。 数组为空则校验成功
// const errors = await Validate(DTO)
const err = await validate(DTO);
if (err.length) {
// 抛出一个异常失败的消息( err 失败内容 , HttpStatus:是一个 RESTFUL规则的枚举)
throw new HttpException(err, HttpStatus.BAD_REQUEST);
} else {
console.log('validation succeed');
}
return value;
}
}
路由引入校验
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
} from '@nestjs/common';
import { LoginService } from './login.service';
import { CreateLoginDto } from './dto/create-login.dto';
import { UpdateLoginDto } from './dto/update-login.dto';
// 引入login pipe
import { LoginPipe } from './login/login.pipe';
@Controller('login')
export class LoginController {
constructor(private readonly loginService: LoginService) {}
@Post()
create(@Body(LoginPipe) createLoginDto: CreateLoginDto) {
return '666';
}
@Get()
findAll() {
return this.loginService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.loginService.findOne(+id);
}
}
13.守卫
路由页面
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
UseGuards,
SetMetadata,
} from '@nestjs/common';
import { GuardService } from './guard.service';
import { CreateGuardDto } from './dto/create-guard.dto';
import { UpdateGuardDto } from './dto/update-guard.dto';
import { RoleGuard } from './role/role.guard';
// 局部守卫
@UseGuards(RoleGuard)
@Controller('guard')
export class GuardController {
constructor(private readonly guardService: GuardService) {}
@Get()
// 定义权限 守卫
@SetMetadata('role', ['admin'])
findAll() {
console.log('666');
return this.guardService.findAll();
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateGuardDto: UpdateGuardDto) {
return this.guardService.update(+id, updateGuardDto);
}
}
守卫页面
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
import { Reflector } from '@nestjs/core';
import type { Request, Response } from 'express';
// 守卫
@Injectable()
export class RoleGuard implements CanActivate {
// Reflector 挂载到属性上
constructor(private Reflector: Reflector) {}
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
// 通过Reflector获取,路由上定义的守卫属性
const admin = this.Reflector.get<string[]>('role', context.getHandler());
// 获取get请求传入的query参数
const req = context.switchToHttp().getRequest<Request>();
const role = req.query.role;
// 对比query 和 守卫参数
if (admin.includes(role as string)) {
return true;
}
return false;
}
}
14.自定义修饰器
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
UseGuards,
SetMetadata,
} from '@nestjs/common';
import { GuardService } from './guard.service';
import { CreateGuardDto } from './dto/create-guard.dto';
import { UpdateGuardDto } from './dto/update-guard.dto';
import { RoleGuard } from './role/role.guard';
import { Role, User } from './role/role.decorator';
// 局部守卫
@Controller('guard')
@UseGuards(RoleGuard)
export class GuardController {
constructor(private readonly guardService: GuardService) {}
@Get()
// 定义权限 守卫
@SetMetadata('role', ['admin'])
findAll() {
return 'is admin';
}
@Get('zidingyi')
@Role('jack')
getjack(@User('mid') url: string) {
console.log('url', url);
return 'is jack';
}
@Get(':id')
// 自定义修饰器
@Role('name')
update(@Param('id') id: string, @Body() updateGuardDto: UpdateGuardDto) {
console.log(id);
return ':id req';
}
}
创建自定义修饰器
$ nest g d '文件名'
自定义修饰器组件
import {
createParamDecorator,
SetMetadata,
ExecutionContext,
} from '@nestjs/common';
import type { Request } from 'express';
export const Role = (...args: string[]) => SetMetadata('role', args);
// 创建一个 形参 @ReqUrl 修饰器
// 路由 => 守卫修饰器 => 守卫模块 => 参数修饰器 => 路由
export const User = createParamDecorator(
// data:传入的参数, ctx:上下文
(data: string, ctx: ExecutionContext) => {
// 获取请求路径
const req = ctx.switchToHttp().getRequest<Request>();
console.log(req.query, '==========', data);
// 返回参数给到路由
return req.url;
},
);
全局注册守卫文件
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
// 引入守卫文件
import { RoleGuard } from './guard/role/role.guard';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 全局注册守卫文件
// app.useGlobalGuards(new RoleGuard());
await app.listen(3000);
}
bootstrap();