Bootstrap

nextjs+nestjs+prisma写todolist全栈项目

技术栈

  • nextjs
  • nestjs
  • prisma

所学知识

  1. Nextjs组件渲染,状态,路由
  2. docker启动Mysql容器
  3. prisma操作Mysql(CRUD)
  4. 允许跨域请求API
  5. TanStack Query异步状态管理
  6. fetch api
  7. 服务器组件预请求数据
  8. nestjs 管道和异常处理
  9. 检测id是否正整数

Docker启动Mysql容器

compose.yml

name: 'todoList'
version: '3.8'
services:
  mysql:
    restart: always
    container_name: todolist
    image: mysql:8
    volumes:
      - ./mysql/datadir:/var/lib/mysql
      - ./mysql/config/my.cnf:/etc/mysql/my.cnf
    environment:
      - "MYSQL_ROOT_PASSWORD=root"
      - "TZ=Asia/Shanghai"
    ports:
      - 3306:3306

切换到compose.yml所在目录,cmd

docker-compose up

![[Pasted image 20241124230249.png]]

初始化prisma

npm install prisma --save-dev
npx prisma init

生成配置文件

设置数据库连接(mysql)

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

设置数据库连接环境变量

DATABASE_URL="mysql://root:root@localhost:3306/todos?schema=public"
  • todos是数据库名

设置表

model Todo {
  id        Int      @id @default(autoincrement())
  title     String
  completed Boolean? @default(false)
  createdAt DateTime @default(now())
}

npx prisma migrate dev --name init

![[Pasted image 20241124221851.png]]

回到初始化状态(测试用)

会删除数据库数据但是prisma配置内容还在

npx prisma migrate reset

定义prisma client

npm install @prisma/client

Prisma Client 是一个类型安全的数据库客户端,它是从 Prisma 模型定义生成的。由于这种方法,Prisma Client 可以公开专门为您的模型量身定制的 CRUD 操作。

请注意,在安装过程中,Prisma 会自动为您调用 prisma generate 命令。将来,您需要在每次更改 Prisma 模型后运行此命令,以更新生成的 Prisma Client。

使用prisma client

prisma.service.ts


import {
    Injectable, OnModuleInit } from '@nestjs/common';
import {
    PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
   
  async onModuleInit() {
   
    await this.$connect();
  }
}

onModuleInit 是可选的 — 如果你省略它,Prisma 将在第一次调用数据库时延迟连接。

注意

app.module要引入PrismaService

import { Module } from '@nestjs/common';
import { PrismaService } from 'src/prisma.service';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TodoController } from './todo/todo.controller';
import { TodoService } from './todo/todo.service';

@Module({
  imports: [],
  controllers: [AppController, TodoController],
  providers: [AppService, TodoService, PrismaService],
})
export class AppModule {}

不然报错

prisma调用数据库操作

接下来,您可以编写可用于从 Prisma 架构对 todo模型进行数据库调用的服务。

import {
    Body, Controller, Get, Post } from '@nestjs/common';
import {
    TodoService } from 'src/todo/todo.service';

@Controller('todo')
export class TodoController {
   
  constructor(private readonly todoService: TodoService) {
   }
  @Post()
  async createTodo(@Body() createTodoDto: any) {
   
    return this.todoService.createTodo(createTodoDto);
  }
}

import {
    Injectable } from '@nestjs/common';
import {
    PrismaService } from 'src/prisma.service';

@Injectable()
export class TodoService {
   
  constructor(private prisma: PrismaService) {
   }

  async createTodo(data: any) {
   
    const todo = await this.prisma.todo.create({
   
      data: {
   
        title: data.title,
        completed: false,
      },
    });
    return todo;
  }
}
  • private

这确保了封装,这意味着没有其他类或外部代码可以直接访问 todoService 属性,这是维护干净且可预测的代码的良好做法。

  • readonly

这是有益的,因为服务实例应在控制器的整个生命周期中保持不变。它可以防止意外重新分配 todoService 属性,这可能会导致 bug。

  @Delete(':id')
  async deleteTodoById(@Param('id') id: string) {
   
    return this.todoService.deleteTodoById(+id);
  }

  async getTodoById(id: number
;