nestjs实战 - buildadmin重构后端(初始化mock接口)

前言

实战项目比写demo更有意义、更有价值,更能考虑实际情况的应用,所以选用了 buildadmin 这个后台管理系统

采用 buildadmin/web 前端项目不改,直接把 php 后端重构成 nestjs 后端

初始化 nestjs

创建服务

bash 复制代码
nest new basys

接口数据格式

在开发 api 之前,我们需要确定它的 api 接口数据格式

json 复制代码
{
    "code": 1,
    "msg": "",
    "time": 1753953842,
    "data": {
        "captcha": true
    }
}
创建 nestjs 拦截器(src/core/interceptors/response.interceptor.ts)

创建 nestjs 拦截器,格式化接口输出格式

ts 复制代码
// src/core/interceptors/response.interceptor.ts
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class ResponseInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const response = context.switchToHttp().getResponse();
    // buildadmin headers
    response.setHeader('access-control-allow-headers', 'think-lang, server, ba_user_token, ba-user-token, ba_token, ba-token, batoken, Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With');
    response.setHeader('access-control-allow-methods', 'GET, POST, PUT, DELETE, OPTIONS');
    return next.handle().pipe(
      map(data => {
        return {
          code: data?.code ?? 1,
          msg: data?.msg ?? '',
          time: Math.floor(Date.now() / 1000),
          data: data?.data ?? data ?? null
        };
      })
    );
  }
}
加载拦截器(src/main.ts)

加载拦截器,顺便设置跨域问题,本地开发会出现端口跨域问题

typescript 复制代码
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ResponseInterceptor } from './core/interceptors/response.interceptor';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // 跨域
  app.enableCors({
    origin: 'http://localhost:1818',
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
    credentials: true,
  });
  // 拦截器
  app.useGlobalInterceptors(new ResponseInterceptor());
  await app.listen(process.env.PORT ?? 8000);
}
bootstrap();

创建 restful api

为了保持 buildadmin 接口格式不变,分析出从登录到进入首页所需接口:

  • [GET] /admin/index/login 登录页信息
  • [GET] /api/common/clickCaptcha 点击验证码
  • [POST] /api/common/checkClickCaptcha 校验验证码
  • [POST] /admin/index/login 提交登录信息(账号密码)
  • [GET] /admin/index/index 首页信息
  • [GET] /admin/dashboard/index 控制台信息

我们先实现这 6 个接口的 mock 数据,基于 MVCNestjs 设计理念,可以这样设计目录结构: /[module]/[submodule]/[controller].[action]

md 复制代码
- src
    - admin
        - admin.module.ts
        - index
            - index.module.ts
            - index.controller.ts # /admin/index/index
            - login.controller.ts # /admin/index/login
        - dashboard
            - dashboard.module.ts
            - index.controller.ts # /admin/dashboard/login
    - api
        - api.module.ts
        - common
            - common.module.ts
            - click-captcha.controller.ts # /api/common/clickCaptcha|checkClickCaptcha

以上先忽略了 xxx.service.ts 后面打通数据库在添加

完善 module

两个主模块导入各自的子模块

src/admin/admin.module.ts
typescript 复制代码
// src/admin/admin.module.ts
import { Module } from '@nestjs/common';
import { IndexModule } from './index/index.module';
import { DashboardModule } from './dashboard/dashboard.module';

@Module({
    imports: [IndexModule, DashboardModule],
})
export class AdminModule {}
src/api/api.module.ts
typescript 复制代码
// src/api/api.module.ts
import { Module } from '@nestjs/common';
import { CommonModule } from './common/common.module';

@Module({
    imports: [CommonModule],
})
export class ApiModule {}
  • 各个子模块
src/admin/index/index.module.ts
typescript 复制代码
// src/admin/index/index.module.ts
import { Module } from '@nestjs/common';
import { IndexController } from './index.controller';
import { LoginController } from './login.controller';

@Module({
  controllers: [IndexController, LoginController]
})
export class IndexModule {}
src/admin/dashboard/dashboard.module.ts
typescript 复制代码
// src/admin/dashboard/dashboard.module.ts
import { Module } from '@nestjs/common';
import { IndexController } from './index.controller';

@Module({
  controllers: [IndexController]
})
export class DashboardModule {}
src/api/common/common.module.ts
typescript 复制代码
// src/api/common/common.module.ts
import { Module } from '@nestjs/common';
import { ClickCaptchaController } from './click-captcha.controller';

@Module({
    controllers: [ClickCaptchaController],
})
export class CommonModule {}

完善 controller

src/admin/index/login.controller.ts
typescript 复制代码
import { Controller, Get, Post } from '@nestjs/common';

@Controller('admin/index')
export class LoginController {
    /**
     * [GET] /admin/index/login
     */
    @Get('login')
    getLogin() {
        return {
            captcha: true
        }
    }

