Files
autoAiWorkSys/_doc/framework_使用文档.md
张成 5d7444cd65 1
2025-11-24 13:23:42 +08:00

32 KiB
Raw Blame History

Node Core Framework 使用说明

📋 概述

node-core-framework.js 是一个基于 Koa2 + Sequelize + MySQL 的企业级 Node.js 后端框架,提供了完整的 MVC 架构、数据库管理、API 文档生成、权限验证等功能。

🚀 快速开始

1. 环境要求

  • Node.js: >= 16.0.0
  • MySQL: >= 5.7
  • Redis: >= 5.0 (可选,用于缓存)

2. 安装依赖

# 安装核心依赖
npm install koa koa-body koa-router koa-static koa2-cors koa2-swagger-ui
npm install sequelize mysql2 redis jsonwebtoken dayjs swagger-jsdoc

3. 基础使用

// app.js
const Framework = require('./dist/node-core-framework.js');

// 配置文件
const config = {
  // 数据库配置
  db: {
    username: "your_username",
    password: "your_password", 
    database: "your_database",
    host: "localhost",
    port: 3306,
    dialect: "mysql",
    timezone: '+08:00'
  },
  
  // Redis配置可选
  redis: {
    host: 'localhost',
    port: 6379,
    password: '',
    db: 0
  },
  
  // 日志路径
  logPath: './logs',
  
  // 基础URL
  baseUrl: 'http://localhost:3001',
  
  // API路径配置
  apiPaths: [
    { 
      path: './controllers', 
      prefix: '/api', 
      authType: 'applet' 
    }
  ],
  
  // 模型路径
  modelPaths: './models',
  
  // 允许的URL无需认证
  allowUrls: [
    '/api/users/login',
    '/api/health',
    '/api/docs'
  ],
  
  // 授权文件路径
  license: {
    licensePath: './license.lic'
  }
};

// 启动应用
async function startApp() {
  try {
    // 创建框架实例
    const framework = await Framework.init(config);
    
    // 启动服务器
    const server = await framework.start(3001);
    
    console.log('🎉 应用启动成功!');
    console.log(`📚 API 文档: http://localhost:3001/api/docs`);
    
    // 使用日志服务
    const logsService = Framework.getServices().logsService;
    logsService.log('应用启动成功', { port: 3001, time: new Date() });
    
  } catch (error) {
    console.error('❌ 启动失败:', error);
    
    // 记录启动错误
    const logsService = Framework.getServices().logsService;
    logsService.error('应用启动失败', error);
  }
}

startApp();

🏗️ 框架架构

核心组件

  1. Framework: 主框架类,负责整体协调
  2. ModelManager: 数据库模型管理器
  3. ServiceManager: 服务层管理器
  4. RequestManager: 请求处理器管理器
  5. RegistrationService: 授权验证服务

目录结构

project/
├── dist/
│   └── node-core-framework.js    # 打包后的框架文件
├── controllers/                   # 控制器目录
│   ├── user_controller.js
│   ├── article_controller.js
│   └── admin/
│       ├── sys_user.js          # 系统用户管理
│       └── sys_log.js           # 日志管理接口
├── models/                       # 数据模型目录
│   ├── user.js
│   └── article.js
├── config.js                     # 配置文件
├── app.js                        # 应用入口
└── logs/                         # 日志目录
    ├── log_2024.01.15.log        # 普通日志文件
    ├── logError_2024.01.15.log   # 错误日志文件
    └── log_2024.01.15_1.log      # 分割后的日志文件

📝 详细配置说明

数据库配置

const config = {
  db: {
    username: "root",              // 数据库用户名
    password: "password",          // 数据库密码
    database: "myapp",             // 数据库名
    host: "localhost",             // 数据库主机
    port: 3306,                   // 数据库端口
    dialect: "mysql",             // 数据库类型
    timezone: '+08:00',           // 时区
    pool: {                       // 连接池配置
      max: 10,                    // 最大连接数
      min: 0,                    // 最小连接数
      acquire: 30000,            // 获取连接超时时间
      idle: 10000               // 连接空闲时间
    },
    logging: true                 // 是否打印SQL日志
  }
};

