Ai编程从零开始全栈开发一个后台管理系统之接口开发node+express+mysql(十五)

云风网
云风笔记
云风知识库

打开cursor,新建文件夹api,输入对应的提示词

javascript 复制代码
在路径E:/web/cursor-project/node-project/api下

请为我开发一个基于 Node.js 和Express 框架的 用户注册登录模块管理后端项目。项目需要实现以下五个 RESTful API 接口:

1. 查询所有已注册用户
    - 接口名: GET /api/getUserList
    - 功能: 从数据库的'user'集合中查询并返回所有用户信息
    - 参数: 创建时间createTime、用户名username、是否黑名单用户isBlackList,参数可为空
    - 返回: 包含所有用户信息的数组
2. 注册新用户
    - 接口名: POST /api/register
    - 功能: 向'user'集合中添加新的用户名以及密码
    - 参数:
    {
     "username": string, // 用户名
     "password":string, // 密码
    }
    - 返回: 新用户信息对象,包含自动生成的唯一 id
3. 更新用户黑名单状态信息
    - 接口名: POST /api/updateUserBlackStatus/
    - 功能: 根据 id 更新用户黑名单状态
    - 参数: id
    - 返回: 更新后的用户信息
4. 删除用户
    - 接口名: POST /api/delUser/
    - 功能: 根据 id 删除指定用户
    - 参数: id
    - 返回: 删除操作的结果状态
5. 登录
    - 接口名: POST /api/login/
    - 功能: 根据 用户名查询校验匹配 user集合中是否包含该用户,用户名密码是否正确
   - 参数: username
    - 返回:登录匹配结果状态以及生成token
技术要求:

1. 使用 Express 框架构建 API,express-jwt校验token的有效性
2. 使用 mysql 作为数据库
3. 实现适当的错误处理和输入验证
4. 使用异步/等待(async/await)语法处理异步操作
5. 遵循 RESTful API 设计原则
6. 添加基本的日志记录功能
7、支持用户查询多参数过滤


以下是数据库连接方式:
username
xxx
password
xxx

外网地址

host
xxx
port
3306

这样cursor会自动生成项目结构以及具体代码

生成步骤如下

一、项目结构

二、项目配置package.json

javascript 复制代码
{
  "name": "user-management-api",
  "version": "1.0.0",
  "description": "User Management System API",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "dev": "node ./node_modules/nodemon/bin/nodemon.js -r dotenv/config server.js"
  },
  "dependencies": {
    "bcryptjs": "^2.4.3",
    "cors": "^2.8.5",
    "dotenv": "^16.0.3",
    "express": "^4.18.2",
    "express-jwt": "^8.4.1",
    "jsonwebtoken": "^9.0.0",
    "mysql2": "^3.6.5",
    "winston": "^3.8.2",
    "nodemon": "^2.0.22"
  }
} 

三、创建数据库配置文件 config/db.js

javascript 复制代码
const mysql = require('mysql2');
const logger = require('../utils/logger');

// 首先创建一个没有指定数据库的连接池
const initPool = mysql.createPool({
  host: process.env.DB_HOST || '47.98.167.203',
  user: process.env.DB_USER || 'root',
  password: process.env.DB_PASSWORD || 'nch123456',
  port: process.env.DB_PORT || 3306,
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
});

const initPromisePool = initPool.promise();

// 创建实际使用的连接池
const pool = mysql.createPool({
  host: process.env.DB_HOST || '外网地址',
  user: process.env.DB_USER || 'root',
  password: process.env.DB_PASSWORD || '密码',
  database: process.env.DB_NAME || 'user_management',
  port: process.env.DB_PORT || 3306,
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
});

// 创建promise包装
const promisePool = pool.promise();

// 初始化数据库和表
const initDB = async () => {
  try {
    // 首先创建数据库(如果不存在)
    await initPromisePool.query(`
      CREATE DATABASE IF NOT EXISTS ${process.env.DB_NAME || 'user_management'}
    `);
    
    logger.info('数据库创建成功或已存在');

    // 使用数据库
    await promisePool.query(`USE ${process.env.DB_NAME || 'user_management'}`);

    // 创建用户表
    await promisePool.query(`
      CREATE TABLE IF NOT EXISTS users (
        id INT AUTO_INCREMENT PRIMARY KEY,
        username VARCHAR(255) NOT NULL UNIQUE,
        password VARCHAR(255) NOT NULL,
        isBlackList BOOLEAN DEFAULT false,
        createTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
      )
    `);
    
    logger.info('数据库表初始化成功');
  } catch (error) {
    logger.error('数据库初始化失败:', error);
    throw error;
  } finally {
    // 关闭初始化连接池
    await initPromisePool.end();
  }
};

module.exports = {
  pool: promisePool,
  initDB
}; 

