feat: 添加用户登录功能及基础服务架构

- 新增 Express 应用入口文件 app.js,包含 CORS 配置、中间件设置、
  数据库连接测试、路由挂载和全局错误处理
- 实现用户登录控制器,支持用户名密码验证和登录逻辑处理
- 创建 User 模型定义,映射数据库 users 表结构
- 配置用户路由模块,提供 /api/login 接口
- 更新 package.json 添加启动脚本和项目描述
- 新增服务启动文件 server.js,支持环境变量配置端口
```
master
Lmx 2 weeks ago
parent 8a8469a59c
commit de281a2106

@ -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;

@ -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 };

@ -0,0 +1,57 @@
const { DataTypes } = require('sequelize');
// 导入数据库连接实例
const { sequelize } = require('../config/db');
// 定义 User 模型(仅映射已手动创建的 users 表,不自动建表)
const User = sequelize.define('User', {
// 字段1id对应表中 id 字段,主键自增)
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
comment: '用户ID'
},
// 字段2username对应表中 username 字段,非空唯一)
username: {
type: DataTypes.STRING(50),
allowNull: false,
unique: true,
comment: '用户名(登录用)'
},
// 字段3password对应表中 password 字段,非空)
password: {
type: DataTypes.STRING(100),
allowNull: false,
comment: '用户密码'
},
// 字段4email对应表中 email 字段,可选唯一)
email: {
type: DataTypes.STRING(100),
unique: true,
allowNull: true,
comment: '用户邮箱'
},
// 字段5-6createdAt/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;

@ -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"
}
}
}

@ -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;

@ -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`);
});
Loading…
Cancel
Save