API路径配置

const config = {
  apiPaths: [
    {
      path: './controllers',        // 控制器目录路径
      prefix: '/api',              // API前缀
      authType: 'applet'           // 认证类型applet | admin
    },
    {
      path: './controllers_admin', // 管理端控制器
      prefix: '/admin_api',        // 管理端API前缀
      authType: 'admin'
    }
  ]
};

权限配置

const config = {
  // 允许的URL无需认证
  allowUrls: [
    '/api/users/login',           // 登录接口
    '/api/users/register',       // 注册接口
    '/api/health',               // 健康检查
    '/api/docs',                 // API文档
    '/api/swagger.json'          // Swagger配置
  ],
  
  // 授权文件路径
  license: {
    licensePath: './license.lic'
  }
};

🎯 控制器开发

基础控制器结构

// controllers/user_controller.js
const { models } = require('../database/db');

module.exports = {
  /**
   * @swagger
   * /api/users:
   *   get:
   *     summary: 获取用户列表
   *     description: 分页获取用户列表
   *     tags:
   *       - 用户管理
   *     parameters:
   *       - in: query
   *         name: page
   *         schema:
   *           type: integer
   *           default: 1
   *         description: 页码
   *       - in: query
   *         name: pageSize
   *         schema:
   *           type: integer
   *           default: 20
   *         description: 每页数量
   *     responses:
   *       200:
   *         description: 获取成功
   */
  "GET /users": async (ctx) => {
    const { user: UserModel } = models;
    
    // 获取分页参数
    const { limit, offset } = ctx.getPageSize();
    
    // 查询用户列表
    const users = await UserModel.findAndCountAll({
      attributes: ['id', 'username', 'email', 'status', 'create_time'],
      limit,
      offset,
      order: [['create_time', 'DESC']]
    });
    
    // 返回成功响应
    ctx.success(users, '获取用户列表成功');
  },

  /**
   * @swagger
   * /api/users:
   *   post:
   *     summary: 创建用户
   *     description: 创建新用户
   *     tags:
   *       - 用户管理
   *     requestBody:
   *       required: true
   *       content:
   *         application/json:
   *           schema:
   *             type: object
   *             required:
   *               - username
   *               - email
   *               - password
   *             properties:
   *               username:
   *                 type: string
   *                 description: 用户名
   *               email:
   *                 type: string
   *                 format: email
   *                 description: 邮箱
   *               password:
   *                 type: string
   *                 description: 密码
   *     responses:
   *       200:
   *         description: 创建成功
   */
  "POST /users": async (ctx) => {
    const { user: UserModel } = models;
    const { username, email, password } = ctx.getBody();
    
    // 参数验证
    if (!username || !email || !password) {
      return ctx.fail('用户名、邮箱和密码不能为空');
    }
    
    // 检查邮箱是否已存在
    const existingUser = await UserModel.findOne({ where: { email } });
    if (existingUser) {
      return ctx.fail('邮箱已存在');
    }
    
    // 创建用户
    const newUser = await UserModel.create({
      username,
      email,
      password,
      status: 1
    });
    
    ctx.success({
      id: newUser.id,
      username: newUser.username,
      email: newUser.email
    }, '用户创建成功');
  }
};

控制器方法说明

请求方法格式

框架支持 GETPOST 两种请求方法,推荐统一使用 POST 请求

  • "POST /users": POST 请求(推荐)

    • 参数通过请求体传递:{ id: 123, username: "张三", pageOption: { page: 1, pageSize: 20 } }
    • 适用场景:所有接口(查询、创建、更新、删除等)
    • 优点:参数传递统一、支持复杂数据结构、更安全
  • "GET /users": GET 请求(不推荐)

    • 参数通过查询字符串传递:?id=123&status=1
    • 仅在简单查询场景下使用

