前言
在Nest中,一个http央求首要会通过Controller
控制器层进行参数验证或转化,再调用Service
服务层处理杂乱的处理逻辑,与数据库交互进行耐久化操作,这节我们对MySQL
单表进行CRUD
操作,结束一个用户处理功用。
MySQL数据库+Typeorm
首要对于前端同学比较少接触的MySQL
而言,需求提前设备适合本机的MySQL
版别。
先发起MySQL
服务,运用命令行实行sql
语句来操作数据库
也可以运用更便利的MySQL
可视化东西navicate
操作表数据,这儿运用的是navicate
,也可挑选白嫖的Sequel Pro
。
在后端系统中,Nest
或Java
等言语都可以直接操作Sql
语句实行CRUD
,可是频频写Sql
语句太麻烦了,能不能像前端相同直接操作数据方针,对特色进行读写,主动同步到视图中。
这就要引入ORM
概念了,即方针联系映射
。ORM
通过将数据库中的表、行、列映射为程序中的方针、特色和相关运用面向方针的编程方式来操作数据库,而无需操作SQL
语句。
其实还有一个相似的概念,叫ODM
,即方针文档映射
,它是针对文档型数据库(NoSql)的,比方MongoDB
这一类,但理念是跟ORM
相同的。
再回来,Typeorm
就是结束ODM
理念的结构,通过装饰器的写法来描绘数据库字段的映射联系。
声明对应字段之后,我们操作数据方针时,Typeorm
主动会实行内部的SQL
语句来同步修正数据库。
了解完怎么进行数据库操作,我们创建一个项目来结束一下。
Nest.js + Typeorm
运用CLI
新建一个项目:nest n nest-mysql -p pnpm
,默认选用pnpm
包处理东西。
接着把它发起起来:pnpm run start:dev
Nest
供应了模块化的结构来处理不同的功用,每个Module
里边有归于自己的Controllers
和Services
,不同的Services
可以通过exports
和imports
进行导出导入结束服务同享。
我们新建一个User
模块,运用nest g resource User
,挑选REST
风格API和生成CRUD
入口点。
详细来看看Controller
中代码
// user.controller.ts
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.userService.create(createUserDto);
}
@Get()
findAll() {
return this.userService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.userService.findOne(+id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.userService.update(+id, updateUserDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.userService.remove(+id);
}
}
通过@Controller('user')
装饰器来声明控制器,并且指定路由途径为user
,标明在这个Controller
下面的一切路由程序都归于/user
途径下的子路由。
@Post()
、@Get()
、@Patch()
、@Delete()
分别对应央求方式,它们也可以指定归于自己的路由途径,如@Post('create-user')
,毕竟拼接为/user/create-user
这个URL,指向create
这个路由办法。
@Param()
、@Body()
、@Query()
这些就是获取央求方针里边的参数或央求体,在Nest
中不需求操作相似express
中的@res
、@req
方针再来拿到里边的特色。
而createUserDto
和UpdateUserDto
是用于声明并验证央求体(Body)传递过来的参数。
Controller
层毕竟调度Service
层,来看看Service
里边的代码:
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
@Injectable()
export class UserService {
create(createUserDto: CreateUserDto) {
return 'This action adds a new user';
}
findAll() {
return `This action returns all user`;
}
findOne(id: number) {
return `This action returns a #${id} user`;
}
update(id: number, updateUserDto: UpdateUserDto) {
return `This action updates a #${id} user`;
}
remove(id: number) {
return `This action removes a #${id} user`;
}
}
在这个样板代码中,Service
没有结束详细的事务逻辑,没有操作数据库,只返回了String
类型数据。
而Service
通过@Injectable()
装饰器进行润饰,它与filter
、interceptor
等共同被称为Provider
供应者,在这个比如中,Controller
可以看做顾客,消费的是由Provider
供应的服务或许其他模块。
完善Service
部分的逻辑,需求运用到与Nest
集成的@nestjs/typeorm
包,需单独设备。
它供应了 TypeOrmModule
模块,在App.module.ts
中引入,它有两个静态办法 forRoot
、forFeature
。
forRoot
用于在入口处初始化数据库连接,接纳数据库相关配备信息
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './user/user.module';
import { TypeOrmModule} from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: '你的暗码',
database: '数据库名',
synchronize: true
}),
UserModule
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
forFeature 用于创建不同实体类对应的 Repository
,在运用的对应 Module
里引入。
在这儿我们是uesr.module.ts
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { User } from './entities/user.entity';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forFeature([User])
],
controllers: [UserController],
providers: [UserService]
})
export class UserModule {}
接着需求创建User
实体user.entity
了,在此之前需求设备typeorm
、mysql
包
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity()
export class User{
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
sex: string;
@Column()
createTime: Date;
@Column()
updateTime: Date;
}
再来完善一下创建用户和更新用户的dto
// create-user.dto.ts
export class CreateUserDto {
name: string;
sex: string;
createTime: Date;
updateTime: Date;
}
PartialType
表格可以更新其间的部分特色字段
// update-user.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateUserDto } from './create-user.dto';
export class UpdateUserDto extends PartialType(CreateUserDto) {
name: string;
sex: string;
createTime: Date;
updateTime: Date;
}
毕竟在Service
中完善实体对应的操作类 Repository
,这样就结束了对用户处理的增删改查了。
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';
@Injectable()
export class UserService {
@InjectRepository(User) private userRepository: Repository<User>
async create(createUserDto: CreateUserDto) {
createUserDto.createTime = createUserDto.updateTime = new Date()
return await this.userRepository.save(createUserDto);
}
async findAll() {
return await this.userRepository.find();
}
async findOne(id: number) {
return this.userRepository.findBy;
}
async update(id: number, updateUserDto: UpdateUserDto) {
updateUserDto.updateTime = new Date()
return await this.userRepository.update(id, updateUserDto);
}
async remove(id: number) {
return await this.userRepository.delete(id);
}
}
我们先把存在的User
表删去,后面央求过来的时分会主动创建表。
后端部分现已结束,我们简略起一个前端项目来结束央求闭环,通过CRA
起一个react
项目
create-react-app nest-mysql-frontend
把项目发起起来
src
目录下起一个setupProxy.js
,把署理配备一下
// setupProxy.js
const proxy = require('http-proxy-middleware')//引入http-proxy-middleware,react脚手架现已设备
module.exports = function(app){
app.use(
proxy.createProxyMiddleware('/api',{ //遇见/api前缀的央求,就会触发该署理配备
target:'http://localhost:3000', //央求转发给谁
changeOrigin:true,//控制服务器收到的央求头中Host的值
pathRewrite:{'^/api':''} //重写央求途径,下面有示例说明
})
)
}
src
下新建api
目录,寄存央求接口
// index.js
import axios from 'axios'
export function createUser(data) {
return axios.post('/api/user', data);
}
export function getUserList() {
return axios.get('/api/user');
}
export function getUserById(id) {
return axios.get('/api/user/' + id);
}
export function updateUserById(id, data) {
return axios.patch('/api/user/' + id, data);
}
export function deleteUserById(id) {
return axios.delete('/api/user/' + id);
}
app.js
中简略写几个按钮触发央求
import './App.css';
import {
Button
} from 'antd'
import {
createUser,
getUserList,
updateUserById,
deleteUserById
} from './api/index'
function App() {
const handleCreateUser = async() => {
await createUser({
name: 'mouse',
sex: '男'
})
}
const handleGetUserList = async() => {
await getUserList()
}
const handleUpdateUser = async() => {
await updateUserById(1, {
sex: '人妖'
})
}
const handleDeleteUser = async() => {
await deleteUserById(1)
}
return (
<div className="App">
<Button type="default" onClick={handleCreateUser}>创建用户</Button>
<Button type="primary" onClick={handleGetUserList}>获取用户列表</Button>
<Button type='link' onClick={handleUpdateUser}>更新用户</Button>
<Button danger onClick={handleDeleteUser}>删去用户</Button>
</div>
);
}
export default App;
点击创建用户
,可以看到成功返回了数据
改写一下,数据库中成功创建了User
表并刺进了一条数据。
点击获取用户列表
,返回了刚刚刺进的数据
点击更新用户
,把我的性别改为人妖
,成功更新一条数据
毕竟点击删去用户
,成功删去库中数据
以上,结束了Nest
操作MySQL
的前后端应用了。
总结
Nest
供应了nest g resource [name]
快速创建CRUD
+REST
风格的代码,通过DTO
格局接纳Body
央求体内容,毕竟传递给Service
层做耐久化操作。
操作Mysql
通常结合Typeorm
的包@nestjs/typeorm
来结束数据库表字段界说和方针映射操作,无需操作SQL
语句。