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",
|
"orm": "typeorm-ts-node-esm -d ./src/database/datasource/index.ts",
|
||||||
"g": "plop --plopfile scripts/template/index.js"
|
"g": "plop --plopfile scripts/template/index.js"
|
||||||
},
|
},
|
||||||
"prettier": {
|
|
||||||
"printWidth": 120,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "all",
|
|
||||||
"endOfLine": "auto"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nestjs/axios": "^3.0.0",
|
"@nestjs/axios": "^3.0.0",
|
||||||
"@nestjs/common": "^9.0.0",
|
"@nestjs/common": "^9.4.3",
|
||||||
"@nestjs/core": "^9.0.0",
|
"@nestjs/core": "^9.4.3",
|
||||||
"@nestjs/platform-express": "^9.0.0",
|
"@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",
|
"axios": "^1.5.0",
|
||||||
|
"class-transformer": "^0.5.1",
|
||||||
|
"class-validator": "^0.14.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rxjs": "^7.2.0",
|
"dayjs": "^1.11.9",
|
||||||
"ua-parser-js": "^1.0.36"
|
"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": {
|
"devDependencies": {
|
||||||
"@nestjs/cache-manager": "^2.1.0",
|
"@nestjs/cache-manager": "^2.1.0",
|
||||||
"@nestjs/cli": "^9.0.0",
|
"@nestjs/cli": "^9.5.0",
|
||||||
"@nestjs/config": "^2.3.1",
|
"@nestjs/schematics": "^9.2.0",
|
||||||
"@nestjs/devtools-integration": "^0.1.4",
|
"@nestjs/testing": "^9.4.3",
|
||||||
"@nestjs/jwt": "^10.0.3",
|
"@types/express": "^4.17.17",
|
||||||
"@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",
|
|
||||||
"@types/jest": "28.1.4",
|
"@types/jest": "28.1.4",
|
||||||
"@types/lodash": "^4.14.192",
|
"@types/lodash": "^4.14.198",
|
||||||
"@types/lodash-es": "^4.17.7",
|
"@types/lodash-es": "^4.17.9",
|
||||||
"@types/mockjs": "^1.0.7",
|
"@types/mockjs": "^1.0.7",
|
||||||
"@types/multer": "^1.4.7",
|
"@types/multer": "^1.4.7",
|
||||||
"@types/node": "^16.0.0",
|
"@types/node": "^16.18.50",
|
||||||
"@types/nodemailer": "^6.4.9",
|
"@types/nodemailer": "^6.4.10",
|
||||||
"@types/supertest": "^2.0.11",
|
"@types/supertest": "^2.0.12",
|
||||||
"@types/uuid": "^9.0.1",
|
"@types/uuid": "^9.0.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||||
"@typescript-eslint/parser": "^5.0.0",
|
"@typescript-eslint/parser": "^5.62.0",
|
||||||
"cache-manager": "^5.2.3",
|
"cache-manager": "^5.2.3",
|
||||||
"cache-manager-redis-store": "^3.0.1",
|
"cache-manager-redis-store": "^3.0.1",
|
||||||
"class-transformer": "^0.5.1",
|
"eslint": "^8.49.0",
|
||||||
"class-validator": "^0.14.0",
|
"eslint-config-prettier": "^8.10.0",
|
||||||
"dayjs": "^1.11.7",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"dotenv": "^16.0.3",
|
|
||||||
"eslint": "^8.0.1",
|
|
||||||
"eslint-config-prettier": "^8.3.0",
|
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
|
||||||
"jest": "28.1.2",
|
"jest": "28.1.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"multer": "1.4.5-lts.1",
|
"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",
|
"plop": "^3.1.2",
|
||||||
"prettier": "^2.3.2",
|
"prettier": "^2.8.8",
|
||||||
"redis": "^4.6.7",
|
"redis": "^4.6.8",
|
||||||
"source-map-support": "^0.5.20",
|
"source-map-support": "^0.5.21",
|
||||||
"sqlite3": "^5.1.6",
|
"sqlite3": "^5.1.6",
|
||||||
"supertest": "^6.1.3",
|
"supertest": "^6.3.3",
|
||||||
"ts-jest": "28.0.5",
|
"ts-jest": "28.0.5",
|
||||||
"ts-loader": "^9.2.3",
|
"ts-loader": "^9.4.4",
|
||||||
"ts-node": "^10.0.0",
|
"ts-node": "^10.9.1",
|
||||||
"tsconfig-paths": "4.0.0",
|
"tsconfig-paths": "4.0.0",
|
||||||
"typeorm": "^0.3.12",
|
"typescript": "^4.9.5",
|
||||||
"typeorm-naming-strategies": "^4.1.0",
|
"webpack": "^5.88.2"
|
||||||
"typescript": "^4.3.5",
|
|
||||||
"uuid": "^9.0.0",
|
|
||||||
"webpack": "5",
|
|
||||||
"winston": "^3.10.0",
|
|
||||||
"winston-daily-rotate-file": "^4.7.1"
|
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"moduleFileExtensions": [
|
"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', {
|
plop.setGenerator('module', {
|
||||||
|
description: '创建一个新的模块',
|
||||||
prompts: [
|
prompts: [
|
||||||
{
|
{
|
||||||
name: 'name',
|
name: 'name',
|
||||||
message: '请输入模块名称',
|
|
||||||
type: 'input',
|
type: 'input',
|
||||||
|
message: '请输入模块名称(支持嵌套,如: x/y)',
|
||||||
validate: (input) => {
|
validate: (input) => {
|
||||||
if (/^(\w+\/)*(\w+)$/.test(input)) {
|
if (/^(\w+\/)*(\w+)$/.test(input)) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -30,8 +31,8 @@ module.exports = function main(/** @type { import('plop').NodePlopAPI } */ plop)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'cnName',
|
name: 'cnName',
|
||||||
message: '请输入模块中文名称',
|
|
||||||
type: 'input',
|
type: 'input',
|
||||||
|
message: '请输入模块中文名称',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
actions: [
|
actions: [
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,14 @@ import { UserModule } from '@/modules/user';
|
||||||
import { ResponseModule } from '@/common/response';
|
import { ResponseModule } from '@/common/response';
|
||||||
import { SerializationModule } from '@/common/serialization';
|
import { SerializationModule } from '@/common/serialization';
|
||||||
import { CacheModule } from './common/cache';
|
import { CacheModule } from './common/cache';
|
||||||
|
import { ScanModule } from './utils/scan.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
/**
|
||||||
|
* 扫描模块
|
||||||
|
*/
|
||||||
|
ScanModule.forRoot(),
|
||||||
/**
|
/**
|
||||||
* 配置模块(全局)
|
* 配置模块(全局)
|
||||||
* @description 加载.env配置文件
|
* @description 加载.env配置文件
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,13 @@ import { initSwagger } from '@/common/swagger';
|
||||||
import { LoggerService } from '@/common/logger';
|
import { LoggerService } from '@/common/logger';
|
||||||
import { ConfigService } from '@/config';
|
import { ConfigService } from '@/config';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
|
import { ScanModule } from './utils/scan.module';
|
||||||
|
|
||||||
async function bootstrap() {
|
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);
|
await app.listen(config.port, config.host);
|
||||||
|
/**
|
||||||
|
* 扫描应用
|
||||||
|
*/
|
||||||
|
ScanModule.scan(app);
|
||||||
/**
|
/**
|
||||||
* 输出项目运行URL
|
* 输出项目运行URL
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { BaseController } from '@/common/base';
|
import { BaseController } from '@/common/base';
|
||||||
import { Respond, RespondType } from '@/common/response';
|
import { Respond, RespondType } from '@/common/response';
|
||||||
import { Body, Controller, Delete, Get, Param, Patch, Post, Query, ParseIntPipe } from '@nestjs/common';
|
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 { CreateLogDto } from './dto/create-log.dto';
|
||||||
import { FindLogDto } from './dto/find-log.dto';
|
import { FindLogDto } from './dto/find-log.dto';
|
||||||
import { UpdateLogDto } from './dto/update-log.dto';
|
import { UpdateLogDto } from './dto/update-log.dto';
|
||||||
|
|
@ -36,6 +36,7 @@ export class LogController extends BaseController {
|
||||||
@Get('login')
|
@Get('login')
|
||||||
@Respond(RespondType.PAGINATION)
|
@Respond(RespondType.PAGINATION)
|
||||||
@ApiOkResponse({ isArray: true, type: LoginLog })
|
@ApiOkResponse({ isArray: true, type: LoginLog })
|
||||||
|
@ApiOperation({ description: '分页查询登陆日志', operationId: 'getLoginLogs' })
|
||||||
getLoginLogs(@Query() query: FindLogDto) {
|
getLoginLogs(@Query() query: FindLogDto) {
|
||||||
return this.logService.findMany(query);
|
return this.logService.findMany(query);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ declare module 'express' {
|
||||||
interface Request {
|
interface Request {
|
||||||
user?: {
|
user?: {
|
||||||
id: number;
|
id: number;
|
||||||
|
token: string;
|
||||||
username: string;
|
username: string;
|
||||||
nickname: 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