废话不多说!
直接忽略掉没有用的理论!
实战!走起!
1.安装nest.js脚手架
cnpm i -g @nestjs/cli
2.创建nest项目
nest new 项目名
3.安装mongoose
项目中我们会用到 Mongoose
来操作我们的数据库,Nest
官方为我们提供了一个 Mongoose
的封装,我们需要安装 mongoose
和 @nestjs/mongoose
:
npm install mongoose @nestjs/mongoose --save
4.创建模块
nest g module user server
脚手架工具会自动在 src/server/user
文件夹下创建一个 user.module.ts
,这是 Nest
的模块文件,Nest
用它来组织整个应用程序的结构。
// user.module.ts
import { Module } from '@nestjs/common';
@Module({})
export class UserModule {}
同时还会在根模块 app.module.ts
中引入 UserModule
这个模块,相当于一个树形结构,在根模块中引入了 User
模块。
执行上面的终端命令之后,app.module.ts
中的代码已经发生了变化,在文件顶部自动引入了 UserModule
,同时也在 @Module
装饰器的 imports
中引入了 UserModule
。
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './server/user/user.module'; // 自动引入
@Module({
imports: [UserModule], // 自动引入
controllers: [AppController],
providers: [AppService]
})
export class AppModule {}
5.创建控制器
nest g controller user server
在 Nest
中,controller
就类似前端的路由,负责处理客户端传入的请求和服务端返回的响应。
举个例子,我们如果要通过 http://localhost:3000/user/users
获取所有的用户信息,那么我们可以在 UserController
中创建一个 GET
方法,路径为 users
的路由,这个路由负责返回所有的用户信息。
// user.controller.ts
import { Controller, Get } from '@nestjs/common';
@Controller('user')
export class UserController {
@Get('users')
findAll(): string {
return "All User's Info"; // [All User's Info] 暂时代替所有用户的信息
}
}
这就是 controller
的作用,负责分发和处理请求和响应。
当然,也可以把 findAll
方法写成异步方法,像这样:
// user.controller.ts
import { Controller, Get } from '@nestjs/common';
@Controller('user')
export class UserController {
@Get('users')
async findAll(): Promise<any> {
return await this.xxx.xxx(); // 一些异步操作
}
}
6.创建 Provider
nest g service user server
provider
我们可以简单地从字面意思来理解,就是服务的提供者。
怎么去理解这个服务提供者呢?
举个例子,我们的 controller
接收到了一个用户的查询请求,我们不能直接在 controller
中去查询数据库并返回,而是要将查询请求交给 provider
来处理,这里我们创建了一个 UserService
,就是用来提供数据库操作服务的。
// user.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class UserService {}
当然,provider
不一定只能用来提供数据库的操作服务,还可以用来做一些用户校验,比如使用 JWT
对用户权限进行校验的策略,就可以写成一个策略类,放到 provider
中,为模块提供相应的服务。
controller
和 provider
都创建完后,user.module.ts
文件中多了一些代码,变成了这样:
// user.module.ts
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
@Module({
controllers: [UserController],
providers: [UserService]
})
export class UserModule {}
7.连接数据库引入 根模块Mongoose
连接数据之前,我们要先在根模块,也就是 app.module.ts
中引入 Mongoose
的连接模块:
// app.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './server/user/user.module';
@Module({ imports: [MongooseModule.forRoot('mongodb://localhost:27017/Users'), UserModule],
controllers: [AppController],
providers: [AppService]
})
export class AppModule {}
如果这里运行后端文件是又可能会报错,如果报错就添加:
npm install @types/mongoose --dev
安装完之后服务就正常重启了。
8.引入 分模块Mongoose
这里我们先要创建一个数据表的格式,在 src/server/user
文件夹下创建一个 user.schema.ts
文件,定义一个数据表的格式:
// user.schema.ts
import { Schema } from 'mongoose';
export const userSchema = new Schema({
_id: { type: String, required: true }, // 覆盖 Mongoose 生成的默认 _id
user_name: { type: String, required: true },
password: { type: String, required: true }
});
然后将我们的 user.module.ts
文件修改成这样:
// user.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { UserController } from './user.controller';
import { userSchema } from './user.schema';
import { UserService } from './user.service';
@Module({
imports: [MongooseModule.forFeature([{ name: 'Users', schema: userSchema }])],
controllers: [UserController],
providers: [UserService]
})
export class UserModule {}
9.CRUD
创建两个文件做数据类型的定义:
user.interface.ts
// user.interface.ts
import { Document } from 'mongoose';
export interface User extends Document {
// readonly _id: string;
readonly user_name: string;
readonly password: string;
}
user.dto.ts
// user.dto.ts
export class CreateUserDTO {
readonly user_name: string;
readonly password: string;
}
export class EditUserDTO {
readonly user_name: string;
readonly password: string;
}
我们打开 user.service.ts
文件,为 UserService
类添加一个构造函数,让其在实例化的时候能够接收到数据库 Model
,这样才能在类中的方法里操作数据库。
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { CreateUserDTO, EditUserDTO } from './user.dto';
import { User } from './user.interface';
@Injectable()
export class UserService {
constructor(@InjectModel('Users') private readonly userModel: Model<User>) { }
// 查找所有用户
async findAll(): Promise<User[]> {
const users = await this.userModel.find();
return users;
}
// 查找单个用户
async findOne(user_name: string): Promise<User> {
return await this.userModel.findOne({user_name});
}
// 添加单个用户
async addOne(body: CreateUserDTO): Promise<void> {
await this.userModel.create(body);
}
// 编辑单个用户
async updateOne(user_name: string, newPassword: string): Promise<void> {
await this.userModel.updateOne({user_name},{password: newPassword});
}
// 删除单个用户
async deleteOne(user_name: string): Promise<void> {
await this.userModel.deleteOne({user_name});
}
}
因为 mongoose
操作数据库其实是异步的,所以这里我们使用 async
函数来处理异步的过程。
现在,我们可以到 user.controller.ts
中设置路由了,将客户端的请求进行处理,调用相应的服务实现相应的功能:
import {
Controller,
Body,
// Delete,
Get,
Param,
Post,
Put
} from '@nestjs/common';
import { CreateUserDTO, EditUserDTO } from './user.dto';
import { User } from './user.interface';
import { UserService } from './user.service';
interface UserResponse<T = unknown> {//这是一个 TypeScript 接口定义,用于描述用户响应的数据结构。它包含一个泛型参数 T,默认值为 unknown,其中包含 code(响应码)、data(响应数据,可选)和 message(响应消息)三个属性。
code: number;
data?: T;
message: string;
}
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) { }
// GET /user/users
@Get('/users')
async findAll(): Promise<UserResponse<User[]>> {
return {
code: 200,
data: await this.userService.findAll(),
message: '查询成功.'
};
}
// GET /user/:_id
@Post('/find_one')
async findOne(@Body() userData: { user_name: string }): Promise<UserResponse> {
await this.userService.findOne(userData.user_name); // 使用传入的 user_name 参数
return {
code: 200,
data: await this.userService.findOne(userData.user_name),
message: '查询成功.'
};
}
// POST /user/user
@Post('/user')
async addOne(@Body() body: CreateUserDTO): Promise<UserResponse> {
await this.userService.addOne(body);
return {
code: 200,
message: '添加成功.'
};
}
// PUT /user/:_id
@Post('/upd')
async updateOne(@Body() userData: { user_name: string, newPassword: string }): Promise<UserResponse> {
await this.userService.updateOne(userData.user_name, userData.newPassword); // 使用传入的 user_name 参数
return {
code: 200,
message: '修改成功.'
};
}
// Post /user/deluser
@Post('/deluser1')
async deleteOne(@Body() userData: { user_name: string }): Promise<UserResponse> {
await this.userService.deleteOne(userData.user_name); // 使用传入的 user_name 参数
return {
code: 200,
message: '删除成功.'
};
}
}
好的,到这里我们的nest.js一个调用mongoose来操作mongoDB数据库的后端程序就已经写好了。
我们接下来用小程序端作为前端来调用后端,将整个完整的前后端+数据库程序跑起来!
10.前端部分
index.js
// pages/index1/index1.js
Page({
/**
* 页面的初始数据
*/
data: {
},
// 增加
// 输入框1的输入事件(姓名)
input1Change(e) {
this.setData({
inputValue1: e.detail.value,
});
},
// 输入框2的输入事件(年龄)
input2Change(e) {
this.setData({
inputValue2: e.detail.value,
});
},
tijiao(){
wx.request({
url: 'http://localhost:3000/user/user',
method:'POST',
data:{
user_name:this.data.inputValue1,
password:this.data.inputValue2
},
})
},
// 删除
input1Change_del(e){
this.setData({
inputValue_del: e.detail.value,
});
},
shanchu() {
wx.request({
url: 'http://localhost:3000/user/deluser1',
method: 'POST',
data: {
user_name: this.data.inputValue_del,
},
success: (res) => {
// 处理成功的情况
console.log(res.data); // 可以打印后端返回的数据
},
fail: (error) => {
// 处理失败的情况
console.error(error);
}
})
},
// 修改
input1Change_upd(e){
this.setData({
inputValue1_upda: e.detail.value,
});
},
input2Change_upd(e){
this.setData({
inputValue2_upda: e.detail.value,
});
},
xiugai(){
wx.request({
url: 'http://localhost:3000/user/upd',
method:'POST',
data:{
// 名字
user_name:this.data.inputValue1_upda,
// 修改后的年龄
newPassword:this.data.inputValue2_upda,
},
})
},
// 查询
input1Change_find(e){
this.setData({
inputValue1_find: e.detail.value,
});
},
find(){
wx.request({
url: 'http://localhost:3000/user/find_one',
method: 'POST',
data:{
// 名字
user_name:this.data.inputValue1_find,
},
success: function(res) {
// 请求成功,处理从服务器返回的数据
console.log('服务器返回的数据:', res.data);
// 检查是否找到匹配的记录
if (res.data && res.data.length > 0) {
// 处理返回的记录数据
const records = res.data;
records.forEach(record => {
console.log('记录:', record);
// 在这里进行您的处理逻辑,例如显示在界面上
});
} else {
console.log('未找到匹配的记录');
// 在界面上显示相应的消息,告知用户未找到匹配的记录
}
},
fail: function(error) {
// 请求失败,处理错误
console.error('请求失败:', error);
// 在界面上显示错误信息,告知用户请求失败
}
});
},
find_all(){
wx.request({
url: 'http://localhost:3000/user/users',
method: 'GET',
success: function(res) {
// 请求成功,处理从服务器返回的数据
console.log('服务器返回的数据:', res.data);
// 检查是否找到匹配的记录
if (res.data && res.data.length > 0) {
// 处理返回的记录数据
const records = res.data;
records.forEach(record => {
console.log('记录:', record);
// 在这里进行您的处理逻辑,例如显示在界面上
});
}
},
fail: function(error) {
// 请求失败,处理错误
console.error('请求失败:', error);
// 在界面上显示错误信息,告知用户请求失败
}
});
}
})