前言

在Nest中,一个http央求首要会通过Controller控制器层进行参数验证或转化,再调用Service服务层处理杂乱的处理逻辑,与数据库交互进行耐久化操作,这节我们对MySQL单表进行CRUD操作,结束一个用户处理功用。

MySQL数据库+Typeorm

首要对于前端同学比较少接触的MySQL而言,需求提前设备适合本机的MySQL版别。

MySQL地址

先发起MySQL服务,运用命令行实行sql语句来操作数据库

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

也可以运用更便利的MySQL可视化东西navicate操作表数据,这儿运用的是navicate,也可挑选白嫖的Sequel Pro

navicate地址

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

在后端系统中,NestJava等言语都可以直接操作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包处理东西。

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

接着把它发起起来:pnpm run start:dev

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

Nest供应了模块化的结构来处理不同的功用,每个Module里边有归于自己的ControllersServices,不同的Services可以通过exportsimports进行导出导入结束服务同享。

我们新建一个User模块,运用nest g resource User,挑选REST风格API和生成CRUD入口点。

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

详细来看看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方针再来拿到里边的特色。

createUserDtoUpdateUserDto是用于声明并验证央求体(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()装饰器进行润饰,它与filterinterceptor等共同被称为Provider供应者,在这个比如中,Controller可以看做顾客,消费的是由Provider供应的服务或许其他模块。

完善Service部分的逻辑,需求运用到与Nest集成的@nestjs/typeorm包,需单独设备。

它供应了 TypeOrmModule模块,在App.module.ts中引入,它有两个静态办法 forRootforFeature

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了,在此之前需求设备typeormmysql

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

把项目发起起来

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

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;

点击创建用户,可以看到成功返回了数据

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

改写一下,数据库中成功创建了User表并刺进了一条数据。

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

点击获取用户列表,返回了刚刚刺进的数据

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

点击更新用户,把我的性别改为人妖,成功更新一条数据

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

毕竟点击删去用户,成功删去库中数据

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

【Nest全栈之旅】第八章:Nest快速上手操作MySQL

以上,结束了Nest操作MySQL的前后端应用了。

总结

Nest供应了nest g resource [name]快速创建CRUD+REST风格的代码,通过DTO格局接纳Body央求体内容,毕竟传递给Service层做耐久化操作。

操作Mysql通常结合Typeorm的包@nestjs/typeorm来结束数据库表字段界说和方针映射操作,无需操作SQL语句。

运用前端反向署理央求后端接口,结束前后端别离并形成闭环,基本上可以上手Nest全栈开发了。