四、创建认证中间件 middleware/auth.js

javascript 复制代码
const { expressjwt: jwt } = require('express-jwt');

const auth = jwt({
  secret: process.env.JWT_SECRET || 'your-secret-key',
  algorithms: ['HS256']
});

module.exports = auth; 

五、创建用户控制器 controllers/userController.js

javascript 复制代码
const { pool } = require('../config/db');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const logger = require('../utils/logger');

// 获取用户列表
exports.getUserList = async (req, res) => {
  try {
    const { username, createTime, isBlackList } = req.query;
    let query = 'SELECT id, username, isBlackList, createTime FROM users WHERE 1=1';
    const params = [];

    if (username) {
      query += ' AND username LIKE ?';
      params.push(`%${username}%`);
    }
    if (createTime) {
      query += ' AND createTime >= ?';
      params.push(createTime);
    }
    if (isBlackList !== undefined) {
      query += ' AND isBlackList = ?';
      params.push(isBlackList === 'true');
    }

    const [users] = await pool.query(query, params);
    res.json({ success: true, data: users });
  } catch (error) {
    logger.error('获取用户列表失败:', error);
    res.status(500).json({ success: false, message: '获取用户列表失败' });
  }
};

// 注册新用户
exports.register = async (req, res) => {
  try {
    const { username, password } = req.body;

    if (!username || !password) {
      return res.status(400).json({ success: false, message: '用户名和密码不能为空' });
    }

    // 检查用户名是否已存在
    const [existing] = await pool.query('SELECT id FROM users WHERE username = ?', [username]);
    if (existing.length > 0) {
      return res.status(400).json({ success: false, message: '用户名已存在' });
    }

    // 加密密码
    const salt = await bcrypt.genSalt(10);
    const hashedPassword = await bcrypt.hash(password, salt);

    // 创建新用户
    const [result] = await pool.query(
      'INSERT INTO users (username, password) VALUES (?, ?)',
      [username, hashedPassword]
    );

    const token = jwt.sign(
      { id: result.insertId },
      process.env.JWT_SECRET || 'your-secret-key',
      { expiresIn: '30d' }
    );

    res.status(201).json({
      success: true,
      data: {
        id: result.insertId,
        username,
        token
      }
    });
  } catch (error) {
    logger.error('用户注册失败:', error);
    res.status(500).json({ success: false, message: '用户注册失败' });
  }
};

// 更新用户黑名单状态
exports.updateUserBlackStatus = async (req, res) => {
  try {
    const { id } = req.params;

    // 检查用户是否存在
    const [user] = await pool.query('SELECT isBlackList FROM users WHERE id = ?', [id]);
    if (user.length === 0) {
      return res.status(404).json({ success: false, message: '用户不存在' });
    }

    // 更新状态(取反)
    const newStatus = !user[0].isBlackList;
    await pool.query(
      'UPDATE users SET isBlackList = ? WHERE id = ?',
      [newStatus, id]
    );

    // 获取更新后的用户信息
    const [updatedUser] = await pool.query(
      'SELECT id, username, isBlackList, createTime FROM users WHERE id = ?',
      [id]
    );

    res.json({ success: true, data: updatedUser[0] });
  } catch (error) {
    logger.error('更新用户状态失败:', error);
    res.status(500).json({ success: false, message: '更新用户状态失败' });
  }
};

// 删除用户
exports.delUser = async (req, res) => {
  try {
    const { id } = req.params;

    const [result] = await pool.query('DELETE FROM users WHERE id = ?', [id]);

    if (result.affectedRows === 0) {
      return res.status(404).json({ success: false, message: '用户不存在' });
    }

    res.json({ success: true, message: '用户删除成功' });
  } catch (error) {
    logger.error('删除用户失败:', error);
    res.status(500).json({ success: false, message: '删除用户失败' });
  }
};

// 用户登录
exports.login = async (req, res) => {
  try {
    const { username, password } = req.body;

    // 查找用户
    const [users] = await pool.query('SELECT * FROM users WHERE username = ?', [username]);
    if (users.length === 0) {
      return res.status(401).json({ success: false, message: '用户名或密码错误' });
    }

    const user = users[0];

    // 检查是否被封禁
    if (user.isBlackList) {
      return res.status(403).json({ success: false, message: '账户已被封禁' });
    }

    // 验证密码
    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) {
      return res.status(401).json({ success: false, message: '用户名或密码错误' });
    }

    // 生成token
    const token = jwt.sign(
      { id: user.id },
      process.env.JWT_SECRET || 'your-secret-key',
      { expiresIn: '30d' }
    );

    res.json({
      success: true,
      data: {
        id: user.id,
        username: user.username,
        token
      }
    });
  } catch (error) {
    logger.error('用户登录失败:', error);
    res.status(500).json({ success: false, message: '登录失败' });
  }
}; 

