From de281a2106daf7862cf634dac5b6f27d0fe6c05c Mon Sep 17 00:00:00 2001 From: Lmx <1960868911@qq.com> Date: Tue, 10 Feb 2026 16:23:20 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=8A=9F=E8=83=BD=E5=8F=8A=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E6=9E=B6=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 Express 应用入口文件 app.js,包含 CORS 配置、中间件设置、 数据库连接测试、路由挂载和全局错误处理 - 实现用户登录控制器,支持用户名密码验证和登录逻辑处理 - 创建 User 模型定义,映射数据库 users 表结构 - 配置用户路由模块,提供 /api/login 接口 - 更新 package.json 添加启动脚本和项目描述 - 新增服务启动文件 server.js,支持环境变量配置端口 ``` --- app.js | 41 ++++++++++++++++++++++ controllers/userController.js | 66 +++++++++++++++++++++++++++++++++++ models/User.js | 57 ++++++++++++++++++++++++++++++ package.json | 10 +++--- routes/userRoutes.js | 13 +++++++ server.js | 11 ++++++ 6 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 controllers/userController.js create mode 100644 models/User.js create mode 100644 routes/userRoutes.js diff --git a/app.js b/app.js index e69de29..7729576 100644 --- a/app.js +++ b/app.js @@ -0,0 +1,41 @@ +const express = require('express'); +const cors = require('cors'); +require('dotenv').config(); // 加载.env环境变量 + +// 导入数据库连接测试和登录路由 +const { testDbConnection } = require('./config/db'); +const userRoutes = require('./routes/userRoutes'); + +// 初始化Express应用 +const app = express(); + +// 1. 配置中间件(必须在挂载路由前) +// 解析JSON请求体(登录时前端传的用户名/密码会用JSON格式) +app.use(express.json()); +// 解析表单请求体(兼容其他场景,如表单提交) +app.use(express.urlencoded({ extended: true })); +// 配置跨域(允许uni-app前端地址访问,从.env读取配置) +app.use(cors({ + origin: process.env.CORS_ORIGIN, + credentials: true // 允许携带Cookie,后续若需记住登录状态可用 +})); + +// 2. 测试数据库连接(启动时自动验证) +testDbConnection(); + +// 3. 挂载路由(所有接口加/api前缀,避免路径冲突) +// 登录接口最终地址:http://localhost:3000/api/login +app.use('/api', userRoutes); + +// 4. 全局错误处理中间件(捕获接口异常,返回统一错误格式) +app.use((err, req, res, next) => { + console.error('服务器异常:', err.stack); + res.status(500).json({ + code: 500, + msg: '服务器内部错误', + error: err.message + }); +}); + +// 导出app实例,给server.js调用 +module.exports = app; \ No newline at end of file diff --git a/controllers/userController.js b/controllers/userController.js new file mode 100644 index 0000000..7f29582 --- /dev/null +++ b/controllers/userController.js @@ -0,0 +1,66 @@ +// 导入 User 模型,用于操作 users 表数据 +const User = require('../models/User'); + +// 核心:登录接口逻辑 +const login = async (req, res) => { + try { + // 1. 检查请求体是否存在 + if (!req.body) { + return res.status(400).json({ + code: 400, + msg: '请求体不能为空' + }); + } + + // 2. 从前端请求体中获取登录参数(用户名、密码) + const { username, password } = req.body; + + // 3. 验证参数是否完整(基础校验,避免空值请求) + if (!username || !password) { + return res.status(400).json({ + code: 400, + msg: '用户名和密码不能为空' + }); + } + + // 3. 从数据库中查询该用户名对应的用户(Sequelize 方法,无需手写 SQL) + const user = await User.findOne({ + where: { username: username } // 条件:用户名匹配 + }); + + // 4. 判断用户是否存在 + if (!user) { + return res.status(401).json({ + code: 401, + msg: '用户名不存在' + }); + } + + // 5. 比对密码(当前入门阶段用明文比对,后续可优化加密) + if (user.password !== password) { + return res.status(401).json({ + code: 401, + msg: '密码错误' + }); + } + + // 6. 登录成功:返回用户信息(隐藏密码,避免泄露) + const { password: _, ...userInfo } = user.dataValues; // 解构删除密码字段 + return res.status(200).json({ + code: 200, + msg: '登录成功', + data: userInfo // 返回用户ID、用户名、邮箱等安全信息 + }); + + } catch (error) { + // 7. 捕获异常(如数据库错误) + return res.status(500).json({ + code: 500, + msg: '登录失败,服务器异常', + error: error.message + }); + } +}; + +// 导出登录方法,供路由调用 +module.exports = { login }; \ No newline at end of file diff --git a/models/User.js b/models/User.js new file mode 100644 index 0000000..7765148 --- /dev/null +++ b/models/User.js @@ -0,0 +1,57 @@ +const { DataTypes } = require('sequelize'); +// 导入数据库连接实例 +const { sequelize } = require('../config/db'); + +// 定义 User 模型(仅映射已手动创建的 users 表,不自动建表) +const User = sequelize.define('User', { + // 字段1:id(对应表中 id 字段,主键自增) + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true, + comment: '用户ID' + }, + // 字段2:username(对应表中 username 字段,非空唯一) + username: { + type: DataTypes.STRING(50), + allowNull: false, + unique: true, + comment: '用户名(登录用)' + }, + // 字段3:password(对应表中 password 字段,非空) + password: { + type: DataTypes.STRING(100), + allowNull: false, + comment: '用户密码' + }, + // 字段4:email(对应表中 email 字段,可选唯一) + email: { + type: DataTypes.STRING(100), + unique: true, + allowNull: true, + comment: '用户邮箱' + }, + // 字段5-6:createdAt/updatedAt(对应表中这两个字段,自动维护,无需手动赋值) + createdAt: { + type: DataTypes.DATE, + allowNull: false, + comment: '创建时间' + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + comment: '更新时间' + } +}, { + // 模型配置:关键是关闭自动建表相关逻辑,仅做表映射 + tableName: 'users', // 明确指定映射的表名(必须和手动创建的表名一致) + timestamps: true, // 开启自动维护 createdAt/updatedAt(表中已手动创建这两个字段) + paranoid: false, // 关闭软删除(和表结构匹配) + charset: 'utf8mb4', + collate: 'utf8mb4_unicode_ci', + freezeTableName: true, // 冻结表名,避免 Sequelize 自动给表名加复数(这里表名已手动设为 users,无需处理) + syncOnAssociation: false // 关闭关联自动同步(避免模型操作影响表结构) +}); + +// 导出模型,供控制器调用(后续登录接口查数据用) +module.exports = User; \ No newline at end of file diff --git a/package.json b/package.json index 7badd03..adaabe5 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,16 @@ { "name": "nodejs", "version": "1.0.0", - "main": "index.js", + "main": "server.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js", + "dev": "nodemon server.js" }, "keywords": [], "author": "YuLeYuan", "license": "ISC", - "description": "", + "description": "Node.js + Express + MySQL 全栈后端(含登录功能)", "dependencies": { "cors": "^2.8.6", "dotenv": "^17.2.4", @@ -20,4 +22,4 @@ "devDependencies": { "nodemon": "^3.1.11" } -} +} \ No newline at end of file diff --git a/routes/userRoutes.js b/routes/userRoutes.js new file mode 100644 index 0000000..67a7fa5 --- /dev/null +++ b/routes/userRoutes.js @@ -0,0 +1,13 @@ +// 导入 Express 路由模块 +const express = require('express'); +const router = express.Router(); // 创建路由实例 + +// 导入控制器中的登录方法 +const { login } = require('../controllers/userController'); + +// 定义登录接口:POST /api/login(前端通过这个路径调用登录) +// 为什么用 POST?因为登录参数(密码)放请求体里,比 GET 更安全 +router.post('/login', login); + +// 导出路由,供 app.js 挂载 +module.exports = router; \ No newline at end of file diff --git a/server.js b/server.js index e69de29..0a2c4df 100644 --- a/server.js +++ b/server.js @@ -0,0 +1,11 @@ +const app = require('./app'); +require('dotenv').config(); + +// 从.env读取端口,若没配置则用3000默认值 +const PORT = process.env.PORT || 3000; + +// 启动服务,监听指定端口 +app.listen(PORT, () => { + console.log(`后端服务已启动!地址:http://localhost:${PORT}`); + console.log(`登录接口地址:http://localhost:${PORT}/api/login`); +}); \ No newline at end of file