上下文方法

// 获取请求体数据
const body = ctx.getBody();

// 获取查询参数
const query = ctx.getQuery();

// 获取分页参数(从前端的 pageOption 中获取 page 和 pageSize
// 前端发送格式:{ pageOption: { page: 1, pageSize: 20 } }
// 返回值:{ limit: 20, offset: 0 }
const { limit, offset } = ctx.getPageSize();

// 成功响应
ctx.success(data, message);

// 失败响应
ctx.fail(message, code);

🗄️ 数据模型开发

模型定义

// models/user.js
const Sequelize = require('sequelize');

module.exports = (db) => {
  return db.define("user", {
    id: {
      type: Sequelize.INTEGER,
      primaryKey: true,
      autoIncrement: true,
      comment: "用户ID"
    },
    username: {
      type: Sequelize.STRING(50),
      allowNull: false,
      comment: "用户名"
    },
    email: {
      type: Sequelize.STRING(100),
      allowNull: false,
      unique: true,
      comment: "邮箱"
    },
    password: {
      type: Sequelize.STRING(255),
      allowNull: false,
      comment: "密码"
    },
    avatar: {
      type: Sequelize.STRING(255),
      comment: "头像URL"
    },
    status: {
      type: Sequelize.INTEGER,
      defaultValue: 1,
      comment: "状态0-禁用1-启用"
    }
  });
};

模型关联

// 在启动文件中定义关联关系
const businessAssociations = (models) => {
  // 用户和文章的一对多关系
  if (models.user && models.article) {
    models.user.hasMany(models.article, {
      foreignKey: 'author_id',
      as: 'articles',
      constraints: false  // 不创建外键约束
    });

    models.article.belongsTo(models.user, {
      foreignKey: 'author_id',
      as: 'author',
      constraints: false
    });
  }
};

// 在框架初始化时传入
const framework = await Framework.init({
  // ... 其他配置
  businessAssociations: businessAssociations
});

🔐 权限验证

Token 验证

框架支持两种认证类型:

  • applet: 小程序端认证
  • admin: 管理端认证

认证中间件

// 在控制器中获取当前用户
"POST /profile": async (ctx) => {
  // 获取当前登录用户信息
  const currentUser = ctx.state.user;

  if (!currentUser) {
    return ctx.fail('未登录', 401);
  }

  ctx.success(currentUser, '获取用户信息成功');
}

📊 API 文档

Swagger 配置

框架自动生成 API 文档,访问地址:http://localhost:3001/api/docs

自定义 Schema

const config = {
  customSchemas: {
    "User": {
      "type": "object",
      "properties": {
        "id": {
          "type": "integer",
          "description": "用户ID"
        },
        "username": {
          "type": "string",
          "description": "用户名"
        },
        "email": {
          "type": "string",
          "format": "email",
          "description": "邮箱"
        }
      }
    }
  }
};

🚀 部署配置

生产环境配置

const config = {
  env: 'production',
  
  db: {
    // 生产数据库配置
    username: process.env.DB_USERNAME,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_DATABASE,
    host: process.env.DB_HOST,
    port: process.env.DB_PORT,
    dialect: "mysql",
    logging: false  // 生产环境关闭SQL日志
  },
  
  redis: {
    host: process.env.REDIS_HOST,
    port: process.env.REDIS_PORT,
    password: process.env.REDIS_PASSWORD
  },
  
  server: {
    port: process.env.PORT || 3001,
    host: '0.0.0.0'
  }
};

PM2 部署

// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'myapp',
    script: 'app.js',
    instances: 'max',
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'production',
      PORT: 3001
    }
  }]
};
# 启动应用
pm2 start ecosystem.config.js

# 查看状态
pm2 status

