技术栈:
前端:Next.js
- 后端:Node.js + Express.js
- 数据库:PostgreSQL
- 对象关系映射:Sequelize
- 面试技术环节项目流程
创建前端
npx create-next-app@latest frontend
touch .env创建后端 & 装后端依賴
mkdir backend
cd backend
npm init -y
npm install express cors dotenv bcryptjs jsonwebtoken pg pg-hstore sequelize
npm install -D nodemon sequelize-cli後端目錄結構指令
mkdir config controllers middleware models routes migrations seeders
touch server.js
touch config/db.js
touch middleware/authMiddleware.js
touch controllers/authController.js
touch controllers/*.js
touch controllers/*.js
touch routes/authRoutes.js
touch routes/*.js
touch routes/*.js
touch .env
前端依賴
cd frontend
npm install axios react-hot-toast
touch .env
若欲设 Tailwind,则往 Tailwind 之网站,择 v3 版本而为之。package.json 脚本
"脚本": {
"始": "啟 node server.js"
"dev":"nodemon server.js"
}Sequelize初始化&PostgreSQL數據庫創建
npx sequelize-cli init
是故生焉:
config/
models/
migrations/
seeders/
啟 PostgreSQL 终端:
創建數據庫 employee_management;後端 與 前端 .env 文件
後端:
PORT=5000
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=yourpassword
DB_NAME=employee_management
JWT_SECRET=mysecretkey
前端:
NEXT_PUBLIC_BASE_URL=http://localhost:5000
PostgreSQL 用 Sequelize 配置
config/config.json
{
"development": {
"username": "postgres",
"password": "",
"database": "",
"host": "localhost",
"dialect": "postgres"
}
}
- 数据库连接 config/db.js
const { Sequelize } = require("sequelize");
require("dotenv").config();
const sequelize = new Sequelize(
process.env.DB_NAME,
process.env.DB_USER,
process.env.DB_PASSWORD,
{
host: process.env.DB_HOST,
port: process.env.DB_PORT,
dialect: "postgres",
logging: false,
}
);
module.exports = sequelize;
生成模型与迁移&运行迁移
用户模型
npx sequelize-cli model:generate --name User --attributes name:string,email:string,password:string
运行迁移
npx sequelize-cli db:migrateExpress服务器设置
server.js
const express = require("express");
const cors = require("cors");
require("dotenv").config();
const app = express();
app.use(cors());
app.use(express.json());
app.use("/api/auth", require("./routes/authRoutes"));
app.use("/api/employees", require("./routes/employeeRoutes"));
app.use("/api/attendance", require("./routes/attendanceRoutes"));
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on ${PORT}`);
});
- 身份验证中间件 middleware/authMiddleware.js
const jwt = require("jsonwebtoken");
module.exports = (req, res, next) => {
try {
const token = req.headers.authorization?.split(" ")[1];
if (!token) {
return res.status(401).json({
message: "No token provided",
});
}
const decoded = jwt.verify(
token,
process.env.JWT_SECRET
);
req.user = decoded;
next();
} catch (error) {
res.status(401).json({
message: "Invalid token",
});
}
};
- 登录控制器 controllers/authController.js
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const { User } = require("../models");
exports.login = async (req, res) => {
try {
const { email, password } = req.body;
const user = await User.findOne({
where: { email },
});
if (!user) {
return res.status(400).json({
message: "User not found",
});
}
const isMatch = await bcrypt.compare(
password,
user.password
);
if (!isMatch) {
return res.status(400).json({
message: "Invalid credentials",
});
}
const token = jwt.sign(
{ id: user.id },
process.env.JWT_SECRET,
{
expiresIn: "1d",
}
);
res.json({
token,
user,
});
} catch (error) {
res.status(500).json({
message: error.message,
});
}
};
- 认证路由 routes/authRoutes.js
const router = require("express").Router();
const controller = require("../controllers/authController");
router.post("/login", controller.login);
module.exports = router;
12. Axios Setup
src/utils/axios.js
import axios from "axios";
const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_BASE_URL,
});
api.interceptors.request.use((config) => {
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
export default api;
- React路由设置 src/app/App.js
import {
createBrowserRouter,
Navigate,
RouterProvider
} from "react-router-dom";
import React from "react";
import ReactDOM from "react-dom/client";
import Login from "./pages/Login";
import Register from "./pages/Register";
import Home from "./pages/Home";
import Profile from "./pages/Profile";
function PrivateRoute({ children }) {
const isLoggedIn = localStorage.getItem("token");
return isLoggedIn
? children
: <Navigate to="/login" />;
}
function PublicRoute({ children }) {
const isLoggedIn = localStorage.getItem("token");
return isLoggedIn
? <Navigate to="/" />
: children;
}
const router = createBrowserRouter([
{
path: "/login",
element: (
<PublicRoute>
<Login />
</PublicRoute>
),
},
{
path: "/register",
element: (
<PublicRoute>
<Register />
</PublicRoute>
),
},
{
path: "/",
element: (
<PrivateRoute>
<Home />
</PrivateRoute>
),
},
{
path: "/profile",
element: (
<PrivateRoute>
<Profile />
</PrivateRoute>
),
},
]);
function App() {
return (
<div>
<RouterProvider router={router} />
</div>
);
}
export default App;
- 登录API示例 src/app/login/login.js
import api from "@/utils/axios";
import { useRouter } from "next/navigation";
const router = useRouter();
const login = async () => {
const res = await api.post("/auth/login", {
email,
password,
});
localStorage.setItem(
"token",
res.data.token
);
router.push("/");
};
- 登出函数
import { useRouter } from "next/navigation";
const router = useRouter();
const logout = () => {
localStorage.removeItem("token");
router.push("/login");
};
示例
- Next.js路由 src/app/login/page.js
源码/app/仪表盘/页.js
源码/app/职员/页.js
- 登录后重定向 导入{路由器}自"next/navigation"
常量路由器=路由器()
路由器推入"/仪表盘"
- 重要PostgreSQL指令 开启PostgreSQL psql -U postgres
显示数据库
\l
连接数据库
员工管理
显诸表
\dt
- 迁徙之令 行迁徙 npx sequelize-cli db:migrate
撤回上一次迁移
npx sequelize-cli db:migrate:undo
撤回所有迁移
npx sequelize-cli db:migrate:undo:all
- 原始查询示例 const sequelize = require("../config/db");
const [employees] = await sequelize.query(
'SELECT * FROM "Employees"'
);
console.log(employees);
- Sequelize Query ExamplesCreateawait Employee.create({name: "Parth",email: "parth@gmail.com"});
Find All
await Employee.findAll();
Find One
待寻雇员其一,其条件为
何处:{
id:一,
},
});
更新
待 Employee 更新
{
名:"更新",
},
{
何处:{
id:一,
},
});
Delete
Employee.destroy({
where: {__JHSNS_SEG_f0456e12_123__
__JHSNS_SEG_f0456e12_124__id: 1,
- });__JHSNS_SEG_f0456e12_126__Example Migration File
migrations/XXXXXXXXXXXX-create-user.js
__JHSNS_SEG_f0456e12_127__"use strict";__JHSNS_SEG_f0456e12_127__module.exports = {
俟之,上之 queryInterface, Sequelize
俟之, queryInterface 营 "Users" 表,其制如左
id:{
不可释,
自增,
为主键,
数为 Sequelize.INTEGER,
}
name: {
type: Sequelize.STRING,
},
email: {
type: Sequelize.STRING,
unique: true,
},
password: {
type: Sequelize.STRING,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
异步下(queryInterface, Sequelize) {
期待 queryInterface.dropTable("Users");
},
};
- 示例模型文件 models/user.js "use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
乃立类曰用户,承于模也。
静联诸模,无他。
}
用户既立,启之,
{
名者,为文也。
email: DataTypes.STRING,
password: DataTypes.STRING,
},
{
sequelize,
modelName: "User",
}
});
返用户之立也。
};
- 载入模型之用 const db = require("../models"); const { User, Employee, Attendance } = db;
Tailwind设其核于React
装Tailwind CSS v3
npm install -D tailwindcss@3造Tailwind配置之文
npx tailwindcss init
此造:
tailwind.config.js設置範本路徑
於tailwind.config.js之內
/** @type {import('tailwindcss').Config} /
export default {
內容: ["./src//.{html,js,jsx}"],
主題: {
延展: {},
},
插件: []
}入索引CSS文件
创:
src/index.css
增:
@tailwind base;
@tailwind components;
@tailwind utilities;始Tailwind构建之程
行:
npx tailwindcss -i ./src/input.css -o ./src/output.css --watch
此令也:
自输入之CSS中读Tailwind之类别
生成最终之CSS,入output.css。
时计以观变












