NestJS框架

203 阅读5分钟

官网:nestjs.com

中文官网: docs.nestjs.cn

Github: github.com/nestjs/nest

controller(控制器)

import { Controller, Get, Render, Post, Body,Response, Query } from '@nestjs/common';
import { RoleService } from "./../../../service/role/role.service";
import { Config } from "./../../../config/config";
import { ToolsService } from '../../../service/tools/tools.service';


@Controller(`${Config.adminPath}/role`)
export class RoleController {

  constructor(private roleService:RoleService,private toolsService:ToolsService){}

  @Get()
  @Render('admin/role/index')
  async index(){
    let result = await this.roleService.find({});
    return {
      roleList:result
    }
  }

  @Get('add')
  @Render('admin/role/add')
  async add(){
    return {}
  }

  @Get('edit')
  @Render('admin/role/edit')
  async edit(@Query() query){
    let result = await this.roleService.find({"_id":query.id})
    return {
      roleList:result[0]
    }
  }
  
  @Post('doAdd')
  async doAdd(@Body() body,@Response() res){
    if (body.title != '') {
      let result = await this.roleService.add(body);
      if (result) {
        this.toolsService.success(res,`/${Config.adminPath}/role`)
      }else{
        this.toolsService.error(res,'添加角色失败',`/${Config.adminPath}/role`)
      }
    }else{
      this.toolsService.error(res,'标题不能为空',`/${Config.adminPath}/role`)
    }
  }

  @Post('doEdit')
  async doEdit(@Body() body,@Response() res){
    if (body.title != '') {
      let result = await this.roleService.update({"_id":body._id},body);
      if (result) {
        this.toolsService.success(res,`/${Config.adminPath}/role`)
      }else{
        this.toolsService.error(res,'修改角色失败',`/${Config.adminPath}/role`)
      }
    }else{
      this.toolsService.error(res,'标题不能为空',`/${Config.adminPath}/role`)
    }
  }

  @Get('delete')
  async delete(@Query() query,@Response() res){
      let result = await this.roleService.delete({"_id":query._id});
      if (result) {
        this.toolsService.success(res,`/${Config.adminPath}/role`)
      }else{
        this.toolsService.error(res,'删除角色失败',`/${Config.adminPath}/role`)
      }
  }
}

service(服务层)

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import {RoleInterface} from './../../interface/role.interface';

@Injectable()
export class RoleService {
  constructor(@InjectModel('Role') private readonly roleModel){}

  /**
   * 查询
   * @param json 
   * @param fields 
   */
  async find(json:RoleInterface,fields?:string){
    try {
      return await this.roleModel.find(json,fields);
    } catch (error) {
      return null;
    }
  }
  /**
   * 新增
   * @param json 
   */
  async add(json:RoleInterface){
    try {
      const role = new this.roleModel(json)
      return await role.save()
    } catch (error) {
      return null;
    }
  }

  /**
   * 更新
   * @param orginJson 
   * @param newJson 
   */
  async update(orginJson:RoleInterface,newJson:RoleInterface){
    try {
      return await this.roleModel.updateOne(orginJson,newJson)
    } catch (error) {
      return null;
    }
  }
  /**
   * 删除
   * @param json 
   */
  async delete(json:RoleInterface){
    try {
      return await this.roleModel.deleteOne(json)
    } catch (error) {
      return null;
    }
  }
}

module(模块)

app.module

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { AdminModule } from './module/admin/admin.module';
import { DefaultModule } from './module/default/default.module';
import { ApiModule } from './module/api/api.module';
import { MongooseModule } from '@nestjs/mongoose';
import {Config} from './config/config';

//引入中间件
import { AdminauthMiddleware } from "./middleware/adminauth.middleware";
import { InitMiddleware } from "./middleware/init.middleware";


@Module({
  imports: [AdminModule, DefaultModule, ApiModule,
    MongooseModule.forRoot('mongodb://admin:123456@120.77.223.59:27017/millet?authSource=admin', { useNewUrlParser: true })],
  controllers: [],
  providers: [],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(AdminauthMiddleware)
      .forRoutes(`${Config.adminPath}/*`)
      .apply(InitMiddleware)
      .forRoutes('*')
  }
}

admin.module

import { Module } from '@nestjs/common';
import { MainController } from './main/main.controller';
import { LoginController } from './login/login.controller';
import { ManagerController } from './manager/manager.controller';
import {ToolsService} from './../../service/tools/tools.service';
import { MongooseModule } from '@nestjs/mongoose';
import { AdminSchema } from "./../../schema/admin.schema";
import { AdminService } from './../../service/admin/admin.service';
import { RoleSchema } from '../../schema/role.schema';
import {RoleService} from './../../service/role/role.service';
import { RoleController } from './role/role.controller';

