基于Next.js、Prisma、Postgres和Fastfy构建全栈APP

译者 | 朱先忠

创新互联专注于富锦企业网站建设,成都响应式网站建设公司,成都做商城网站。富锦网站建设公司,为富锦等地区提供建站服务。全流程按需开发,专业设计,全程项目跟踪,创新互联专业和态度为您提供的服务

审校 | 孙淑娟

在本文中,我们将学习如何使用Next.js、Prisma、Postgres和Fastify来联合开发一个完整的全栈Web应用程序。具体地说,我们将构建一个考勤管理演示应用程序,用于管理员工的考勤信息。该应用程序的流程比较简单:一个管理用户登录页面,创建当天的考勤表界面,还有每个员工可以在考勤表上登录和注销的界面等。

何谓Next.js?

Next.js是一个灵活的基于React框架的工具,它能够为您提供创建快速Web应用程序的组件。它通常被称为全栈式React框架,因为它可以使前端和后端应用程序位于同一个代码基上;并且,这种实现使用的是无服务器端(Serverless)功能。

何谓Prisma?

Prisma是一个开源的ORM框架,同样基于Node.js框架和Typescript脚本实现。Prisma大大简化了SQL数据库的数据建模、迁移和数据访问过程。截止撰写本文时,Prisma支持以下数据库管理系统:PostgreSQL、MySQL、MariaDB、SQLite、AWS Aurora、Microsoft SQL Server、Azure SQL和MongoDB。当然,有关Prisma所有受支持的数据库管理系统的列表信息,您可以参考地址https://www.prisma.io/docs/reference/database-reference/supported-databases。

何谓Postgres?

Postgres也称为PostgreSQL,是一个免费开源的关系数据库管理系统。它是SQL语言的超集,具有许多优秀特性,允许开发人员安全地存储和扩展复杂的数据工作负载。

示例项目开发先决条件

本文是一个实践演示教程。因此,为了顺利调试通过这个项目,最好确保先在您的计算机上安装以下软件:

  • Node.js已经成功地安装在您的计算机上
  • PostgreSQL数据库服务器正运行在您的计算机上

注意:本教程的代码可以在​​Github网站​​上找到;所以,您可以随意克隆下所有源码并继续学习。

项目设置

让我们从设置Next.js应用程序开始。首先,请运行下面的命令。

npx create-next-app@latest

等待安装完成,然后运行下面的命令来安装依赖项。

yarn add fastify fastify-nextjs iron-session @prisma/client
yarn add prisma nodemon --dev

等待安装完成即可。

设置Next.js和Fastify

默认情况下,Next.js不使用Fastify作为其服务器。为了使用Fastfy作为我们的Next.js应用程序的服务器,需要在你的package.json配置文件中添加以下代码段:

"scripts": {
"dev": "nodemon server.js",
"build": "next build",
"start": "next start",
"lint": "next lint"
}

创建我们的Fastify服务器

接下来,我们创建一个名字为server.js的文件。这个文件是我们应用程序的入口点。然后,我们添加命令require('fastfy-nextjs'),以便包括一个特定的插件,此插件能够暴露Fastify中的Next.js API来处理页面的渲染任务。

接下来,打开server.js文件,并添加以下代码段:

const fastify = require('fastify')()
async function noOpParser(req, payload) {
return payload;
}
fastify.register(require('fastify-nextjs')).after(() => {
fastify.addContentTypeParser('text/plain', noOpParser);
fastify.addContentTypeParser('application/json', noOpParser);
fastify.next('/*')
fastify.next('/api/*', { method: 'ALL' });
})
fastify.listen(3000, err => {
if (err) throw err
console.log('Server listening on ')
})