    /**
     * [POST] /admin/index/login
     */
    @Post('login')
    postLogin() {
        return {
            "userInfo": {
                "id": 1,
                "username": "admin",
                "nickname": "Admin",
                "avatar": "\/static\/images\/avatar.png",
                "last_login_time": "2025-07-31 16:50:23",
                "token": "128adae3-665e-4424-94d8-124089ddd460",
                "refresh_token": ""
            }
        };
    }
}
src/api/common/click-captcha.controller.ts
typescript 复制代码
import { Controller, Get, Post, Query } from '@nestjs/common';

@Controller('/api/common')
export class ClickCaptchaController {
    /**
     * [GET] /api/common/clickCaptcha
     */
    @Get('clickCaptcha')
    getCaptcha(@Query('id') id: string) {
        return {
            id,
            "text": [
                "检",
                "步"
            ],
            "base64": "",
            "width": 350,
            "height": 200
        };
    }

    /**
     * [POST] /api/common/checkClickCaptcha
     */
    @Post('checkClickCaptcha')
    postCheckCaptcha() {
        // 假装校验通过
        return null;
    }
}
src/admin/dashboard/index.controller.ts
typescript 复制代码
import { Controller, Get } from '@nestjs/common';

@Controller('admin/dashboard')
export class IndexController {
    /**
     * [GET] /admin/dashboard/index
     */
    @Get('index')
    index() {
        return {
            "remark": "开源等于互助;开源需要大家一起来支持,支持的方式有很多种,比如使用、推荐、写教程、保护生态、贡献代码、回答问题、分享经验、打赏赞助等;欢迎您加入我们!"
        };
    }
}
src/admin/index/index.controller.ts
typescript 复制代码
import { Controller, Get } from '@nestjs/common';

@Controller('admin/index')
export class IndexController {
    /**
     * [GET] /admin/index/index
     */
    @Get('index')
    index() {
        return {
            "adminInfo": {
                "id": 1,
                "username": "admin",
                "nickname": "Admin",
                "avatar": "\/static\/images\/avatar.png",
                "last_login_time": "2025-07-31 16:50:24",
                "super": true
            },
            "menus": [
                {
                    "id": 1,
                    "pid": 0,
                    "type": "menu",
                    "title": "控制台",
                    "name": "dashboard",
                    "path": "dashboard",
                    "icon": "fa fa-dashboard",
                    "menu_type": "tab",
                    "url": "",
                    "component": "\/src\/views\/backend\/dashboard.vue",
                    "keepalive": "dashboard",
                    "extend": "none",
                    "children": [
                        {
                            "id": 94,
                            "pid": 1,
                            "type": "button",
                            "title": "查看",
                            "name": "dashboard\/index",
                            "path": "",
                            "icon": "",
                            "menu_type": null,
                            "url": "",
                            "component": "",
                            "keepalive": 0,
                            "extend": "none"
                        }
                    ]
                },
            ],
            "siteConfig": {
                "siteName": "BuildAdmin",
                "version": "v1.0.0",
                "cdnUrl": "\/\/demo.buildadmin.com",
                "apiUrl": "https:\/\/buildadmin.com",
                "upload": {
                    "maxSize": 10485760,
                    "saveName": "\/storage\/{topic}\/{year}{mon}{day}\/{fileName}{fileSha1}{.suffix}",
                    "allowedSuffixes": "jpg,png,bmp,jpeg,gif,webp,zip,rar,wav,mp4,mp3",
                    "allowedMimeTypes": [],
                    "mode": "local"
                }
            },
            "terminal": {
                "phpDevelopmentServer": false,
                "npmPackageManager": "pnpm"
            }
        };
    }
}

到这里基本完成 nestjs 的接口设计,直接 npm run start 就能跑起来服务

之后直接运行前端项目,就能看到界面了

代码放这里了 buildadmin-nestjs

相关推荐
撰卢3 分钟前
总结一下vue3的组件之间数据转递,子组件传父组件,父组件传子组件
前端·javascript·vue.js
SimonKing7 分钟前
无需重启!动态修改日志级别的神技,运维开发都哭了
java·后端·程序员
架构精进之路26 分钟前
多智能体系统不是银弹
后端·架构·aigc
前端开发爱好者42 分钟前
Vue3 超强“积木”组件!5 分钟搞定可交互 3D 机房蓝图!
前端·javascript·vue.js
前端开发爱好者1 小时前
尤雨溪力荐!Vue3 专属!100+ 动效组件!
前端·javascript·vue.js
前端开发爱好者1 小时前
尤雨溪力荐!Vue3 生态最强大的 14 个 UI 组件库!
前端·javascript·vue.js
lb29171 小时前
关于多个el-input的自动聚焦,每输入完一个el-input,自动聚焦到下一个
前端·javascript·vue.js
lingliang1 小时前
使用 JS 渲染页面并导出为PDF 常见问题与修复
javascript·pdf·vue
涡能增压发动积1 小时前
MySQL数据库为何逐渐黯淡,PostgreSQL为何能新王登基
人工智能·后端
架构精进之路1 小时前
多智能体系统架构解析
后端·架构·ai编程