日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
基于Next.js、Prisma、Postgres和Fastfy構(gòu)建全棧APP

譯者 | 朱先忠

創(chuàng)新互聯(lián)專注于富錦企業(yè)網(wǎng)站建設(shè),成都響應(yīng)式網(wǎng)站建設(shè)公司,成都做商城網(wǎng)站。富錦網(wǎng)站建設(shè)公司,為富錦等地區(qū)提供建站服務(wù)。全流程按需開(kāi)發(fā),專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)

審校 | 孫淑娟

在本文中,我們將學(xué)習(xí)如何使用Next.js、Prisma、Postgres和Fastify來(lái)聯(lián)合開(kāi)發(fā)一個(gè)完整的全棧Web應(yīng)用程序。具體地說(shuō),我們將構(gòu)建一個(gè)考勤管理演示應(yīng)用程序,用于管理員工的考勤信息。該應(yīng)用程序的流程比較簡(jiǎn)單:一個(gè)管理用戶登錄頁(yè)面,創(chuàng)建當(dāng)天的考勤表界面,還有每個(gè)員工可以在考勤表上登錄和注銷(xiāo)的界面等。

何謂Next.js?

Next.js是一個(gè)靈活的基于React框架的工具,它能夠?yàn)槟峁﹦?chuàng)建快速Web應(yīng)用程序的組件。它通常被稱為全棧式React框架,因?yàn)樗梢允骨岸撕秃蠖藨?yīng)用程序位于同一個(gè)代碼基上;并且,這種實(shí)現(xiàn)使用的是無(wú)服務(wù)器端(Serverless)功能。

何謂Prisma?

Prisma是一個(gè)開(kāi)源的ORM框架,同樣基于Node.js框架和Typescript腳本實(shí)現(xiàn)。Prisma大大簡(jiǎn)化了SQL數(shù)據(jù)庫(kù)的數(shù)據(jù)建模、遷移和數(shù)據(jù)訪問(wèn)過(guò)程。截止撰寫(xiě)本文時(shí),Prisma支持以下數(shù)據(jù)庫(kù)管理系統(tǒng):PostgreSQL、MySQL、MariaDB、SQLite、AWS Aurora、Microsoft SQL Server、Azure SQL和MongoDB。當(dāng)然,有關(guān)Prisma所有受支持的數(shù)據(jù)庫(kù)管理系統(tǒng)的列表信息,您可以參考地址https://www.prisma.io/docs/reference/database-reference/supported-databases。

何謂Postgres?

Postgres也稱為PostgreSQL,是一個(gè)免費(fèi)開(kāi)源的關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)。它是SQL語(yǔ)言的超集,具有許多優(yōu)秀特性,允許開(kāi)發(fā)人員安全地存儲(chǔ)和擴(kuò)展復(fù)雜的數(shù)據(jù)工作負(fù)載。

示例項(xiàng)目開(kāi)發(fā)先決條件

本文是一個(gè)實(shí)踐演示教程。因此,為了順利調(diào)試通過(guò)這個(gè)項(xiàng)目,最好確保先在您的計(jì)算機(jī)上安裝以下軟件:

  • Node.js已經(jīng)成功地安裝在您的計(jì)算機(jī)上
  • PostgreSQL數(shù)據(jù)庫(kù)服務(wù)器正運(yùn)行在您的計(jì)算機(jī)上

注意:本教程的代碼可以在??Github網(wǎng)站??上找到;所以,您可以隨意克隆下所有源碼并繼續(xù)學(xué)習(xí)。

項(xiàng)目設(shè)置

讓我們從設(shè)置Next.js應(yīng)用程序開(kāi)始。首先,請(qǐng)運(yùn)行下面的命令。

npx create-next-app@latest

等待安裝完成,然后運(yùn)行下面的命令來(lái)安裝依賴項(xiàng)。

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

等待安裝完成即可。

設(shè)置Next.js和Fastify

默認(rèn)情況下,Next.js不使用Fastify作為其服務(wù)器。為了使用Fastfy作為我們的Next.js應(yīng)用程序的服務(wù)器,需要在你的package.json配置文件中添加以下代碼段:

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

創(chuàng)建我們的Fastify服務(wù)器

接下來(lái),我們創(chuàng)建一個(gè)名字為server.js的文件。這個(gè)文件是我們應(yīng)用程序的入口點(diǎn)。然后,我們添加命令require('fastfy-nextjs'),以便包括一個(gè)特定的插件,此插件能夠暴露Fastify中的Next.js API來(lái)處理頁(yè)面的渲染任務(wù)。

接下來(lái),打開(kāi)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來(lái)暴露Fastify中的Next.js API,以便幫助我們完成渲染任務(wù)。然后,我們使用noOpParser函數(shù)分析發(fā)來(lái)的請(qǐng)求。具體地說(shuō),此函數(shù)負(fù)責(zé)在我們的Next.js API路由處理器中可以使用請(qǐng)求體中的內(nèi)容。注意到,這里我們通過(guò)命令[fastify.next](定義了程序中的兩個(gè)路由。然后我們創(chuàng)建了Fastify服務(wù)器,并讓它監(jiān)聽(tīng)端口3000。

接下來(lái),我們使用“yarn dev”命令運(yùn)行上面的應(yīng)用程序。于是,程序會(huì)在地址localhost:3000上運(yùn)行起來(lái)。

Prisma設(shè)置

首先,運(yùn)行以下命令以獲得基本的Prisma設(shè)置:

npx prisma init

上面的命令將創(chuàng)建一個(gè)名字為Prisma的目錄,其下還有一個(gè)相應(yīng)的配置文件名是schema.prisma。此文件是您的主Prisma配置文件,其中將包含您的數(shù)據(jù)庫(kù)模式。此外,一個(gè).env文件也將添加到項(xiàng)目的根目錄中。注意,您需要打開(kāi)這個(gè).env文件,并將虛擬連接URL替換為PostgreSQL數(shù)據(jù)庫(kù)的真實(shí)連接URL。

現(xiàn)在,把prisma/schema.prisma文件中的內(nèi)容替換成如下代碼:

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
}