@Module({
  imports:[MongooseModule.forFeature([
    { name: 'Admin', schema: AdminSchema,collection:'admin' },
    { name:'Role',schema: RoleSchema,collection:'role'}
  ])],
  controllers: [MainController, LoginController, ManagerController, RoleController],
  providers:[ToolsService,AdminService,RoleService]
})
export class AdminModule {}

守卫

安装

nest g guard 文件夹/文件名
nest g guard guard/auth

基本使用

auth.guard.ts

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const request = context.switchToHttp().getRequest();
    return validateRequest(request);
  }
}

控制器类上使用

@Controller('cats')
@UseGuards(AuthGuard)
export class CatsController {
    ...
}

控制器方法上使用

@Get('guard')
@UseGuards(AuthGuard)
guard(@Query() info){
	console.log(info);
	return `this is guard`;
}

全局使用

main.ts

app.useGlobalGuards(new AuthGuard());

在守卫中获取Cookie和Session

main.ts

//配置cookie中间件
app.use(cookieParser("this signed cookies"))
//配置session中间件
app.use(session({secret:'keyboard cat',cookie:{maxAge:9000,httpOnly:true}}))
//配置全局守卫
app.useGlobalGuards(new AuthGuard());

login.controller.ts

@Controller('login')
@UseGuards(AuthGuard)
export class LoginController {
    
    @Get()
    index(@Request() req){
        req.session.username = '张三'return '登录成功'
    }
}

auth.guard.ts

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActivate {
	canActivate(context: ExecutionContext,): boolean | Promise<boolean> | Observable<boolean> {
        let req = context.switchToHttp().getRequest()
        if(req.path == 'admin/login'){
            return true;
        }else{
            //context.switchToHttp().getRequest().cookies
			let userinfo = context.switchToHttp().getRequest().session.username
            if(userinfo){
                return true;
            }
			return false;
        }
		
	}
}

第三方中间件

第三方包

cookie-parser(cookie)

npm install cookie-parser --save

//main.ts

import * as cookieParser from 'cookie-parser'

app.use(cookieParser)

#设置cookie
res.cookie("name",'zhangsan',{maxAge: 900000, httpOnly: true});
//HttpOnly 默认 false 不允许 客户端脚本访问


#获取cookie
@Get('getCookies')
getCookies(@Request() req){
	return req.cookies.name;
}

#删除cookie
res.cookie('rememberme', '', { expires: new Date(0)});

设置cookie参数

domain: (String) 域名 expires:(Date) 过期时间(秒),在设置的某个时间点后该 Cookie 就会失效,如expires=Wednesday, 09-Nov-99 23:12:40 GMT maxAge:(String) 最大失效时间(毫秒),设置在多少后失效 secure:(Boolean) 当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效 path:(String) 表示 cookie 影响到的路,如 path=/。如果路径不能匹配时,浏览器则不发送这个 Cookie httpOnly:(Boolean) 是微软对 COOKIE 做的扩展。如果在 COOKIE 中设置了“httpOnly”属性,则通过程序(JS 脚本、applet 等)将无法读取到 COOKIE 信息,防止 XSS 攻击产生 signed:(Boolean) 表示是否签名 cookie, 设为 true 会对这个 cookie 签名,这样就需要用res.signedCookies 而不是 res.cookies 访问它。被篡改的签名 cookie 会被服务器拒绝,并且cookie 值会重置为它的原始值

Nestjs 中 Cookie 加密

  1. 配置中间件的时候需要传参
  app.use(cookieParser('123456')); //相当于密钥
  1. 设置 cookie 的时候配置 signed 属性
  res.cookie('userinfo','hahaha',{domain:'.ccc.com',maxAge:900000,httpOnly:true,signed:true});
  1. signedCookies 调用设置的 cookie
  console.log(req.signedCookies);

express-session(session)

npm install express-session --save

import * as session from 'express-session';

app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))

#设置值
 req.session.username = "张三";

#获取值
req.session.username

配置参数

app.use(session({
	secret: '12345',
	name: 'name',
	cookie: {maxAge: 60000},
	resave: false,
	saveUninitialized: true
}));
参数作用
secret一个 String 类型的字符串,作为服务器端生成 session 的签名。
name返回客户端的 key 的名称,默认为 connect.sid,也可以自己设置。
resave强制保存 session 即使它并没有变化,。默认为 true。建议设置成 false。 don't save session if unmodifie
saveUninitialized强制将未初始化的 session 存储。当新建了一个 session 且未设定属性或值时,它就处于未初始化状态。在设定一个 cookie 前,这对于登陆验证,减轻服务端存储压力,权限控制是有帮助的。(默认:true)。建议手动添加。
cookie设置返回到前端 key 的属性,默认值为{ path: ‘/’, httpOnly: true, secure: false, maxAge: null }。
rolling在每次请求时强行设置 cookie,这将重置 cookie 过期时间(默认:false)

