docs: update readme (#8)

更新 README。

/kind documentation

```release-note
None
```
This commit is contained in:
Ryan Wang
2023-02-27 15:26:15 +08:00
committed by GitHub
parent 43c88472fc
commit 54a6a695c2

384
README.md
View File

@@ -1,393 +1,45 @@
# plugin-starter
Halo 2.0 插件开发快速开始模板WIP
## 项目结构介绍
```text
.
├── LICENSE
├── README.md
├── console
│   ├── README.md
│   ├── env.d.ts
│   ├── package.json
│   ├── pnpm-lock.yaml
│   ├── src
│   │   ├── assets
│   │   │   └── logo.svg
│   │   ├── components
│   │   │   └── HelloWorld.vue
│   │   ├── index.ts # Console 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
│   └── starter
│   ├── Apple.java
│   ├── ApplesController.java
│   └── StarterPlugin.java # Main Class
└── resources
├── console
│   ├── main.js # Console 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
```
对于以上目录树:
- `console` 插件前端项目目录,为一个 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 {
}
```
关键在于标注 `@GVK` 注解和 `extends AbstractExtension`,当如此定义了一个模型后,插件启动时会根据 `@GVK`
配置自动生成`CRUD`的 `RESTful API`
,以此为例子会生成如下 `APIs`
```http
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](https://github.com/halo-dev/rfcs/tree/main/extension)
- `TemplatePlugin.java`:插件生命周期入口,它继承 `BasePlugin`,可以通过 `getApplicationContext()`
方法获取到 `SchemeManager`,然后在 `start()`
方法中注册自定义模型,这一步必不可少,所有定义的自定义模型都需要在此注册,并在 `stop()` 生命周期方法中清理资源。
```java
public class StarterPlugin 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`,示例:
```java
@ApiVersion("v1alpha1")
@RestController
@RequestMapping("colors")
public class ApplesController {
@GetMapping
public Mono<String> hello() {
return Mono.just("Hello world");
}
}
```
插件定义 `Controller` 必须要标注 `@ApiVersion` 注解,否则启动时会报错。如果定义了这样的 `Controller`
,插件启动后会生成如下的 `APIs`
```http
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](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`
插件还允许使用 `@Service`、`@Component` 注解将其声明为一个 `Spring Bean`,便可通过依赖注入使用 `Spring Bean`,示例:
```java
@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`:目录为插件资源目录
- `console` 目录下为插件前端打包后的产物存放目录,固定为 `main.js` 和 `style.css `两个文件
- `extensions` 存放自定义模型资源配置
- `plugin.yaml`为插件描述配置
- `static` 为静态资源示例目录
插件启动时会加载 `extensions` 目录的 `yaml` 保存到数据库,`apple.yaml` 为本项目自定义的模型的数据示例,当启用插件后调用
```text
GET /apis/apple.guqing.xyz/v1alpha1/apples
```
便可查询到 `apple.yaml` 中定义的记录
```json
[
{
"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 中提供的模型,表示反向代理,允许插件配置规则代理到插件目录
```yaml
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` 表示插件允许提供角色模版,定义格式如下:
```yaml
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](https://github.com/halo-dev/rfcs/blob/main/identity/002-security.md)
Halo 2.0 插件开发快速开始模板
## 开发环境
### 环境要求
- OpenJDK 17
- NodeJS 16+
- pnpm 7+
### 拉取 Halo 相关项目源码
插件开发的详细文档请查阅:<https://docs.halo.run/developer-guide/plugin/hello-world>
```bash
mkdir ./halo-dev
git clone git@github.com:halo-sigs/plugin-starter.git
mkdir ./halo-dev/dev-plugins # 存放插件源码
# 或者当你 fork 之后
git clone git@github.com:{your_github_id}/plugin-starter.git
```
```bash
cd ./halo-dev
git clone https://github.com/halo-dev/halo --branch main
cd path/to/plugin-starter
```
```bash
git clone https://github.com/halo-dev/console --branch main
# macOS / Linux
./gradlew pnpmInstall
# Windows
./gradlew.bat pnpmInstall
```
```bash
cd ./dev-plugins
# macOS / Linux
./gradlew build
git clone https://github.com/halo-dev/plugin-starter
# Windows
./gradlew.bat build
```
### Halo 配置文件修改
修改 halo/src/main/resources/application-dev.yaml
修改 Halo 配置文件
```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"
runtime-mode: development
fixedPluginPath:
- "/path/to/plugin-starter"
```
### 编译插件
下载前端依赖:
```bash
cd ./halo-dev/dev-plugins/plugin-starter
./gradlew.bat pnpmInstall
# or macOS/Linux
./gradlew pnpmInstall
```
构建:
```bash
./gradlew.bat build
# or macOS/Linux
./gradlew build
```
### 启动 Halo
```bash
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。
### 启动 Console
```bash
cd ./halo-dev/console
pnpm install
pnpm build:packages
pnpm dev
```
### 访问后台
在浏览器中访问 https://localhost:3000 即可,登录用户名和密码为上方 `application-dev.yaml` 配置中的 `super-admin-username`
和 `super-admin-password`。
然后在左侧菜单中选择 `插件`,即可查看所有插件的状态。
### 开发
修改前端代码或者后端代码,然后运行 `./gradlew.bat build` 或者 `./gradlew build`macOS/Linux即可构建插件无需重启
Halo。但修改配置文件后需要 build 插件以及重启 Halo。
## 构建生产产物
```
./gradlew -x build
```
然后只需复制例如`build/libs/plugin-starter-0.0.1-SNAPSHOT-plain.jar` 的 `jar` 包即可使用。