在上面的代碼片段中,我們創(chuàng)建了一個(gè)用戶,一個(gè)考勤表AttendanceSheet和Attention模型,并定義了每個(gè)模型之間的關(guān)系。

接下來(lái),需要在數(shù)據(jù)庫(kù)中創(chuàng)建表格。請(qǐng)運(yùn)行以下命令:

npx prisma db push

運(yùn)行上述命令后,您應(yīng)該會(huì)在終端中看到如下屏幕截圖所示的輸出:

創(chuàng)建實(shí)用工具函數(shù)

Prisma設(shè)置完成后,讓我們創(chuàng)建三個(gè)實(shí)用函數(shù),它們將不時(shí)在我們的應(yīng)用程序中使用。

為此,打開(kāi)文件lib/parseBody.js,并添加以下代碼段。此函數(shù)的任務(wù)是將請(qǐng)求正文解析為JSON:

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

然后,打開(kāi)/lib/request.js文件,添加以下代碼段。此函數(shù)負(fù)責(zé)返回iron-session的會(huì)話屬性對(duì)象。

export const sessionCookie = () => {
return ({
cookieName: "auth",
password: process.env.SESSION_PASSWORD,
// 安全提示:在生產(chǎn)環(huán)境(使用HTTPS協(xié)議)中應(yīng)當(dāng)把secure設(shè)置為true,但是不能在開(kāi)發(fā)環(huán)境(HTTP)下使用true
cookieOptions: {
secure: process.env.NODE_ENV === "production",
},
})
}

接下來(lái),將SESSION_PASSWORD添加到.env文件:它應(yīng)該是至少32個(gè)字符的字符串。

設(shè)計(jì)應(yīng)用程序的樣式

完成上面的實(shí)用函數(shù)開(kāi)發(fā)后,讓我們?yōu)閼?yīng)用程序添加一些樣式。我們將為這個(gè)應(yīng)用程序定義幾個(gè)CSS模塊。為此,打開(kāi)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;

創(chuàng)建邊欄組件

造型完成后,讓我們創(chuàng)建邊欄組件,以便幫助我們導(dǎo)航到應(yīng)用程序控制面板上的不同頁(yè)面。為此,打開(kāi)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

開(kāi)發(fā)登錄頁(yè)面

現(xiàn)在打開(kāi)page/index.js文件,刪除其中默認(rèn)的所有代碼并添加以下代碼段。下面的代碼將post請(qǐng)求與通過(guò)表單提供的電子郵件和密碼一起發(fā)送到localhost:3000/api/login路由。一旦憑據(jù)驗(yàn)證為有效,它就會(huì)調(diào)用router.push('/dashboard')方法;此方法負(fù)責(zé)把用戶重定向到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})} />






)
}

設(shè)置登錄API路由

現(xiàn)在打開(kāi)頁(yè)面page/api/login.js,并添加以下代碼段。我們將使用PrismaClient進(jìn)行數(shù)據(jù)庫(kù)查詢。其中,withIronSessionApiRoute是在RESTful應(yīng)用程序中用來(lái)負(fù)責(zé)處理用戶會(huì)話的iron-session函數(shù)。

該路由處理通過(guò)localhost:3000/api/login登錄后的POST請(qǐng)求,并在用戶經(jīng)過(guò)身份驗(yàn)證后生成身份驗(yàn)證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()

//按唯一標(biāo)識(shí)符
const user = await prisma.user.findUnique({
where: {
email
},})

if(user.password === password) {

//從數(shù)據(jù)庫(kù)中獲取用戶,然后:
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(),
);

設(shè)置注銷(xiāo)API路由

打開(kāi)/page/api/logout文件并添加下面的代碼段。此路由負(fù)責(zé)處理對(duì)localhost:3000/api/logout的GET請(qǐng)求,該請(qǐng)求通過(guò)銷(xiāo)毀會(huì)話Cookie注銷(xiāo)用戶。

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()
);

創(chuàng)建控制面板頁(yè)面

此頁(yè)面為用戶提供了登錄和注銷(xiāo)考勤表的界面。當(dāng)然,管理員還可以通過(guò)此界面創(chuàng)建考勤表?,F(xiàn)在,打開(kāi)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函數(shù)來(lái)生成頁(yè)面數(shù)據(jù),而withIronSessionSsr是一個(gè)用于處理服務(wù)器端呈現(xiàn)頁(yè)面功能的iron-session函數(shù)。在下面的代碼段中,我們使用數(shù)據(jù)庫(kù)考勤表中的一行查詢考勤表的最后一行。其中,userId等于存儲(chǔ)在用戶會(huì)話中的用戶id。我們還檢查用戶是否是管理員(ADMIN)角色。

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

const user = req.session.user

const prisma = new PrismaClient()

const att
新聞名稱:基于Next.js、Prisma、Postgres和Fastfy構(gòu)建全棧APP
文章來(lái)源:http://www.dlmjj.cn/article/dhpohis.html