六、创建路由文件 routes/userRoutes.js

javascript 复制代码
const express = require('express');
const router = express.Router();
const auth = require('../middleware/auth');
const {
  getUserList,
  register,
  updateUserBlackStatus,
  delUser,
  login
} = require('../controllers/userController');

router.get('/getUserList', auth, getUserList);
router.post('/register', register);
router.post('/updateUserBlackStatus/:id', auth, updateUserBlackStatus);
router.post('/delUser/:id', auth, delUser);
router.post('/login', login);

module.exports = router; 

七、创建主服务器文件 server.js

javascript 复制代码
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const { initDB } = require('./config/db');
const userRoutes = require('./routes/userRoutes');
const logger = require('./utils/logger');

const app = express();

// 中间件
app.use(cors());
app.use(express.json());

// 添加请求日志中间件
app.use((req, res, next) => {
  logger.info(`${req.method} ${req.url}`);
  next();
});

// 初始化数据库
initDB().catch(err => {
  logger.error('数据库初始化失败:', err);
  process.exit(1);
});

// 路由
app.use('/api', userRoutes);

// 错误处理
app.use((err, req, res, next) => {
  logger.error('错误:', err.stack);
  if (err.name === 'UnauthorizedError') {
    return res.status(401).json({ success: false, message: '无效的token' });
  }
  res.status(500).json({ success: false, message: '服务器内部错误' });
});

const PORT = process.env.PORT || 8090;

// 修改监听配置,允许所有IP访问
app.listen(PORT, '0.0.0.0', () => {
  logger.info(`服务器运行在端口 ${PORT}`);
  logger.info(`环境变量: ${JSON.stringify(process.env, null, 2)}`);
});

// 优雅退出
process.on('SIGINT', async () => {
  logger.info('正在关闭服务器...');
  process.exit(0);
}); 

八、创建环境变量文件 .env

javascript 复制代码
DB_HOST=xxx
DB_USER=xxx
DB_PASSWORD=xxx
DB_NAME=user_management
DB_PORT=3306
PORT=8090
JWT_SECRET=xxx

九、创建日志工具 utils/logger.js

javascript 复制代码
const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
});

if (process.env.NODE_ENV !== 'production') {
  logger.add(new winston.transports.Console({
    format: winston.format.combine(
      winston.format.colorize(),
      winston.format.simple()
    )
  }));
}

module.exports = logger; 

十、安装依赖,启动服务

javascript 复制代码
cd api
npm install
npm run dev

十一、测试用例

再次输入提示词,进行测试用例编写

javascript 复制代码
请帮我用curl生成这5个接口测试用例以及接口成功和不成功的返回值





测试步骤:
  • 先注册一个用户
  • 使用注册返回的token替换后续请求中的 YOUR_TOKEN_HERE
  • 测试登录功能
  • 使用token测试获取用户列表
  • 测试更新用户状态
  • 最后测试删除用户
注意事项:
  • 所有需要认证的接口都需要在请求头中加入 token
  • token 格式为 "Bearer " + 实际的token字符串
  • 参数查询时可以组合使用多个条件
  • 密码在传输和存储时都是加密的
  • 被加入黑名单的用户无法登录

十二、测试验证

1、注册


2、登录
3、获取用户列表
4、更新用户黑名单状态
5、删除用户

至此整个增删改查用户管理流程顺利测试完成,全程手动输入两次提示词,配置数据库信息,其他代码都由Ai自动生成完成。

相关推荐
就是蠢啊13 分钟前
SpringBoot 基础知识,HTTP 概述
数据库·mysql·spring
Captaincc2 小时前
Gemini 大模型逆袭,给了 Google Cloud「AI 基建」的勇气
ai编程
玲小珑2 小时前
LLMOps开发(三) RAG
langchain·node.js·ai编程
seeyoutlb3 小时前
bash脚本手动清空mysql表数据
mysql·adb·bash
Loving_enjoy3 小时前
从响应式编程到未来架构革命:解锁高并发时代的底层思维范式
python·ai编程
Goboy5 小时前
老婆问我:“什么是大模型的‘微调’?”
llm·aigc·ai编程
Goboy5 小时前
老婆问我:“什么是大模型的‘预训练’?”
llm·aigc·ai编程
Fancier__5 小时前
Redis 缓存 + MySql 持久化 实现点赞服务
redis·mysql·缓存·增量同步·点赞
SmallFatMan6 小时前
智能客服系统中的意图识别与分类技术详解
大数据·人工智能·ai·数据挖掘·ai编程
Dav_209914 小时前
dav_1_MySQL数据库排查cpu消耗高的sql
数据库·sql·mysql