You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不同属性的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 02:55:16