{"id":22561778,"url":"https://github.com/bpcloud/bpframework","last_synced_at":"2025-04-10T10:20:30.843Z","repository":{"id":49547426,"uuid":"311271737","full_name":"bpcloud/bpframework","owner":"bpcloud","description":"Write SpringBoot / SpringCloud in Typescript","archived":false,"fork":false,"pushed_at":"2025-03-20T14:19:32.000Z","size":379,"stargazers_count":3,"open_issues_count":1,"forks_count":4,"subscribers_count":2,"default_branch":"dev","last_synced_at":"2025-04-01T07:21:12.620Z","etag":null,"topics":["async","autowired","controller","feignclient","middleware","nodejs-java","spring","springboot","springcloud","task","web-framework"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bpcloud.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-09T08:30:34.000Z","updated_at":"2025-03-20T14:19:36.000Z","dependencies_parsed_at":"2025-02-12T17:39:44.379Z","dependency_job_id":null,"html_url":"https://github.com/bpcloud/bpframework","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bpcloud%2Fbpframework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bpcloud%2Fbpframework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bpcloud%2Fbpframework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bpcloud%2Fbpframework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bpcloud","download_url":"https://codeload.github.com/bpcloud/bpframework/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248198977,"owners_count":21063641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","autowired","controller","feignclient","middleware","nodejs-java","spring","springboot","springcloud","task","web-framework"],"created_at":"2024-12-07T22:09:45.201Z","updated_at":"2025-04-10T10:20:30.826Z","avatar_url":"https://github.com/bpcloud.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cfont color=red\u003eThis project is still in development\u003c/font\u003e\n\n- [Setup.](#setup)\n- [Example.](#example)\n- [Feature.](#feature)\n- [Configure.](#configure)\n  - [@FindMicroserviceConfigure](#findmicroserviceconfigure)\n  - [@RestControllerConfigure](#restcontrollerconfigure)\n  - [@IgnoreRestLogger](#ignorerestlogger)\n  - [@RequestConditional](#requestconditional)\n  - [@FeignClientConfigure](#feignclientconfigure)\n  - [@Value](#value)\n- [Middleware.](#middleware)\n- [Event Listener.](#event-listener)\n  - [@ContextRefreshedEventListener](#contextrefreshedeventlistener)\n  - [@RefreshRemoteEventListener](#refreshremoteeventlistener)\n  - [@InstanceRegisteredEventListener](#instanceregisteredeventlistener)\n- [Scheduling](#scheduling)\n  - [@Scheduled](#scheduled)\n- [Bean](#bean)\n  - [@Service](#service)\n  - [@Bean](#bean-1)\n  - [@Autowired](#autowired)\n  - [@Value](#value-1)\n\n## Setup.\n\nuse cli to create a project.\n\n```bash\nnpm i bpframework-cli -g\n```\n\ncreate a project.\n\n```bash\nbpframework init\n```\n\n## Example.\n\nsee directory [./examples](./examples)\n\n## Feature.\n\n| feature     | supports                           |\n| ----------- | ---------------------------------- |\n| config      | bootstrap.yml\u003cbr\u003eSpringCloudConfig |\n| discovery   | nacos                              |\n| scheduling  | @Scheduled                         |\n| api routers | @RestController                    |\n\n## Configure.\n\nThe appropriate configuration is required to enable the corresponding feature: [config](./config.md)\n\n| name                                                    | description                           |\n| ------------------------------------------------------- | ------------------------------------- |\n| [FindMicroserviceConfigure](#findmicroserviceconfigure) | 定义自定义的服务发现处理方法          |\n| [FeignClientConfigure](#feignclientconfigure)           | 定义FeignClient的默认headers等信息    |\n| [RestControllerConfigure](#restcontrollerconfigure)     | 定义RestController的默认headers等信息 |\n\n\n### @FindMicroserviceConfigure\n\nBy default, nacos is used to find micro-service; You can customize it by `@FindMicroserviceConfigure`.\n\n```js\n@Service()\nclass Configure {\n  @FindMicroserviceConfigure\n  async onFindMicroservice(serviceName: string, excludeHost: string): Promise\u003cServiceInfo\u003e {\n    return {\n      ip,\n      port,\n      serviceName,\n      metadata,\n    }\n  }\n}\n```\n\n### @RestControllerConfigure\n\n定义RestController的默认headers等信息, 使用如下方式.\n\n```js\n@Service()\nclass Configure {\n  @RestControllerConfigure\n  onConfigure(): bp.RestControllerConfigureInfo {\n    return {\n      defaultHeaders: {'content-type': 'application/json;charset=utf-8'},\n    }\n  }\n}\n```\n\n### @IgnoreRestLogger\n\n用于忽略rest请求的日志, 使用如下方式.\n\n```js\n@RestController({ path: '/api' })\nclass Rest {\n  @IgnoreRestLogger\n  @RequestMapping({ path: '/url', method: RequestMethod.GET })\n  async request(\n    @RestObject obj: RestObjectTypeRest\u003ckoa.Context\u003e // or RestObjectType\n  ): Promise\u003cListRolesRequest\u003e {\n    ...\n  }\n}\n```\n\n### @RequestConditional\n\n用于判断rest请求是否执行\n\n```js\ntype RequestMatchFunction = (restObjec: RestObjectType\u003cany\u003e | RestObjectTypeFeign\u003cany\u003e) =\u003e Promise\u003cboolean\u003e;\n/**\n * @desc 当match函数返回false时，不继续执行请求.\n * \n * @returns {MethodDecorator}\n */\nexport function RequestConditional(match: RequestMatchFunction): MethodDecorator;\n```\n\n实例\n\n```js\n@RestController({ path: '/api' })\nclass Rest {\n  @RequestConditional(async (restObject:RestObjectType\u003cany\u003e):Promise\u003cboolean\u003e =\u003e {\n    return false;\n  })\n  @RequestMapping({ path: '/url', method: RequestMethod.GET })\n  async request(\n    @RestObject obj: RestObjectTypeRest\u003ckoa.Context\u003e // or RestObjectType\n  ): Promise\u003cListRolesRequest\u003e {\n    // 将不执行.\n  }\n}\n```\n\n### @FeignClientConfigure\n\n定义FeignClient的默认headers等信息, 使用如下方式.\n\n```js\n@Service()\nclass Configure {\n  @FeignClientConfigure\n  onConfigure(): bp.FeignClientConfigureInfo {\n    return {\n      defaultHeaders: {'content-type': 'application/json;charset=utf-8'},\n      /**\n       * 对每次请求后接收的消息进行过滤.\n       */\n      filterResponseCallback: (data: FeignClientFilterResponseData) =\u003e {\n        \n      },\n      /**\n       * Processing the data of the request.\n       */\n      filterRequestCallback: (data: FeignClientFilterRequestData, feignData: FeignDataType) =\u003e {\n\n      }\n    }\n  }\n}\n```\n\n### @Value\n\n使用 @Value 注解设置初始值或获取配置值.\n\n```js\n@Service()\nclass Demo {\n  @Value(\"Miss A\")\n  teacher1Name: string; // will set to 'Miss A'\n\n  @Value(\"${teacherName2}\")\n  teacher2Name: string; // will set to config value \"teacherName2\"\n\n  @Value(\"${teacherName3:defaultName}\")\n  teacher3Name: string; // will set to 'defaultName' if config value \"teacherName3\" isn't existed.\n}\n```\n\n## Middleware.\n\nsee https://github.com/bpcloud/middleware.git\n\n## Event Listener.\n\n| name                                                                | description                                 |\n| ------------------------------------------------------------------- | ------------------------------------------- |\n| [ContextRefreshedEventListener](#ContextRefreshedEventListener)     | 本地配置加载完成, 系统service对象初始化完成 |\n| [RefreshRemoteEventListener](#RefreshRemoteEventListener)           | 远程配置动态刷新事件                        |\n| [InstanceRegisteredEventListener](#InstanceRegisteredEventListener) | 实例注册到注册中心后的事件                  |\n\n### @ContextRefreshedEventListener\n\n本地配置加载完成, 系统service对象初始化完成.\n\n```js\n@Service()\nclass ApplicationEvent {\n  @ContextRefreshedEventListener\n  async onContextRefreshed(ev:ContextRefreshedEvent):void {\n\n  }\n}\n```\n\n### @RefreshRemoteEventListener\n\n远程配置动态刷新事件.\n\n```js\n@Service()\nclass ApplicationEvent {\n  @RefreshRemoteEventListener\n  async onRefreshRemote(ev:RefreshRemoteEvent):void {\n\n  }\n}\n```\n\n### @InstanceRegisteredEventListener\n\n实例注册到注册中心后的事件.\n\n```js\n@Service()\nclass ApplicationEvent {\n  @InstanceRegisteredEventListener\n  async onInstanceRegistered(ev:InstanceRegisteredEvent):void {\n    \n  }\n}\n```\n\n## Scheduling\n\n### @Scheduled\n\n全局启动scheduled\n\n```js\nglobal.__enableScheduled = true;\n```\n\n使用此注解可以开启一个定时任务.\n\n```js\n@Service()\nclass Demo {\n  @Scheduled({cron:'* * * * * *'})\n  async onTick(): Promise\u003cfalse|void\u003e {\n    return false; // 返回false则表明停止此task.\n  }\n}\n```\n\n- Start task:  当类实例被创建后, task即按照时间间隔运行\n- Stop task: 当@Scheduled修饰的方法明确返回false时, task将停止\n\n## Bean\n\n### @Service\n\n可以使用此注解实例化对象\n\n```js\n\n/**\n * 加载所有的bean, 并进行实例化等操作.\n */\nexport function finishBeans(): Promise\u003cvoid\u003e;\n\n/**\n* @desc 获得已装配完的指定类型的service.\n*/\nexport function getServiceInstances(key: any): ServiceInstanceType;\n\n/**\n * 无需等待执行 finishBeans().\n * \n * @returns {ClassDecorator}\n */\nexport function ImmediatelyService(name: string): ClassDecorator;\nexport function ImmediatelyService(cfg?: { singleton?: boolean, name?: string }): ClassDecorator;\n\n/**\n * @desc 表明指定的类为Service类.\n * \n * 定义为Service的类, 在源文件被引用后, 单例bean将会自动在全局创建一个实例.\n * \n * @description \n *  `Service` 与 `Bean` 都是延迟注入类型; 需要在 `finishBeans()` 方法调用之后才能够生效.\n *  需实现立即生效类型使用 `ImmediatelyService`\n * \n * @param cfg.singleton 是否为单例; (默认单例)\n * @param cfg.name      使用名称注入; 如不使用名称,则使用类型注入.\n *\n * @returns {ClassDecorator}\n */\nexport function Service(name: string): ClassDecorator;\nexport function Service(cfg?: { singleton?: boolean, name?: string }): ClassDecorator;\n```\n\n示例：\n\n```js\n/**\n * 在app初始化完成后将自动实例化.\n */\n@Service()\nclass Example {\n  constructor() {}\n}\n\n/**\n * 立即自动实例化.\n */\n@ImmediatelyService()\nclass Example {\n  constructor() {}\n}\n```\n\n### @Bean\n\n```js\n\n/**\n * @desc 表明指定的属性为Bean.\n * \n * \u003cBean修饰的方法不允许带参数, 并且返回的类型作为注入对象的类型.\u003e\n * 定义为Bean, 在源文件被引用后, 单例bean将会自动在全局创建一个实例.\n * \n * @description \n *  `Service` 与 `Bean` 都是延迟注入类型; 需要在 `finishBeans()` 方法调用之后才能够生效.\n *  需实现立即生效类型使用 `ImmediatelyService`\n * \n * @param cfg.singleton 是否为单例; (默认单例)\n * @param cfg.name      使用名称注入; 如不使用名称,则使用方法名注入.\n * \n * @example\n * \n * ﹫Service()\n * class {\n *       ﹫Bean() \n *       foo(): Object { \n *           return {};\n *       }\n * \n *       ﹫Autowired('foo')\n *       private obj: Object;\n * }\n * @returns {PropertyDecorator}\n */\nexport function Bean(name: string): MethodDecorator;\nexport function Bean(cfg?: { singleton?: boolean, name?: string }): MethodDecorator;\n```\n\n\n### @Autowired\n\n\n```js\n/**\n * @desc 表明指定的属性可以自动装载指定的Service实例.\n * \n * @example\n *  ﹫Autowired(ClassA)\n *  obj: ClassA;  // will to auto create object.\n * \n * @returns {PropertyDecorator}\n */\nexport function Autowired(type: Function|string): PropertyDecorator;\n```\n\n### @Value\n\n```js\n/**\n * @desc 表明指定的属性可以自动装载指定的值.\n * @description 无需添加 RefreshScope 注解; 在配置刷新时会自动变更值.\n * @example\n *   ﹫Service()\n *   class Demo {\n *     ﹫Value(\"Miss A\")\n *     teacher1Name: string; // will set to 'Miss A'\n * \n *     ﹫Value(\"${teacherName2}\")\n *     teacher2Name: string; // will set to config value \"teacherName2\"\n * \n *     ﹫Value(\"${teacherName3:defaultName}\")\n *     teacher3Name: string; // will set to 'defaultName' if config value \"teacherName3\" isn't existed.\n *   }\n * \n * @returns {PropertyDecorator}\n */\n\nexport function Value(value: any): PropertyDecorator;\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbpcloud%2Fbpframework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbpcloud%2Fbpframework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbpcloud%2Fbpframework/lists"}