docs: update plugin development document

Signed-off-by: Ryan Wang <i@ryanc.cc>
This commit is contained in:
Ryan Wang
2022-07-15 18:03:10 +08:00
parent a058a08907
commit cb8508bb5f

251
README.md
View File

@@ -1,6 +1,6 @@
# halo-plugin-template
# plugin-template
A Halo plugin template for backend development
Halo 2.0 插件开发快速开始模板WIP
## 如何开发一个 Halo 插件
@@ -16,59 +16,82 @@ A Halo plugin template for backend development
├── LICENSE
├── README.md
├── admin-frontend
│   ├── ...
├── build
│   ├── classes
│   ├── libs
│   │   ├── halo-plugin-template-0.0.1-SNAPSHOT-plain.jar
│   ├── resources
│   ├── 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
│   └── io
│   └── github
│   └── guqing
│   └── run
│   └── halo
│   └── template
│   ├── Apple.java
│   ├── ApplePlugin.java
│   └── ApplesController.java
│   ├── ApplesController.java
│   └── TemplatePlugin.java # Main Class
└── resources
├── admin
│   ├── main.js
│   ├── main.js # Admin Frontend Entry file(production build)
│   └── style.css
├── extensions
│   ├── apple.yaml
│   ├── reverseProxy.yaml
│   ── roleTemplate.yaml
├── plugin.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 项目
- `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` 为自定义模型
- `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` 为自定义模型
```java
@GVK(group = "apple.guqing.xyz", kind = "Apple",
version = "v1alpha1", singular = "apple", plural = "apples")
@Data
@EqualsAndHashCode(callSuper = true)
public class Apple extends AbstractExtension {}
public class Apple extends AbstractExtension {
}
```
关键在于标注 `@GVK `注解和 `extends AbstractExtension`,当如此定义了一个模型后,插件启动时会根据 `@GVK` 配置自动生成`CRUD``RESTful API`,以此为例子会生成如下`APIs`
关键在于标注 `@GVK` 注解和 `extends AbstractExtension`,当如此定义了一个模型后,插件启动时会根据 `@GVK` 配置自动生成`CRUD`的 `RESTful API`
,以此为例子会生成如下 `APIs`
```text
```http
GET /apis/apple.guqing.xyz/v1alpha1/apples
POST /apis/apple.guqing.xyz/v1alpha1/apples
@@ -82,9 +105,13 @@ DELETE /apis/apple.guqing.xyz/v1alpha1/apples/{name}
生成规则见:[Halo extension RFC](https://github.com/halo-dev/rfcs/tree/main/extension)
- `ApplePlugin.java`:插件生命周期入口,它继承 `BasePlugin`,可以通过`getApplicationContext()`方法获取到 `SchemeManager`,然后在 `start()` 方法中注册自定义模型,这一步必不可少,所有定义的自定义模型都需要在此注册,并在 `stop()` 生命周期方法中清理资源。
- `TemplatePlugin.java`:插件生命周期入口,它继承 `BasePlugin`,可以通过 `getApplicationContext()` 方法获取到 `SchemeManager`,然后在 `start()`
方法中注册自定义模型,这一步必不可少,所有定义的自定义模型都需要在此注册,并在 `stop()` 生命周期方法中清理资源。
```java
public class TemplatePlugin extends BasePlugin {
// ...
@Override
public void start() {
schemeManager.register(Apple.class);
@@ -92,10 +119,12 @@ public void start() {
@Override
public void stop() {
// TODO 优化取消注册自定义模型的写法
Scheme scheme = schemeManager.get(Apple.class);
schemeManager.unregister(scheme);
}
// ...
}
```
注意:该类不能标注 `@Component` 等能将其声明为 `Spring Bean` 的注解
@@ -103,6 +132,7 @@ public void stop() {
- `ApplesController.java`:如果根据模型自动生成的 `CURD RESTful APIs` 无法满足业务需要,可以写常规 `Controller` 来自定义 `APIs`,示例:
```java
@ApiVersion("v1alpha1")
@RestController
@RequestMapping("colors")
@@ -115,9 +145,9 @@ public class ApplesController {
}
```
插件定义 `Controller` 必须要标注 `@ApiVersion` 注解,否则启动时会报错。如果定义了这样的 `Controller` ,插件启动后会生成如下的 `APIs`
插件定义 `Controller` 必须要标注 `@ApiVersion` 注解,否则启动时会报错。如果定义了这样的 `Controller` ,插件启动后会生成如下的 `APIs`
```text
```http
GET /api/v1alpha1/plugins/apples/colors
```
@@ -125,8 +155,8 @@ GET /api/v1alpha1/plugins/apples/colors
其中:
- `version`:来自 `@ApiVersion("v1alpha1") `的 value详情参考[Halo plugin API composition](https://github.com/halo-dev/rfcs/blob/main/plugin/pluggable-design.md#api-%E6%9E%84%E6%88%90%E8%AE%A8%E8%AE%BA)
- `version`:来自 `@ApiVersion("v1alpha1")` 的
value详情参考[Halo plugin API composition](https://github.com/halo-dev/rfcs/blob/main/plugin/pluggable-design.md#api-%E6%9E%84%E6%88%90%E8%AE%A8%E8%AE%BA)
- `plugin-name`:值来自 `plugin.yaml` 中的 `metadata.name` 属性
- `mapping-in-class`:来自标注在类上的 `@RequestMapping("colors")`
- `mapping-in-method`:来自标注在方法上的 `@GetMapping`
@@ -134,6 +164,7 @@ GET /api/v1alpha1/plugins/apples/colors
插件还允许使用 `@Service`、`@Component` 注解将其声明为一个 `Spring Bean`,便可通过依赖注入使用 `Spring Bean`,示例:
```java
@Service
public class ColorService {
public String getColor(String appleName) {
@@ -146,6 +177,7 @@ public class ColorService {
@RequestMapping("colors")
public class ApplesController {
private final ColorService colorService;
// 构造器注入,当然也同样允许 @Autowired 注入 和 setter 方法注入
public ApplesController(ColorService colorService) {
this.colorService = colorService;
@@ -154,27 +186,10 @@ public class ApplesController {
```
- `resources`:目录为插件资源目录
`admin` 目录下为插件前端打包后的产物存放目录,固定为 `main.js``style.css `两个文件
`extensions` 存放自定义模型资源配置
`plugin.yaml`为插件描述配置
`static` 为静态资源示例目录
├── admin
│ ├── main.js
│ └── style.css
├── extensions
│ ├── apple.yaml
│ ├── reverseProxy.yaml
│ └── roleTemplate.yaml
├── plugin.yaml
└── static
├── image.jpeg
├── some.txt
└── test.html
- `admin` 目录下为插件前端打包后的产物存放目录,固定为 `main.js` 和 `style.css `两个文件
- `extensions` 存放自定义模型资源配置
- `plugin.yaml`为插件描述配置
- `static` 为静态资源示例目录
插件启动时会加载 `extensions` 目录的 `yaml` 保存到数据库,`apple.yaml` 为本项目自定义的模型的数据示例,当启用插件后调用
@@ -250,38 +265,128 @@ rules:
更多详情参考:[Halo security RFC](https://github.com/halo-dev/rfcs/blob/main/identity/002-security.md)
### 打包
### 开发环境
#### 打包前端项目
#### 环境要求
1.`admin-frontend` 目录下执行
- openJDK 17
- NodeJS 16+
- pnpm 7+
#### 拉取 Halo 相关项目源码
```bash
mkdir ./halo-dev
mkdir ./halo-dev/dev-plugins # 存放插件源码
```
```bash
cd ./halo-dev
git clone https://github.com/halo-dev/halo --branch next
```
```bash
git clone https://github.com/halo-dev/halo-admin --branch next
```
```bash
cd ./dev-plugins
git clone https://github.com/halo-sigs/plugin-template
```
#### Halo 配置文件修改
修改 halo/src/resources/application-dev.yaml
```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"
```
#### 编译插件
下载前端依赖:
```bash
cd ./halo-dev/dev-plugins/plugin-template
./gradlew.bat pnpmInstall
# or macOS/Linux
./gradlew pnpmInstall
```
构建:
```bash
./gradlew.bat build
# or macOS/Linux
./gradlew build
```
#### 启动 Halo
```bash
cd ./halo-dev/halo
./graldew.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
```bash
cd ./halo-dev/halo-admin
```shell
pnpm install
pnpm dev
```
2. 开发时执行
#### 访问后台
```shell
pnpm run dev
```
在浏览器中访问 https://localhost:3000 即可,登录用户名和密码为上方 `application-dev.yaml` 配置中的 `super-admin-username`
和 `super-admin-password`。
3. 打包时执行
然后在左侧菜单中选择 `插件`,即可查看所有插件的状态。
```shell
pnpm run build
```
#### 开发
#### 构建后端
修改前端代码或者后端代码,然后运行 `./gradlew.bat build` 或者 `./gradlew build`macOS/Linux即可构建插件无需重启 Halo。但修改配置文件后需要 build 插件以及重启 Halo。
1. 开发时可以使用 `command + F9 / ctrl + F9`
2. 生产时:点击 `gradle``build`
或者执行
### 构建生产产物
```
./gradlew -x build
```
然后只需复制例如`build/libs/halo-plugin-template-0.0.1-SNAPSHOT-plain.jar``jar` 包即可使用
然后只需复制例如`build/libs/plugin-template-0.0.1-SNAPSHOT-plain.jar` 的 `jar` 包即可使用