Skip to content

dysf888/plugin-s3

Repository files navigation

plugin-template

Halo 2.0 插件开发快速开始模板(WIP)

项目结构介绍

.
├── LICENSE
├── README.md
├── admin-frontend
│   ├── README.md
│   ├── env.d.ts
│   ├── package.json
│   ├── pnpm-lock.yaml
│   ├── src
│   │   ├── assets
│   │   │   └── logo.svg
│   │   ├── components
│   │   │   └── HelloWorld.vue
│   │   ├── index.ts                                        # Admin Frontend Entry file
│   │   ├── styles
│   │   │   └── index.css
│   │   └── views
│   │       └── DefaultView.vue                             # Views Component
│   ├── tsconfig.app.json
│   ├── tsconfig.config.json
│   ├── tsconfig.json
│   ├── tsconfig.vitest.json
│   └── vite.config.ts                                              
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── lib
│   └── halo-2.0.0-SNAPSHOT-plain.jar
├── settings.gradle
└── src
    └── main
        ├── java
        │   └── run
        │       └── halo
        │           └── template
        │               ├── Apple.java
        │               ├── ApplesController.java
        │               └── TemplatePlugin.java                     # Main Class
        └── resources
            ├── admin
            │   ├── main.js                                         # Admin Frontend Entry file(production build)
            │   └── style.css
            ├── extensions
            │   ├── apple.yaml                                  
            │   ├── reverseProxy.yaml                               # Reverse Proxy Config
            │   ├── roleTemplate.yaml                               # Role Template Config
            │   └── settings.yaml                                   # Settings Config
            ├── plugin.yaml                                         # Plugin Config
            └── static
                ├── image.jpeg
                ├── some.txt
                └── test.html

