Shiro
基于OneBot协议的QQ机器人快速开发框架
Install / Use
/learn @MisakaTAT/ShiroREADME
Shiro
✨ 基于 OneBot 协议的 QQ机器人 快速开发框架 ✨
</div> <p align="center"> <a href="https://search.maven.org/search?q=com.mikuac.shiro"><img src="https://img.shields.io/maven-central/v/com.mikuac/shiro.svg?label=Maven%20Central&style=flat-square" alt="maven" /></a> <a href="https://github.com/MisakaTAT/Shiro/issues"><img src="https://img.shields.io/github/issues/MisakaTAT/Shiro?style=flat-square" alt="issues" /></a> <a href="https://github.com/MisakaTAT/Shiro/blob/main/LICENSE"><img src="https://img.shields.io/github/license/MisakaTAT/Shiro?style=flat-square" alt="license"></a> <img src="https://img.shields.io/badge/JDK-17+-brightgreen.svg?style=flat-square" alt="jdk-version"> <a href=""><img src="https://img.shields.io/badge/QQ群-1009137235-brightgreen.svg?style=flat-square" alt="qq-group"></a> <a href="https://github.com/howmanybots/onebot"><img src="https://img.shields.io/badge/OneBot-v11-blue?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABABAMAAABYR2ztAAAAIVBMVEUAAAAAAAADAwMHBwceHh4UFBQNDQ0ZGRkoKCgvLy8iIiLWSdWYAAAAAXRSTlMAQObYZgAAAQVJREFUSMftlM0RgjAQhV+0ATYK6i1Xb+iMd0qgBEqgBEuwBOxU2QDKsjvojQPvkJ/ZL5sXkgWrFirK4MibYUdE3OR2nEpuKz1/q8CdNxNQgthZCXYVLjyoDQftaKuniHHWRnPh2GCUetR2/9HsMAXyUT4/3UHwtQT2AggSCGKeSAsFnxBIOuAggdh3AKTL7pDuCyABcMb0aQP7aM4AnAbc/wHwA5D2wDHTTe56gIIOUA/4YYV2e1sg713PXdZJAuncdZMAGkAukU9OAn40O849+0ornPwT93rphWF0mgAbauUrEOthlX8Zu7P5A6kZyKCJy75hhw1Mgr9RAUvX7A3csGqZegEdniCx30c3agAAAABJRU5ErkJggg=="></a> </p> <p align="center"> <a href="https://misakatat.github.io/shiro-docs">文档</a> · <a href="https://github.com/MisakaTAT/Shiro/releases">下载</a> · <a href="https://misakatat.github.io/shiro-docs">快速开始</a> · <a href="">参与贡献</a> </p> <div align="center"> </div>Migration Guide
v2版本开始仅支持JDK 17+与SpringBoot 3.0.0+v2迁移指南
v2.5.1版本开始仅支持JDK 21+与SpringBoot 4.0.0+
QuickStart
依赖引入
引入依赖时请替换版本
latest为Maven Central实际的最新版本
Maven
<dependency>
<groupId>com.mikuac</groupId>
<artifactId>shiro</artifactId>
<version>latest</version>
</dependency>
Gradle Kotlin DSL
implementation("com.mikuac:shiro:latest")
Gradle Groovy DSL
implementation 'com.mikuac:shiro:latest'
示例插件
注解调用
编写
application.yaml配置文件 或参考 进阶配置文件
server:
port: 5000
@Shiro
@Component
public class ExamplePlugin {
// 更多用法详见 @MessageHandlerFilter 注解源码
// 当机器人收到的私聊消息消息符合 cmd 值 "hi" 时,这个方法会被调用。
@PrivateMessageHandler
@MessageHandlerFilter(cmd = "hi")
public void fun1(Bot bot, PrivateMessageEvent event, Matcher matcher) {
// 构建消息
String sendMsg = MsgUtils.builder().face(66).text("Hello, this is shiro demo.").build();
// 发送私聊消息
bot.sendPrivateMsg(event.getUserId(), sendMsg, false);
}
// 如果 at 参数设定为 AtEnum.NEED 则只有 at 了机器人的消息会被响应
@GroupMessageHandler
@MessageHandlerFilter(at = AtEnum.NEED)
public void fun2(GroupMessageEvent event) {
// 以注解方式调用可以根据自己的需要来为方法设定参数
// 例如群组消息可以传递 GroupMessageEvent, Bot, Matcher 多余的参数会被设定为 null
System.out.println(event.getMessage());
}
// 同时监听群组及私聊消息 并根据消息类型(私聊,群聊)回复
@AnyMessageHandler
@MessageHandlerFilter(cmd = "say hello")
public void fun3(Bot bot, AnyMessageEvent event) {
bot.sendMsg(event, "hello", false);
}
}
重写父类方法
- 注解方式编写的插件无需在插件列表
plugin-list定义 - 服务端配置文件
resources/application.yaml追加如下内容 - 插件列表为顺序执行,如果前一个插件返回了
MESSAGE_BLOCK将不会执行后续插件
编写
application.yaml配置文件 或参考 进阶配置文件
server:
port: 5000
shiro:
plugin-list:
- com.example.bot.plugins.ExamplePlugin
@Component
public class ExamplePlugin extends BotPlugin {
@Override
public int onPrivateMessage(Bot bot, PrivateMessageEvent event) {
if ("hi".equals(event.getMessage())) {
// 构建消息
String sendMsg = MsgUtils.builder()
.face(66)
.text("hello, this is shiro example plugin.")
.build();
// 发送私聊消息
bot.sendPrivateMsg(event.getUserId(), sendMsg, false);
}
// 返回 MESSAGE_IGNORE 执行 plugin-list 下一个插件,返回 MESSAGE_BLOCK 则不执行下一个插件
return MESSAGE_IGNORE;
}
@Override
public int onGroupMessage(Bot bot, GroupMessageEvent event) {
if ("hi".equals(event.getMessage())) {
// 构建消息
String sendMsg = MsgUtils.builder()
.at(event.getUserId())
.face(66)
.text("hello, this is shiro example plugin.")
.build();
// 发送群消息
bot.sendGroupMsg(event.getGroupId(), sendMsg, false);
}
// 返回 MESSAGE_IGNORE 执行 plugin-list 下一个插件,返回 MESSAGE_BLOCK 则不执行下一个插件
return MESSAGE_IGNORE;
}
}
加载外部插件
工作流程
<details> <summary>点击展开/折叠 Shiro 插件加载流程图</summary>graph TD
A[Shiro 启动] --> B[扫描 plugins/ 目录]
B --> C{是否存在 JAR 文件?}
C -- 否 --> D[跳过插件加载]
C -- 是 --> E1[解析 JAR 的 manifest]
subgraph 依赖处理
E1 --> E2[提取 Dependencies 属性]
E2 --> E3{是否有依赖需要解析?}
E3 -- 是 --> E4[通过 DependencyResolver 解析依赖]
E4 --> E5[下载缺失的依赖到 dependencies 目录]
E3 -- 否 --> E6[跳过依赖解析]
E5 --> E6
end
E6 --> E7[创建包含插件和依赖的 URLClassLoader]
E7 --> E[加载并注册插件]
subgraph 加载并注册插件
E --> F[使用 URLClassLoader 加载 JAR]
F --> G[使用 ServiceLoader 加载 BotPlugin]
G --> H{插件是否实现 BotPlugin?}
H -- 否 --> I[跳过插件]
H -- 是 --> H1{是否有 @Component 注解?}
H1 -- 否 --> I
H1 -- 是 --> H2[注册到 Spring 容器]
H2 --> J[检查主项目 BotPlugin]
J --> K{主项目是否实现相同事件?}
K -- 否 --> L[注册插件到事件列表]
K -- 是 --> M[插件 onGroupMessage 低优先级执行]
M --> N{主项目 MESSAGE_BLOCK 是否触发?}
N -- 是 --> O[阻断插件逻辑]
N -- 否 --> P[执行插件 onGroupMessage]
end
P --> Q[插件加载完成]
</details>
目录结构
Shiro 支持自动加载 .jar 格式的插件,并通过 ServiceLoader 进行管理。默认情况下,Shiro 会扫描当前运行路径下的
plugins 目录,并尝试加载所有符合 BotPlugin 接口的插件。
以下只是一个示例结构(可根据实际情况调整,比如替换 Gradle 为 Maven)
ForeignPluginExample/
├── src/ # 源代码目录
│ ├── main/java/com/mikuac/demo/DemoPlugin.java # 插件实现
│ ├── main/resources/META-INF/services/com.mikuac.shiro.core.BotPlugin # SPI 注册文件
├── build.gradle.kts # Gradle 构建脚本
├── settings.gradle.kts # Gradle 设置文件
├── gradlew # Gradle 可执行文件(Linux/macOS)
├── gradlew.bat # Gradle 可执行文件(Windows)
└── gradle/wrapper/ # Gradle Wrapper 相关文件
开发指南
插件类定义
插件必须实现 BotPlugin 接口,并使用 @Component 注解,以便 Shiro 能够正确识别。
package com.mikuac.demo;
import com.mikuac.shiro.core.Bot;
import com.mikuac.shiro.core.BotPlugin;
import com.mikuac.shiro.dto.event.message.GroupMessageEvent;
import org.springframework.stereotype.Component;
@Component
public class DemoPlugin extends BotPlugin {
@Override
public int onGroupMessage(Bot bot, GroupMessageEvent event) {
String msg = event.getMessage();
if (msg.equals("ping")) {
bot.sendGroupMsg(event.getGroupId(), "pong", false);
return MESSAGE_BLOCK;
}
return MESSAGE_IGNORE;
}
}
配置 META-INF/services
为了让 ServiceLoader 能够发现插件,需要在 src/main/resources/META-INF/services/ 目录下创建
com.mikuac.shiro.core.BotPlugin 文件,并填写插件的完整类名。
com.mikuac.demo.DemoPlugin
配置构建脚本
在 build.gradle.kts 中添加以下配置,用于正确处理插件打包和依赖管理:
tasks.withType<Jar> {
// 处理JAR中的重复文件,INCLUDE策略表示保留所有重复项
duplicatesStrategy = DuplicatesStrategy.INCLUDE
// 将主源集的所有编译输出加入JAR包
from(sourceSets.main.get().output)
manifest {
// 添加基本信息到 MANIFEST.MF
attributes(
mapOf(
"Implementation-Title" to project.name, // 使用项目名称
"Implementation-Version" to project.version, // 添加版本信息
"Built-By" to System.getProperty("user.name"),
"Created-By" to "Gradle ${gradle.gradleVersion}"
)
)
// 生成并添加依赖清单
val dependenciesString = configurations
.getByName("runtimeClasspath") // 获取运行时实际解析的依赖
.resolvedConfiguration
.resolvedArtifacts
.map {
// 将依赖格式化为 "groupId:artifactId:version" 格式
"${it.moduleVersion.id.group}:${it.moduleVersion.id.name}:${it.moduleVersion.id.version}"
}
.distinct() // 移除重复项
.filterNot { coordinates ->
// 过滤掉不应由插件加载的依赖
// 这些依赖应当由 Shiro 主程序提供,避免类加载冲突
coordinates.startsWith("org.springframework") || // Spring框架
coordinates.startsWith("com.mikuac:shiro") || // Shiro
coordinates.startsWith("org.slf4j") || // 日志门面
coordinates.startsWith("ch.qos.logback") // 日志实现
}
.joinToString(", ") // 使用逗号分隔依赖列表
// 添加依赖列表到 manifest 中,Shiro 将解析此属性来下载所需依赖
attributes(mapOf("Dependencies" to dependenciesString))
}
}
// 可选:配置依赖项
dependencies {
// Shiro 本身仅在编译时需要,运行时由主程序提供
compileOnly("com.mikuac:shiro:latest")
// 添加其他依赖,这些将被包含在Dependencies清单中
implementation("com.example:some-library:1.0.0")
}
Related Skills
openhue
339.5kControl Philips Hue lights and scenes via the OpenHue CLI.
sag
339.5kElevenLabs text-to-speech with mac-style say UX.
weather
339.5kGet current weather and forecasts via wttr.in or Open-Meteo
tweakcc
1.5kCustomize Claude Code's system prompts, create custom toolsets, input pattern highlighters, themes/thinking verbs/spinners, customize input box & user message styling, support AGENTS.md, unlock private/unreleased features, and much more. Supports both native/npm installs on all platforms.
