├── .gitignore ├── build.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── pom.xml ├── readme.md ├── settings.gradle.kts └── src └── main ├── java └── wiki │ └── IceCream │ └── yuq │ └── demo │ ├── Start.java │ ├── controller │ ├── BpController.java │ ├── JsonController.java │ ├── TestContextController.java │ ├── TestGroupController.java │ ├── TestPrivateController.java │ └── WeatherController.java │ ├── event │ ├── FriendListEvent.java │ ├── GroupManager.java │ ├── OnMessageEvent.java │ └── myEvent │ │ ├── MessageStartWithTag1.java │ │ ├── MessageStartWithTag2.java │ │ └── MyNewEvent.java │ └── job │ └── JobMain.java └── resources ├── conf └── YuQ.properties ├── ehcache-YuQ-Mirai-demo.xml └── logback.xml /.gitignore: -------------------------------------------------------------------------------- 1 | device.json 2 | 3 | .gradle/ 4 | build/ 5 | target/ 6 | .idea/ 7 | 8 | tmp/ 9 | log/ 10 | src/main/resources/conf/test** 11 | 12 | *.iml -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | java 3 | id("com.github.johnrengelman.shadow") version "5.2.0" 4 | eclipse 5 | } 6 | 7 | group = "org.example" 8 | version = "1.0-SNAPSHOT" 9 | 10 | repositories { 11 | // Gradle 的 扫包是从上至下的。 12 | // YuQ-Mirai 的依赖位于中央库和 jcenter。 13 | // Dev 包均位于 IceCream 的 Maven 仓库。 14 | // mavenCentral() 15 | mavenLocal() 16 | maven("https://maven.IceCreamQAQ.com/repository/maven-public/") 17 | } 18 | 19 | dependencies { 20 | implementation("com.IceCreamQAQ.YuQ:YuQ-Mirai:0.1.0.0-DEV24") 21 | } 22 | 23 | tasks { 24 | withType { 25 | options.encoding = "UTF-8" 26 | } 27 | 28 | jar { 29 | finalizedBy(shadowJar) 30 | } 31 | 32 | shadowJar { 33 | manifest { 34 | attributes["Main-Class"] = "wiki.IceCream.yuq.demo.Start" 35 | } 36 | 37 | from("./") { 38 | include("build.gradle") 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuQWorks/YuQ-Mirai-Demo/c9cd67515deaa44394184d5a37cb62b69c3e7c8e/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto init 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto init 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | 88 | @rem Execute Gradle 89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 90 | 91 | :end 92 | @rem End local scope for the variables with windows NT shell 93 | if "%ERRORLEVEL%"=="0" goto mainEnd 94 | 95 | :fail 96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 97 | rem the _cmd.exe /c_ return code! 98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 99 | exit /b 1 100 | 101 | :mainEnd 102 | if "%OS%"=="Windows_NT" endlocal 103 | 104 | :omega 105 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | YuQ-Mirai-Demo 9 | 1.0-SNAPSHOT 10 | 11 | 12 | UTF-8 13 | UTF-8 14 | 1.8 15 | 1.8 16 | 1.8 17 | 18 | 19 | 20 | 21 | com.IceCreamQAQ.YuQ 22 | YuQ-Mirai 23 | 0.1.0.0-DEV24 24 | 25 | 26 | 27 | 28 | 29 | 30 | org.apache.maven.plugins 31 | maven-assembly-plugin 32 | 3.1.0 33 | 34 | 35 | 36 | wiki.IceCream.yuq.demo.Start 37 | 38 | 39 | 40 | jar-with-dependencies 41 | 42 | 43 | 44 | 45 | make-assemble 46 | package 47 | 48 | single 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | IceCream 59 | https://maven.IceCreamQAQ.com/repository/maven-public/ 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # YuQ-Mirai 2 | 3 | YuQ-Mirai 是一个依赖于 [Mirai](https://github.com/mamoe/mirai) 的 YuQ Framework 的机器人实现。 4 | 5 | YuQ Framework 的目的就是让机器人开发变得更简单和更有效率。 6 | 7 | 这是一个 Demo 项目。 8 | 框架依旧处于开发阶段,我将尽可能的保证 API 尽量少的变动。 9 | 10 | ## 11 | 12 | Demo 同时提供了 Maven 和 Gradle 的项目配置。 13 | 请选择一个喜欢的使用。 14 | 15 | ## 基础开发介绍: 16 | 17 | 在 YuQ 我们仅需很简单的代码,就可以完成很复杂的功能。 18 | 比如,我们要针对一个指令"菜单",进行一个标准的菜单消息回复。 19 | ```Java 20 | @GroupController 21 | public class GroupMenu{ 22 | @Action("菜单") 23 | public String menu(){ 24 | return "这是具体的菜单内容。"; 25 | } 26 | } 27 | ``` 28 | YuQ 会在指令式机器人的开发中,提供非常好的帮助,让开发者能有更好的开发体验。 29 | 在 Controller 中,我们的 Action 方法,返回的内容,会直接构建成消息,并发送当当前消息源。 30 | 通过路由映射,我们可以很方便的编写指令,只需要将 Class 声明为一个 Controller,并且编写 Action 方法。 31 | 其余的,YuQ 会帮您完成。 32 | 33 | 比如我们想禁言一个人,禁言的指令为"ban @xxx或QQ号码 time" 34 | 我们只需要编写: 35 | ```Java 36 | @GroupController 37 | public class GroupMenu{ 38 | @Action("ban {ban} {time}") 39 | public String ban(Member ban, int time){ 40 | ban.ban(time); 41 | return "好的!"; 42 | } 43 | } 44 | ``` 45 | 这样,我们就可以很轻易的完成 ban 这个指令了。 46 | 47 | 对于需要连续对话的指令式机器人,基于 YuQ 也可以轻松满足。 48 | 49 | 更详细的使用文档:[文档](https://yuqworks.github.io/YuQ-Doc/) 50 | 51 | ## 特性 52 | 53 | ### 路由映射 54 | 参考 wiki.IceCream.yuq.demo.controller.TestGroupController 55 | ### 依赖注入 56 | 参考 wiki.IceCream.yuq.demo.controller.TestGroupController 57 | ### 事件系统 58 | 参考 wiki.IceCream.yuq.demo.event.OnMessageEvent 59 | ### 后台队列 60 | 参考 wiki.IceCream.yuq.demo.job.JobMain 61 | ### 数据库支持 62 | 使用方法参考 [SuperDemo](https://github.com/YuQWorks/YuQ-SuperDemo) 63 | ### Web支持 64 | 使用方法参考 [SuperDemo](https://github.com/YuQWorks/YuQ-SuperDemo) 65 | ## 使用方法: 66 | clone 67 | 编辑 /src/main/resource/conf/YuQ.properties 填写合适的内容。 68 | run wiki.IceCream.yuq.demo.Start 69 | 70 | YuQ-Mirai 可直接启动,无需任何外部手段/依赖。 71 | 72 | 打包: 73 | ``` 74 | ./gradlew build 75 | ``` 76 | 对于 Eclipse 用户,可以考虑使用 `./gradlew eclipse` 命令生成 Eclipse 项目。 -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "YuQ-Mirai-Demo" 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/Start.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo; 2 | 3 | import com.icecreamqaq.yuq.mirai.YuQMiraiStart; 4 | 5 | public class Start { 6 | 7 | /*** 8 | * 请不要往本类里面添加任何项目代码,也不要在本类里面引用任何类,以防止增强失败。 9 | * 这个问题在之后会解决。 10 | * 消息处理顺序 接受---->事件处理(参看event包)---->路由(参看controller包) 11 | * 特殊功能 job -->定时器 具体查看Job包 12 | * @param args 启动参数 13 | */ 14 | public static void main(String[] args) { 15 | YuQMiraiStart.start(args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/controller/BpController.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo.controller; 2 | 3 | import com.IceCreamQAQ.Yu.annotation.Action; 4 | import com.icecreamqaq.yuq.FunKt; 5 | import com.icecreamqaq.yuq.annotation.GroupController; 6 | import com.icecreamqaq.yuq.controller.ContextSession; 7 | import com.icecreamqaq.yuq.controller.QQController; 8 | import com.icecreamqaq.yuq.message.Message; 9 | 10 | @GroupController 11 | public class BpController extends QQController { 12 | 13 | /*** 14 | * 可以通过声明一个参数为 ContextSession 类型,名叫 session 的参数。 15 | * 调用 session 的 waitNextMessage 方法,可以挂起当前线程,并且等待一条新消息。 16 | *

17 | * 注意:消息在被传递到这里之前,会先经过 MessageEvent,则代表当取消事件时,消息并不会被传递到本处。 18 | *

19 | * Message 的相关快捷方法,被封装在 Message 的伴生对象内,既为 Message.Companion。 20 | * Message.Companion.firstString 方法,获取 MessageBody 的第一个文字元素,并且转换为 String。 21 | */ 22 | @Action("绑手机") 23 | public String bp(ContextSession session) { 24 | reply("请输入手机号码"); 25 | String phone = Message.Companion.firstString(session.waitNextMessage()); 26 | reply("请输入手机验证码"); 27 | String key = Message.Companion.firstString(session.waitNextMessage()); 28 | return String.format("您输入的手机号码为:%s,手机验证码为:%s。", phone, key); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/controller/JsonController.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo.controller; 2 | 3 | import com.IceCreamQAQ.Yu.annotation.Action; 4 | import com.icecreamqaq.yuq.annotation.GroupController; 5 | import com.icecreamqaq.yuq.controller.ContextSession; 6 | import com.icecreamqaq.yuq.controller.QQController; 7 | import com.icecreamqaq.yuq.message.JsonEx; 8 | import com.icecreamqaq.yuq.message.Message; 9 | 10 | @GroupController 11 | public class JsonController extends QQController { 12 | 13 | /*** 14 | * 可以通过声明一个参数为 ContextSession 类型,名叫 session 的参数。 15 | * 调用 session 的 waitNextMessage 方法,可以挂起当前线程,并且等待一条新消息。 16 | * 17 | * 注意:消息在被传递到这里之前,会先经过 MessageEvent,则代表当取消事件时,消息并不会被传递到本处。 18 | * 19 | * Message 的相关快捷方法,被封装在 Message 的伴生对象内,既为 Message.Companion。 20 | * Message.Companion.firstString 方法,获取 MessageBody 的第一个文字元素,并且转换为 String。 21 | */ 22 | @Action("准备json") 23 | public JsonEx json(ContextSession session) { 24 | reply("您请说"); 25 | return mif.jsonEx(Message.Companion.firstString(session.waitNextMessage())); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/controller/TestContextController.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo.controller; 2 | 3 | import com.IceCreamQAQ.Yu.annotation.Action; 4 | import com.icecreamqaq.yuq.annotation.*; 5 | import com.icecreamqaq.yuq.controller.BotActionContext; 6 | import com.icecreamqaq.yuq.controller.NextActionContext; 7 | import com.icecreamqaq.yuq.message.Message; 8 | 9 | /** 10 | * 此方法接近弃用,因为单路径有更加简洁的情况。 11 | * @see BpController 12 | */ 13 | @ContextController 14 | public class TestContextController { 15 | 16 | /** 17 | * 在 ContextController 里面的所有 Action,会被自动映射成上下文路由。 18 | *

19 | * 当上下文路由存在时,将优先进行上下文路由匹配。 20 | * 当上下文匹配失败时,并不会再进行正常的指令匹配。 21 | *

22 | * 上下文 Action 的功能与普通 Action 一致,只是触发条件不同。 23 | *

24 | * Save 注解表示,当 Action 正常完成时,将本参数内容,保存到 Session,可以供后续注入。 25 | * Save 保存名为 Named 注解声明内容,如参数未声明 Named 注解,则为参数名。 26 | */ 27 | @Action("bindPhone") 28 | @NextContext("phoneVerKey") 29 | @ContextTip("请输入手机号码。") 30 | @ContextTip(value = "手机号码输入错误,请重新输入。", status = 1) 31 | public void bindPhone(@Save @PathVar(0) String phone) { 32 | if (phone.length() != 11) throw new NextActionContext("bindPhone", 1); 33 | } 34 | 35 | /** 36 | * 此处的 phone 则是上一步中保存下来的 phone 37 | *

38 | * 当不再提供一个 NextContext 时,则完成一个上下文,回归普通。 39 | */ 40 | @Action("phoneVerKey") 41 | @ContextTip("请输入手机验证码。") 42 | @ContextTip(value = "手机验证码输入错误,请重新输入。", status = 1) 43 | public String phoneVerKey(@PathVar(0) String key, String phone) { 44 | if (key.length() != 4) throw new NextActionContext("phoneVerKey", 1); 45 | return String.format("您要绑定的手机号为:%s,手机验证码为:%s,绑定成功!", phone, key); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/controller/TestGroupController.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo.controller; 2 | 3 | import com.IceCreamQAQ.Yu.annotation.Action; 4 | import com.IceCreamQAQ.Yu.annotation.Before; 5 | import com.IceCreamQAQ.Yu.annotation.Synonym; 6 | import com.IceCreamQAQ.Yu.job.JobManager; 7 | import com.icecreamqaq.yuq.YuQ; 8 | import com.icecreamqaq.yuq.annotation.GroupController; 9 | import com.icecreamqaq.yuq.annotation.NextContext; 10 | import com.icecreamqaq.yuq.entity.Group; 11 | import com.icecreamqaq.yuq.entity.Member; 12 | import com.icecreamqaq.yuq.message.Message; 13 | import com.icecreamqaq.yuq.message.MessageItem; 14 | import com.icecreamqaq.yuq.message.MessageItemFactory; 15 | 16 | import javax.inject.Inject; 17 | 18 | /*** 19 | * GroupController 代表了,这个 Controller 将响应群消息。 20 | */ 21 | @GroupController 22 | public class TestGroupController { 23 | 24 | /*** 25 | * YuQ 接口是 YuQ Framework 向用户提供的一个便于使用的 API。 26 | * 通过注入 YuQ 来获得 YuQ 的实例,来调用 YuQ Framework 的绝大部分功能。 27 | * 如发送消息,撤回消息等等。 28 | */ 29 | @Inject 30 | private YuQ yuq; 31 | 32 | /*** 33 | * MessageItemFactory 用来创建 Message 的具体内容。 34 | */ 35 | @Inject 36 | private MessageItemFactory mif; 37 | 38 | /*** 39 | * Before 则为具体的控制器的动作前置验证,也可以称作拦截器,负责在 Action 处理消息之前进行验证。 40 | * 41 | * Before 方法接收 0 - 多个参数,通常,您所写下的参数,将会以名称匹配来进行依赖注入。 42 | * 支持注入的名称 - 注入的内容 43 | * qq - 发送消息的 QQ 账号 44 | * group - 发送消息的 QQ 群号 45 | * message - 具体的 Message 对象 46 | * messageId - 消息 ID 47 | * sourceMessage - 未经处理的源消息内容,则为具体的 Runtime 的消息内容 48 | * actionContext - 当前消息的 ActionContext 对象 49 | * 以及,您 Before 传递回来的需要保存的对象。 50 | * 51 | * Before 方法可以接受任何类型的返回值,当您返回了一个值的时候,框架会帮您保存起来,名称则为将类名的第一个字母转化小写后的名字。 52 | * 53 | * Before 方法可以抛出异常,来作为验证失败的中断处理方法。 54 | * 当您抛出了一个 Message 类型的异常后,如果您没有设置任何接收的 QQ,或 QQ 群,那么我们将会将消息发送至当前消息来源者,如果您设置了接收对象,那么发送至您的接收对象。 55 | * 当您想中断处理链路,并且不进行任何返回的时候,您可以抛出 DoNone 类型的异常。 56 | * 57 | * 一个 Controller 类内,可以接受多个 Before,他们按照一定的顺序依次执行,当所有 Before 执行完成之后,将继续执行 Action。 58 | */ 59 | @Before 60 | public void before(long qq) { 61 | if (qq % 2 == 0) throw mif.text("你没有使用该命令的权限!").toMessage().toThrowable(); 62 | } 63 | 64 | private boolean menuFlag = true; 65 | 66 | /*** 67 | * Action 则为具体的控制器的动作,负责处理收到的消息。 68 | * 69 | * Action 方法接收 0 - 多个参数,通常,您所写下的参数,将会以名称匹配来进行依赖注入。 70 | * 支持注入的名称 - 注入的内容 71 | * qq - 发送消息的 QQ 账号 72 | * group - 发送消息的 QQ 群号 73 | * message - 具体的 Message 对象 74 | * messageId - 消息 ID 75 | * sourceMessage - 未经处理的源消息内容,则为具体的 Runtime 的消息内容 76 | * actionContext - 当前消息的 ActionContext 对象 77 | * 以及,您 Before 传递回来的需要保存的对象。 78 | * 79 | * Action 可接收方法可以接受任何类型的返回值,当您返回了一个值的时候, 80 | * 如果您返回的是 Message 类型的时候,我们会帮您发送这个消息,如果您没有设置任何接收的 QQ,或 QQ 群,那么我们将会将消息发送至当前消息来源者,如果您设置了接收对象,那么发送至您的接收对象。 81 | * 如果您返回了一个 String 类型的时候,我们会帮您构建一个 Message,并发送到当前消息的来源。 82 | * 如果您返回了一个 MessageItem 类型的时候,我们会帮您构建一个 Message,并发送到当前消息的来源。 83 | * 如果您返回的是其他类型,我们会帮您调用 toString 方法,并构建一个 Message,然后发送到当前消息的来源。 84 | * 85 | * Action 方法可以抛出异常,来返回一些信息。 86 | * 当您抛出了一个 Message 类型的异常后,如果您没有设置任何接收的 QQ,或 QQ 群,那么我们将会将消息发送至当前消息来源者,如果您设置了接收对象,那么发送至您的接收对象。 87 | * 当您想中断处理链路,并且不进行任何返回的时候,您可以抛出 DoNone 类型的异常。 88 | * @return 89 | */ 90 | @Action("菜单") 91 | public Object menu(long qq) { 92 | if (menuFlag) 93 | return mif.at(qq).plus(",您好。\n" + 94 | "这里是基础菜单。" + 95 | "但是由于这是一个演示 Demo,他没有什么功能。" + 96 | "所以也并没有菜单。" + 97 | "那就这样吧。"); 98 | return "菜单被禁用!"; 99 | } 100 | 101 | /*** 102 | * Action 内,不仅可以写单级指令,还可以写多级指令。 103 | * 最后的 {flag} 则代表了一个可变内容,他可以根据方法参数类型,自动映射为指定类型。 104 | */ 105 | @Action("设置 菜单开关 {flag}") 106 | public String menu2(boolean flag) { 107 | menuFlag = flag; 108 | return "菜单开关:" + flag; 109 | } 110 | 111 | /*** 112 | * 可以在路由内书写 { 名称 : 正则表达式 } 来动态匹配指令上的内容。 113 | * 如果你想匹配任意内容,则 : 及后续可以省略。示例:{color} 114 | * 本例子则代表只匹配单个文本。 115 | */ 116 | @Action("发个{color:.}包") 117 | public String sendPackage(String color) { 118 | return String.format("QQ%s包!", color); 119 | } 120 | 121 | /*** 122 | * YuQ 可以将您发送的数字QQ号,或者 At 某人,智能转化为您所需要的内容。 123 | * 本处就将对象转化为 Member 的实例。 124 | * 通过调用 Member 的 ban 方法,可以将目标禁言一段时间。单位:秒。 125 | * 通过书写 Member 类型的 qq 参数,即可获取当前消息发送者的 Member 实例。 126 | * 通过调用 Member 的 isAdmin 方法,可以获取当前目标是否具有管理员权限。(管理员与群主都具有管理员权限) 127 | * 128 | * 本 Action 的作用,如果发送者是管理员,就将目标禁言一段时间,如果发送人不是管理员,就将自己禁言一段时间。 129 | */ 130 | @Action("禁言 {sb} {time}") 131 | @Synonym({"ban {sb} {time}"}) 132 | public String ban(Member sb, Member qq, int time) { 133 | if (time < 60) time = 60; 134 | if (qq.isAdmin()) { 135 | sb.ban(time); 136 | return "好的"; 137 | } 138 | qq.ban(time); 139 | return "您没有使用该命令的权限!为了防止恶意操作,你已被禁言相同时间。"; 140 | } 141 | 142 | @Inject 143 | private JobManager jobManager; 144 | 145 | /*** 146 | * 我们可以通过注入 JobManager 快速,动态的创建定时与时钟任务。 147 | * 写在路由中的 {time} 与整级路由 {nr} 最大的不同,就是写在路由中的,只能用 String 类型接受,并不能智能匹配成其他类型。 148 | */ 149 | @Action("{time}秒后说 {nr}") 150 | public Object timeSend(String time, MessageItem nr, Group group) { 151 | Message nm = new Message().plus(nr); 152 | jobManager.registerTimer(() -> group.sendMessage(nm), Integer.parseInt(time) * 1000); 153 | return "好的"; 154 | } 155 | 156 | 157 | /*** 158 | * NextContext 注解用来声明完成之后进入某个上下文。 159 | * 这是一个用来进入上下文的 Action,当然,他与普通的 Action 没有什么区别。 160 | * 他可以完成普通 Action 的所有功能。 161 | * 只是当他在正常完成之后,会帮你把上下文自动切换到 NextContext 中声明的内容。 162 | * 163 | * 正常完成则为,当 Action 方法没有产生任何异常时,Action 方为正常完成。 164 | */ 165 | @Action("绑定手机号") 166 | @NextContext("bindPhone") 167 | public void bindPhone(long qq) { 168 | if (qq % 2 == 0) throw mif.text("您无需绑定手机号码。").toMessage().toThrowable(); 169 | } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/controller/TestPrivateController.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo.controller; 2 | 3 | import com.IceCreamQAQ.Yu.annotation.Action; 4 | import com.icecreamqaq.yuq.annotation.PrivateController; 5 | 6 | 7 | /** 8 | * 该触发器响应私聊消息,其他与群聊路由一致 9 | */ 10 | @PrivateController 11 | public class TestPrivateController { 12 | 13 | 14 | @Action("hello") 15 | public String helloYuQ(){ 16 | return "hello,welcome to yuq."; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/controller/WeatherController.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo.controller; 2 | 3 | import com.IceCreamQAQ.Yu.annotation.*; 4 | import com.IceCreamQAQ.Yu.controller.ActionContext; 5 | import com.IceCreamQAQ.Yu.entity.DoNone; 6 | import com.icecreamqaq.yuq.YuQ; 7 | import com.icecreamqaq.yuq.annotation.GroupController; 8 | import com.icecreamqaq.yuq.annotation.QMsg; 9 | import com.icecreamqaq.yuq.controller.BotActionContext; 10 | import com.icecreamqaq.yuq.message.Message; 11 | import com.icecreamqaq.yuq.message.MessageItemFactory; 12 | import javax.inject.Inject; 13 | 14 | @GroupController 15 | public class WeatherController { 16 | @Inject 17 | private MessageItemFactory mif; 18 | 19 | /** 20 | * weight表示权重,越低越优先,默认值是0 21 | * @param group 信息发送者所在群 YuQ会自动注入 22 | * @param qq 信息发送者的ID YuQ会自动注入 23 | * @throws DoNone 不做任何事情的异常 24 | */ 25 | @Before(weight = 0) 26 | public void WeatherBefore(long group,long qq) throws DoNone, Exception{ 27 | if(group != 12345L) { 28 | //通过抛出异常来停止信息前往 Action,抛出 DoNone 异常,会中断处理链路并声明路由完成。 29 | throw new DoNone(); 30 | } 31 | if(qq != 122222L){ 32 | //将一条 Message.toThrowable() 会让这个信息返回到信息来源处。可以起到提示的作用。 33 | throw mif.text("你无权使用这个类里面的命令").toMessage().toThrowable(); 34 | } 35 | } 36 | 37 | /** 38 | * 此处使用 @Action 将函数变成指令的响应器 39 | *

40 | * 指令格式应该是 "weather 南京" 41 | *

42 | * 使用 @Synonym 使命令拥有别名 43 | *

44 | * 所以”天气 南京“ 和 ”天气预报 南京“ 同样会触发命令 45 | */ 46 | @Action("weather {city}") 47 | @Synonym({"天气 {city}","天气预报 {city}"}) 48 | @QMsg 49 | public Message weather(String city){ 50 | if(city.equals("")){ 51 | //使用mif将String变成Message 52 | return mif.text("要查询的城市名称不能为空").toMessage(); 53 | } 54 | //使用伴生方法将String变成Message 55 | return Message.Companion.toMessage(city+"的天气是。。。。"); 56 | } 57 | 58 | 59 | /** 60 | * After与 Before 极其类似,除了出现的时间点不同,使用和逻辑上基本一致 61 | * @param reMessage 这是由Action处理完发送的信息,目前还没有交给服务器 62 | * @param qq 同Before 63 | * @return 并非直接返回信息来源,可以在后续@After中进行使用,所以这个方法无返回值,直接修改reMessage也可实现。 64 | */ 65 | @After 66 | public Message addNotice(Message reMessage,long qq){ 67 | //使用mif添加At效果,同理可使用mif添加图片等。 68 | return reMessage.plus(mif.at(qq)); 69 | } 70 | 71 | 72 | /** 73 | * 直接使用注入来获取YuQ对象,对象内存储着Bot的各种信息,包括 群列表,好友列表等。 74 | */ 75 | @Inject 76 | private YuQ yuq; 77 | 78 | /** 79 | * Catch 与 Before 、 After 类似,但是必须要求参数来捕获指定异常 80 | * @param exception 这里捕获空指针异常 81 | * @return 也并非返回信息来源,而是留给后续使用 82 | */ 83 | @Catch(error = NullPointerException.class) 84 | public void reportNullPoint(NullPointerException exception){ 85 | //从YuQ(此时的YuQ是你的Bot)中获取指定对象并且发送信息。 86 | yuq.getFriends().get(12345L).sendMessage(mif.text(exception.toString()).toMessage()); 87 | } 88 | 89 | 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/event/FriendListEvent.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo.event; 2 | 3 | import com.IceCreamQAQ.Yu.annotation.Event; 4 | import com.IceCreamQAQ.Yu.annotation.EventListener; 5 | import com.icecreamqaq.yuq.event.NewFriendRequestEvent; 6 | 7 | @EventListener 8 | public class FriendListEvent { 9 | 10 | /*** 11 | * 事件的注册,并不会限制你在某个类去注册,只要你的类标记了 EventListener_ 注解。 12 | * 有利于对事件进行分类 13 | * 具体的事件列表请查看github文档 14 | * https://yuqworks.github.io/YuQ-Doc/#/ 15 | * 16 | * NewFriendRequestEvent 事件 17 | * 当有新的好友申请的时候,会触发本事件。 18 | * 如果您将事件的 accept 属性设置为 true,并同时取消了事件,那么将同意好友请求。 19 | * 否则将忽略(不进行任何处理)这个好友请求。 20 | */ 21 | @Event 22 | public void newFriendRequestEvent(NewFriendRequestEvent event) { 23 | event.setAccept(true); 24 | event.setCancel(true); 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/event/GroupManager.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo.event; 2 | 3 | import com.IceCreamQAQ.Yu.annotation.Event; 4 | import com.IceCreamQAQ.Yu.annotation.EventListener; 5 | import com.icecreamqaq.yuq.event.GroupMemberJoinEvent; 6 | import com.icecreamqaq.yuq.event.GroupMemberRequestEvent; 7 | import com.icecreamqaq.yuq.message.Message; 8 | 9 | 10 | @EventListener 11 | public class GroupManager { 12 | 13 | 14 | //表明这是一个事件 15 | @Event(weight = Event.Weight.normal) 16 | /** 17 | * 需要处理的种种事件,直接寻找对应参数,进行处理即可。 18 | * @GroupMemberRequestEvent 是群申请入群事件 19 | */ 20 | public void requestGroup(GroupMemberRequestEvent event){ 21 | if("暗号".equals(event.getMessage())){ 22 | //同意进群申请 23 | event.setAccept(true); 24 | }else { 25 | //拒绝进群事情 26 | event.setAccept(false); 27 | //设置拒绝原因 28 | event.setRejectMessage("暗号错误"); 29 | } 30 | //取消事件(这样事件才会返回拒绝或者同意的请求,没有这一步事件是不会完成的。 31 | event.setCancel(true); 32 | } 33 | 34 | @Event 35 | public void welcome(GroupMemberJoinEvent event){ 36 | event.getGroup().sendMessage(Message.Companion.toMessage("欢迎新朋友~")); 37 | } 38 | 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/event/OnMessageEvent.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo.event; 2 | 3 | import com.IceCreamQAQ.Yu.annotation.Event; 4 | import com.IceCreamQAQ.Yu.annotation.EventListener; 5 | import com.icecreamqaq.yuq.event.GroupMessageEvent; 6 | import com.icecreamqaq.yuq.event.MessageEvent; 7 | import com.icecreamqaq.yuq.event.PrivateMessageEvent; 8 | import com.icecreamqaq.yuq.message.Message; 9 | 10 | @EventListener 11 | public class OnMessageEvent { 12 | 13 | 14 | /*** 15 | * 整体 16 | * 17 | * 当收到群聊消息时,本方法会被调用。 18 | * 事件会优先于控制器收到响应。 19 | * 事件可以被取消,当事件被取消之后,控制器将不会再响应。 20 | * @param event 事件 21 | */ 22 | @Event(weight = Event.Weight.normal) 23 | public void onGroupMessage(GroupMessageEvent event) { 24 | System.out.printf("消息来自群:%s(%d)%n", event.getGroup().getName(), event.getGroup().getId()); 25 | System.out.printf("消息来自群成员:%s(%d)%n" , event.getSender().getNameCard(),event.getSender().getId()); 26 | } 27 | 28 | /*** 29 | * 一个事件可以被重复注册多次,并可以通过指定优先级来让他们保持一定的先后顺序。 30 | * 本事件则简单地介绍了一个取消事件的方式。 31 | * 32 | * 当消息事件被取消后,后续将不会再进行控制器部分的响应了。 33 | * 也就是说,群号为 111 的群,永远不会响应到 Controller 34 | */ 35 | @Event(weight = Event.Weight.low) 36 | public void onGroupMessageLow(GroupMessageEvent event) { 37 | if (111 == event.getGroup().getId()) { 38 | event.setCancel(true); 39 | } 40 | } 41 | 42 | /*** 43 | * 当收到私聊消息时,本方法会被调用。 44 | * 事件会优先于控制器收到响应。 45 | * 事件可以被取消,当事件被取消之后,控制器将不会再响应。 46 | * @param event 事件 47 | */ 48 | @Event 49 | public void onPrivateMessage(PrivateMessageEvent event) { 50 | System.out.printf("消息来自群成员:%s(%d)%n" , event.getSender().getName(),event.getSender().getId()); 51 | } 52 | 53 | /*** 54 | * 当你注册了某个事件的父事件的时候,则这个父事件的所有子事件都会被响应。 55 | * 如 MessageEvent 是 PrivateMessageEvent 和 GroupMessageEvent 的父事件, 56 | * 则 PrivateMessageEvent 和 GroupMessageEvent 事件触发的时候,监听了 MessageEvent 事件的监听器都会受到响应。 57 | */ 58 | @Event 59 | public void onMessage(MessageEvent event) { 60 | 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/event/myEvent/MessageStartWithTag1.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo.event.myEvent; 2 | 3 | 4 | import com.IceCreamQAQ.Yu.event.events.Event; 5 | import com.icecreamqaq.yuq.event.MessageEvent; 6 | 7 | /** 8 | * 自定义事件第一步,继承Event 9 | */ 10 | public class MessageStartWithTag1 extends Event { 11 | 12 | /** 13 | * 第二步 确定你的事件内容 14 | * 可以直接是其他的event方便你对事件进行二次包装 15 | * 也能是其他情况,这里只是简单举例 16 | */ 17 | MessageEvent messageEvent; 18 | String startTag; 19 | 20 | /** 21 | * 最后一步,一个构造器 22 | * @param messageEvent 23 | * @param startTag 24 | */ 25 | public MessageStartWithTag1(MessageEvent messageEvent, String startTag) { 26 | this.messageEvent = messageEvent; 27 | this.startTag = startTag; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/event/myEvent/MessageStartWithTag2.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo.event.myEvent; 2 | 3 | import com.IceCreamQAQ.Yu.event.events.Event; 4 | import com.icecreamqaq.yuq.event.MessageEvent; 5 | 6 | /** 7 | * 参考一即可。 8 | */ 9 | public class MessageStartWithTag2 extends Event { 10 | 11 | MessageEvent messageEvent; 12 | String startTag; 13 | 14 | public MessageStartWithTag2(MessageEvent messageEvent, String startTag) { 15 | this.messageEvent = messageEvent; 16 | this.startTag = startTag; 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/event/myEvent/MyNewEvent.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo.event.myEvent; 2 | 3 | 4 | import com.IceCreamQAQ.Yu.annotation.Event; 5 | import com.IceCreamQAQ.Yu.annotation.EventListener; 6 | import com.IceCreamQAQ.Yu.event.EventBus; 7 | import com.icecreamqaq.yuq.event.MessageEvent; 8 | import com.icecreamqaq.yuq.message.Message; 9 | 10 | import javax.inject.Inject; 11 | 12 | /** 13 | * 此处展示如何进行自定义事件 14 | * 通过自定义事件可以更好,更简单的实现自己想要的功能 15 | */ 16 | @EventListener 17 | public class MyNewEvent { 18 | 19 | @Inject 20 | private EventBus eventBus; 21 | 22 | /** 23 | * 该事件将实现以@和!开头的信息导入不同的事件中 24 | */ 25 | @Event 26 | public void isStartWithSpecialTag(MessageEvent event){ 27 | String messageString = Message.Companion.firstString(event.getMessage()); 28 | if(messageString.startsWith("!")){ 29 | event.getSender(); 30 | /** 31 | * 使用new一下你的事件,然后把必要的属性放上去 32 | * 然后post一下,就会到你的事件里面了 33 | */ 34 | MessageStartWithTag1 e = new MessageStartWithTag1(event,"!"); 35 | eventBus.post(e); 36 | } 37 | if(messageString.startsWith("@")){ 38 | MessageStartWithTag2 e = new MessageStartWithTag2(event,"@"); 39 | eventBus.post(e); 40 | } 41 | 42 | 43 | 44 | } 45 | 46 | @Event 47 | public void forTheTag1(MessageStartWithTag1 event){ 48 | System.out.println("------tag1------"); 49 | //获取消息 50 | event.messageEvent.getMessage(); 51 | System.out.println(event.messageEvent.getMessage()); 52 | //获取自定义事件中的内容 53 | String s =event.startTag; 54 | System.out.println(s); 55 | //发送信息 56 | event.messageEvent.getSender().sendMessage(Message.Companion.toMessage("收到了以!开头的信息,").plus(event.messageEvent.getMessage())); 57 | //取消事件 58 | event.setCancel(true); 59 | 60 | } 61 | @Event 62 | public void forTheTag2(MessageStartWithTag2 event){ 63 | System.out.println("------tag2------"); 64 | //获取消息 65 | event.messageEvent.getMessage(); 66 | System.out.println(event.messageEvent.getMessage()); 67 | //获取自定义事件中的内容 68 | String s =event.startTag; 69 | System.out.println(s); 70 | //发送信息 71 | event.messageEvent.getSender().sendMessage(Message.Companion.toMessage("收到了以@开头的信息,").plus(event.messageEvent.getMessage())); 72 | //取消事件 73 | event.setCancel(true); 74 | 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/wiki/IceCream/yuq/demo/job/JobMain.java: -------------------------------------------------------------------------------- 1 | package wiki.IceCream.yuq.demo.job; 2 | 3 | import com.IceCreamQAQ.Yu.annotation.Cron; 4 | import com.IceCreamQAQ.Yu.annotation.JobCenter; 5 | import com.IceCreamQAQ.Yu.util.DateUtil; 6 | import com.icecreamqaq.yuq.YuQ; 7 | import com.icecreamqaq.yuq.message.Message; 8 | 9 | import javax.inject.Inject; 10 | 11 | @JobCenter 12 | public class JobMain { 13 | 14 | /*** 15 | * 时钟任务。 16 | * value 参数可接受 1d 1h 1m 1s 1S(天,小时,分钟,秒,毫秒)的参数。 17 | * 同时也支持类似于 5m5s 的组合参数。 18 | * 19 | * 当然如果你愿意,1d2S111m56h7998s333m 这样的参数也能顺利解析并正确使用。 20 | * 但是代码是写给自己看的,为什么要跟自己过不去呢? 21 | * 22 | * 时钟任务方法不接受任何参数,也不接受任何返回值。 23 | */ 24 | @Cron("10s") 25 | public void ten() { 26 | System.out.println("到十秒钟啦!"); 27 | } 28 | 29 | @Inject 30 | private DateUtil dateUtil; 31 | 32 | @Inject 33 | private YuQ yuq; 34 | 35 | @Cron("At::h::00") 36 | public void printTime() { 37 | // Message message = new Message().plus("内容"); 38 | 39 | // yuq.getGroups().get(123456789L).sendMessage(message); 40 | } 41 | 42 | /*** 43 | * 定时任务。 44 | * value 必须按规范写成组合 45 | * 以 At:: 开头。 46 | * 如果匹配每天的第几个小时的第几分钟,则接下来写 d。 47 | * 如果匹配某小时的第几分钟则写 h。 48 | * 接下来写分隔符 :: 49 | * 如果上一步写的是 d,则写 小时:分钟(这里只有一个 : )(二十四小时制)。例如: 12:00 50 | * 如果上一步写的是 h,则直接写第几分钟。例如: 00 51 | * 所有的冒号均是英文半角。 52 | * 53 | * 本实例在每个小时刚开始触发。 54 | * 55 | * 定时任务方法不接受任何参数,也不接受任何返回值。 56 | * 57 | * At::h::8:15 (每天的八点十五 58 | * 59 | * At::d::30 (每个小时的第30分钟 60 | */ 61 | @Cron("At::h::00") 62 | public void at00() { 63 | System.out.println("现在是每个小时开始的第一分钟!" + dateUtil.formatDate()); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/resources/conf/YuQ.properties: -------------------------------------------------------------------------------- 1 | 2 | # 运行模式,该模式会影响配置文件读取,或某些模块的行为。默认为 dev 3 | # yu.config.runMode = dev 4 | 5 | # 扫描包路径 6 | yu.scanPackages = wiki.IceCream.yuq.demo 7 | # 如果需要添加多个扫包路径,我们可以在当前配置节点前添加一个 [ 声明配置为一个 Array。 8 | # 多个扫包路径,我们只需要重复叠 [ 就可以了。 9 | # yu.[scanPackages = xxx.xxx 10 | # yu.[[scanPackages = yyy.yyy 11 | 12 | # 机器人名,可不配置。 13 | # YuQ.bot.name = Yu 14 | 15 | # 自定义 Ehcache 配置文件 16 | # yu.cache.ehcache.config = ehcache-YuQ-Mirai.xml 17 | 18 | # 登录的 QQ 号 19 | YuQ.Mirai.user.qq = 451717812 20 | # 登录的 QQ 号的密码 21 | YuQ.Mirai.user.pwd = qqqwww111 -------------------------------------------------------------------------------- /src/main/resources/ehcache-YuQ-Mirai-demo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 15 | 16 | 17 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | true 11 | 12 | %date %highlight(%-5level) %cyan(%logger{5}@[%-4.30thread]) - %msg%n 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ${LOG_HOME}/YuQ-Mirai.log.%d{yyyy-MM-dd}.log 21 | 22 | 30 23 | 24 | 25 | 26 | %d{yyyy-MM-dd_HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 10MB 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | --------------------------------------------------------------------------------