# 查看日志
pm2 logs myapp

🔧 常用功能

日志服务

框架内置了完整的日志服务,支持普通日志、错误日志和请求日志记录。

获取日志服务

// 在控制器中获取日志服务
const Framework = require('./dist/node-core-framework.js');
const logsService = Framework.getServices().logsService;



#### 基本日志记录

```javascript
// 普通日志
logsService.log('用户登录成功', { userId: 123, username: 'admin' });
logsService.log('数据更新完成', '用户信息已更新');

// 错误日志
try {
  // 业务逻辑
  throw new Error('数据库连接失败');
} catch (error) {
  logsService.error('数据库操作失败', error);
}

// 上下文错误日志(包含请求信息)
logsService.ctxError(error, ctx);

日志文件管理

// 日志文件自动管理
// - 按日期分割log_2024.01.15.log
// - 错误日志logError_2024.01.15.log
// - 文件大小超过5MB自动分割log_2024.01.15_1.log
// - 自动创建日志目录

日志API接口

框架提供了日志管理的API接口

// 获取所有日志文件列表
GET /admin_api/sys_log/all

// 查看日志文件内容
GET /admin_api/sys_log/detail?title=log_2024.01.15.log

// 删除指定日志文件
GET /admin_api/sys_log/delete?title=log_2024.01.15.log

// 删除所有日志文件
GET /admin_api/sys_log/delete_all

日志配置

const config = {
  // 日志目录配置
  logPath: './logs',  // 相对路径,基于项目根目录
  
  // 其他配置...
};

// 日志目录结构
// project/
// ├── logs/
// │   ├── log_2024.01.15.log          # 普通日志
// │   ├── logError_2024.01.15.log     # 错误日志
// │   └── log_2024.01.15_1.log        # 分割后的日志

实际使用示例

// controller/user.js
const Framework = require('../framework');
const logsService = Framework.getServices().logsService;

module.exports = {
  "POST /login": async (ctx) => {
    try {
      const { username, password } = ctx.getBody();
      
      // 记录登录尝试
      logsService.log('用户登录尝试', { username, ip: ctx.ip });
      
      // 验证用户
      const user = await UserModel.findOne({ where: { username } });
      
      if (!user) {
        logsService.log('登录失败:用户不存在', { username });
        return ctx.fail('用户名或密码错误');
      }
      
      // 验证密码
      const isValid = await bcrypt.compare(password, user.password);
      
      if (!isValid) {
        logsService.log('登录失败:密码错误', { username });
        return ctx.fail('用户名或密码错误');
      }
      
      // 登录成功
      logsService.log('用户登录成功', { 
        userId: user.id, 
        username: user.username,
        ip: ctx.ip 
      });
      
      ctx.success({ token: generateToken(user) }, '登录成功');
      
    } catch (error) {
      // 记录系统错误
      logsService.ctxError(error, ctx);
      ctx.fail('登录失败,请稍后重试');
    }
  }
};

Token服务

框架内置了JWT Token服务支持Token生成、验证、解析和微信数据解密。

获取Token服务

// 在控制器中获取Token服务
const Framework = require('./dist/node-core-framework.js');
const tokenService = Framework.getServices().tokenService;

// 或者通过框架实例获取
const framework = await Framework.init(config);
const tokenService = Framework.getServices().tokenService;

基本Token操作

// 创建Token
const userInfo = { id: 123, username: 'admin', role: 'admin' };
const token = tokenService.create(userInfo);

// 解析Token获取用户信息
const userData = tokenService.parse(token);
console.log(userData); // { id: 123, username: 'admin', role: 'admin' }

// 验证Token检查是否有效
const isValid = tokenService.verify(token);
console.log(isValid); // true 或 false

微信数据解密

// 解密微信小程序数据
const encryptedData = 'encrypted_data_from_wechat';
const sessionKey = 'session_key_from_wechat';
const iv = 'iv_from_wechat';

const decryptedData = tokenService.decryptWxData(encryptedData, sessionKey, iv);
console.log(decryptedData); // 解密后的用户信息

MD5加密

// MD5加密
const password = '123456';
const encryptedPassword = tokenService.getMd5(password);
console.log(encryptedPassword); // e10adc3949ba59abbe56e057f20f883e

实际使用示例

// controller/auth.js
const Framework = require('../framework');
const tokenService = Framework.getServices().tokenService;

module.exports = {
  "POST /login": async (ctx) => {
    try {
      const { username, password } = ctx.getBody();
      
      // 验证用户
      const user = await UserModel.findOne({ where: { username } });
      if (!user) {
        return ctx.fail('用户不存在');
      }
      
      // 验证密码
      const isValidPassword = await bcrypt.compare(password, user.password);
      if (!isValidPassword) {
        return ctx.fail('密码错误');
      }
      
      // 生成Token
      const userInfo = {
        id: user.id,
        username: user.username,
        role: user.role
      };
      const token = tokenService.create(userInfo);
      
      ctx.success({ token, user: userInfo }, '登录成功');
      
    } catch (error) {
      ctx.fail('登录失败');
    }
  },
  
  "POST /verify": async (ctx) => {
    const { token } = ctx.getBody();

    if (!token) {
      return ctx.fail('缺少Token');
    }

    const userData = tokenService.parse(token);
    if (!userData) {
      return ctx.fail('Token无效');
    }

    ctx.success(userData, 'Token验证成功');
  }
};

Redis服务

框架内置了Redis缓存服务支持数据缓存、分布式锁等功能。

获取Redis服务

// 在控制器中获取Redis服务
const Framework = require('./dist/node-core-framework.js');
const redisService = Framework.getServices().redisService;

// 或者通过框架实例获取
const framework = await Framework.init(config);
const redisService = Framework.getServices().redisService;

基本缓存操作

// 设置缓存默认12小时过期
await redisService.set('user:123', JSON.stringify({ name: '张三', age: 25 }));

// 设置缓存(自定义过期时间,单位:秒)
await redisService.set('session:abc', 'session_data', 3600); // 1小时

// 获取缓存
const userData = await redisService.get('user:123');
console.log(JSON.parse(userData)); // { name: '张三', age: 25 }

// 删除缓存
await redisService.del('user:123');

原子操作

// 原子设置仅当key不存在时设置
const success = await redisService.setIfAbsent('lock:order:123', 'locked', 300);
if (success) {
  console.log('获取锁成功');
  // 执行业务逻辑
  await redisService.del('lock:order:123'); // 释放锁
} else {
  console.log('获取锁失败,资源被占用');
}

连接状态管理

// 检查Redis连接状态
const isConnected = redisService.isConnected();
console.log('Redis连接状态:', isConnected);

// 手动重连
redisService.reconnect();

// 关闭连接
redisService.close();

实际使用示例

// controller/cache.js
const Framework = require('../framework');
const redisService = Framework.getServices().redisService;

module.exports = {
  "POST /cache/user/detail": async (ctx) => {
    const { id } = ctx.getBody();  // 从请求体获取 id

    if (!id) {
      return ctx.fail('用户ID不能为空');
    }

    const cacheKey = `user:${id}`;

    try {
      // 先尝试从缓存获取
      let userData = await redisService.get(cacheKey);

      if (userData) {
        // 缓存命中
        console.log('从缓存获取用户数据');
        return ctx.success(JSON.parse(userData));
      }

      // 缓存未命中,从数据库获取
      const user = await UserModel.findByPk(id);
      if (!user) {
        return ctx.fail('用户不存在');
      }

      // 存入缓存1小时过期
      await redisService.set(cacheKey, JSON.stringify(user.toJSON()), 3600);

      ctx.success(user);

    } catch (error) {
      ctx.fail('获取用户信息失败');
    }
  },
  
  "POST /cache/clear": async (ctx) => {
    const { pattern } = ctx.getBody();
    
    // 清除指定模式的缓存
    // 注意:这里需要根据实际需求实现模式匹配删除
    await redisService.del(pattern);
    
    ctx.success(null, '缓存清除成功');
  }
};

Swagger服务

框架内置了Swagger API文档服务支持自动生成API文档和Schema。

获取Swagger服务

// 在控制器中获取Swagger服务
const Framework = require('./dist/node-core-framework.js');
const swaggerService = Framework.getServices().createSwaggerService();

// 或者通过框架实例获取
const framework = await Framework.init(config);
const swaggerService = Framework.getServices().createSwaggerService();

生成API文档

// 生成Swagger规范
const swaggerSpec = swaggerService.generateSpecs(req, res);

// 获取Swagger配置
const swaggerConfig = swaggerService.generateSwaggerConfig(req, res);

// 获取Swagger选项
const swaggerOptions = swaggerService.getSwaggerOptions();

安全配置管理

// 获取当前安全配置
const securityConfig = swaggerService.getCurrentSecurityConfig(req, res);

// 更新安全配置
const newConfig = [
  { 'admin-token': [] },
  { 'applet-token': [] }
];
const result = swaggerService.updateSecurityConfig(req, res, newConfig);

// 清除安全配置
swaggerService.clearSecurityConfigCookie(res);

实际使用示例

// controller/docs.js
const Framework = require('../framework');

module.exports = {
  "POST /api-docs": async (ctx) => {
    const swaggerService = Framework.getServices().createSwaggerService();

    // 生成Swagger规范
    const swaggerSpec = swaggerService.generateSpecs(ctx.request, ctx.response);

    ctx.response.type = 'application/json';
    ctx.response.body = swaggerSpec;
  },

  "POST /swagger-ui": async (ctx) => {
    // 返回Swagger UI页面
    const swaggerUIManager = Framework.getSwaggerUIManager();
    const html = swaggerUIManager.getSwaggerUIHTML();

    ctx.response.type = 'text/html';
    ctx.response.body = html;
  }
};

平台项目服务

框架内置了平台项目服务,支持与外部平台的交互。

获取平台项目服务

// 在控制器中获取平台项目服务
const Framework = require('./dist/node-core-framework.js');
const platformService = Framework.getServices().platformProjectService;

// 或者通过框架实例获取
const framework = await Framework.init(config);
const platformService = Framework.getServices().platformProjectService;

基本平台操作

// 获取所有模型
const models = await platformService.modelAll();

// 生成表单
const formData = await platformService.formGenerate({ id: 'form_id' });

// 创建表单
const createResult = await platformService.createForm({
  name: '用户表单',
  fields: ['name', 'email', 'phone']
});

// 更新表单
const updateResult = await platformService.updateForm({
  id: 'form_id',
  name: '更新后的表单'
});

// 删除表单
const deleteResult = await platformService.delteForm({ id: 'form_id' });

// 重新生成模型
const modelResult = await platformService.modelGenerate({ id: 'model_id' });

文件下载

// 下载平台文件
const downloadResult = await platformService.downloadPlatformFile('/path/to/file');

实际使用示例

// controller/platform.js
const Framework = require('../framework');
const platformService = Framework.getServices().platformProjectService;

module.exports = {
  "POST /platform/models": async (ctx) => {
    try {
      const models = await platformService.modelAll();
      ctx.success(models);
    } catch (error) {
      ctx.fail('获取模型列表失败');
    }
  },

  "POST /platform/form": async (ctx) => {
    try {
      const formData = ctx.getBody();
      const result = await platformService.createForm(formData);
      ctx.success(result, '表单创建成功');
    } catch (error) {
      ctx.fail('表单创建失败');
    }
  }
};

HTTP服务

框架内置了HTTP请求服务支持各种HTTP请求方法。

获取HTTP服务

// 直接引入HTTP服务
const { postPlatformUrl, downloadPlatformFile, post, get } = require('./services/http');

基本HTTP操作

// GET请求
const getData = await get('https://api.example.com/users', { page: 1, limit: 10 });

// POST请求
const postData = await post('https://api.example.com/users', {
  name: '张三',
  email: 'zhangsan@example.com'
});

// POST表单数据
const formData = await postFormData('https://api.example.com/upload', {
  file: 'file_content',
  name: 'filename.jpg'
});

平台API调用

// 调用平台API
const platformData = await postPlatformUrl('/form/generate', { id: 'form_id' });

// 下载平台文件
await downloadPlatformFile('/path/to/file', './local/path/file');

实际使用示例

// controller/external.js
const { post, get } = require('../services/http');

module.exports = {
  "POST /external/users": async (ctx) => {
    try {
      // 调用外部API
      const users = await get('https://jsonplaceholder.typicode.com/users');
      ctx.success(users);
    } catch (error) {
      ctx.fail('获取外部数据失败');
    }
  },

  "POST /external/sync": async (ctx) => {
    try {
      const { data } = ctx.getBody();

      // 同步数据到外部系统
      const result = await post('https://api.external.com/sync', data);

      ctx.success(result, '数据同步成功');
    } catch (error) {
      ctx.fail('数据同步失败');
    }
  }
};

分页查询

框架提供了 ctx.getPageSize() 方法来获取分页参数。

前端发送格式:

// 方式1: 通过 POST 请求体发送
{
  pageOption: {
    page: 1,      // 页码从1开始
    pageSize: 20  // 每页数量
  }
}

// 方式2: 通过 GET 查询参数发送
// GET /api/users?pageOption[page]=1&pageOption[pageSize]=20

后端使用示例:

"POST /users/list": async (ctx) => {
  // ctx.getPageSize() 从前端的 pageOption 中获取 page 和 pageSize
  // 返回值:{ limit: 20, offset: 0 }
  // limit: 每页数量 (pageSize)
  // offset: 跳过的记录数 ((page - 1) * pageSize)
  const { limit, offset } = ctx.getPageSize();
  const { username, status } = ctx.getBody();  // 从请求体获取查询条件

  // 构建查询条件
  const where = {};
  if (username) {
    where.username = { [Op.like]: `%${username}%` };
  }
  if (status !== undefined) {
    where.status = status;
  }

  const users = await UserModel.findAndCountAll({
    where,
    limit,
    offset,
    order: [['create_time', 'DESC']]
  });

  ctx.success(users, '获取用户列表成功');
}

文件上传

"POST /upload": async (ctx) => {
  const file = ctx.request.files.file;
  
  if (!file) {
    return ctx.fail('请选择文件');
  }
  
  // 处理文件上传逻辑
  const fileName = `${Date.now()}_${file.name}`;
  const filePath = `./upload/${fileName}`;
  
  // 保存文件
  const fs = require('fs');
  fs.writeFileSync(filePath, file.buffer);
  
  ctx.success({
    fileName,
    filePath,
    size: file.size
  }, '文件上传成功');
}

错误处理

// 全局错误处理
framework.app.on('error', (err, ctx) => {
  console.error('服务器错误:', err);
  
  // 记录错误日志
  const logger = require('./services/logs');
  logger.error('服务器错误', {
    error: err.message,
    stack: err.stack,
    url: ctx.url,
    method: ctx.method
  });
});

📝 最佳实践

1. 控制器设计

// 好的实践:统一使用 POST 请求,清晰的路由命名
module.exports = {
  "POST /users/list": getUserList,       // 获取用户列表
  "POST /users/detail": getUserDetail,   // 获取用户详情
  "POST /users/create": createUser,      // 创建用户
  "POST /users/update": updateUser,      // 更新用户
  "POST /users/delete": deleteUser       // 删除用户
};

// 查询列表示例:支持分页和条件查询
async function getUserList(ctx) {
  const { limit, offset } = ctx.getPageSize();  // 从 pageOption 获取分页参数
  const { username, status } = ctx.getBody();   // 从请求体获取查询条件

  // 构建查询条件
  const where = {};
  if (username) {
    where.username = { [Op.like]: `%${username}%` };
  }
  if (status !== undefined) {
    where.status = status;
  }

  const users = await UserModel.findAndCountAll({
    where,
    limit,
    offset,
    order: [['create_time', 'DESC']]
  });

  ctx.success(users, '获取用户列表成功');
}

// 查询详情示例
async function getUserDetail(ctx) {
  const { id } = ctx.getBody();  // 从请求体获取 id

  if (!id) {
    return ctx.fail('用户ID不能为空');
  }

  const user = await UserModel.findByPk(id);
  if (!user) {
    return ctx.fail('用户不存在');
  }

  ctx.success(user, '获取成功');
}

// 创建示例
async function createUser(ctx) {
  const { username, email, password } = ctx.getBody();

  if (!username || !email || !password) {
    return ctx.fail('用户名、邮箱和密码不能为空');
  }

  const newUser = await UserModel.create({ username, email, password });
  ctx.success(newUser, '创建成功');
}

// 更新示例
async function updateUser(ctx) {
  const { id, username, email } = ctx.getBody();

  if (!id) {
    return ctx.fail('用户ID不能为空');
  }

  await UserModel.update({ username, email }, { where: { id } });
  ctx.success(null, '更新成功');
}

// 删除示例
async function deleteUser(ctx) {
  const { id } = ctx.getBody();

  if (!id) {
    return ctx.fail('用户ID不能为空');
  }

  await UserModel.destroy({ where: { id } });
  ctx.success(null, '删除成功');
}

2. 数据验证

// 好的实践:参数验证
"POST /users": async (ctx) => {
  const { username, email, password } = ctx.getBody();
  
  // 参数验证
  if (!username || !email || !password) {
    return ctx.fail('用户名、邮箱和密码不能为空');
  }
  
  // 邮箱格式验证
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRegex.test(email)) {
    return ctx.fail('邮箱格式不正确');
  }
  
  // 业务逻辑...
}

3. 错误处理

// 好的实践:统一的错误处理
"POST /users": async (ctx) => {
  try {
    const { username, email, password } = ctx.getBody();
    
    // 验证参数
    validateUserInput({ username, email, password });
    
    // 检查用户是否存在
    await checkUserExists(email);
    
    // 创建用户
    const user = await createUser({ username, email, password });
    
    ctx.success(user, '用户创建成功');
    
  } catch (error) {
    // 统一错误处理
    if (error.code === 'VALIDATION_ERROR') {
      return ctx.fail(error.message, 400);
    }
    
    if (error.code === 'USER_EXISTS') {
      return ctx.fail(error.message, 409);
    }
    
    // 未知错误
    console.error('创建用户失败:', error);
    ctx.fail('服务器内部错误', 500);
  }
}

常见问题

Q1: 数据库连接失败

解决方案:

  1. 检查数据库服务是否启动
  2. 验证配置文件中的数据库连接信息
  3. 确认数据库用户权限

Q2: 端口被占用

解决方案:

# 查看端口占用
netstat -ano | findstr :3001

# 终止进程
taskkill /PID <进程ID> /F

Q3: 模块找不到

解决方案:

# 重新安装依赖
npm install

# 清除缓存
npm cache clean --force

Q4: 权限验证失败

解决方案:

  1. 检查请求头中的 token
  2. 确认 token 格式正确
  3. 验证 token 是否过期

📚 更多资源


🎉 恭喜!你已经掌握了 Node Core Framework 的基本使用方法!

如有问题,请查看项目文档或提交 Issue。