feat: 添加扫描模块
parent
868769880e
commit
69976a67f8
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"printWidth": 120,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
99
package.json
99
package.json
|
|
@ -23,83 +23,72 @@
|
|||
"orm": "typeorm-ts-node-esm -d ./src/database/datasource/index.ts",
|
||||
"g": "plop --plopfile scripts/template/index.js"
|
||||
},
|
||||
"prettier": {
|
||||
"printWidth": 120,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"endOfLine": "auto"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/axios": "^3.0.0",
|
||||
"@nestjs/common": "^9.0.0",
|
||||
"@nestjs/core": "^9.0.0",
|
||||
"@nestjs/platform-express": "^9.0.0",
|
||||
"@nestjs/common": "^9.4.3",
|
||||
"@nestjs/core": "^9.4.3",
|
||||
"@nestjs/serve-static": "^3.0.1",
|
||||
"@nestjs/swagger": "^6.3.0",
|
||||
"@nestjs/typeorm": "^9.0.1",
|
||||
"@nestjs/config": "^2.3.4",
|
||||
"@nestjs/jwt": "^10.1.1",
|
||||
"@nestjs/platform-express": "^9.4.3",
|
||||
"axios": "^1.5.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"rxjs": "^7.2.0",
|
||||
"ua-parser-js": "^1.0.36"
|
||||
"dayjs": "^1.11.9",
|
||||
"dotenv": "^16.3.1",
|
||||
"rxjs": "^7.8.1",
|
||||
"typeorm": "^0.3.17",
|
||||
"typeorm-naming-strategies": "^4.1.0",
|
||||
"ua-parser-js": "^1.0.36",
|
||||
"uuid": "^9.0.1",
|
||||
"winston": "^3.10.0",
|
||||
"nodemailer": "^6.9.5",
|
||||
"mysql2": "^3.6.1",
|
||||
"winston-daily-rotate-file": "^4.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cache-manager": "^2.1.0",
|
||||
"@nestjs/cli": "^9.0.0",
|
||||
"@nestjs/config": "^2.3.1",
|
||||
"@nestjs/devtools-integration": "^0.1.4",
|
||||
"@nestjs/jwt": "^10.0.3",
|
||||
"@nestjs/passport": "^9.0.3",
|
||||
"@nestjs/schematics": "^9.0.0",
|
||||
"@nestjs/serve-static": "^3.0.1",
|
||||
"@nestjs/swagger": "^6.3.0",
|
||||
"@nestjs/testing": "^9.0.0",
|
||||
"@nestjs/typeorm": "^9.0.1",
|
||||
"@types/express": "^4.17.13",
|
||||
"@nestjs/cli": "^9.5.0",
|
||||
"@nestjs/schematics": "^9.2.0",
|
||||
"@nestjs/testing": "^9.4.3",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jest": "28.1.4",
|
||||
"@types/lodash": "^4.14.192",
|
||||
"@types/lodash-es": "^4.17.7",
|
||||
"@types/lodash": "^4.14.198",
|
||||
"@types/lodash-es": "^4.17.9",
|
||||
"@types/mockjs": "^1.0.7",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^16.0.0",
|
||||
"@types/nodemailer": "^6.4.9",
|
||||
"@types/supertest": "^2.0.11",
|
||||
"@types/uuid": "^9.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||
"@typescript-eslint/parser": "^5.0.0",
|
||||
"@types/node": "^16.18.50",
|
||||
"@types/nodemailer": "^6.4.10",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@types/uuid": "^9.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
"cache-manager": "^5.2.3",
|
||||
"cache-manager-redis-store": "^3.0.1",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint": "^8.0.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint": "^8.49.0",
|
||||
"eslint-config-prettier": "^8.10.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"jest": "28.1.2",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mockjs": "^1.1.0",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"mysql2": "^3.2.0",
|
||||
"nodemailer": "^6.9.4",
|
||||
"passport": "^0.6.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"plop": "^3.1.2",
|
||||
"prettier": "^2.3.2",
|
||||
"redis": "^4.6.7",
|
||||
"source-map-support": "^0.5.20",
|
||||
"prettier": "^2.8.8",
|
||||
"redis": "^4.6.8",
|
||||
"source-map-support": "^0.5.21",
|
||||
"sqlite3": "^5.1.6",
|
||||
"supertest": "^6.1.3",
|
||||
"supertest": "^6.3.3",
|
||||
"ts-jest": "28.0.5",
|
||||
"ts-loader": "^9.2.3",
|
||||
"ts-node": "^10.0.0",
|
||||
"ts-loader": "^9.4.4",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsconfig-paths": "4.0.0",
|
||||
"typeorm": "^0.3.12",
|
||||
"typeorm-naming-strategies": "^4.1.0",
|
||||
"typescript": "^4.3.5",
|
||||
"uuid": "^9.0.0",
|
||||
"webpack": "5",
|
||||
"winston": "^3.10.0",
|
||||
"winston-daily-rotate-file": "^4.7.1"
|
||||
"typescript": "^4.9.5",
|
||||
"webpack": "^5.88.2"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
|
|
|
|||
2412
pnpm-lock.yaml
2412
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -16,11 +16,12 @@ module.exports = function main(/** @type { import('plop').NodePlopAPI } */ plop)
|
|||
});
|
||||
|
||||
plop.setGenerator('module', {
|
||||
description: '创建一个新的模块',
|
||||
prompts: [
|
||||
{
|
||||
name: 'name',
|
||||
message: '请输入模块名称',
|
||||
type: 'input',
|
||||
message: '请输入模块名称(支持嵌套,如: x/y)',
|
||||
validate: (input) => {
|
||||
if (/^(\w+\/)*(\w+)$/.test(input)) {
|
||||
return true;
|
||||
|
|
@ -30,8 +31,8 @@ module.exports = function main(/** @type { import('plop').NodePlopAPI } */ plop)
|
|||
},
|
||||
{
|
||||
name: 'cnName',
|
||||
message: '请输入模块中文名称',
|
||||
type: 'input',
|
||||
message: '请输入模块中文名称',
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
|
|
|
|||
|
|
@ -13,9 +13,14 @@ import { UserModule } from '@/modules/user';
|
|||
import { ResponseModule } from '@/common/response';
|
||||
import { SerializationModule } from '@/common/serialization';
|
||||
import { CacheModule } from './common/cache';
|
||||
import { ScanModule } from './utils/scan.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
/**
|
||||
* 扫描模块
|
||||
*/
|
||||
ScanModule.forRoot(),
|
||||
/**
|
||||
* 配置模块(全局)
|
||||
* @description 加载.env配置文件
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@ import { initSwagger } from '@/common/swagger';
|
|||
import { LoggerService } from '@/common/logger';
|
||||
import { ConfigService } from '@/config';
|
||||
import { AppModule } from './app.module';
|
||||
import { ScanModule } from './utils/scan.module';
|
||||
|
||||
async function bootstrap() {
|
||||
/**
|
||||
* 创建应用
|
||||
*/
|
||||
const app = await NestFactory.create(AppModule, { bufferLogs: false });
|
||||
const app = await NestFactory.create(AppModule, { bufferLogs: false, snapshot: ScanModule.enable });
|
||||
/**
|
||||
* 获取配置服务
|
||||
*/
|
||||
|
|
@ -42,6 +43,10 @@ async function bootstrap() {
|
|||
* 监听端口
|
||||
*/
|
||||
await app.listen(config.port, config.host);
|
||||
/**
|
||||
* 扫描应用
|
||||
*/
|
||||
ScanModule.scan(app);
|
||||
/**
|
||||
* 输出项目运行URL
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { BaseController } from '@/common/base';
|
||||
import { Respond, RespondType } from '@/common/response';
|
||||
import { Body, Controller, Delete, Get, Param, Patch, Post, Query, ParseIntPipe } from '@nestjs/common';
|
||||
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
|
||||
import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import { CreateLogDto } from './dto/create-log.dto';
|
||||
import { FindLogDto } from './dto/find-log.dto';
|
||||
import { UpdateLogDto } from './dto/update-log.dto';
|
||||
|
|
@ -36,6 +36,7 @@ export class LogController extends BaseController {
|
|||
@Get('login')
|
||||
@Respond(RespondType.PAGINATION)
|
||||
@ApiOkResponse({ isArray: true, type: LoginLog })
|
||||
@ApiOperation({ description: '分页查询登陆日志', operationId: 'getLoginLogs' })
|
||||
getLoginLogs(@Query() query: FindLogDto) {
|
||||
return this.logService.findMany(query);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ declare module 'express' {
|
|||
interface Request {
|
||||
user?: {
|
||||
id: number;
|
||||
token: string;
|
||||
username: string;
|
||||
nickname: string;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
import { DynamicModule, INestApplication, Module } from '@nestjs/common';
|
||||
import { DiscoveryModule, DiscoveryService, MetadataScanner, NestContainer } from '@nestjs/core';
|
||||
import {
|
||||
Entrypoint,
|
||||
HttpEntrypointMetadata,
|
||||
MiddlewareEntrypointMetadata,
|
||||
} from '@nestjs/core/inspector/interfaces/entrypoint.interface';
|
||||
|
||||
@Module({})
|
||||
export class ScanModule {
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
static enable = Boolean(process.env.xx);
|
||||
|
||||
/**
|
||||
* 注册模块
|
||||
*/
|
||||
static forRoot(): DynamicModule {
|
||||
return {
|
||||
module: ScanModule,
|
||||
imports: ScanModule.enable ? [DiscoveryModule] : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描路由/装饰器参数等信息
|
||||
* @param app 应用实例
|
||||
*/
|
||||
static scan(app: INestApplication) {
|
||||
if (!ScanModule.enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
const container = (app as any).container as NestContainer;
|
||||
const graph1 = container.serializedGraph.toJSON();
|
||||
const entries = Object.values(graph1.entrypoints).flat();
|
||||
for (const entry of entries) {
|
||||
if (ScanModule.isHttpEntryPoint(entry)) {
|
||||
console.log(entry.metadata.path);
|
||||
}
|
||||
if (ScanModule.isMiddlewareEntryPoint(entry)) {
|
||||
console.log(entry.metadata.path);
|
||||
}
|
||||
}
|
||||
|
||||
const scanner = app.get(MetadataScanner);
|
||||
const discover = app.get(DiscoveryService);
|
||||
const controllers = discover.getControllers();
|
||||
for (const wrapper of controllers) {
|
||||
const prototype = Object.getPrototypeOf(wrapper.instance);
|
||||
const methodNames = scanner.getAllMethodNames(prototype);
|
||||
console.log('method names:', methodNames);
|
||||
const metakeys = Reflect.getMetadataKeys(prototype);
|
||||
console.log('controller meta keys:', metakeys);
|
||||
for (const methodName of methodNames) {
|
||||
const metadata = Reflect.getMetadataKeys(prototype[methodName]);
|
||||
console.log('method meta keys:', metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否HTTP端点
|
||||
*/
|
||||
static isHttpEntryPoint(input: Entrypoint<unknown>): input is Entrypoint<HttpEntrypointMetadata> {
|
||||
return input.type === 'http-endpoint';
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否中间件端点
|
||||
*/
|
||||
static isMiddlewareEntryPoint(input: Entrypoint<unknown>): input is Entrypoint<MiddlewareEntrypointMetadata> {
|
||||
return input.type === 'middleware';
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue