如何在不同属性的User与Admin Schema复用控制器函数
优化用户与管理员注册控制器,消除代码重复
问题描述
我定义了User和Admin两个Mongoose Schema,二者属性存在差异。目前已完成User控制器函数的编写,但发现两者的登录、注册等控制器逻辑基本一致,存在大量代码复用。我需要修改控制器函数,让用户注册时仅处理User的属性,管理员注册时仅处理Admin的属性,且无需让注册者手动选择身份。
现有Schema与控制器代码
Admin Schema
import mongoose, { Schema } from 'mongoose' import pkg from 'validator' const { isEmail } = pkg; const adminSchema = new Schema({ adminId:{ type: String, required: true, unique: true, length: 10, }, name:{ type: String, required: [true, '此字段为必填项'], }, dob:{ type: Date, required: [true, '此字段为必填项'], }, email: { type: String, required: true, validator: [isEmail, '请输入有效的邮箱地址'], lowercase: true, }, password:{ type: String, required: [true, '此字段为必填项'], validator: [(password)=>pkg.matches(password, "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$"), "密码需包含大小写字母、数字及特殊字符,长度至少8位" ], }, }) const Admin = mongoose.model('Admin', adminSchema); export default Admin;
User Schema
import mongoose, { Schema } from 'mongoose' import pkg from 'validator' const { isEmail } = pkg; const userSchema = new Schema({ fullname: { type: String, required: [true, '此字段为必填项'] }, username: { type: String, required: [true, '此字段为必填项'], unique: true, }, email: { type: String, required: [true, '此字段为必填项'], lowercase: true, validator: [isEmail, '请输入有效的邮箱地址'] }, password: { type: String, required: [true, '此字段为必填项'], validator: [(password)=>pkg.matches(password, "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$"), "密码需包含大小写字母、数字及特殊字符,长度至少8位" ], }, }) const User = mongoose.model('User', userSchema); export default User;
现有重复的注册控制器
管理员注册控制器
const admin_signup_post = async (req, res)=>{ try{ const {name, dob, email, password } = req.body; const hashedPwd = await hashedPassword(password); const newadminId = createID(name); const admin = new Admin({adminId: newadminId, name, dob, email, password: hashedPwd}); await admin.save(); res.status(201).json({ admin }); }catch(err){ const errors = handleErrors(err); res.status(400).json({ errors }); } }
用户注册控制器
const user_signup_post = async (req, res)=>{ try{ const { fullname, username, email, password } = req.body; const hashedPwd = await hashedPassword(password); const user = new User({fullname, username, email, password: hashedPwd}); await user.save(); res.status(201).json({ user }); }catch(err){ const errors = handleErrors(err); res.status(400).json({ errors }); } }
解决方案:创建通用控制器工厂函数
通过工厂模式生成针对不同模型的注册控制器,提取公共逻辑,仅保留模型特有的处理逻辑。
步骤1:定义通用注册工厂函数
// 通用注册控制器工厂 const createSignupController = (Model, prepareUserData) => { return async (req, res) => { try { const hashedPwd = await hashedPassword(req.body.password); // 调用传入的自定义处理函数,生成模型所需的数据 const modelData = await prepareUserData(req.body, hashedPwd); const entity = new Model(modelData); await entity.save(); res.status(201).json({ [Model.modelName.toLowerCase()]: entity }); } catch (err) { const errors = handleErrors(err); res.status(400).json({ errors }); } }; };
步骤2:为User和Admin生成对应的注册控制器
// 用户注册控制器 const user_signup_post = createSignupController(User, async (body, hashedPwd) => { const { fullname, username, email } = body; return { fullname, username, email, password: hashedPwd }; }); // 管理员注册控制器 const admin_signup_post = createSignupController(Admin, async (body, hashedPwd) => { const { name, dob, email } = body; const newadminId = createID(name); return { adminId: newadminId, name, dob, email, password: hashedPwd }; });
步骤3:路由配置(无需用户选择身份)
在路由层分别配置不同的注册接口,前端调用对应接口即可完成身份注册:
// 用户注册路由 router.post('/user/signup', user_signup_post); // 管理员注册路由 router.post('/admin/signup', admin_signup_post);
核心优势
- 消除代码重复:密码哈希、错误处理、数据保存等公共逻辑仅需编写一次
- 扩展性强:新增其他角色(如Moderator)时,只需编写对应的属性处理函数即可生成控制器
- 职责清晰:每个模型的特有逻辑(如Admin的adminId生成)被封装在独立的处理函数中
内容的提问来源于stack exchange,提问作者arshi02
相关产品推荐
相关产品推荐

