Generating commit message...

This commit is contained in:
2025-08-30 14:33:49 +08:00
parent 4d469e95f0
commit 7f9bfbb381
99 changed files with 69225 additions and 35 deletions

View File

@@ -0,0 +1,96 @@
const mongoose = require('mongoose')
class Database {
constructor() {
this.mongoose = mongoose
this.isConnected = false
}
async connect() {
if (this.isConnected) {
return
}
try {
// 连接数据库
const mongodbUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/jiebanke'
await this.mongoose.connect(mongodbUri, {
useNewUrlParser: true,
useUnifiedTopology: true
})
this.isConnected = true
console.log('✅ MongoDB连接成功')
// 监听连接事件
this.mongoose.connection.on('error', (error) => {
console.error('❌ MongoDB连接错误:', error)
this.isConnected = false
})
this.mongoose.connection.on('disconnected', () => {
console.warn('⚠️ MongoDB连接断开')
this.isConnected = false
})
this.mongoose.connection.on('reconnected', () => {
console.log('🔁 MongoDB重新连接成功')
this.isConnected = true
})
} catch (error) {
console.error('❌ MongoDB连接失败:', error)
process.exit(1)
}
}
async disconnect() {
if (!this.isConnected) {
return
}
try {
await this.mongoose.disconnect()
this.isConnected = false
console.log('✅ MongoDB连接已关闭')
} catch (error) {
console.error('❌ MongoDB断开连接失败:', error)
}
}
// 健康检查
async healthCheck() {
try {
await this.mongoose.connection.db.admin().ping()
return { status: 'healthy', connected: this.isConnected }
} catch (error) {
return { status: 'unhealthy', connected: this.isConnected, error: error.message }
}
}
// 获取连接状态
getStatus() {
return {
connected: this.isConnected,
readyState: this.mongoose.connection.readyState,
host: this.mongoose.connection.host,
name: this.mongoose.connection.name
}
}
}
// 创建单例实例
const database = new Database()
// 进程退出时关闭数据库连接
process.on('SIGINT', async () => {
await database.disconnect()
process.exit(0)
})
process.on('SIGTERM', async () => {
await database.disconnect()
process.exit(0)
})
module.exports = database

View File

@@ -0,0 +1,79 @@
// 自定义应用错误类
class AppError extends Error {
constructor(message, statusCode) {
super(message)
this.statusCode = statusCode
this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error'
this.isOperational = true
Error.captureStackTrace(this, this.constructor)
}
}
// 异步错误处理包装器
const catchAsync = (fn) => {
return (req, res, next) => {
fn(req, res, next).catch(next)
}
}
// 404错误处理
const notFound = (req, res, next) => {
const error = new AppError(`无法找到 ${req.originalUrl}`, 404)
next(error)
}
// 全局错误处理中间件
const globalErrorHandler = (err, req, res, next) => {
err.statusCode = err.statusCode || 500
err.status = err.status || 'error'
err.message = err.message || '服务器内部错误'
// 开发环境详细错误信息
if (process.env.NODE_ENV === 'development') {
res.status(err.statusCode).json({
status: err.status,
error: err,
message: err.message,
stack: err.stack
})
} else {
// 生产环境简化错误信息
res.status(err.statusCode).json({
status: err.status,
message: err.message
})
}
}
// MongoDB重复键错误处理
const handleDuplicateFieldsDB = (err) => {
const value = err.errmsg.match(/(["'])(\\?.)*?\1/)[0]
const message = `字段值 ${value} 已存在,请使用其他值`
return new AppError(message, 400)
}
// MongoDB验证错误处理
const handleValidationErrorDB = (err) => {
const errors = Object.values(err.errors).map(el => el.message)
const message = `输入数据无效: ${errors.join('. ')}`
return new AppError(message, 400)
}
// JWT错误处理
const handleJWTError = () =>
new AppError('无效的token请重新登录', 401)
const handleJWTExpiredError = () =>
new AppError('token已过期请重新登录', 401)
module.exports = {
AppError,
catchAsync,
notFound,
globalErrorHandler,
handleDuplicateFieldsDB,
handleValidationErrorDB,
handleJWTError,
handleJWTExpiredError
}

View File

@@ -0,0 +1,70 @@
// 成功响应格式
const success = (data = null, message = '操作成功') => {
return {
success: true,
code: 200,
message,
data,
timestamp: new Date().toISOString()
}
}
// 分页响应格式
const paginate = (data, pagination, message = '获取成功') => {
return {
success: true,
code: 200,
message,
data: {
list: data,
pagination: {
page: pagination.page,
pageSize: pagination.pageSize,
total: pagination.total,
totalPages: Math.ceil(pagination.total / pagination.pageSize)
}
},
timestamp: new Date().toISOString()
}
}
// 错误响应格式
const error = (message = '操作失败', code = 400, errors = null) => {
return {
success: false,
code,
message,
errors,
timestamp: new Date().toISOString()
}
}
// 创建成功响应
const created = (data = null, message = '创建成功') => {
return {
success: true,
code: 201,
message,
data,
timestamp: new Date().toISOString()
}
}
// 无内容响应
const noContent = (message = '无内容') => {
return {
success: true,
code: 204,
message,
data: null,
timestamp: new Date().toISOString()
}
}
module.exports = {
success,
paginate,
error,
created,
noContent
}