路由配置与用户模型设计指南
一、路由统一配置与使用
1. API根路径配置
为了便于API版本管理和统一前缀配置,在配置文件中添加API根路径:
// config/index.js
module.exports = {
DBHOST: '127.0.0.1', // 数据库主机
DBPORT: 27017, // 数据库端口
DBNAME: 'node-ruoyi', // 数据库名称
API_ROOT: '/trserver', // 接口统一根路径
COUNTERS_COLLECTION: 'auto_increment_counters', // 自增ID计数集合
// ... 其他配置
}
2. Express应用路由配置
在应用入口文件中使用统一的路由配置:
// app.js
const createError = require('http-errors')
const express = require('express')
const path = require('path')
const cookieParser = require('cookie-parser')
const logger = require('morgan')
const { API_ROOT } = require('./config') // 引入配置
const routes = require('./routes') // 统一路由入口
const app = express()
// 视图引擎配置
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
// 中间件配置
app.use(logger('dev'))
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(express.static(path.join(__dirname, 'public')))
// 使用统一API前缀注册路由
app.use(API_ROOT, routes)
// 404错误处理
app.use(function(req, res, next) {
next(createError(404))
})
// 全局错误处理
app.use(function(err, req, res, next) {
res.locals.message = err.message
res.locals.error = req.app.get('env') === 'development' ? err : {}
res.status(err.status || 500)
res.render('error')
})
module.exports = app
配置说明:
- API_ROOT:为所有接口提供统一前缀,便于API版本管理和路由分组
- 模块化路由:将所有路由集中管理,提高代码可维护性
- 中间件链:确保中间件按正确顺序执行
二、Mongoose Sequence插件安装
安装mongoose-sequence插件,实现业务ID自增功能:
npm install mongoose-sequence --save
三、用户数据模型详细设计
1. 用户模型文件结构
// models/system/user.js
const mongoose = require('mongoose')
const { AtModel } = require('./../base') // 基础时间戳模型
const utils = require('./../../utils') // 工具函数
const { SEX, STATUS } = require('./../../enums/user') // 枚举定义
const mongooseSequence = require('mongoose-sequence')(mongoose) // 自增插件
const { COUNTERS_COLLECTION } = require('./../../config/index')
const { AUTO_INCREMENT_USER_ID } = require('./../../utils/constant')
// 用户模式定义
const userSchema = new mongoose.Schema({
...AtModel, // 继承创建时间和更新时间字段
// 基础信息
avatar: {
type: String,
default: '',
description: '用户头像URL'
},
nickName: {
type: String,
default: '',
required: [true, '昵称不能为空'],
description: '用户昵称'
},
userName: {
type: String,
default: '',
unique: [true, '用户名已存在'],
trim: true,
description: '用户名',
required: [true, '用户名不能为空'],
index: true // 添加索引提升查询性能
},
// 联系信息
email: {
type: String,
default: '',
description: '邮箱地址',
trim: true,
validate: {
validator: val => (val ? utils.isEmail(val) : true),
message: '邮箱格式错误'
}
},
phonenumber: {
type: String,
default: '',
description: '手机号码',
required: [true, '手机号不能为空'],
trim: true,
validate: {
validator: val => utils.isPhone(val),
message: '手机号格式错误'
},
index: true // 添加索引提升查询性能
},
// 安全信息
password: {
type: String,
default: '123456',
select: false, // 查询时不返回密码字段
description: '登录密码',
required: [true, '密码不能为空'],
minlength: [6, '密码长度不能小于6位'],
maxlength: [20, '密码长度不能大于20位'],
trim: true,
validate: {
validator: val => /^[^<>"'|\\]+$/.test(val),
message: '密码不能包含非法字符:< > " \' \\ |'
}
},
// 状态信息
sex: {
type: String,
enum: Object.values(SEX),
default: SEX.MAN,
description: '性别:0-男,1-女,2-未知'
},
status: {
type: String,
enum: Object.values(STATUS),
default: STATUS.NORMAL,
description: '状态:0-正常,1-停用'
},
// 登录信息
loginDate: {
type: Date,
default: null,
description: '最后登录时间'
},
loginIp: {
type: String,
default: '',
description: '最后登录IP'
},
// 权限信息
permissions: {
type: [String], // 使用数组简写语法
default: []
},
roleIds: {
type: [Number], // 使用数组简写语法
default: [],
description: '角色ID列表',
required: [true, '角色ID列表不能为空']
},
// 组织信息
deptId: {
type: Number,
default: null,
description: '部门ID'
},
tenantId: {
type: String,
default: '',
description: '租户ID',
required: [true, '租户ID不能为空']
},
// 自增业务ID
userId: {
type: Number,
description: '用户业务ID',
unique: [true, '用户ID已存在'],
index: true // 添加索引提升查询性能
},
userType: {
type: String,
default: 'sys_user',
description: '用户类型'
},
// 岗位信息
postIds: {
type: [Number], // 使用数组简写语法
default: []
},
// 备注
remark: {
type: String,
default: '',
description: '备注信息'
}
})
// 应用自增插件
userSchema.plugin(mongooseSequence, {
inc_field: AUTO_INCREMENT_USER_ID, // 自增字段名
start_seq: 1, // 起始序列号
id: `${AUTO_INCREMENT_USER_ID}_seq`, // 序列ID
collection_name: COUNTERS_COLLECTION // 计数器集合名称
})
// 创建模型
module.exports = mongoose.model('Users', userSchema)
2. 支持文件说明
枚举定义文件 (enums/user.js):
// enums/user.js
const SEX = {
MAN: '0', // 男
WOMAN: '1', // 女
UNKNOWN: '2' // 未知
}
const STATUS = {
NORMAL: '0', // 正常
DISABLE: '1' // 停用
}
module.exports = {
SEX,
STATUS
}
常量定义文件 (utils/constant.js):
// utils/constant.js
const AUTO_INCREMENT_USER_ID = 'userId'
module.exports = {
AUTO_INCREMENT_USER_ID
}
四、管理员用户初始化脚本
1. 初始化脚本实现
// scripts/initAdminUser.js
const {
SystemModel: { UsersModel }
} = require('../models')
const db = require('../db/db')
/**
* 初始化管理员用户
* 创建默认的admin用户,用于系统初始登录
*/
const initAdminUser = async () => {
try {
// 检查是否已存在admin用户
const existingAdmin = await UsersModel.findOne({ userName: 'admin' })
if (existingAdmin) {
console.log('⚠️ admin用户已存在,跳过初始化')
return Promise.resolve({ skipped: true, user: existingAdmin })
}
// 创建管理员用户
const adminData = {
avatar: 'https://i.pravatar.cc/100',
email: 'crazyLionLi@163.com',
loginDate: null,
loginIp: '::ffff:127.0.0.1',
nickName: '疯狂的狮子Li',
password: 'admin123', // 注意:实际应用中密码应加密存储
phonenumber: '15888888888',
remark: '系统管理员',
sex: '1', // 使用枚举值SEX.MAN
status: '0', // 使用枚举值STATUS.NORMAL
permissions: ['*:*:*'], // 拥有所有权限
deptId: 6, // 默认部门ID
tenantId: '000000', // 默认租户ID
userType: 'sys_user', // 系统用户类型
userName: 'admin',
roleIds: [1], // 管理员角色ID
postIds: [] // 无关联岗位
}
const createdUser = await UsersModel.create(adminData)
console.log('✅ admin用户初始化成功')
return Promise.resolve({
success: true,
user: {
userId: createdUser.userId,
userName: createdUser.userName,
nickName: createdUser.nickName
}
})
} catch (error) {
console.error('❌ admin用户初始化失败:', error.message)
return Promise.reject(error)
}
}
// 执行初始化
db(() => {
console.log('🚀 开始初始化admin用户...')
initAdminUser()
.then(result => {
if (result.skipped) {
console.log('📋 admin用户已存在,详细信息:', result.user)
} else {
console.log('🎉 初始化完成,创建的用户信息:', result.user)
}
process.exit(0) // 正常退出
})
.catch(error => {
console.error('💥 初始化过程中出现错误:', error)
process.exit(1) // 异常退出
})
})
2. 执行初始化脚本
在项目根目录下执行:
node scripts/initAdminUser.js
3. 执行结果说明
成功情况:
🚀 开始初始化admin用户...
✅ admin用户初始化成功
🎉 初始化完成,创建的用户信息: { userId: 1, userName: 'admin', nickName: '疯狂的狮子Li' }
已存在情况:
🚀 开始初始化admin用户...
⚠️ admin用户已存在,跳过初始化
📋 admin用户已存在,详细信息: { userId: 1, userName: 'admin', ... }
失败情况:
🚀 开始初始化admin用户...
❌ admin用户初始化失败: [错误信息]
💥 初始化过程中出现错误: [错误详情]