每天分享最新软件开发,Devops,敏捷,测试以及项目管理最新,最热门的文章,每天花3分钟学习何乐而不为,希望大家点赞,加关注,你的支持是我最大的动力。 在本文中,我们将学习如何使用Next。js、Prisma、Postgres和Fastify构建一个Fullstack应用程序。 在本文中,我们将学习如何使用Next。js、Prisma、Postgres和Fastify构建一个Fullstack应用程序。我们将建立一个考勤管理演示应用程序,管理员工的考勤。这个应用程序的流程很简单:管理用户登录,创建当天的出勤表,然后每个员工在出勤表上进出。什么是Next。js? Next。Js是一个灵活的React框架,它为您提供了创建快速Web应用程序的构建块。它通常被称为全栈React框架,因为它可以让前端和后端应用程序在相同的代码基上使用无服务器函数来实现这一点。什么是Prisma? Prisma是一个开源的、Node。js和TypecriptORM,它极大地简化了SQL数据库的数据建模、迁移和数据访问。在撰写本文时,Prisma支持以下数据库管理系统:PostgreSQL、MySQL、MariaDB、SQLite、AWSAurora、MicrosoftSQLServer、AzureSQL和MongoDB。您可能还希望单击此处查看所有受支持的数据库管理系统的列表。什么是Postgres? Postgres也被称为PostgreSQL,它是一个免费的开源关联式资料库管理系统。它是SQL语言的超集,具有许多特性,使开发人员能够安全地存储和扩展复杂的数据工作负载。先决条件 本教程是一个实践演示教程。因此,最好在你的电脑上安装以下软件:安装在你的机器上数据库服务器正在运行 这个教程的代码可以在Github上找到,所以你可以克隆它,然后跟着学习。 https:github。comClaradev32attendance项目设置 让我们从设置Next。js应用程序开始。 Shellnpxcreatenextapplatest 等待安装完成,然后运行下面的命令来安装我们的依赖项。 Shellyarnaddfastifyfastifynextjsironsessionprismaclientbryarnaddprismanodemondev 等待安装完成。设置Next。js和Fastify 默认情况下,Next。js不使用Fastify作为其服务器。要使用Fastify为我们的Next。js应用程序提供服务,请编辑package。json文件中的脚本字段,其代码片段如下所示。 JSONscripts:{dev:nodemonserver。js,build:nextbuild,start:nextstart,lint:nextlint} 创建我们的Fastify服务器 现在让我们创建一个server。js文件。这个文件是我们的应用程序的入口点,然后我们添加了一个需求(‘fasttifynextjs’)来包含一个插件,这个插件在Fastify公开了Next。jsAPI来处理渲染。 打开server。js文件,并添加以下代码段:constfastifyrequire(fastify)()asyncfunctionnoOpParser(req,payload){}fastify。register(require(fastifynextjs))。after((){fastify。addContentTypeParser(textplain,noOpParser);fastify。addContentTypeParser(applicationjson,noOpParser);fastify。next()fastify。next(api,{method:ALL});})fastify。listen(3000,err{if(err)throwerrconsole。log(Serverlisteningonhttp:localhost:3000)}) 在上面的代码片段中,我们使用了fastnextjs插件,它在Fastify公开了处理呈现的Next。jsAPI。然后,我们使用noopParser函数解析传入的请求,这使得请求体可用于我们的Next。jsAPI路由处理程序,我们使用〔fasttify。next〕(http:fastify。next命令)为我们的应用定义两个路由。然后我们创建Fastify服务器,让它监听端口3000。 现在继续并使用纱线dev命令运行应用程序:应用程序将在localhost:3000上运行。Prisma设置 首先,运行以下命令来获得一个基本的Prisma设置: Shellnpxprismainit 上面的命令将创建一个包含schema。Prisma文件的Prisma目录。这是您的主Prisma配置文件,它将包含您的数据库模式。还有。Env文件将被添加到项目的根目录中。打开。Env文件,并用PostgreSQL数据库的连接URL替换虚拟连接URL。 将prismaschema。prisma文件中的代码替换为以下内容: Propertiesfiles属性文件datasourcedb{urlenv(DATABASEURL)providerpostgresql}generatorclient{providerprismaclientjs}modelUser{idIntiddefault(autoincrement())createdAtDateTimedefault(now())emailStringuniquenameStringpasswordStringroleRoledefault(EMPLOYEE)attendanceAttendance〔〕AttendanceSheetAttendanceSheet〔〕}modelAttendanceSheet{idIntiddefault(autoincrement())createdAtDateTimedefault(now())updatedAtDateTimeupdatedAtcreatedByUser?relation(fields:〔userId〕,references:〔id〕)userIdInt?}modelAttendance{idIntiddefault(autoincrement())createdAtDateTimedefault(now())updatedAtDateTimeupdatedAtsignInBooleandefault(true)signOutBooleansignInTimeDateTimedefault(now())signOutTimeDateTimeuserUser?relation(fields:〔userId〕,references:〔id〕)userIdInt?}enumRole{EMPLOYEEADMIN} 在上面的代码片段中,我们创建了User、AttendanceSheet和AttendanceModel,定义了每个模型之间的关系。 接下来,在数据库中创建这些表: Shellnpxprismadbpush 在运行上面的命令之后,您应该可以在终端中看到如下截图所示的输出: 创建实用程序函数 完成Prisma设置后,让我们创建三个实用函数,它们将在我们的应用程序中不时使用。 打开libparseBody。js文件并添加以下代码片段: JavaScriptexportconstparseBody(body){if(typeofbodystring)returnJSON。parse(body)returnbody} 打开librequest。js文件并添加以下代码片段。 JavaScriptexportconstsessionCookie(){return({cookieName:auth,password:process。env。SESSIONPASSWORD,secure:trueshouldbeusedinproduction(HTTPS)butcantbeusedindevelopment(HTTP)cookieOptions:{secure:process。env。NODEENVproduction,},})} 打开librequest。js文件并添加以下代码片段。此函数返回铁会话铁会话的会话属性对象。 JavaScriptexportconstsessionCookie(){return({cookieName:auth,password:process。env。SESSIONPASSWORD,secure:trueshouldbeusedinproduction(HTTPS)butcantbeusedindevelopment(HTTP)cookieOptions:{secure:process。env。NODEENVproduction,},})} 接下来,将SESSIONPASSWORD添加到。env文件:它应该是一个至少有32个字符的字符串。应用程序的样式 完成我们的实用程序功能后,让我们给应用程序添加一些样式。我们正在为这个应用程序使用CSS模块,所以打开styleHome。modules。CSS文件并添加以下代码片段: CSS。container{padding:02}。man{minheight:100padding:4rem0;flex:1;display:flexdirection:justifycontent:alignitems:}。login{width:450}。logininput{width:100;height:50margin:4}。loginbutton{width:100;height:50margin:4}。dashboard{display:gridtemplatecolumns:3fr9gridtemplaterows:1gridcolumngap:0gridrowgap:0height:calc(100vh60px);}。navbar{height:60backgroundcolor:} 创建侧边栏组件 设计完成后,让我们创建侧边栏组件来帮助我们在应用程序仪表板上导航到不同的页面。打开ComponentSideBar。js文件,并粘贴下面的代码片段。 JavaScriptimportLinkfromnextlinkimport{useRouter}fromnextrouterimportstylesfrom。。stylesSideBar。module。cssconstSideBar(){constrouteruseRouter()constlogoutasync(){try{constresponseawaitfetch(apilogout,{method:GET,credentials:sameorigin,});if(response。status200)router。push()}catch(e){alert(e)}}return(navclassName{styles。sidebar}ulliLinkhrefdashboardDashboardLinkliliLinkhrefdashboardattendanceAttendanceLinkliliLinkhrefdashboardattendancesheetAttendanceSheetLinklilionClick{logout}Logoutliulnav)}exportdefaultSideBar登入网页 现在打开pageindex。js文件,删除其中的所有代码,并添加以下代码段。下面的代码通过表单向localhost:3000apilogin路由发送包含电子邮件和密码的发送请求。一旦验证了凭据,它就调用router。push(’dashboard’)方法将用户重定向到localhost:3000apidashboard: JavaScriptimportHeadfromnextheadimport{postData}from。。importstylesfrom。。stylesHome。module。cssimport{useState}import{useRouter}fromnextrouterexportdefaultfunctionHome({posts}){const〔data,setData〕useState({email:null,password:null});constrouteruseRouter()constsubmit(e){e。preventDefault()if(data。emaildata。password){postData(apilogin,data)。then(data{console。log(data);if(data。statussuccess)router。push(dashboard)});}}return(HeadtitleLogintitlemetanamedescriptioncontentLoginlinkreliconhreffavicon。icoHeadmainclassName{styles。main}main)} 设置登录API路由 现在打开页面apilogin。js文件并添加以下代码片段。我们将使用PrismaClient进行数据库查询,IronSessionApiRoute是用于处理RESTful应用程序中的用户会话的铁会话函数。 此路由处理对localhost:3000apilogin的登录POST请求,并在用户通过身份验证后生成身份验证Cookie。 JavaScriptimport{PrismaClient}fromprismaclientimport{withIronSessionApiRoute}import{parseBody}from。。。。libparseBimport{sessionCookie}from。。。。exportdefaultwithIronSessionApiRoute(asyncfunctionloginRoute(req,res){const{email,password}parseBody(req。body)constprismanewPrismaClient()Byuniqueidentifierconstuserawaitprisma。user。findUnique({where:{email},})if(user。passwordpassword){getuserfromdatabasethen:user。passwordundefinedreq。session。useruserawaitreq。session。save();returnres。send({status:success,data:user});};res。send({status:error,message:incorrectemailorpassword});},sessionCookie(),);设置注销API路由 打开pageapilogout文件并添加下面的代码段。此路由处理对localhost的GET请求:3000apilogout,该请求通过销毁会话cookie将用户注销。 JavaScriptimport{withIronSessionApiRoute}import{sessionCookie}from。。。。exportdefaultwithIronSessionApiRoute(functionlogoutRoute(req,res,session){req。session。destroy();res。send({status:success});},sessionCookie());创建仪表板页 此页面为用户提供了登录和退出考勤表的界面。管理员还可以创建考勤表。打开pagedashboardindex。js文件并添加下面的代码片段。 JavaScriptimport{withIronSessionSsr}importHeadfromnextheadimport{useState,useCallback}import{PrismaClient}fromprismaclientimportSideBarfrom。。。。componentsSideBarimportstylesfrom。。。。stylesHome。module。cssimportdashboardfrom。。。。stylesDashboard。module。cssimport{sessionCookie}from。。。。import{postData}from。。。。exportdefaultfunctionPage(props){const〔attendanceSheet,setState〕useState(JSON。parse(props。attendanceSheet));constsignuseCallback((action){constbody{attendanceSheetId:attendanceSheet〔0〕?。id,action}postData(apisignattendance,body)。then(data{if(data。statussuccess){setState(prevState{constnewState〔。。。prevState〕newState〔0〕。attendance〔0〕data。datareturnnewState})}})},〔attendanceSheet〕)constcreateAttendanceuseCallback((){postData(apicreateattendance)。then(data{if(data。statussuccess){alert(NewAttendanceSheetCreated)setState(〔{。。。data。data,attendance:〔〕}〕)}})},〔〕)return(HeadtitleAttendanceManagementDashboardtitlemetanamedescriptioncontentdashboardHeadmainclassName{styles。dashboard}SideBar{props。isAdminbuttonclassName{dashboard。create}onClick{createAttendance}CreateAttendanceSheetbutton}{attendanceSheet。length0tableclassName{dashboard。table}theadtrthIdththCreatedAtththSignInththSignOutthtrtheadtbodytrtd{attendanceSheet〔0〕?。id}tdtd{attendanceSheet〔0〕?。createdAt}td{attendanceSheet〔0〕?。attendance。length!0?td{attendanceSheet〔0〕?。attendance〔0〕?。signInTime}tdtd{attendanceSheet〔0〕?。attendance〔0〕?。signOut?attendanceSheet〔0〕?。attendance〔0〕?。signOutTime:buttononClick{()sign(signout)}SignOutbutton}td:tdbuttononClick{()sign()}SignInbuttontdtd{}td}trtbodytable}main)} 我们使用getServerSideProps来生成页面数据,而IronSessionSsr是用于处理服务器端呈现页面的Ironsession函数。在下面的代码片段中,我们使用考勤表中的一行查询考勤表的最后一行,其中userId等于存储在用户会话上的Userid。我们还检查用户是否是ADMIN。 JavaScriptexportconstgetServerSidePropswithIronSessionSsr(async({req}){constuserreq。session。userconstprismanewPrismaClient()constattendanceSheetawaitprisma。attendanceSheet。findMany({take:1,orderBy:{id:desc,},include:{attendance:{where:{userId:user。id},}}})return{props:{attendanceSheet:JSON。stringify(attendanceSheet),isAdmin:user。roleADMIN}}},sessionCookie())设置创建出勤API路由 打开页面apicreatearound。js文件并添加下面的代码片段。 JavaScriptimport{PrismaClient}fromprismaclientimport{withIronSessionApiRoute}import{sessionCookie}from。。。。exportdefaultwithIronSessionApiRoute(asyncfunctionhandler(req,res){constprismanewPrismaClient()constuserreq。session。userconstattendanceShe设置签到API路由 此路由处理我们对localhost的APIPOST请求:3000APIsignpublications。该路由接受POST请求,而attanceSheetId和action用于登录和退出attancesheet。 打开pageapisignaround。js文件并添加下面的代码片段。 JavaScriptimport{PrismaClient}fromprismaclientimport{withIronSessionApiRoute}import{parseBody}from。。。。libparseBimport{sessionCookie}from。。。。exportdefaultwithIronSessionApiRoute(asyncfunctionhandler(req,res){constprismanewPrismaClient()const{attendanceSheetId,action}parseBody(req。body)constuserreq。session。userconstattendanceawaitprisma。attendance。findMany({where:{userId:user。id,attendanceSheetId:attendanceSheetId}})checkifatendancehavebeencreatedif(attendance。length0){constattendanceawaitprisma。attendance。create({data:{userId:user。id,attendanceSheetId:attendanceSheetId,signIn:true,signOut:false,signOutTime:newDate()},})returnres。json({status:success,data:attendance});}elseif(actionsignout){awaitprisma。attendance。updateMany({where:{userId:user。id,attendanceSheetId:attendanceSheetId},data:{signOut:true,signOutTime:newDate()},})returnres。json({status:success,data:{。。。attendance〔0〕,signOut:true,signOutTime:newDate()}});}res。json({status:success,data:attendance});},sessionCookie())创建出勤页面 此服务器端呈现的页面显示了登录用户的所有出勤表。打开pagedashboardattance。js文件并添加下面的代码片段。 JavaScriptimport{withIronSessionSsr}importHeadfromnextheadimport{PrismaClient}fromprismaclientimportSideBarfrom。。。。componentsSideBarimportstylesfrom。。。。stylesHome。module。cssimportdashboardfrom。。。。stylesDashboard。module。cssimport{sessionCookie}from。。。。exportdefaultfunctionPage(props){constdataJSON。parse(props。attendanceSheet)return(HeadtitleAttendanceManagementDashboardtitlemetanamedescriptioncontentdashboardHeadmainclassName{styles。dashboard}SideBartableclassName{dashboard。table}theadtrthAttendanceIdththDateththSignInTimeththSignOutTimethtrtheadtbody{data。map(data{const{id,createdAt,attendance}datareturn(trkey{id}td{id}tdtd{createdAt}td{attendance。length0?(tdYoudidnotSignIntdtdYoudidnotSignOuttd):(td{attendance〔0〕?。signInTime}tdtd{attendance〔0〕?。signOut?attendance〔0〕?。signOutTime:YoudidnotSignOut}td)}tr)})}tbodytablemain)}Inthecodesnippetbelow,wequeryforalltherowsfromtheattendanceSheettableandalsofetchtheattendancewheretheuserIdisequaltotheuseridstoredintheusersession。exportconstgetServerSidePropswithIronSessionSsr(async({req}){constuserreq。session。userconstprismanewPrismaClient()constattendanceSheetawaitprisma。attendanceSheet。findMany({orderBy:{id:desc,},include:{attendance:{where:{userId:user。id},}}})return{props:{attendanceSheet:JSON。stringify(attendanceSheet),}}},sessionCookie())创建出勤单页 这个服务器端呈现的页面显示了所有的考勤表以及在该考勤表上签名的员工。打开pagedashboardattance。js文件并添加下面的代码片段。 JavaScriptimport{withIronSessionSsr}importHeadfromnextheadimport{PrismaClient}fromprismaclientimportSideBarfrom。。。。componentsSideBarimportstylesfrom。。。。stylesHome。module。cssimportdashboardfrom。。。。stylesDashboard。module。cssimport{sessionCookie}from。。。。exportdefaultfunctionPage(props){constdataJSON。parse(props。attendanceSheet)return(HeadtitleAttendanceManagementDashboardtitlemetanamedescriptioncontentdashboardHeadmainclassName{styles。dashboard}SideBar{data?。map(data{const{id,createdAt,attendance}datareturn(tablekey{data。id}className{dashboard。table}theadtrthAttendanceIdththDateththNameththEmailththRoleththSignInTimeththSignOutTimethtrtheadtbody{(attendance。length0)(trtd{id}tdtd{createdAt}tdtdcolSpan{5}NoUsersignedthissheettdtr)}{attendance。map(data{const{name,email,role}data。userreturn(trkey{id}td{id}tdtd{createdAt}tdtd{name}tdtd{email}tdtd{role}tdtd{data。signInTime}tdtd{data。signOut?attendance〔0〕?。signOutTime:UserdidnotSignOut}tdtr)})}tbodytable)})}main)} 在下面的代码片段中,我们将查询attancesheet表中的所有行,并通过选择姓名、电子邮件和角色来获取出席率。 JavaScriptexportconstgetServerSidePropswithIronSessionSsr(async(){constprismanewPrismaClient()constattendanceSheetawaitprisma。attendanceSheet。findMany({orderBy:{id:desc,},include:{attendance:{include:{user:{select:{name:true,email:true,role:true}}}},},})return{props:{attendanceSheet:JSON。stringify(attendanceSheet),}}},sessionCookie())测试应用程序 首先,我们必须将用户添加到数据库中。我们要用Prisma做这个。要启动Prisma,请运行以下命令: Shellnpxprismastudio Prisma索引页面如下: 要创建一个具有ADMIN角色的数据库用户和多个具有EMPLOYEE角色的用户,请访问以下页面: 单击Addrecord,然后填写所需的字段:password、name、email和role。完成后,单击绿色的Save1change按钮。注意,为了简单起见,我们没有散列密码。 用yarndev启动服务器。这将启动服务器并在〔localhost:3000〕(http:localhost:3000)上运行应用程序,登录页面如下所示。 使用具有ADMIN角色的用户登录,因为只有管理用户可以创建考勤表。一旦登录成功,应用程序将重定向到您的仪表板。 单击CreateAtnatureShet按钮创建考勤表,然后等待请求完成,考勤表将出现。用户仪表板如下所示。 出勤表如下所示,单击登录按钮即可登录。登录成功后,将显示登录时间,并且可以看到SignOut按钮。单击登出按钮登出,并与不同的用户多次重复此过程。 接下来点击侧边栏中的出席链接,查看用户的出席情况。结果应与下列结果相符: 接下来点击侧边栏上的出勤表链接,查看所有用户的出勤情况。结果如下: 结论 在本文中,您学习了如何在Next。js中使用自定义Fastify服务器。您还了解了Prisma和Prisma工作室。我已经向您介绍了如何将Prisma连接到Postgres数据库,以及如何使用Prisma客户端和Prismastudio创建、读取和更新数据库。 您还学习了如何使用铁会话对用户进行身份验证。在本教程中,我们构建了一个完整的应用程序,它使用Next。js、Prisma、Postgres和Fastify管理员工出勤率。请继续收听,下次再见。