今天的学习真是让我大开眼界啊!作为一个前端初学者,我一直觉得后端数据库操作是件很复杂的事情,但通过今天的实践,我发现用Next.js配合Prisma可以如此轻松地完成全栈开发。让我来好好回顾一下今天学到的内容,把这些知识牢牢地记在脑子里。
prisma是何方神圣
prisma是什么
一开始我接触到了Prisma这个神奇的工具。Prisma是什么呢?简单来说,它是一个ORM(对象关系映射)工具,让我们不需要直接写复杂的SQL语句,就能像操作普通JavaScript对象一样来操作数据库。这真是太方便了!想象一下,如果不用Prisma,我们要操作数据库就得写各种SQL查询语句,像什么SELECT、INSERT、UPDATE之类的,不仅容易出错,而且代码也很难维护。Prisma的出现让我们摆脱了这些烦恼,可以用更加直观的方式来处理数据。
prisma安装和初始化
安装Prisma很简单,只需要在项目里运行pnpm i prisma @prisma/client命令就可以了。这里安装了两个包:prisma是核心工具,提供了命令行功能;@prisma/client则是客户端库,让我们能在代码中实际使用Prisma的功能。
初始化Prisma是通过npx prisma init命令完成的。这个命令会创建一个prisma文件夹,里面包含一个schema.prisma文件,这是Prisma的核心配置文件。同时还会生成一个.env文件,用来存放环境变量,特别是数据库连接字符串。
当然连接数据库得先有数据库,这里我用得是小皮面板里面集成了数据库等各种环境,非常方便,一键式安装,不需要做任何配置:
说到数据库连接,我在.env文件中做了如下配置:
# Environment variables declared in this file are automatically made available to Prisma. # See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema # Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. # See the documentation for all the connection string options: https://pris.ly/d/connection-strings # The followingDATABASE_URL="mysql://用户:密码@localhost:3306/数据库名这个连接字符串告诉Prisma如何连接到我的MySQL数据库。它包含了用户名、密码、数据库服务器地址(localhost:3306)和数据库名。这样配置好后,Prisma就知道该往哪里读写数据了。
接下来是定义数据模型,这是在schema.prisma文件中完成的。我创建了一个Todo模型,用来表示待办事项:
model Todo { id Int @id @default(autoincrement()) title String completed Boolean @default(false) createdAt DateTime @default(now()) }这个模型定义了四个字段:id是主键,会自动递增;title是字符串类型,存储待办事项的内容;completed是布尔类型,表示是否已完成,默认是false;createdAt是日期时间类型,会自动设置为创建时间。这种定义方式非常直观,就像是在定义一个TypeScript接口一样,但实际上它背后会转换成数据库的表结构。
定义好模型后,需要运行npx prisma migrate dev --name init命令来创建迁移文件并执行迁移。迁移(Migration)是数据库结构变更的记录,比如建表、改字段等操作。Prisma会帮我们生成SQL语句并执行,同时记录下这些变更,这样团队协作时大家都能保持数据库结构的一致性。这一步真的很重要,它让数据库的版本控制变得像代码版本控制一样简单。
可以看到我们确实是成功建立todo这个表,里面的数据是我在后续的操作存入的 !
后端API开发
数据库层面准备好后,我开始着手API的开发。Next.js提供了App Router功能,让我们能很容易地创建API端点,不需要再像react-route-dom一样搭建路由。我在app/api/todos/route.ts文件中创建了处理待办事项相关请求的API。
获取待办事项
先来看看如何处理获取所有待办事项的GET请求:
export async function GET() { const todos = await prisma.todo.findMany({ orderBy: { createdAt: 'desc' } }) return NextResponse.json(todos) }这段代码创建了一个Prisma客户端实例,然后使用findMany方法获取所有的待办事项。orderBy参数指定了按创建时间降序排列,这样最新的待办事项会显示在最前面。最后将结果以JSON格式返回给前端。
添加新待办事项
添加新待办事项的POST请求处理也很简单:
export async function POST(req: Request) { const { title } = await req.json() const todo = await prisma.todo.create({ data: { title, } }) return NextResponse.json(todo) }这里从请求体中获取title字段,然后使用Prisma的create方法创建新的待办事项。Prisma会自动处理id、completed和createdAt字段的默认值,我们只需要提供title就可以了。创建成功后返回新创建的待办事项对象。
除了基本的获取和添加功能,我还实现了更新和删除待办事项的API。这些API放在app/api/todos/[id]/route.ts文件中,使用了动态路由来根据id操作特定的待办事项。
更新待办事项
更新待办事项(主要是切换完成状态)的PATCH请求处理:
export async function PATCH(req: Request, { params }: { params: { id: string } }) { const { completed } = await req.json(); const todo = await prisma.todo.update({ where: { id: Number(params.id) }, data: { completed } }) return NextResponse.json(todo) }这里从路由参数中获取id,从请求体中获取completed状态,然后使用Prisma的update方法更新特定的待办事项。where条件指定了要更新哪条记录,data指定了要更新的字段。
删除待办事项
删除待办事项的DELETE请求处理:
export async function DELETE(req: Request, { params }: { params: { id: string } }) { await prisma.todo.delete({ where: { id: Number(params.id) } }) return NextResponse.json({ success: true }) }同样从路由参数中获取id,然后使用Prisma的delete方法删除对应的记录。删除成功后返回一个简单的成功标志。
前端页面
前端页面部分,我创建了一个简单的待办事项列表页面。这个页面使用了React的useState和useEffect钩子来管理状态和副作用。
首先定义了Todo接口来规范数据类型:
export interface Todo { id: number; title: string; completed: boolean; createdAt: string }获取数据
然后在组件中定义了状态和相关的处理函数:
export default function Home() { const [todos, setTodos] = useState<Todo[]>([]); const [input, setInput] = useState(""); useEffect(() => { fetchTodos() }, []) // 其他函数... }todos状态用来存储待办事项列表,input状态用来存储输入框的内容。useEffect在组件挂载时调用fetchTodos函数获取数据。
fetchTodos函数通过调用我们之前创建的API来获取数据:
const fetchTodos = async () => { const res = await fetch("/api/todos"); const data = await res.json(); setTodos(data); }这里使用了原生的fetch API来发送请求,然后解析返回的JSON数据并更新状态。
添加数据
添加待办事项的函数稍微复杂一些:
const addTodo = async () => { if (!input.trim()) return const res = await fetch('api/todos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: input }) }) const newTodo = await res.json() setTodos([newTodo, ...todos]) setInput('') }首先检查输入是否为空,然后发送POST请求到API,将新待办事项添加到数据库。成功后,将返回的新待办事项添加到列表的最前面,并清空输入框。
更新数据
切换待办事项完成状态的函数:
const toogleTodo = async (id: number, completed: boolean) => { const res = await fetch(发送PATCH请求更新特定待办事项的完成状态,然后更新本地状态以反映变化。
删除
删除待办事项的函数:
const deleteTodo = async (id: number) => { await fetch(发送DELETE请求删除特定待办事项,然后从本地状态中移除该项。
Tailwind CSS
页面的UI部分使用了简单的HTML和Tailwind CSS类来样式化:
<main className=" max-w-xl max-auto p-6"> <h1 className="text-2xl font-bold mb-4">Todos</h1> <div className="flex gap-2 mb-4"> <input value={input} onChange={(e) => setInput(e.target.value)} placeholder="Add todo..." className="border p-2 rounded flex-1" type="text" /> <button className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600" onClick={addTodo} > Add </button> </div> <ul className="space-y-2"> {todos.map(todo => ( <li key={todo.id} className="flex justify-between items-center p-2 border rounded"> <span onClick={() => toogleTodo(todo.id, todo.completed)} className={有一个输入框和添加按钮用于添加新待办事项,还有一个列表显示所有待办事项。每个待办事项可以点击文本来切换完成状态(会有删除线效果),也可以点击删除按钮来删除。
总结
回顾整个开发过程,我发现Prisma+Next.js的组合真的很强大。Prisma让我们能够以类型安全的方式操作数据库,减少了出错的可能性,提高了开发效率。Next.js则提供了全栈开发的能力,前后端可以在同一个项目中协同工作,避免了跨项目协作的复杂性。
这种开发模式的好处是显而易见的:首先,数据类型前后一致,因为我们都使用TypeScript,前后端可以共享类型定义;其次,开发效率高,不需要频繁切换上下文;最后,部署简单,整个应用可以一起部署,减少了配置复杂度。
通过今天的学习,我对全栈开发有了更深入的理解。不再觉得后端开发是前端开发者的禁地,反而发现只要选对工具,后端开发也可以很直观、很高效。Prisma的模型定义、查询语法都非常直观,Next.js的API路由让创建后端接口变得简单易懂。
当然,这只是一个开始,还有很多高级特性等待我去探索,比如Prisma的关系查询、事务处理、聚合查询等,以及Next.js的服务器组件、中间件、缓存策略等。但今天的基础打得很扎实,让我有信心继续深入学习。
如果你也是前端开发者,想尝试全栈开发,我真的强烈推荐从Next.js+Prisma开始。这个组合入门门槛低,但能力强大,能够帮你快速构建完整的Web应用。今天的待办事项应用虽然简单,但涵盖了一个完整应用的核心功能:数据的增删改查。理解了这些基础,后续学习更复杂的功能就会容易得多。
好了,今天的回顾就到这里。希望通过这篇文章,不仅能帮自己巩固知识,也能给其他学习者一些启发。全栈开发并不难,关键在于选对工具和方法。Next.js+Prisma无疑是一个极佳的选择,值得每一个前端开发者学习和掌握。
Loading comments...