在上面代码片断中,我们使用插件fastify-nextjs来暴露Fastify中的Next.js API,以便帮助我们完成渲染任务。然后,我们使用noOpParser函数分析发来的请求。具体地说,此函数负责在我们的Next.js API路由处理器中可以使用请求体中的内容。注意到,这里我们通过命令[fastify.next](定义了程序中的两个路由。然后我们创建了Fastify服务器,并让它监听端口3000。

接下来,我们使用“yarn dev”命令运行上面的应用程序。于是,程序会在地址localhost:3000上运行起来。

Prisma设置

首先,运行以下命令以获得基本的Prisma设置:

npx prisma init

上面的命令将创建一个名字为Prisma的目录,其下还有一个相应的配置文件名是schema.prisma。此文件是您的主Prisma配置文件,其中将包含您的数据库模式。此外,一个.env文件也将添加到项目的根目录中。注意,您需要打开这个.env文件,并将虚拟连接URL替换为PostgreSQL数据库的真实连接URL。

现在,把prisma/schema.prisma文件中的内容替换成如下代码:

datasource db {
url = env("DATABASE_URL")
provider="postgresql"
}
generator client {
provider = "prisma-client-js"
}
model User {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
email String @unique
name String
password String
role Role @default(EMPLOYEE)
attendance Attendance[]
AttendanceSheet AttendanceSheet[]
}
model AttendanceSheet {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdBy User? @relation(fields: [userId], references: [id])
userId Int?
}
model Attendance {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
signIn Boolean @default(true)
signOut Boolean
signInTime DateTime @default(now())
signOutTime DateTime
user User? @relation(fields: [userId], references: [id])
userId Int?
}
enum Role {
EMPLOYEE
ADMIN
}

在上面的代码片段中,我们创建了一个用户,一个考勤表AttendanceSheet和Attention模型,并定义了每个模型之间的关系。

接下来,需要在数据库中创建表格。请运行以下命令:

npx prisma db push

运行上述命令后,您应该会在终端中看到如下屏幕截图所示的输出:

创建实用工具函数

Prisma设置完成后,让我们创建三个实用函数,它们将不时在我们的应用程序中使用。

为此,打开文件lib/parseBody.js,并添加以下代码段。此函数的任务是将请求正文解析为JSON:

export const parseBody = (body) => {
if (typeof body === "string") return JSON.parse(body)
return body
}

然后,打开/lib/request.js文件,添加以下代码段。此函数负责返回iron-session的会话属性对象。

export const sessionCookie = () => {
return ({
cookieName: "auth",
password: process.env.SESSION_PASSWORD,
// 安全提示:在生产环境(使用HTTPS协议)中应当把secure设置为true,但是不能在开发环境(HTTP)下使用true
cookieOptions: {
secure: process.env.NODE_ENV === "production",
},
})
}

接下来,将SESSION_PASSWORD添加到.env文件:它应该是至少32个字符的字符串。

设计应用程序的样式

完成上面的实用函数开发后,让我们为应用程序添加一些样式。我们将为这个应用程序定义几个CSS模块。为此,打开styles/Home.modules.css文件,并添加以下代码段:

.container {
padding: 0 2rem;
}
.man {
min-height: 100vh;
padding: 4rem 0;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;

创建边栏组件

造型完成后,让我们创建边栏组件,以便帮助我们导航到应用程序控制面板上的不同页面。为此,打开components/SideBar.js文件,并粘贴下面的代码段。

import Link from 'next/link'
import { useRouter } from 'next/router'
import styles from '../styles/SideBar.module.css'

const SideBar = () => {

const router = useRouter()

const logout = async () => {

try {

const response = await fetch('/api/logout', {
method: 'GET',
credentials: 'same-origin',
});

if(response.status === 200) router.push('/')

} catch (e) {
alert(e)
}

}


return (

)

}

export default SideBar

开发登录页面

现在打开page/index.js文件,删除其中默认的所有代码并添加以下代码段。下面的代码将post请求与通过表单提供的电子邮件和密码一起发送到localhost:3000/api/login路由。一旦凭据验证为有效,它就会调用router.push('/dashboard')方法;此方法负责把用户重定向到localhost:3000/api/dashboard:

import Head from 'next/head'
import { postData } from '../lib/request';
import styles from '../styles/Home.module.css'
import { useState } from 'react';
import { useRouter } from 'next/router'

export default function Home({posts}) {

const [data, setData] = useState({email: null, password: null});

const router = useRouter()

const submit = (e) => {
e.preventDefault()

if(data.email && data.password) {
postData('/api/login', data).then(data => {
console.log(data);

if (data.status === "success") router.push('/dashboard')

});
}

}

return (


Login








type={"text"}
placeholder="Enter Your Email"
onChange={(e) => setData({...data, email: e.target.value})} />

type={"password"}
placeholder="Enter Your Password"
onChange={(e) => setData({...data, password: e.target.value})} />






)
}

设置登录API路由

现在打开页面page/api/login.js,并添加以下代码段。我们将使用PrismaClient进行数据库查询。其中,withIronSessionApiRoute是在RESTful应用程序中用来负责处理用户会话的iron-session函数。

该路由处理通过localhost:3000/api/login登录后的POST请求,并在用户经过身份验证后生成身份验证Cookie。

import { PrismaClient } from '@prisma/client'
import { withIronSessionApiRoute } from "iron-session/next";
import { parseBody } from '../../lib/parseBody';
import { sessionCookie } from '../../lib/session';

export default withIronSessionApiRoute(
async function loginRoute(req, res) {

const { email, password } = parseBody(req.body)

const prisma = new PrismaClient()

//按唯一标识符
const user = await prisma.user.findUnique({
where: {
email
},})

if(user.password === password) {

//从数据库中获取用户,然后:
user.password = undefined
req.session.user = user
await req.session.save();

return res.send({ status: 'success', data: user });

};

res.send({ status: 'error', message: "incorrect email or password" });

},
sessionCookie(),
);

设置注销API路由

打开/page/api/logout文件并添加下面的代码段。此路由负责处理对localhost:3000/api/logout的GET请求,该请求通过销毁会话Cookie注销用户。

import { withIronSessionApiRoute } from "iron-session/next";
import { sessionCookie } from "../../lib/session";

export default withIronSessionApiRoute(
function logoutRoute(req, res, session) {
req.session.destroy();
res.send({ status: "success" });
},
sessionCookie()
);

创建控制面板页面

此页面为用户提供了登录和注销考勤表的界面。当然,管理员还可以通过此界面创建考勤表。现在,打开page/dashboard/index.js文件,并添加下面代码段。

import { withIronSessionSsr } from "iron-session/next";
import Head from 'next/head'
import { useState, useCallback } from "react";
import { PrismaClient } from '@prisma/client'
import SideBar from '../../components/SideBar'
import styles from '../../styles/Home.module.css'
import dashboard from '../../styles/Dashboard.module.css'
import { sessionCookie } from "../../lib/session";
import { postData } from "../../lib/request";

export default function Page(props) {

const [attendanceSheet, setState] = useState(JSON.parse(props.attendanceSheet));

const sign = useCallback((action="") => {

const body = {
attendanceSheetId: attendanceSheet[0]?.id,
action
}

postData("/api/sign-attendance", body).then(data => {

if (data.status === "success") {

setState(prevState => {

const newState = [...prevState]

newState[0].attendance[0] = data.data

return newState

})

}

})

}, [attendanceSheet])

const createAttendance = useCallback(() => {

postData("/api/create-attendance").then(data => {

if (data.status === "success") {
alert("New Attendance Sheet Created")
setState([{...data.data, attendance:[]}])
}

})

}, [])

return (



Attendance Management Dashboard











{
props.isAdmin &&
}

{ attendanceSheet.length > 0 &&













{
attendanceSheet[0]?.attendance.length != 0 ?
<>



:
<>



}



Id Created At Sign In Sign Out
{attendanceSheet[0]?.id} {attendanceSheet[0]?.createdAt} {attendanceSheet[0]?.attendance[0]?.signInTime} {
attendanceSheet[0]?.attendance[0]?.signOut ?
attendanceSheet[0]?.attendance[0]?.signOutTime: }
{""}


}






)
}

我们使用getServerSideProps函数来生成页面数据,而withIronSessionSsr是一个用于处理服务器端呈现页面功能的iron-session函数。在下面的代码段中,我们使用数据库考勤表中的一行查询考勤表的最后一行。其中,userId等于存储在用户会话中的用户id。我们还检查用户是否是管理员(ADMIN)角色。

export const getServerSideProps = withIronSessionSsr( async ({req}) => {

const user = req.session.user

const prisma = new PrismaClient()

const att

网站标题:基于Next.js、Prisma、Postgres和Fastfy构建全栈APP
新闻来源:http://www.mswzjz.cn/qtweb/news4/542904.html

攀枝花网站建设、攀枝花网站运维推广公司-贝锐智能,是专注品牌与效果的网络营销公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 贝锐智能