对于以上目录树:

  • admin-frontend: 插件前端项目目录,为一个 Vue 项目,技术栈为 Vue 3 + Vite,其中已经预配置好了构建策略。

  • build:插件后端构建目录,build/libs 下的 jar 包为最终插件产物。

  • lib:为临时的 Halo 依赖,为了使用 Halo 中提供的类在 build.gradle 中作为编译时依赖引入 compileOnly files("lib/halo-2.0.0-SNAPSHOT-plain.jar") ,待 2.0 正式发布会将其发布到 maven 中央仓库,便可通过 gradle 依赖。

  • src: 为插件后端源码目录。

  • Apple.java: 为自定义模型。

    @GVK(group = "apple.guqing.xyz", kind = "Apple",
            version = "v1alpha1", singular = "apple", plural = "apples")
    @Data
    @EqualsAndHashCode(callSuper = true)
    public class Apple extends AbstractExtension {
    }

    关键在于标注 @GVK 注解和 extends AbstractExtension,当如此定义了一个模型后,插件启动时会根据 @GVK 配置自动生成CRUDRESTful API ,以此为例子会生成如下 APIs

    GET /apis/apple.guqing.xyz/v1alpha1/apples
    
    POST /apis/apple.guqing.xyz/v1alpha1/apples
    
    GET /apis/apple.guqing.xyz/v1alpha1/apples/{name}
    
    PUT /apis/apple.guqing.xyz/v1alpha1/apples/{name}
    
    DELETE /apis/apple.guqing.xyz/v1alpha1/apples/{name}

    生成规则见:Halo extension RFC

  • TemplatePlugin.java:插件生命周期入口,它继承 BasePlugin,可以通过 getApplicationContext() 方法获取到 SchemeManager,然后在 start() 方法中注册自定义模型,这一步必不可少,所有定义的自定义模型都需要在此注册,并在 stop() 生命周期方法中清理资源。

    public class TemplatePlugin extends BasePlugin {
        // ...
    
        @Override
        public void start() {
            schemeManager.register(Apple.class);
        }
    
        @Override
        public void stop() {
            Scheme scheme = schemeManager.get(Apple.class);
            schemeManager.unregister(scheme);
        }
    
        // ...
    }

    注意:该类不能标注 @Component 等能将其声明为 Spring Bean 的注解

  • ApplesController.java:如果根据模型自动生成的 CURD RESTful APIs 无法满足业务需要,可以写常规 Controller 来自定义 APIs,示例:

    @ApiVersion("v1alpha1")
    @RestController
    @RequestMapping("colors")
    public class ApplesController {
    
        @GetMapping
        public Mono<String> hello() {
            return Mono.just("Hello world");
        }
    }

    插件定义 Controller 必须要标注 @ApiVersion 注解,否则启动时会报错。如果定义了这样的 Controller ,插件启动后会生成如下的 APIs

    GET /api/v1alpha1/plugins/apples/colors

    生成规则为 /api/{version}/plugins/{plugin-name}/{mapping-in-class}/{mapping-in-method}

    其中:

    • version:来自 @ApiVersion("v1alpha1") 的 value,详情参考:Halo plugin API composition
    • plugin-name:值来自 plugin.yaml 中的 metadata.name 属性
    • mapping-in-class:来自标注在类上的 @RequestMapping("colors")
    • mapping-in-method:来自标注在方法上的 @GetMapping

    插件还允许使用 @Service@Component 注解将其声明为一个 Spring Bean,便可通过依赖注入使用 Spring Bean,示例:

    @Service
    public class ColorService {
        public String getColor(String appleName) {
            return "red";
        }
    }
    
    @ApiVersion("v1alpha1")
    @RestController
    @RequestMapping("colors")
    public class ApplesController {
        private final ColorService colorService;
    
        // 构造器注入,当然也同样允许 @Autowired 注入 和 setter 方法注入
        public ApplesController(ColorService colorService) {
            this.colorService = colorService;
        }
    }
  • resources:目录为插件资源目录

    • admin 目录下为插件前端打包后的产物存放目录,固定为 main.jsstyle.css 两个文件
    • extensions 存放自定义模型资源配置
    • plugin.yaml为插件描述配置
    • static 为静态资源示例目录

    插件启动时会加载 extensions 目录的 yaml 保存到数据库,apple.yaml 为本项目自定义的模型的数据示例,当启用插件后调用

    GET /apis/apple.guqing.xyz/v1alpha1/apples
    

    便可查询到 apple.yaml 中定义的记录

    [
      {
        "spec": {
          "varieties": "Fuji",
          "color": "red",
          "size": "middle",
          "producingArea": "China"
        },
        "apiVersion": "apple.guqing.xyz/v1alpha1",
        "kind": "Apple",
        "metadata": {
          "name": "Fuji-apple",
          "labels": {
            "plugin.halo.run/plugin-name": "apples"
          },
          "version": 0,
          "creationTimestamp": "2022-06-24T04:03:22.890741Z"
        }
      }
    ]

    reverseProxy.yaml 为 Halo 中提供的模型,表示反向代理,允许插件配置规则代理到插件目录

    apiVersion: plugin.halo.run/v1alpha1
    kind: ReverseProxy
    metadata:
      name: reverse-proxy-template
    rules:
      - path: /static/**
        file:
          directory: static

    它表示访问 GET /assets/{plugin-name}/static/** 时代理访问到插件的 resources/static 目录,本插件便可访问到一下静态资源

    GET /assets/apples/static/image.jpeg
    GET /assets/apples/static/some.txt
    GET /assets/apples/static/test.html
    

    roleTemplate.yaml 文件中 kind: Role 表示插件允许提供角色模版,定义格式如下:

    apiVersion: v1alpha1
    kind: Role
    metadata:
      name: a name here
      labels:
        plugin.halo.run/role-template: "true"
      annotations:
        plugin.halo.run/module: "module name"
        plugin.halo.run/alias-name: "display name"
    rules:
    # ...

    必须带有plugin.halo.run/role-template: "true" labels,表示该角色为角色模版,当用户启用插件后,创建角色或修改角色时会将其列在权限列表位置。

    插件如果不提供角色模版除非是超级管理员否则其他账号没有权限访问,因为 Halo 规定 /api/apis 开头的 api 都需要授权才能访问,因此插件不提供角色模版的自定义资源,就无法将其分配给用户。

更多详情参考:Halo security RFC

开发环境

环境要求

  • OpenJDK 17
  • NodeJS 16+
  • pnpm 7+

拉取 Halo 相关项目源码

mkdir ./halo-dev

mkdir ./halo-dev/dev-plugins # 存放插件源码
cd ./halo-dev

git clone https://github.com/halo-dev/halo --branch next
git clone https://github.com/halo-dev/halo-admin --branch next
cd ./dev-plugins

git clone https://github.com/halo-sigs/plugin-template

Halo 配置文件修改

修改 halo/src/main/resources/application-dev.yaml

halo:
  security:
    initializer:
      super-admin-username: admin
      super-admin-password: P@88w0rd
    oauth2:
      jwt:
        jwsAlgorithm: rs512
        public-key-location: classpath:app.pub
        private-key-location: classpath:app.key
  plugin:
    runtime-mode: development # development, deployment
    classes-directories:
      - "build/classes"
      - "build/resources"
    lib-directories:
      - "libs"
    plugins-root: /Users/ryanwang/Workspace/github/ruibaby/halo-dev/dev-plugins # 修改为上方存放插件源码的实际目录
  initial-extension-locations: # 初始化资源加载配置,需要配置当前开发中插件的资源目录或者文件
    - "/Users/ryanwang/Workspace/github/ruibaby/halo-dev/dev-plugins/plugin-template/src/main/resources/plugin.yaml"

编译插件

下载前端依赖:

cd ./halo-dev/dev-plugins/plugin-template

./gradlew.bat pnpmInstall

# or macOS/Linux

./gradlew pnpmInstall

构建:

./gradlew.bat build

# or macOS/Linux

./gradlew build

启动 Halo

cd ./halo-dev/halo

./gradlew.bat bootRun --args="--spring.profiles.active=dev"

# or macOS/Linux

./gradlew bootRun --args="--spring.profiles.active=dev"

或者在 IntelliJ IDEA 中运行 Application 启动类。但注意需要配置好 spring.profiles.active 为 dev。

启动 Halo Admin

cd ./halo-dev/halo-admin

pnpm install

pnpm build:packages

pnpm dev

访问后台

在浏览器中访问 https://localhost:3000 即可,登录用户名和密码为上方 application-dev.yaml 配置中的 super-admin-usernamesuper-admin-password

然后在左侧菜单中选择 插件,即可查看所有插件的状态。

开发

修改前端代码或者后端代码,然后运行 ./gradlew.bat build 或者 ./gradlew build(macOS/Linux)即可构建插件,无需重启 Halo。但修改配置文件后需要 build 插件以及重启 Halo。

构建生产产物

./gradlew -x build

然后只需复制例如build/libs/plugin-template-0.0.1-SNAPSHOT-plain.jarjar 包即可使用。

About

为 Halo 提供 S3 对象存储协议的存储策略

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Java 71.7%
  • Vue 18.6%
  • TypeScript 9.3%
  • JavaScript 0.4%