常用方法

/*销毁 session*/
req.session.destroy(function(err) {})

req.session.username='张三';     //设置 session

req.session.username             //获取 session

req.session.cookie.maxAge=0;     //重新设置 cookie 的过期时间

模板引擎

ejs

npm install ejs --save

nunjucks

官网

安装使用

npm install nunjucks -S

main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
import {join} from 'path';
import * as nunjucks from 'nunjucks';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  // app.useStaticAssets('public'); 
  app.useStaticAssets(join(__dirname, '..', 'public'),{
    prefix: '/static/',   //设置虚拟路径
 });
 app.setBaseViewsDir(join(__dirname, '..', 'views')) // 放视图的文件
 app.engine("html", nunjucks.configure('views',{
  autoescape: true, //(默认值: true) 控制输出是否被转义
  throwOnUndefined: false, //(default: false) 当输出为 null 或 undefined 会抛出异常
  trimBlocks: false, // (default: false) 自动去除 block/tag 后面的换行符
  lstripBlocks: false, //(default: false) 自动去除 block/tag 签名的空格
  watch: true, //(默认值: false) 当模板变化时重新加载。使用前请确保已安装可选依赖 chokidar。
  express: app //传入 express 实例初始化模板设置
 }).render);
  app.setViewEngine('html');
  await app.listen(3000);
}
bootstrap();


noCache: (default: false) 不使用缓存,每次都重新编译
web: 浏览器模块的配置项
	useCache: (default: false) 是否使用缓存,否则会重新请求下载模板
	async: (default: false) 是否使用 ajax 异步下载模板
tags: (默认值: see nunjucks syntax) 定义模板语法,

svg-captcha(验证码)

在node.js中生成svg格式的验证码

github

npm install --save svg-captcha

//nestjs中引入



var svgCaptcha = require('svg-captcha');

app.get('/captcha', function (req, res) {
	var captcha = svgCaptcha.create();
	req.session.captcha = captcha.text;
	
	res.type('svg');
	res.status(200).send(captcha.data);
});

md5(加密)

npm地址

npm install md5 --save

silly-datetime(时间格式化)

github

npm i silly-datetime --save

nest-mongoose

安装

npm install --save @nestjs/mongoose mongoose

配置数据库

app.module.ts

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';

@Module({
  imports: [MongooseModule.forRoot('mongodb://admin:123456@172.0.0.1:27017/millet?authSource=admin', { useNewUrlParser: true })],
})
export class AppModule {}

nest中的增删改查

schema.ts

import * as mongoose from 'mongoose';
const d = new Date();

export const RoleSchema = new mongoose.Schema({
  title:{
    type:String
  },
  description:{
    type: String
  },
  status:{
    type:Number,
    default:1
  },
  add_time:{
    type:Number,
    default:d.getTime()
  }
})

module.ts

import {RoleService} from './../../service/role/role.service';

@Module({
  imports:[MongooseModule.forFeature([
    { name:'Role',schema: RoleSchema,collection:'role'}
  ])],
  controllers: [MainController, LoginController, ManagerController],
  providers:[ToolsService,AdminService,RoleService]
})
export class AdminModule {}

interface.ts

export interface RoleInterface {
  _id?:String,
  title?:String,
  description?:String,
  status?:Number,
}

service.ts

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import {RoleInterface} from './../../interface/role.interface';

@Injectable()
export class RoleService {
  constructor(@InjectModel('Role') private readonly roleModel){}

  /**
   * 查询
   * @param json 
   * @param fields 
   */
  async find(json:RoleInterface,fields?:string){
    try {
      return await this.roleModel.find(json,fields);
    } catch (error) {
      return null;
    }
  }
  /**
   * 新增
   * @param json 
   */
  async add(json:RoleInterface){
    try {
      const role = new this.roleModel(json)
      return await role.save()
    } catch (error) {
      return null;
    }
  }

  /**
   * 更新
   * @param orginJson 
   * @param newJson 
   */
  async update(orginJson:RoleInterface,newJson:RoleInterface){
    try {
      return await this.roleModel.updateOne(orginJson,newJson)
    } catch (error) {
      return null;
    }
  }
  /**
   * 删除
   * @param json 
   */
  async delete(json:RoleInterface){
    try {
      return await this.roleModel.deleteOne(json)
    } catch (error) {
      return null;
    }
  }
}