Files
xlxumu/backend/api/server.js

330 lines
9.0 KiB
JavaScript
Raw Normal View History

const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const dotenv = require('dotenv');
const rateLimit = require('express-rate-limit');
const mysql = require('mysql2/promise');
const path = require('path');
// 导入路由模块
const authModule = require('./routes/auth');
const usersModule = require('./routes/users');
const cattleModule = require('./routes/cattle');
const financeModule = require('./routes/finance');
const tradingModule = require('./routes/trading');
const governmentModule = require('./routes/government');
const mallModule = require('./routes/mall');
// 加载环境变量
dotenv.config();
// 数据库连接
let pool, testDatabaseConnection;
if (process.env.DB_TYPE === 'sqlite') {
// 使用SQLite
const sqliteDb = require('./database-sqlite');
pool = sqliteDb.pool;
testDatabaseConnection = sqliteDb.testDatabaseConnection;
} else {
// 使用MySQL
const mysql = require('mysql2/promise');
// 数据库连接配置
const dbConfig = {
host: process.env.DB_HOST,
port: process.env.DB_PORT,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
charset: process.env.DB_CHARSET || 'utf8mb4',
connectionLimit: 10,
acquireTimeout: 60000,
timeout: 60000
};
// 创建数据库连接池
pool = mysql.createPool(dbConfig);
// 测试数据库连接
testDatabaseConnection = async function() {
try {
const connection = await pool.getConnection();
console.log('✅ MySQL数据库连接成功');
console.log(`📍 连接到: ${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`);
connection.release();
return true;
} catch (error) {
console.error('❌ 数据库连接失败:', error.message);
console.log('⚠️ 服务将继续运行,但数据库功能不可用');
return false;
}
};
}
// 创建Express应用
const app = express();
const PORT = process.env.PORT || 8888;
// 初始化数据库和中间件的异步函数
async function initializeApp() {
// 启动时测试数据库连接
await testDatabaseConnection();
// 设置路由模块的数据库连接
authModule.setPool(pool);
usersModule.setMiddleware(authModule.authenticateToken, authModule.checkPermission, pool);
cattleModule.setMiddleware(authModule.authenticateToken, authModule.checkPermission, pool);
financeModule.setMiddleware(authModule.authenticateToken, authModule.checkPermission, pool);
tradingModule.setMiddleware(authModule.authenticateToken, authModule.checkPermission, pool);
governmentModule.setMiddleware(authModule.authenticateToken, authModule.checkPermission, pool);
mallModule.setMiddleware(authModule.authenticateToken, authModule.checkPermission, pool);
console.log('✅ 中间件初始化完成');
}
// 初始化应用(不阻塞服务启动)
initializeApp().catch(console.error);
// 导入错误处理中间件
const { errorHandler, notFoundHandler, requestLogger, performanceMonitor } = require('./middleware/errorHandler');
// 中间件
app.use(requestLogger); // 请求日志
app.use(performanceMonitor); // 性能监控
app.use(helmet()); // 安全头部
app.use(cors({
origin: process.env.CORS_ORIGIN || '*',
credentials: true
})); // 跨域支持
app.use(express.json({ limit: '10mb' })); // JSON解析
app.use(express.urlencoded({ extended: true, limit: '10mb' })); // URL编码解析
// 速率限制
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 限制每个IP 15分钟内最多100个请求
message: '请求过于频繁,请稍后再试'
});
app.use(limiter);
// 基础路由
app.get('/', (req, res) => {
res.json({
message: '欢迎使用锡林郭勒盟地区智慧养殖产业平台API服务',
version: '1.0.0',
timestamp: new Date().toISOString()
});
});
app.get('/health', async (req, res) => {
try {
// 测试数据库连接
const connection = await pool.getConnection();
const [rows] = await connection.execute('SELECT 1 as test');
connection.release();
res.json({
status: 'OK',
timestamp: new Date().toISOString(),
database: 'Connected',
environment: process.env.NODE_ENV,
version: '1.0.0'
});
} catch (error) {
res.status(500).json({
status: 'ERROR',
timestamp: new Date().toISOString(),
database: 'Disconnected',
error: error.message
});
}
});
// API路由
app.use('/api/v1/auth', authModule.router);
app.use('/api/v1/users', usersModule.router);
app.use('/api/v1/cattle', cattleModule.router);
app.use('/api/v1/finance', financeModule.router);
app.use('/api/v1/trading', tradingModule.router);
app.use('/api/v1/government', governmentModule.router);
app.use('/api/v1/mall', mallModule.router);
// 数据库查询接口
app.get('/api/v1/database/tables', async (req, res) => {
try {
const [tables] = await pool.execute(
'SELECT TABLE_NAME, TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?',
[process.env.DB_NAME]
);
res.json({
success: true,
data: {
database: process.env.DB_NAME,
tables: tables,
count: tables.length
},
timestamp: new Date().toISOString()
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message,
timestamp: new Date().toISOString()
});
}
});
// 数据库连接状态接口
app.get('/api/v1/database/status', async (req, res) => {
try {
const [statusResult] = await pool.execute('SHOW STATUS LIKE "Threads_connected"');
const [versionResult] = await pool.execute('SELECT VERSION() as version');
res.json({
success: true,
data: {
connected: true,
version: versionResult[0].version,
threads_connected: statusResult[0].Value,
database: process.env.DB_NAME,
host: process.env.DB_HOST,
port: process.env.DB_PORT
},
timestamp: new Date().toISOString()
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message,
timestamp: new Date().toISOString()
});
}
});
app.get('/api/v1/dashboard/map/regions', (req, res) => {
// 模拟锡林郭勒盟各区域数据
const regions = [
{
id: 'xlg',
name: '锡林浩特市',
coordinates: [116.093, 43.946],
cattle_count: 25600,
farm_count: 120,
output_value: 650000000
},
{
id: 'dwq',
name: '东乌旗',
coordinates: [116.980, 45.514],
cattle_count: 18500,
farm_count: 95,
output_value: 480000000
},
{
id: 'xwq',
name: '西乌旗',
coordinates: [117.615, 44.587],
cattle_count: 21200,
farm_count: 108,
output_value: 520000000
},
{
id: 'abg',
name: '阿巴嘎旗',
coordinates: [114.971, 44.022],
cattle_count: 16800,
farm_count: 86,
output_value: 420000000
},
{
id: 'snz',
name: '苏尼特左旗',
coordinates: [113.653, 43.859],
cattle_count: 12400,
farm_count: 65,
output_value: 310000000
}
];
res.json({ regions });
});
app.get('/api/v1/dashboard/map/region/:regionId', (req, res) => {
const { regionId } = req.params;
// 模拟各区域详细数据
const regionDetails = {
'xlg': {
region: {
id: 'xlg',
name: '锡林浩特市',
coordinates: [116.093, 43.946],
cattle_count: 25600,
farm_count: 120,
output_value: 650000000,
trend: 'up'
},
farms: [
{
id: 'FARM001',
name: '锡林浩特市第一牧场',
coordinates: [116.120, 43.950],
cattle_count: 2450,
output_value: 62000000
},
{
id: 'FARM002',
name: '锡林浩特市第二牧场',
coordinates: [116.080, 43.930],
cattle_count: 2100,
output_value: 53000000
}
]
},
'dwq': {
region: {
id: 'dwq',
name: '东乌旗',
coordinates: [116.980, 45.514],
cattle_count: 18500,
farm_count: 95,
output_value: 480000000,
trend: 'up'
},
farms: [
{
id: 'FARM003',
name: '东乌旗牧场A',
coordinates: [116.990, 45.520],
cattle_count: 1950,
output_value: 49000000
}
]
}
};
const detail = regionDetails[regionId];
if (detail) {
res.json(detail);
} else {
res.status(404).json({ error: '区域未找到' });
}
});
// 错误处理中间件(必须放在所有路由之后)
app.use(notFoundHandler); // 404处理
app.use(errorHandler); // 统一错误处理
// 启动服务器
const HOST = process.env.HOST || '0.0.0.0';
app.listen(PORT, HOST, () => {
console.log(`API服务器正在监听: http://${HOST}:${PORT}`);
console.log(`服务器绑定到: ${HOST}, 端口: ${PORT}`);
console.log('尝试使用以下URL访问:');
console.log(` http://localhost:${PORT}`);
console.log(` http://127.0.0.1:${PORT}`);
});
module.exports = app;