如何将Express项目路由拆分至不同模块,无需重写代码?
无需重写代码的路由拆分方案
完全可以通过Express内置的express.Router()实现路由拆分,不需要修改现有路由的业务逻辑,仅需迁移代码并完成挂载即可。以下是具体步骤:
1. 抽离共享资源
先把路由中需要复用的中间件、模型、配置单独拆分,避免重复定义:
1.1 抽离认证中间件
创建middleware/auth.js,把authenticateToken和isAdmin移到这里:
const jwt = require('jsonwebtoken'); const db = require('../db'); const authenticateToken = (req, res, next) => { const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; console.log('Token received:', token); if (token == null) return res.sendStatus(401); jwt.verify(token, 'your_secret_key_here', (err, user) => { if (err) { console.error('Token verification failed:', err); return res.sendStatus(403); } req.user = user; console.log('User from token:', user); next(); }); }; const isAdmin = async (req, res, next) => { try { const user = await db.User.findByPk(req.user.id); if (user && user.RoleID === 2) { next(); } else { res.sendStatus(403); } } catch (err) { res.sendStatus(500); } }; module.exports = { authenticateToken, isAdmin };
1.2 抽离文件上传配置
创建middleware/upload.js,把multer配置移到这里:
const multer = require('multer'); const path = require('path'); const storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, 'uploads/'); }, filename: function (req, file, cb) { cb(null, `${Date.now()}-${file.originalname}`); } }); const upload = multer({ storage: storage }); module.exports = upload;
1.3 抽离Sequelize实例和模型
创建config/sequelize.js,单独存放数据库连接实例:
const { Sequelize } = require('sequelize'); const sequelize = new Sequelize('school_canteen', 'root', 'password', { host: 'localhost', dialect: 'mysql' }); module.exports = sequelize;
创建models/Photo.js,把Photo模型移到这里:
const { Sequelize, DataTypes } = require('sequelize'); const sequelize = require('../config/sequelize'); const Photo = sequelize.define('Photo', { PhotoID: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true }, photoUrl: { type: Sequelize.STRING, allowNull: false }, productId: { type: Sequelize.INTEGER, allowNull: false }, altText: { type: Sequelize.STRING, allowNull: true } }, { tableName: 'photos' }); module.exports = Photo;
2. 创建独立路由文件
创建routes/photos.js,把原server.js中照片相关的路由全部迁移过来,用router替代app:
const express = require('express'); const router = express.Router(); const Photo = require('../models/Photo'); const { authenticateToken, isAdmin } = require('../middleware/auth'); const upload = require('../middleware/upload'); // 新增照片(管理员) router.post('/admin/photos', authenticateToken, isAdmin, upload.single('photo'), async (req, res) => { const { productId, altText } = req.body; const photoUrl = req.file ? req.file.path : undefined; console.log('Request Body:', req.body); console.log('Uploaded File:', req.file); if (!productId || !photoUrl) { return res.status(400).json({ error: 'ProductID and PhotoURL are required' }); } try { const newPhoto = await Photo.create({ photoUrl, productId, altText }); res.status(201).json(newPhoto); } catch (err) { console.error('Error creating photo:', err); res.status(500).send('Server Error'); } }); // 更新照片(管理员) router.put('/admin/photos/:photoId', authenticateToken, isAdmin, upload.single('photo'), async (req, res) => { const { photoId } = req.params; const { productId, altText } = req.body; const photoUrl = req.file ? req.file.path : undefined; try { const photo = await Photo.findByPk(photoId); if (!photo) return res.status(404).json({ msg: 'Photo not found' }); photo.productId = productId || photo.productId; photo.altText = altText || photo.altText; if (photoUrl) { photo.photoUrl = photoUrl; } await photo.save(); res.json(photo); } catch (err) { console.error(err.message); res.status(500).send('Server Error'); } }); // 删除照片 router.delete('/admin/photos/:photoId', authenticateToken, async (req, res) => { const { photoId } = req.params; try { const photo = await Photo.findByPk(photoId); if (!photo) { return res.status(404).json({ error: 'Photo not found' }); } await photo.destroy(); res.status(200).json({ message: 'Photo deleted successfully' }); } catch (error) { console.error('Error deleting photo:', error); res.status(500).json({ error: 'Failed to delete photo' }); } }); // 获取所有照片 router.get('/photos', authenticateToken, async (req, res) => { try { const photos = await Photo.findAll(); res.json(photos); } catch (error) { console.error('Error fetching photos:', error); res.status(500).json({ error: 'Failed to fetch photos' }); } }); // 根据产品ID获取照片 router.get('/photos/:productId', authenticateToken, async (req, res) => { try { const photos = await Photo.findAll({ where: { productId: req.params.productId } }); res.json(photos); } catch (err) { console.error('Error fetching photos:', err.message); res.status(500).send('Server Error'); } }); module.exports = router;
3. 简化server.js并挂载路由
修改原server.js,删除所有照片路由代码,替换为路由挂载:
const express = require('express'); const bodyParser = require('body-parser'); const cors = require('cors'); const path = require('path'); const sequelize = require('./config/sequelize'); const db = require('./db'); // 引入拆分后的路由 const photosRoutes = require('./routes/photos'); const app = express(); const PORT = process.env.PORT || 3001; app.use(cors()); app.use(bodyParser.json()); app.use('/uploads', express.static(path.join(__dirname, 'uploads'))); // 挂载照片路由,前缀为/api app.use('/api', photosRoutes); sequelize.sync().then(() => { console.log('Database synchronized'); }).catch(error => { console.error('Error synchronizing the database:', error); }); app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });
后续扩展
其他路由(如用户、订单、菜单等)都可以按照相同逻辑拆分:
- 新建对应路由文件(如
routes/users.js、routes/orders.js) - 迁移对应路由代码到文件中
- 在server.js中引入并挂载
内容的提问来源于stack exchange,提问作者V4lis
相关产品推荐
相关产品推荐

