MiraiForum

    • 注册
    • 登录
    • 搜索
    • 热门
    • 最新
    • 未解决
    • 标签
    • 群组
    • 友情链接
    1. 主页
    2. Yuanning
    3. 主题
    Y
    • 资料
    • 关注 0
    • 粉丝 0
    • 主题 4
    • 帖子 13
    • 最佳 0
    • 有争议的 0
    • 群组 0

    Yuanning 创建的主题

    • Y

      开发mcl插件时,集成mybatis进行开发的方法
      开发交流 • • Yuanning

      1
      0
      赞同
      1
      帖子
      188
      浏览

      Y

      注:在本文中,所有PluginMain无特殊说明均指代继承了KotlinPlugin抽象类的子类,也即该插件的主类。

      开发环境:gradle:7.6版,jdk:eclipse-temurin-17,kotlin版本:1.8.0,mirai-console版本:2.14.0,mybatis依赖版本:3.5.11(org.mybatis:mybatis:3.5.11)

      使用该方法配置成功的插件项目:rss_subscribe-订阅rss更新的插件,如果一切顺利的话,等发布0.3.x版本时就能看到了该项目集成mybatis了(目前版本是0.2.0)(虽然估计到时候集成了也没用上)

      好了,作者罗嗦完了,接下来进入正题

      首先我们要达成一个共识,即直接都用mybatis官方的配置文件直接进行配置是可行的,但我们开发插件是为了给别人用,因此不能在mybatis-config.xml文件中把数据库链接的配置写死,但是在我探索出来的方法中,使用mybatis-config.xml进行配置是必须的,否则调用Mapper接口时,会抛出无法绑定Mapper.xml文件之类的异常。

      因此对于在mybatis-config.xml文件中把数据库链接的配置写死和自行修改数据库链接配置中的不同点在于,拦截官方样例中如下方式

      String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

      通过输入流得到的configuration对象实例,修改其中的数据库链接配置,然后在将修改后的configuration移交给SqlSessionFactoryBuilder().build,即

      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

      首先我们要根据官方样例,生成一个具有正确的数据库链接配置的environment:

      DataSource dataSource = BlogDataSourceFactory.getBlogDataSource(); TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment("development", transactionFactory, dataSource);

      代码样例(仅作为参考,请自行修改):

      fun getEnvironmentOfConfiguration() : Environment{ val dataSource = PooledDataSource() dataSource.username = RssConfig.mysqlConfig.userName dataSource.password = RssConfig.mysqlConfig.password dataSource.url = RssConfig.mysqlConfig.url dataSource.driver = RssConfig.mysqlConfig.driver val transactionFactory: TransactionFactory = JdbcTransactionFactory() val environment = Environment("development", transactionFactory, dataSource) return environment }//得到具有正确的数据库链接配置的environment实例

      其次我们用输入流生成configuration实例,然后更改configuration实例的environment为自己手动生成的environment,最后我们将修改好的configuration交给SqlSessionFactoryBuilder().build方法

      private var sqlSessionFactory : SqlSessionFactory // MybatisUtil的用于保存全局唯一sqlSessionFactory的变量 init { val thread = Thread.currentThread() val oc = thread.contextClassLoader try { thread.contextClassLoader = PluginMain::class.java.classLoader //此处切换类加载器是为了正确加载resource中的所有xml配置文件,包括Mapper.xml val resource = "mybatis-config.xml" val inputStream: InputStream = Resources.getResourceAsStream(resource)!! //TODO 此处强制转为非空,因为mybatis-config.xml文件是存在的,以及类加载器是正常的,我们确定可以读取到该配置文件 val configuration = XMLConfigBuilder(inputStream).parse() //从inputStream流生成configuration实例 configuration.environment = getEnvironmentOfConfiguration() //修改configuration的environment的值为自己需要的值 sqlSessionFactory = SqlSessionFactoryBuilder().build(configuration) } finally { thread.contextClassLoader = oc } }// MybatisUtil的构造函数的执行体,因为MybatisUtil是object,所以第一次调用MybatisUtil时会自动调用该段代码

      当然,为了方便,我们可以封装一个切换线程类加载器的方法:

      fun changeClassLoader(block : () -> Unit){ val thread = Thread.currentThread() val oc = thread.contextClassLoader try { thread.contextClassLoader = PluginMain::class.java.classLoader block() } finally { thread.contextClassLoader = oc } }

      此时,我们得到了可供参考的MybatisUtil.kt的参考版本:

      object MybatisUtil { private lateinit var sqlSessionFactory : SqlSessionFactory fun getEnvironmentOfConfiguration() : Environment{ val dataSource = PooledDataSource() dataSource.username = RssConfig.mysqlConfig.userName dataSource.password = RssConfig.mysqlConfig.password dataSource.url = RssConfig.mysqlConfig.url dataSource.driver = RssConfig.mysqlConfig.driver dataSource.poolMaximumActiveConnections = 100 dataSource.poolMaximumIdleConnections = 8 val transactionFactory: TransactionFactory = JdbcTransactionFactory() val environment = Environment("development", transactionFactory, dataSource) return environment }//得到具有正确的数据库链接配置的environment实例 init { ChangeClassLoaderUtil.changeClassLoader { val resource = "mybatis-config.xml" val inputStream: InputStream = Resources.getResourceAsStream(resource)!!//TODO 此处强制转为非空,因为mybatis-config.xml文件是存在的,以及类加载器是正常的 val configuration = XMLConfigBuilder(inputStream).parse() configuration.environment = getEnvironmentOfConfiguration() sqlSessionFactory = SqlSessionFactoryBuilder().build(configuration) } } fun getSqlSession():SqlSession{ return sqlSessionFactory.openSession() } }

      mybatis-config.xml配置文件的参考版本:

      <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <mappers> <mapper resource="mapper/UserMapper.xml"/> </mappers> </configuration>

      注:由于configuration的environment是被我们拦截了下来,使用的我们自己生成的environment,所以在此处配置configuration标签的子标签environment是无效的,必须在MybatisUtil.getEnvironmentOfConfiguration()方法中手动修改对应参数,或将对应参数设计默认值后"映射"到Config类中,让插件使用者可以自己修改对应的配置

      致谢:
      关于如何切换类加载器的方法的文章:切换类加载器,解决Java Services 加载问题(大概也能解决Spring的上下文问题)
      以及让我找到上面那篇文章的文章:使用Mybatis时找不到配置文件

    • Y

      rss_subscribe —— 订阅rss更新的插件
      插件发布 • • Yuanning

      16
      0
      赞同
      16
      帖子
      1802
      浏览

      Y

      项目地址:
      github地址
      gitee地址

      rss-subscribe

      Mirai Console 插件, 使用 Kotlin + Gradle.

      订阅rss更新的项目√

      项目的0.3.0版本,对item标签的title,link,description元素可以在config中进行替换

      项目使用方式:

      该插件第一次运行结束后,会生成config/top.yuanning.rss_subscribe/RssConfig.yml和data/top.yuanning.rss_subscribe/RssData.yml两个文件,

      RssConfig样例如下:

      # 订阅内容有更新时发送的消息的模板, # ${title}替换item的title # ${link}替换item的link # ${description}替换item的description # ${pubDate}替换item的pubDate subscribeInfoSendMessage: "订阅内容更新了\n标题:${title}\n链接:${link}\n更新时间:${pubDate}" # 发送消息的周期,即发送消息后,经过该时间段后才会继续执行订阅任务,单位:毫秒 sendMessageTime: 5000 # 检测的周期,检测结束后,经过该时间段才会开始下一轮检测,单位:毫秒 checkTime: 60000 # 最多通知更新的数量,最大值为20,建议不要设置的过大,防止封号,最小值为1 maxNotifyNum: 2 # mysql连接配置,都是字符串格式,用不上,不用管这个配置, # 这只是作者突然抽风想试试能不能把mirai插件集成mybatis后的结果 # 项目暂时还用不到(以后大概率也不会用到)mysql数据库,所以在目前版本中,即使不配置这个,也不会报错 # 该配置不支持启动后修改,必须在mcl关闭的情况下修改 mysqlConfig: driver: com.mysql.cj.jdbc.Driver url: 'jdbc:mysql://localhost:3306/temp' userName: root password: root

      RssData样例如下:

      subscribes: - name: Lolihouse组的《别当欧尼酱》 targetUrl: 'https://www.miobt.com/rss-%E5%88%AB%E5%BD%93%E6%AC%A7%E5%B0%BC%E9%85%B1+LoliHouse.xml' subscribers: - type: friend id: 123456 notifideDate: '2023年02月10日-02时54分24秒' - type: group id: 123456 notifideDate: '2023年02月10日-02时54分24秒' initialized: false minNotifideDate: '2023年02月10日-02时54分24秒'

      如果想要添加订阅,则需要修改RssData,

      name是自定义订阅的名称(目前没用上)

      targetUrl是订阅rss的地址,要求是访问该地址是返回且只返回rss订阅信息(xml格式)

      subscribers是订阅者集合,其中type只有两种值:friend或group,id则是对应的qq号或群号,

      其他配置项为插件自用,不建议修改,用于判断是否需要通知

      注意事项:

      在第一次加载插件生成config以及data文件后请退mcl,修改config与data为想要的且正确的内容后重新启动mcl,
      当然,有插件使用经验的人可以直接拷贝上面的样例,改改拿去用

      目前版本为0.3.0,在1.0.0版本以前,项目的每次0.x.0版本的更新都有可能会有较大的更新,导致上一个0.x-1.0版本的config,data文件不能直接拿来用,在版本升级的过程中请注意
      本插件的使用有一个前提条件,就是rss订阅中,item的属性中必须包含且直接包含pubDate属性,否则按照目前逻辑无法检查是否需要通知,会出现未经测试的bug。(比如密柑计划的rss订阅的item子属性就是没有直接包含pubDate属性的,因此该插件无法使用于订阅密柑计划的rss)

      同时注意:RssData中的样例配置是无法通知到的,如果保留的话会导致每次项目检查更新时都会尝试通知该样例配置的subscriber,影响性能

      功能上的注意:本插件目前版本的作用更多的是倾向于通知有更新了,让使用者去看更新了啥,而不是插件通知都更新了哪些内容。

      比如,在检测更新的间隔内,网站更新了6条数据,如果配置了maxNotifyNum为2,那么本插件只会通知两条数据,剩下的四条没通知到的数据不会再进行通知

      换句话说,作为使用者,如果在某个时刻接受到了插件的通知,那么这个时刻之前的通知,就算没有通知到,也不会再通知了

      本软件的后续版本可能会考虑集成mybatis,从而对已通知内容进行记录,才有可能保证不会有没通知到的更新

      项目情况概述:

      目前的通知策略:如果该subscriber通知不到(有可能是因为没有bot能联系上该好友/群聊)则会跳过该subscriber,等到下一次检查更新时再尝试通知
      因此请确保所有的作为订阅者的联系人/群都在bot(如果登录了多个bot只需要在任意一个bot)的好友列表/群列表中

      如果发现bug作者看到了的话会进行修复

      虽说功能测试正常,但是用起来不方便,目前只能通过修改data文件的方式修改订阅。以后1.x.x版本开始可能会做通过控制台和通过qq聊天的方式,根据权限修改订阅

    • Y

      已解决 mcl-kotlin插件-如何关闭ServerSocket以及里面的while循环
      开发交流 • • Yuanning

      3
      0
      赞同
      3
      帖子
      249
      浏览

      Y

      (kotlin新手求助)
      我在onEnable中初始化了并监听了一个ServerSocket,想要在onDisable函数中关闭它,但是失败了

      报错大概信息如下:
      MIRAI CONSOLE CRASH REPORT.
      Console has take too long to shutdown.

      我的onDisable函数是这么写的

      override fun onDisable() { logger.info { "准备关闭socket" } serverToClose?.close() }

      注:
      serverToClose的初始化操作如下:

      PluginMain.launch { try { println("Socket服务器开始运行...") val serverSocket = ServerSocket(12345) serverSocketToClose = serverSocket while (true) { val socket = serverSocket.accept() println("接受了一个socket链接") Thread(ServerHandler(socket)).start() } } catch (e: Exception) { e.printStackTrace() } }

      但是在“准备关闭socket”这句话输出前就已经报错了,也就是我貌似无法在onDisable中关闭ServerSocket以及试图退出while循环

      不知道应该怎么在mcl退出时,关闭之前的ServerSocket以及while循环,从而正常退出mcl。

      求大佬指点

    • Y

      咨询关于ipv6
      开发交流 • • Yuanning

      3
      0
      赞同
      3
      帖子
      294
      浏览

      Y

      这个项目目前支持ipv6么,如果不支持,以后会考虑支持么(问题背景:今天在一台只有ipv6的便宜国外服务器上跑mcl,看报错说是网络连接失败,所以过来咨询一下,为了了解一下可能是哪方面除了问题)(问题的末尾,趁机感谢大佬的贡献,降低了插件编写的门槛,像我这种刚学java一个月的都能写出代码和功能都很简单的插件了)

    • 1 / 1