快速nestjs框架搭建
npm i -g @nestjs/cli nest new project-name
NestJS实现Restful API
// Param:restful api参数
// Query:url 参数
// body:post 参数
import { Controller, Get,Post,Put,Delete,Param,Query,Body } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get('/')
getHello(): string {
return this.appService.getHello();
}
// Get:获取数据
// post 插入数据
// put 更新
// delete 删除
// http://localhost:300/data/10
@Get('/data/:id')
getData(@Param() param):string{
return 'data'
}
@Get('/data')
getAllData(){
return 'get all data'
}
// http://localhost:300/data?id=10
@Post('/data')
addData(@Body() body,@Query() query){
console.log(body,query)
return 'add data:' + JSON.stringify(body) + ',id=' + query.id
}
@Put('/data')
updateData(){
return 'update data'
}
@Delete('/data/:id')
deleteData(){
return 'delete data'
}
}
模块
创建模块
nest g module user
创建控制器
nest g controller user
连接数据库mysql TypeORM
MySQL8安装+数据库导入
npm install --save @nestjs/typeorm typeorm mysql2
app.modele.ts 引入
@Module({
imports: [
TypeOrmModule.forRoot({
type:'mysql',
host:'127.0.0.1',
port:3306,
username:'root',
password:'123456',
database:'vben-book-dev',
}),
UserModule,
AuthModule,
BookModule],
controllers: [AppController, BookController],
providers: [AppService],
})
数据库实体Entity创建
//数据库实体Entity创建 手动创建
import {Entity,Column, Unique, PrimaryGeneratedColumn} from 'typeorm';
@Entity('admin_user')
export class User{
@PrimaryGeneratedColumn()
id:number;
@Column()
@Unique(['username'])
username:string;
@Column()
password:string;
@Column()
avatar:string;
@Column()
role:string;
@Column()
nickname:string;
@Column()
active:number;
}
MySQL表关联和查询逻辑实现
第一步 创建服务层 service
// 这里是手动创建 不过可以命令创建 nest g service module/user
import {InjectRepository} from '@nestjs/typeorm';
import {User} from './user.entity';
import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
@Injectable()
export class UserService{
constructor(@InjectRepository(User) private readonly usersRepository:Repository<User>){}
findOne(id:number):Promise<User>{
return this.usersRepository.findOneBy({id})
}
}
第二步 在模块导入
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { TypeOrmModule} from '@nestjs/typeorm';
import {User} from './user.entity';
import { UserService } from './user.service';
@Module({
imports:[TypeOrmModule.forFeature([User])],
controllers: [UserController],
providers:[UserService]
})
export class UserModule {}
第三步 在控制层 请求数据
import { Controller, Param,Get,ParseIntPipe } from '@nestjs/common';
import {UserService} from './user.service'
@Controller('user')
export class UserController {
constructor(private readonly userService:UserService){}
@Get(':id')
getUser(@Param('id',ParseIntPipe) id:number){
return this.userService.findOne(id);
}
}
有个看不懂的返回
await 一下
数据库新增和删除逻辑实现
NestJS请求守卫开发
实现登录鉴权接口的调用链路
登录密码校验逻辑实现
加密依赖
npm i md5
JWT基本概念讲解
Token 本质是字符串,用于请求时附带在请求头中,检验请求是否合法及判断用户身份
npm install -S @nestjs/jwt
import {JwtModule} from '@nestjs/jwt';
// 创建模块 nest g module module/auth
@Module({
// 实现登录鉴权接口的调用链路 第一步 引入模块
imports:[
UserModule,
JwtModule.register({
global:true,
secret:'abcdefg', // 密钥
signOptions:{expiresIn:30 * 40 * 60 *60 + 's'} // 过期时间
})
],
生成token
统一返回
export function successCount(data,count,msg){
return {
code:0,
result:data,
message:msg,
count,
};
}
export function success(data,msg){
return{
code:0,
result:data,
message:msg
}
}
export function error(msg) {
return {
code: -1,
message: msg,
};
}
export function wrapperResponse(p, msg) {
return p
.then((data) => success(data, msg))
.catch((err) => error(err.message));
}
// 加上注解 允许被请求
@Public()
@Post('login')
// 接口进行统一拦截器处理
@UseFilters(new HttpExceptionFilter())
async login(@Body() body){
return this.authService.login(body.username,body.password)
.then((data)=> success(data,'登录成功'))
.catch((err)=> error("登录失败"))
}
JsonWebTokenError: invalid signature
获取用户信息API开发
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';
import { IS_PUBLIC_KEY } from './public.decorator';
import { JwtService } from '@nestjs/jwt';
import { JWT_SECRET_KEY } from './auth.jwt.secrect';
@Injectable()
// 第二步 实现一个接口
export class AuthGuard implements CanActivate{
constructor(private jwtService:JwtService,private reflector:Reflector){}
async canActivate(context: ExecutionContext): Promise<boolean> {
// 请求可以被处理之前,可以这里处理 验证是否登录
// console.log('canActive',context)
// 第四步 通过API通过IS_PUBLIC_KEY 判断是否允许被请求
const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY,[
context.getHandler(),
context.getClass(),
]);
// 如果为true 允许被调用
if(isPublic){
return true;
}
// 获取request对象
const request = context.switchToHttp().getRequest();
console.log("6456",request.headers.authorization)
const token = request.headers.authorization
if(!token){
throw new UnauthorizedException()
}
try {
const user = this.jwtService.verify(token)
console.log(user)
request['user'] = user;
}catch(e){
console.log(e)
throw new UnauthorizedException();
}
//解析token
return true;
}
}
function extractTokenFromHeader(request){
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : '';
}
服务层执行sql
findAll() {
const sql = 'select * from menu order by id asc';
return this.menuRepository.query(sql);
}
// 新增
create(body) {
return this.menuRepository.save(body.data || body);
}
@Post()
create(@Body() body) {
return wrapperResponse(
this.menuService.create(body),
'菜单创建成功',
);
}
修改菜单
update(body) {
const id = body?.data?.id || body.id;
const data = body.data || body;
return this.menuRepository.update(id, data);
}
@Put()
update(@Body() body) {
return wrapperResponse(
this.menuService.update(body),
'菜单更新成功',
);
}
根据id查询book Param
getBook(id){
const sql = `SELECT * FROM book WHERE id="${id}"`
return this.repository.query(sql);
}
// http://localhost:3000/book/1 Param
@Get(':id')
getBook(@Param('id',ParseIntPipe) id){
return wrapperResponse(
this.bookService.getBook(id),
'查询电子书成功'
)
}
新增
Field 'updateType' doesn't have a default value
updateType 字段不能为空
async addBook(params){
const {title,author,fileName,category,categoryText,cover,language,publisher,rootFile} = params;
const insertSql = `INSERT INTO book(
title,
author,
fileName,
category,
categoryText,
cover,
language,
publisher,
rootFile
)VALUES(
'${title}',
'${author}',
'${fileName}',
'${category}',
'${categoryText}',
'${cover}',
'${language}',
'${publisher}',
'${rootFile}'
)`;
return this.repository.query(insertSql);
}
@Post()
insertBook(@Body() body){
return wrapperResponse(
this.bookService.addBook(body),
'新增电子书成功'
)
}
更新
async updateBook(params){
const { id, title, author, category, categoryText, language, publisher } = params;
const setSql = [];
if(title){
setSql.push(`title="${title}"`);
}
if(author){
setSql.push(`author="${author}"`);
}
const updateSql = `UPDATE book SET ${setSql.join(',')} WHERE id=${id}` ;
return this.repository.query(updateSql);
}
@Put()
updateBook(@Body() body){
return wrapperResponse(
this.bookService.updateBook(body),
'更新电子书成功'
)
}
删除
async deleteBook(id){
const deleteSql = `DELETE FROM book WHERE id = ${id}`
return this.repository.query(deleteSql);
}
@Delete()
deleteBook(@Body() body){
console.log(body)
return wrapperResponse(
this.bookService.deleteBook(body.id),
'删除电子书成功'
)
}
分页功能 @Query
//图书列表分页组件开发
async getBookList(params:any = {}){
let page = +params.page || 1;
let pageSize = +params.pageSize || 20;
const {title = '',author = ''} = params;
if(page <= 0){
page =1;
}
if(pageSize <= 0){
pageSize = 20;
}
let where = 'where 1=1';
if(title){
where += ` AND title LIKE '%${title}%'`;
}
if(author){
where += ` AND author LIKE '%${author}%'`;
}
// const categoryAuth = await this.getCategoryAuth(userid);
// if (categoryAuth.length > 0) {
// where += ` AND categoryText IN (${categoryAuth.join(',')})`;
// }
const sql = `select * from book ${where} limit ${pageSize} offset ${(page - 1) * pageSize}`;
const res = await this.repository.query(sql);
return res
}
async countBookList(params: any = {}) {
const { title = '', author = '' } = params;
let where = 'where 1=1';
if (title) {
where += ` AND title LIKE '%${title}%'`;
}
if (author) {
where += ` AND author LIKE '%${author}%'`;
}
// const categoryAuth = await this.getCategoryAuth(userid);
// if (categoryAuth.length > 0) {
// where += ` AND categoryText IN (${categoryAuth.join(',')})`;
// }
const sql = `select count(*) as count from book ${where}`;
return this.repository.query(sql);
}
// 控制器
// 分页查询book列表
@Get()
getBookList(@Query() params){
return wrapperCountResponse(
this.bookService.getBookList(params),
this.bookService.countBookList(params),
'获取图片列表成功',
)
}