
本文详解如何在 NestJS 项目中集成 AdminJS 并正确配置 Mongoose 适配器,解决因 registerAdapter 调用位置错误导致的 Express 中间件类型异常问题,并指导将 User Schema 注册为 AdminJS 资源。
本文详解如何在 nestjs 项目中集成 adminjs 并正确配置 mongoose 适配器,解决因 `registeradapter` 调用位置错误导致的 express 中间件类型异常问题,并指导将 user schema 注册为 adminjs 资源。
AdminJS 本身不直接依赖框架,但其 Mongoose 适配器(@adminjs/mongoose)需在 AdminJS 实例初始化之前全局注册,而非作为 Express 中间件挂载。你当前报错 Router.use() requires a middleware function but got undefined 的根本原因,正是将 AdminJS.default.registerAdapter(...) 错误地放在了 expressApp.use(...) 调用链中——registerAdapter 返回 void,并非中间件函数,因此 Express 报错。
✅ 正确做法是:先注册适配器,再创建 AdminJS 实例,最后构建并挂载路由。以下是完整、可运行的配置方案:
1. 安装必要依赖
npm install adminjs @adminjs/nestjs @adminjs/express @adminjs/mongoose # 确保已安装 mongoose 及 NestJS Mongoose 模块 npm install @nestjs/mongoose mongoose
2. 在 main.ts 中正确初始化适配器与 AdminJS
import * as process from 'process';
import { HttpAdapterHost, NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
import { json, urlencoded } from 'express';
// ✅ 关键:提前导入并注册 Mongoose 适配器(必须在 new AdminJS() 之前!)
import AdminJS from 'adminjs';
import AdminJSExpress from '@adminjs/express';
import AdminJSMongoose from '@adminjs/mongoose';
// ⚠️ 必须在此处注册,且仅执行一次
AdminJS.registerAdapter({
Resource: AdminJSMongoose.Resource,
Database: AdminJSMongoose.Database,
});
async function bootstrap() {
const PORT = Number(process.env.PORT) || 5000;
const app = await NestFactory.create<nestexpressapplication>(AppModule);
// 获取底层 Express 实例
const expressApp = app.get(HttpAdapterHost).httpAdapter;
// ✅ 创建 AdminJS 实例(此时适配器已注册,User Schema 可被自动识别)
const adminJs = new AdminJS.AdminJS({
rootPath: '/admin',
resources: [
// ? 显式注册 User 资源(推荐,确保可控)
{
resource: { model: 'User', database: 'mongodb://localhost:27017/arm-club-control' },
options: {
properties: {
name: { isVisible: { list: true, filter: true, show: true, edit: true } },
email: { isVisible: { list: true, filter: true, show: true, edit: true } },
role: { type: 'string', availableValues: ['user', 'admin', 'moderator'] },
},
},
},
],
// ? 认证与会话配置(保持原有逻辑)
auth: {
authenticate: async (email, password) => {
// 实现你的登录逻辑(例如查询 User 模型校验密码)
return { email, password }; // 示例占位,需替换为真实逻辑
},
cookieName: 'adminjs',
cookiePassword: 'your-secure-secret-here',
},
sessionOptions: {
resave: true,
saveUninitialized: true,
secret: 'your-session-secret-here',
},
});
// ✅ 构建路由中间件(这才是真正的 Express 中间件)
const router = AdminJSExpress.buildRouter(adminJs);
// ✅ 挂载到 Express 实例(非适配器注册!)
expressApp.use(adminJs.options.rootPath, router);
// 其他应用配置...
app.setGlobalPrefix('api');
app.enableCors();
app.use(json({ limit: '50mb' }));
app.use(urlencoded({ extended: true, limit: '50mb' }));
await app.listen(PORT, '0.0.0.0');
console.log(`? AdminJS running at http://localhost:${PORT}/admin`);
}
bootstrap();</nestexpressapplication>
3. 在 AppModule 中简化 AdminModule 配置
移除 AdminModule.createAdminAsync 中冗余的适配器注册逻辑,仅保留基础配置:
import { Module } from '@nestjs/common';
import { AdminModule } from '@adminjs/nestjs'; // ✅ 仅用于 NestJS 生命周期集成
import { MongooseModule } from '@nestjs/mongoose';
import { UserModule } from './user/user.module';
@Module({
imports: [
// ✅ AdminModule 仅负责注入,适配器已在 main.ts 注册
AdminModule.createAdminAsync({
useFactory: () => ({
adminJsOptions: {
rootPath: '/admin',
// resources 已在 main.ts 统一管理,此处可留空或仅作基础声明
},
auth: { /* 同上,或移至 main.ts 统一配置 */ },
sessionOptions: { /* 同上 */ },
}),
}),
MongooseModule.forRoot('mongodb://localhost:27017/arm-club-control'),
UserModule,
],
})
export class AppModule {}
4. 确保 User Schema 被 Mongoose 正确识别
AdminJS 的 Mongoose 适配器会自动扫描已连接的 Mongoose Model。请确认你的 UserModule 已正确注册模型:
// user.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { User, UserSchema } from './user.schema';
@Module({
imports: [
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
],
// ...
})
export class UserModule {}
? 验证技巧:启动应用后访问
http://localhost:5000/admin,若左侧菜单出现User条目且可增删改查,即表示适配成功。若未显示,请检查控制台是否打印 Mongoose 连接日志,并确认UserModel 名称与forFeature中注册的名称一致(默认为类名User)。
⚠️ 注意事项总结
- ❌
AdminJS.registerAdapter()绝不可出现在expressApp.use()内部; - ✅ 适配器注册必须在
new AdminJS()之前,且全局仅执行一次; - ✅
buildRouter()返回的是标准 Express 中间件,才可安全use(); - ✅ 推荐在
main.ts中集中管理 AdminJS 实例、资源与路由,避免模块间耦合; - ? 生产环境务必替换
cookiePassword和sessionOptions.secret为强随机密钥; - ? 若使用多数据库,
resource.database需指向对应连接 URL 或已注册的 Mongoose Connection 实例。
通过以上调整,AdminJS 将无缝对接 NestJS + Mongoose,为你提供开箱即用的数据管理后台。











