React+Nest全栈开发结合了React的高效前端组件化和Nest的强大后端模块化,提供了一种无缝集成的解决方案,提高开发效率和代码可维护性。通过详细的技术说明,本文介绍了从环境搭建到项目集成的全过程,帮助开发者快速上手React+Nest全栈开发。
React+Nest全栈开发简介React 是一个由 Facebook 开发并维护的开源 JavaScript 库,用于构建用户界面。它主要用于构建单页应用,提供了一种高效且灵活的方式来创建可重用的UI组件。React 通过虚拟DOM和高效的渲染机制,提升了应用的性能,使得开发变得更为简单。
Nest 是一个用于构建高效、可扩展的服务器端 Node.js 应用程序的框架。它基于 Express,提供了一组强大的工具来构建复杂的服务器端逻辑,包括中间件、装饰器、依赖注入等。Nest 的设计目标是利用 TypeScript 的强类型系统来保证代码的可维护性,同时提供了简洁的 API 使得开发更加高效。
React 和 Nest 的组合为开发者提供了一种无缝集成前后端的解决方案。前端使用 React 可以构建快速、响应式的用户界面,而后端使用 Nest 能够构建高性能、可扩展的服务器端逻辑。这种组合不仅提高了开发效率,还简化了前后端的通信,使得整个开发过程更加顺畅。
React 的组件化和 Nest 的模块化设计使得开发和维护都变得更加容易。React 组件可以被轻松地重用和组合,而 Nest 的服务和控制器则可以按照业务逻辑进行拆分,使得代码结构清晰,易于维护。此外,由于 React 和 Nest 都支持 TypeScript,开发者可以利用类型检查和静态分析功能来减少潜在的错误。
开发环境的搭建包括安装 Node.js、NPM(或 Yarn)、创建 React 项目和 Nest 项目。
Node.js 是一个开源、跨平台的 JavaScript 运行时环境,NPM 是 Node.js 的包管理和分发工具。首先,访问 Node.js 官方网站 (https://nodejs.org/),下载最新的 LTS(长期支持)版本并安装。安装完成后,可以通过命令行验证安装是否成功:
node -v npm -v
Yarn 是一个由 Facebook 开发的包管理器,提供了一个更安全、更快速的依赖管理方案。可以通过以下命令安装 Yarn:
npm install -g yarn
使用 Create React App 工具可以快速搭建一个基本的 React 项目。以下是创建项目的步骤:
安装 Create React App:
npx create-react-app my-app
进入项目目录并启动开发服务器:
cd my-app npm start
使用 Nest CLI 工具可以快速搭建一个基本的 Nest 项目。以下是创建项目的步骤:
安装 Nest CLI:
npm i -g @nestjs/cli
创建一个新的 Nest 项目:
nest new my-nest-app
进入项目目录并启动开发服务器:
cd my-nest-app npm run start:dev
完成以上步骤后,你将拥有一个基本的 React 前端和 Nest 后端项目,并可以通过浏览器访问它们。
本节将详细介绍 React 的基本概念和开发技巧,包括创建项目、组件与状态管理、路由与导航以及样式与 CSS 引入。
你已经通过 create-react-app
创建了一个基本的 React 项目。为了进一步了解 React,我们来创建一个新的 React 组件:
src
目录下创建一个新的文件夹 components
。在 components
文件夹中创建一个新文件 HelloWorld.tsx
:
import React from 'react'; const HelloWorld: React.FC = () => { return <div>Hello World!</div>; }; export default HelloWorld;
在 App.tsx
文件中引入并使用 HelloWorld
组件:
import React from 'react'; import HelloWorld from './components/HelloWorld'; function App() { return ( <div className="App"> <HelloWorld /> </div> ); } export default App;
React 中的组件分为两种类型,一种是无状态组件(Stateless Component),另一种是有状态组件(Stateful Component)。无状态组件只接收输入,不保存自身的状态;而有状态组件可以通过定义状态(state)来存储和管理数据。
以下是如何定义一个有状态组件:
import React, { Component } from 'react'; class Counter extends Component { state = { count: 0, }; increment = () => { this.setState((prevState) => { return { count: prevState.count + 1 }; }); }; render() { return ( <div> <h1>Count: {this.state.count}</h1> <button onClick={this.increment}>Increment</button> </div> ); } } export default Counter;
在这个示例中,Counter
组件维护了一个状态 count
,并提供了一个 increment
方法来增加这个状态。
React 中通常使用 react-router-dom
来实现路由。首先需要安装 react-router-dom
:
npm install react-router-dom
接下来,创建一些路由:
import React from 'react'; import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom'; import Counter from './Counter'; import HelloWorld from './HelloWorld'; const App: React.FC = () => { return ( <Router> <div> <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/counter">Counter</Link> </li> <li> <Link to="/hello">HelloWorld</Link> </li> </ul> </nav> <Switch> <Route path="/counter"> <Counter /> </Route> <Route path="/hello"> <HelloWorld /> </Route> <Route path="/"> <Home /> </Route> </Switch> </div> </Router> ); }; export default App;
在这个示例中,我们定义了三个路由:/counter
、/hello
和 /'
(根目录),分别对应 Counter
组件、HelloWorld
组件和 Home
组件。
React 中可以使用多种方式引入 CSS,包括内联样式、CSS 文件和 CSS-in-JS 库。这里我们将使用普通的 CSS 文件来引入样式:
在 src
目录下创建一个 App.css
文件,并添加一些样式:
.App { text-align: center; font-family: Arial, sans-serif; } nav { background-color: #333; padding: 10px; } nav ul { list-style: none; padding: 0; } nav ul li { display: inline; margin-right: 10px; } nav a { color: white; text-decoration: none; }
在 App.tsx
文件中引入这个 CSS 文件:
import React from 'react'; import './App.css'; import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom'; import Counter from './Counter'; import HelloWorld from './HelloWorld'; const App: React.FC = () => { return ( <Router> <div className="App"> <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/counter">Counter</Link> </li> <li> <Link to="/hello">HelloWorld</Link> </li> </ul> </nav> <Switch> <Route path="/counter"> <Counter /> </Route> <Route path="/hello"> <HelloWorld /> </Route> <Route path="/"> <Home /> </Route> </Switch> </div> </Router> ); }; const Home: React.FC = () => <h2>Welcome to the Home Page</h2>; export default App;
通过这种方式,你可以轻松地为你的 React 应用添加样式。
本节将详细介绍 Nest 的基本概念和开发技巧,包括创建项目、控制器与服务、数据库集成与操作、RESTful API设计与实现。
你已经通过 nest new
命令创建了一个基本的 Nest 项目。为了进一步了解 Nest,我们将创建一个新的控制器和服务。
创建一个新的控制器 app.controller.ts
:
import { Controller, Get, Post } from '@nestjs/common'; import { AppService } from './app.service'; @Controller('app') export class AppController { constructor(private readonly appService: AppService) {} @Get() getHello(): string { return this.appService.getHello(); } }
创建一个新的服务 app.service.ts
:
import { Injectable } from '@nestjs/common'; @Injectable() export class AppService { getHello(): string { return 'Hello World!'; } }
在 main.ts
文件中引入并使用创建的控制器和服务:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { AppController } from './app.controller'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.getHttpAdapter().useStaticResponses({ '404': 'Not Found', }); await app.listen(3000); } bootstrap();
在 Nest 中,控制器(Controller)负责处理 HTTP 请求,而服务(Service)则用于实现业务逻辑。控制器可以依赖注入服务来执行业务操作。
例如,我们可以通过以下方式实现一个简单的登录功能:
创建一个新的服务 auth.service.ts
:
import { Injectable } from '@nestjs/common'; @Injectable() export class AuthService { async login(username: string, password: string): Promise<string> { // 模拟登录逻辑 if (username === 'admin' && password === 'admin') { return 'Login successful'; } else { throw new Error('Invalid credentials'); } } }
在 app.module.ts
文件中导入并提供服务:
import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { AuthService } from './auth.service'; @Module({ imports: [], controllers: [AppController], providers: [AppService, AuthService], }) export class AppModule {}
创建一个新的控制器 auth.controller.ts
:
import { Controller, Post } from '@nestjs/common'; import { AuthService } from './auth.service'; @Controller('auth') export class AuthController { constructor(private readonly authService: AuthService) {} @Post('login') async login(username: string, password: string): Promise<string> { return this.authService.login(username, password); } }
通过这种方式,你可以在 Nest 中实现复杂的业务逻辑,并通过 HTTP 请求进行调用。
Nest 允许集成各种数据库,包括 MySQL、PostgreSQL、MongoDB 等。这里我们以 MongoDB 为例,展示如何进行数据库集成。
安装 MongoDB 相关依赖:
npm install @nestjs/mongoose mongoose
创建一个新的模块 app.module.ts
:
import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { AuthService } from './auth.service'; import { AuthController } from './auth.controller'; import { MongooseModule } from '@nestjs/mongoose'; import { UserSchema } from './user.schema'; import { UserController } from './user.controller'; import { UserService } from './user.service'; @Module({ imports: [ MongooseModule.forRoot('mongodb://localhost:27017/mydb'), MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]), ], controllers: [AppController, AuthController, UserController], providers: [AppService, AuthService, UserService], }) export class AppModule {}
创建一个新的模式 user.schema.ts
:
import { Schema, Document } from 'mongoose'; import { User } from './user.interface'; export const UserSchema: Schema = new Schema<User>({ username: { type: String, required: true }, password: { type: String, required: true }, });
创建一个新的服务 user.service.ts
:
import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { User } from './user.interface'; import { UserSchema } from './user.schema'; @Injectable() export class UserService { constructor(@InjectModel(UserSchema.name) private userModel: Model<User>) {} async createUser(user: User): Promise<User> { const createdUser = new this.userModel(user); return createdUser.save(); } async findUser(username: string): Promise<User | null> { return this.userModel.findOne({ username }); } }
创建一个新的控制器 user.controller.ts
:
import { Controller, Post, Req, Body } from '@nestjs/common'; import { UserService } from './user.service'; import { User } from './user.interface'; @Controller('users') export class UserController { constructor(private readonly userService: UserService) {} @Post('register') async registerUser(@Body() user: User): Promise<User> { return this.userService.createUser(user); } @Post('login') async loginUser(@Body() { username, password }): Promise<User | null> { const user = await this.userService.findUser(username); if (user && user.password === password) { return user; } return null; } }
通过这种方式,你可以在 Nest 中实现数据库操作,并通过 HTTP 请求进行调用。
RESTful API 使用 HTTP 协议定义了一系列资源的操作,包括 GET、POST、PUT、DELETE 等。为了实现这些操作,我们可以通过 Nest 中的控制器来定义具体的路由和处理函数。
例如,我们可以通过以下方式实现 CRUD 操作:
创建一个新的服务 user.service.ts
:
import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { User } from './user.interface'; import { UserSchema } from './user.schema'; @Injectable() export class UserService { constructor(@InjectModel(UserSchema.name) private userModel: Model<User>) {} async createUser(user: User): Promise<User> { const createdUser = new this.userModel(user); return createdUser.save(); } async findUser(username: string): Promise<User | null> { return this.userModel.findOne({ username }); } async findAllUsers(): Promise<User[]> { return this.userModel.find().exec(); } async updateUser(username: string, user: User): Promise<User> { return this.userModel.findOneAndUpdate({ username }, user, { new: true }).exec(); } async deleteUser(username: string): Promise<User | null> { return this.userModel.findOneAndRemove({ username }).exec(); } }
创建一个新的控制器 user.controller.ts
:
import { Controller, Post, Req, Body, Get, Param } from '@nestjs/common'; import { UserService } from './user.service'; import { User } from './user.interface'; @Controller('users') export class UserController { constructor(private readonly userService: UserService) {} @Post('register') async registerUser(@Body() user: User): Promise<User> { return this.userService.createUser(user); } @Post('login') async loginUser(@Body() { username, password }): Promise<User | null> { const user = await this.userService.findUser(username); if (user && user.password === password) { return user; } return null; } @Get() async findAllUsers(): Promise<User[]> { return this.userService.findAllUsers(); } @Get(':username') async findUser(@Param('username') username: string): Promise<User | null> { return this.userService.findUser(username); } @Post(':username/edit') async updateUser(@Param('username') username: string, @Body() user: User): Promise<User> { return this.userService.updateUser(username, user); } @Post(':username/delete') async deleteUser(@Param('username') username: string): Promise<User | null> { return this.userService.deleteUser(username); } }
通过这种方式,你可以在 Nest 中实现 RESTful API 的设计与实现,通过 HTTP 请求进行 CRUD 操作。
本节将详细介绍如何将 React 前端项目与 Nest 后端项目进行集成,包括跨域资源共享配置、数据交互与 API 调用、用户认证与授权实现。
为了使 React 前端项目能够与 Nest 后端项目进行通信,我们需要在 Nest 中配置跨域资源共享(CORS)。
创建一个新的中间件 cors.middleware.ts
:
import { Injectable, NestMiddleware } from '@nestjs/common'; import * as cors from 'cors'; @Injectable() export class CorsMiddleware implements NestMiddleware { use(req: any, res: any, next: () => void) { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); next(); } }
在 main.ts
文件中使用中间件:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { CorsMiddleware } from './cors.middleware'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.use(new CorsMiddleware().use); await app.listen(3000); } bootstrap();
为了在 React 前端项目中调用 Nest 后端项目中的 API,我们需要使用 HTTP 客户端库,例如 axios
。
安装 axios:
npm install axios
创建一个新的服务 api.service.ts
:
import { Injectable } from '@nestjs/common'; import axios from 'axios'; @Injectable({ providedIn: 'root', }) export class ApiService { private readonly baseUrl = 'http://localhost:3000'; async getHello(): Promise<string> { const { data } = await axios.get(`${this.baseUrl}/app`); return data; } async registerUser(user: User): Promise<User> { const { data } = await axios.post(`${this.baseUrl}/users/register`, user); return data; } async loginUser(username: string, password: string): Promise<User | null> { const { data } = await axios.post(`${this.baseUrl}/users/login`, { username, password }); return data; } async findAllUsers(): Promise<User[]> { const { data } = await axios.get(`${this.baseUrl}/users`); return data; } async findUser(username: string): Promise<User | null> { const { data } = await axios.get(`${this.baseUrl}/users/${username}`); return data; } async updateUser(username: string, user: User): Promise<User> { const { data } = await axios.post(`${this.baseUrl}/users/${username}/edit`, user); return data; } async deleteUser(username: string): Promise<User | null> { const { data } = await axios.post(`${this.baseUrl}/users/${username}/delete`); return data; } }
通过这种方式,你可以在 React 中调用 Nest 后端项目的 API,并实现数据交互。
为了实现用户认证与授权,我们需要在 Nest 后端项目中实现认证逻辑,并在 React 前端项目中进行相应的处理。
在 auth.service.ts
中实现认证逻辑:
import { Injectable } from '@nestjs/common'; import { Request } from 'express'; import * as jwt from 'jsonwebtoken'; const secret = 'secret'; @Injectable() export class AuthService { generateToken(user: any) { return jwt.sign(user, secret, { expiresIn: '1h' }); } validateToken(token: string) { try { return jwt.verify(token, secret); } catch (error) { return null; } } }
在 auth.controller.ts
中实现登录功能:
import { Controller, Post, Req, Body, HttpException, HttpStatus } from '@nestjs/common'; import { AuthService } from './auth.service'; import { UserService } from './user.service'; import { User } from './user.interface'; @Controller('auth') export class AuthController { constructor(private readonly authService: AuthService, private readonly userService: UserService) {} @Post('login') async login(@Req() req, @Body() { username, password }): Promise<{ token: string }> { const user = await this.userService.findUser(username); if (!user || user.password !== password) { throw new HttpException('Invalid credentials', HttpStatus.UNAUTHORIZED); } const token = this.authService.generateToken(user); return { token }; } @Post('profile') async getProfile(@Req() req) { return req.user; } }
在 user.service.ts
中实现用户服务:
import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { User } from './user.interface'; import { UserSchema } from './user.schema'; @Injectable() export class UserService { constructor(@InjectModel(UserSchema.name) private userModel: Model<User>) {} async createUser(user: User): Promise<User> { const createdUser = new this.userModel(user); return createdUser.save(); } async findUser(username: string): Promise<User | null> { return this.userModel.findOne({ username }); } }
在 user.controller.ts
中实现用户管理功能:
import { Controller, Post, Req, Body, Get, Param } from '@nestjs/common'; import { UserService } from './user.service'; import { User } from './user.interface'; import { AuthService } from './auth.service'; @Controller('users') export class UserController { constructor(private readonly userService: UserService, private readonly authService: AuthService) {} @Post('register') async registerUser(@Body() user: User): Promise<User> { return this.userService.createUser(user); } @Get() async findAllUsers(@Req() req): Promise<User[]> { return this.userService.findAllUsers(); } @Get(':username') async findUser(@Param('username') username: string, @Req() req): Promise<User | null> { return this.userService.findUser(username); } }
在 app.module.ts
中提供 AuthService
和 UserService
:
import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { AuthService } from './auth.service'; import { AuthController } from './auth.controller'; import { UserSchema } from './user.schema'; import { UserController } from './user.controller'; import { UserService } from './user.service'; import { MongooseModule } from '@nestjs/mongoose'; import { CorsMiddleware } from './cors.middleware'; @Module({ imports: [ MongooseModule.forRoot('mongodb://localhost:27017/mydb'), MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]), ], controllers: [AppController, AuthController, UserController], providers: [AppService, AuthService, UserService, CorsMiddleware], }) export class AppModule {}
在 auth.service.ts
中使用 jsonwebtoken
进行认证:
import { Injectable } from '@nestjs/common'; import { Request } from 'express'; import * as jwt from 'jsonwebtoken'; const secret = 'secret'; @Injectable() export class AuthService { generateToken(user: any) { return jwt.sign(user, secret, { expiresIn: '1h' }); } validateToken(token: string) { try { return jwt.verify(token, secret); } catch (error) { return null; } } }
在 auth.controller.ts
中实现登录功能:
import { Controller, Post, Req, Body, HttpException, HttpStatus } from '@nestjs/common'; import { AuthService } from './auth.service'; import { UserService } from './user.service'; import { User } from './user.interface'; @Controller('auth') export class AuthController { constructor(private readonly authService: AuthService, private readonly userService: UserService) {} @Post('login') async login(@Req() req, @Body() { username, password }): Promise<{ token: string }> { const user = await this.userService.findUser(username); if (!user || user.password !== password) { throw new HttpException('Invalid credentials', HttpStatus.UNAUTHORIZED); } const token = this.authService.generateToken(user); return { token }; } @Post('profile') async getProfile(@Req() req) { return req.user; } }
在 user.controller.ts
中实现用户管理功能:
import { Controller, Post, Req, Body, Get, Param } from '@nestjs/common'; import { UserService } from './user.service'; import { User } from './user.interface'; import { AuthService } from './auth.service'; @Controller('users') export class UserController { constructor(private readonly userService: UserService, private readonly authService: AuthService) {} @Post('register') async registerUser(@Body() user: User): Promise<User> { return this.userService.createUser(user); } @Get() async findAllUsers(@Req() req): Promise<User[]> { return this.userService.findAllUsers(); } @Get(':username') async findUser(@Param('username') username: string, @Req() req): Promise<User | null> { return this.userService.findUser(username); } }
通过这种方式,你可以在 Nest 中实现用户认证与授权,并在 React 中进行相应的处理。
本节将通过一个简单的 CRUD 应用来展示 React 和 Nest 的集成,并介绍前端设计、后端 API 设计、数据持久化与数据库操作、用户界面与后端交互优化。
前端设计:
创建一个新的组件 Login.tsx
:
import React, { useState } from 'react'; import { useLogin } from '../hooks/useLogin'; import { useNavigate } from 'react-router-dom'; import { ApiService } from '../services/api.service'; const Login: React.FC = () => { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const navigate = useNavigate(); const { login, loading, error } = useLogin(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { await login(username, password); navigate('/dashboard'); } catch (err) { console.error(err); } }; return ( <div> <h2>Login</h2> <form onSubmit={handleSubmit}> <div> <label htmlFor="username">Username:</label> <input type="text" id="username" name="username" value={username} onChange={(e) => setUsername(e.target.value)} /> </div> <div> <label htmlFor="password">Password:</label> <input type="password" id="password" name="password" value={password} onChange={(e) => setPassword(e.target.value)} /> </div> <button type="submit" disabled={loading}> Login </button> {error && <p>{error}</p>} </form> </div> ); }; export default Login;
创建一个新的组件 Dashboard.tsx
:
import React, { useEffect, useState } from 'react'; import { useGetUsers } from '../hooks/useGetUsers'; import { useNavigate } from 'react-router-dom'; import { ApiService } from '../services/api.service'; const Dashboard: React.FC = () => { const [users, setUsers] = useState<User[]>([]); const navigate = useNavigate(); const { loading, error } = useGetUsers(); useEffect(() => { if (error) { navigate('/login'); } }, [error, navigate]); const fetchUsers = async () => { try { const fetchedUsers = await ApiService.findAllUsers(); setUsers(fetchedUsers); } catch (err) { console.error(err); } }; useEffect(() => { fetchUsers(); }, []); return ( <div> <h2>Dashboard</h2> <table> <thead> <tr> <th>Username</th> <th>Password</th> </tr> </thead> <tbody> {users.map((user) => ( <tr key={user._id}> <td>{user.username}</td> <td>{user.password}</td> </tr> ))} </tbody> </table> </div> ); }; export default Dashboard;
后端 API 设计:
创建一个新的服务 auth.service.ts
:
import { Injectable } from '@nestjs/common'; import { Request } from 'express'; import * as jwt from 'jsonwebtoken'; const secret = 'secret'; @Injectable() export class AuthService { generateToken(user: any) { return jwt.sign(user, secret, { expiresIn: '1h' }); } validateToken(token: string) { try { return jwt.verify(token, secret); } catch (error) { return null; } } }
创建一个新的控制器 auth.controller.ts
:
import { Controller, Post, Req, Body, HttpException, HttpStatus } from '@nestjs/common'; import { AuthService } from './auth.service'; import { UserService } from './user.service'; import { User } from './user.interface'; @Controller('auth') export class AuthController { constructor(private readonly authService: AuthService, private readonly userService: UserService) {} @Post('login') async login(@Req() req, @Body() { username, password }): Promise<{ token: string }> { const user = await this.userService.findUser(username); if (!user || user.password !== password) { throw new HttpException('Invalid credentials', HttpStatus.UNAUTHORIZED); } const token = this.authService.generateToken(user); return { token }; } @Post('profile') async getProfile(@Req() req) { return req.user; } }
创建一个新的控制器 user.controller.ts
:
import { Controller, Post, Req, Body, Get, Param } from '@nestjs/common'; import { UserService } from './user.service'; import { User } from './user.interface'; import { AuthService } from './auth.service'; @Controller('users') export class UserController { constructor(private readonly userService: UserService, private readonly authService: AuthService) {} @Post('register') async registerUser(@Body() user: User): Promise<User> { return this.userService.createUser(user); } @Get() async findAllUsers(@Req() req): Promise<User[]> { return this.userService.findAllUsers(); } @Get(':username') async findUser(@Param('username') username: string, @Req() req): Promise<User | null> { return this.userService.findUser(username); } }
数据持久化:
创建一个新的服务 user.service.ts
:
import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { User } from './user.interface'; import { UserSchema } from './user.schema'; @Injectable() export class UserService { constructor(@InjectModel(UserSchema.name) private userModel: Model<User>) {} async createUser(user: User): Promise<User> { const createdUser = new this.userModel(user); return createdUser.save(); } async findUser(username: string): Promise<User | null> { return this.userModel.findOne({ username }); } async findAllUsers(): Promise<User[]> { return this.userModel.find().exec(); } }
创建一个新的模式 user.schema.ts
:
import { Schema, Document } from 'mongoose'; import { User } from './user.interface'; export const UserSchema: Schema = new Schema<User>({ username: { type: String, required: true }, password: { type: String, required: true }, });
在 main.ts
文件中配置数据库连接:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { CorsMiddleware } from './cors.middleware'; import { MongooseModule } from '@nestjs/mongoose'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.use(new CorsMiddleware().use); await app.listen(3000); } bootstrap();
在 app.module.ts
文件中导入并提供服务:
import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { AuthService } from './auth.service'; import { AuthController } from './auth.controller'; import { UserService } from './user.service'; import { UserController } from './user.controller'; import { MongooseModule } from '@nestjs/mongoose'; import { UserSchema } from './user.schema'; import { CorsMiddleware } from './cors.middleware'; @Module({ imports: [ MongooseModule.forRoot('mongodb://localhost:27017/mydb'), MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]), ], controllers: [AppController, AuthController, UserController], providers: [AppService, AuthService, UserService, CorsMiddleware], }) export class AppModule {}
用户界面优化:
创建一个新的组件 UserForm.tsx
:
import React, { useState } from 'react'; import { useRegisterUser } from '../hooks/useRegisterUser'; import { useNavigate } from 'react-router-dom'; import { ApiService } from '../services/api.service'; const UserForm: React.FC = () => { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const navigate = useNavigate(); const { registerUser } = useRegisterUser(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); try { await registerUser(username, password); setError(''); navigate('/dashboard'); } catch (err) { setError(err.message); } finally { setLoading(false); } }; return ( <div> <h2>Register User</h2> <form onSubmit={handleSubmit}> <div> <label htmlFor="username">Username:</label> <input type="text" id="username" name="username" value={username} onChange={(e) => setUsername(e.target.value)} /> </div> <div> <label htmlFor="password">Password:</label> <input type="password" id="password" name="password" value={password} onChange={(e) => setPassword(e.target.value)} /> </div> <button type="submit" disabled={loading}> Register </button> {error && <p>{error}</p>} </form> </div> ); }; export default UserForm;
创建一个新的组件 UserList.tsx
:
import React, { useEffect, useState } from 'react'; import { useGetUsers } from '../hooks/useGetUsers'; import { useNavigate } from 'react-router-dom'; import { ApiService } from '../services/api.service'; const UserList: React.FC = () => { const [users, setUsers] = useState<User[]>([]); const navigate = useNavigate(); const { loading, error } = useGetUsers(); useEffect(() => { if (error) { navigate('/login'); } }, [error, navigate]); const fetchUsers = async () => { try { const fetchedUsers = await ApiService.findAllUsers(); setUsers(fetchedUsers); } catch (err) { console.error(err); } }; useEffect(() => { fetchUsers(); }, []); return ( <div> <h2>User List</h诋毁