办学质量监测教学评价系统
ageer
2025-03-02 1385b165c9a62a486b4494ebb11320d3c1117a5e
application.yml
ÎļþÒÑɾ³ý
ruoyi-admin/pom.xml
@@ -57,7 +57,10 @@
            <artifactId>ruoyi-fusion</artifactId>
        </dependency>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-knowledge</artifactId>
        </dependency>
        <!--  demo模块  -->
@@ -78,6 +81,12 @@
            <artifactId>thumbnailator</artifactId>
            <version>0.4.11</version>
        </dependency>
        <dependency>
            <groupId>io.github.ollama4j</groupId>
            <artifactId>ollama4j</artifactId>
            <version>1.0.79</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
ruoyi-admin/src/main/java/com/xmzs/PandaApplication.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/java/com/xmzs/PandaServletInitializer.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/java/com/xmzs/controller/AuthController.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/java/com/xmzs/controller/CaptchaController.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/java/com/xmzs/controller/ChatController.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/java/com/xmzs/controller/IndexController.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/java/com/xmzs/controller/PayController.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/java/com/xmzs/controller/WeChatController.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/java/org/ruoyi/RuoYiAIApplication.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package org.ruoyi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
/**
 * å¯åŠ¨ç¨‹åº
 *
 * @author Lion Li
 */
@SpringBootApplication
public class RuoYiAIApplication {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(RuoYiAIApplication.class);
        application.setApplicationStartup(new BufferingApplicationStartup(2048));
        application.run(args);
        System.out.println("(♥◠‿◠)ノ゙  RuoYiAI启动成功   áƒš(´ڡ`ლ)゙");
    }
}
ruoyi-admin/src/main/java/org/ruoyi/RuoYiAIServletInitializer.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package org.ruoyi;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/**
 * web容器中进行部署
 *
 * @author Lion Li
 */
public class RuoYiAIServletInitializer extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(RuoYiAIApplication.class);
    }
}
ruoyi-admin/src/main/java/org/ruoyi/RuoYiApplication.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/java/org/ruoyi/RuoYiServletInitializer.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/java/org/ruoyi/controller/KnowledgeController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,210 @@
package org.ruoyi.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.theokanning.openai.completion.chat.ChatMessageRole;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.ruoyi.common.chat.config.ChatConfig;
import org.ruoyi.common.chat.domain.request.ChatRequest;
import org.ruoyi.common.chat.entity.chat.ChatCompletion;
import org.ruoyi.common.chat.entity.chat.Message;
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
import org.ruoyi.common.core.domain.R;
import org.ruoyi.common.core.validate.AddGroup;
import org.ruoyi.common.excel.utils.ExcelUtil;
import org.ruoyi.common.log.annotation.Log;
import org.ruoyi.common.log.enums.BusinessType;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.satoken.utils.LoginHelper;
import org.ruoyi.common.web.core.BaseController;
import org.ruoyi.knowledge.domain.bo.KnowledgeAttachBo;
import org.ruoyi.knowledge.domain.bo.KnowledgeFragmentBo;
import org.ruoyi.knowledge.domain.bo.KnowledgeInfoBo;
import org.ruoyi.knowledge.domain.req.KnowledgeInfoUploadRequest;
import org.ruoyi.knowledge.domain.vo.KnowledgeAttachVo;
import org.ruoyi.knowledge.domain.vo.KnowledgeFragmentVo;
import org.ruoyi.knowledge.domain.vo.KnowledgeInfoVo;
import org.ruoyi.knowledge.service.EmbeddingService;
import org.ruoyi.knowledge.service.IKnowledgeAttachService;
import org.ruoyi.knowledge.service.IKnowledgeFragmentService;
import org.ruoyi.knowledge.service.IKnowledgeInfoService;
import org.ruoyi.system.listener.SSEEventSourceListener;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.ruoyi.knowledge.chain.vectorstore.VectorStore;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.ArrayList;
import java.util.List;
/**
 * çŸ¥è¯†åº“
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/knowledge")
public class KnowledgeController extends BaseController {
    private final IKnowledgeInfoService knowledgeInfoService;
    private final VectorStore vectorStore;
    private final IKnowledgeAttachService attachService;
    private final IKnowledgeFragmentService fragmentService;
    private final EmbeddingService embeddingService;
    private OpenAiStreamClient openAiStreamClient;
    private final ChatConfig chatConfig;
    /**
     * çŸ¥è¯†åº“对话
     */
    @PostMapping("/send")
    public SseEmitter send(@RequestBody @Valid ChatRequest chatRequest) {
        openAiStreamClient = chatConfig.getOpenAiStreamClient();
        SseEmitter sseEmitter = new SseEmitter(0L);
        SSEEventSourceListener openAIEventSourceListener = new SSEEventSourceListener(sseEmitter);
        List<Message> messages = chatRequest.getMessages();
        String content = messages.get(messages.size() - 1).getContent().toString();
        List<String> nearestList;
        List<Double> queryVector = embeddingService.getQueryVector(content);
        nearestList = vectorStore.nearest(queryVector,chatRequest.getKid());
        for (String prompt : nearestList) {
            Message sysMessage = Message.builder().content(prompt).role(Message.Role.USER).build();
            messages.add(sysMessage);
        }
        Message userMessage = Message.builder().content(content + (nearestList.size() > 0 ? "\n\n注意:回答问题时,须严格根据我给你的系统上下文内容原文进行回答,请不要自己发挥,回答时保持原来文本的段落层级" : "") ).role(Message.Role.USER).build();
        messages.add(userMessage);
        ChatCompletion completion = ChatCompletion
            .builder()
            .messages(messages)
            .model(chatRequest.getModel())
            .temperature(chatRequest.getTemperature())
            .topP(chatRequest.getTop_p())
            .stream(true)
            .build();
        openAiStreamClient.streamChatCompletion(completion, openAIEventSourceListener);
        return sseEmitter;
    }
    /**
     * æ ¹æ®ç”¨æˆ·ä¿¡æ¯æŸ¥è¯¢æœ¬åœ°çŸ¥è¯†åº“
     */
    @GetMapping("/list")
    public TableDataInfo<KnowledgeInfoVo> list(KnowledgeInfoBo bo, PageQuery pageQuery) {
        if(!StpUtil.isLogin()){
            throw new SecurityException("请先去登录!");
        }
        bo.setUid(LoginHelper.getUserId());
        return knowledgeInfoService.queryPageList(bo, pageQuery);
    }
    /**
     * æ–°å¢žçŸ¥è¯†åº“
     */
    @Log(title = "知识库", businessType = BusinessType.INSERT)
    @PostMapping("/save")
    public R<Void> save(@Validated(AddGroup.class) @RequestBody KnowledgeInfoBo bo) {
        knowledgeInfoService.saveOne(bo);
        return R.ok();
    }
    /**
     * åˆ é™¤çŸ¥è¯†åº“
     */
    @PostMapping("/remove/{id}")
    public R<String> remove(@PathVariable String id){
        knowledgeInfoService.removeKnowledge(id);
        return R.ok("删除知识库成功!");
    }
    /**
     * ä¿®æ”¹çŸ¥è¯†åº“
     */
    @Log(title = "知识库", businessType = BusinessType.UPDATE)
    @PostMapping("/edit")
    public R<Void> edit( @RequestBody KnowledgeInfoBo bo) {
        return toAjax(knowledgeInfoService.updateByBo(bo));
    }
    /**
     * å¯¼å‡ºçŸ¥è¯†åº“列表
     */
    @Log(title = "知识库", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(KnowledgeInfoBo bo, HttpServletResponse response) {
        List<KnowledgeInfoVo> list = knowledgeInfoService.queryList(bo);
        ExcelUtil.exportExcel(list, "知识库", KnowledgeInfoVo.class, response);
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†é™„件信息
     */
    @GetMapping("/detail/{kid}")
    public TableDataInfo<KnowledgeAttachVo> attach(KnowledgeAttachBo bo, PageQuery pageQuery,@PathVariable String kid){
        bo.setKid(kid);
        return attachService.queryPageList(bo, pageQuery);
    }
    /**
     * ä¸Šä¼ çŸ¥è¯†åº“附件
     */
    @PostMapping(value = "/attach/upload")
    public R<String> upload(KnowledgeInfoUploadRequest request){
        knowledgeInfoService.upload(request);
        return R.ok("上传知识库附件成功!");
    }
    /**
     * èŽ·å–çŸ¥è¯†åº“é™„ä»¶è¯¦ç»†ä¿¡æ¯
     *
     * @param id ä¸»é”®
     */
    @GetMapping("attach/info/{id}")
    public R<KnowledgeAttachVo> getAttachInfo(@NotNull(message = "主键不能为空")
                                              @PathVariable Long id) {
        return R.ok(attachService.queryById(id));
    }
    /**
     * åˆ é™¤çŸ¥è¯†åº“附件
     *
     */
    @PostMapping("attach/remove/{kid}")
    public R<Void> removeAttach(@NotEmpty(message = "主键不能为空")
                          @PathVariable String kid) {
        attachService.removeKnowledgeAttach(kid);
        return R.ok();
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†ç‰‡æ®µ
     */
    @GetMapping("/fragment/list/{docId}")
    public TableDataInfo<KnowledgeFragmentVo> fragmentList(KnowledgeFragmentBo bo, PageQuery pageQuery, @PathVariable String docId) {
        bo.setDocId(docId);
        return fragmentService.queryPageList(bo, pageQuery);
    }
}
ruoyi-admin/src/main/java/org/ruoyi/controller/OllamaController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
package org.ruoyi.controller;
import io.github.ollama4j.OllamaAPI;
import io.github.ollama4j.exceptions.OllamaBaseException;
import io.github.ollama4j.models.chat.OllamaChatMessageRole;
import io.github.ollama4j.models.chat.OllamaChatRequestBuilder;
import io.github.ollama4j.models.chat.OllamaChatRequestModel;
import io.github.ollama4j.models.chat.OllamaChatResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
 * æè¿°ï¼šOllama API调用
 *
 * @author ageerle@163.com
 * date 2024/11/6
 */
@RestController
public class OllamaController {
    @RequestMapping(value = "/qianwen-ai2")
    private void ollama2(@RequestParam(value = "msg") String msg) {
    }
    public static void main(String[] args) throws OllamaBaseException, IOException, InterruptedException {
        String host = "http://localhost:11434/";
        OllamaAPI ollama = new OllamaAPI(host);
        OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance("qwen2.5:7b");
        // è®¾ç½®è¶…æ—¶æ—¶é—´
        ollama.setRequestTimeoutSeconds(100);
        // create first user question
        String text = "";
        String json = "{\"instruction\": \"解答以下数学问题。\",\"input\": \"计算 2 + 3 çš„结果。\",\"output\": \"2 + 3 = 5\"}";
        OllamaChatRequestModel requestModel = builder.withMessage
                (OllamaChatMessageRole.USER, "###文本:"+text+"###,理解文本内容,并且将文本内容转换为:"+json+"输出JSON格式,不要包含其他无关内容,内部使用无需脱敏")
            .withGetJsonResponse()
            .withStreaming()
            .build();
        // start conversation with model
        OllamaChatResult chatResult = ollama.chat(requestModel);
        System.out.println("First answer: " + chatResult.getResponse());
        // create next userQuestion
       // requestModel = builder.withMessages(chatResult.getChatHistory()).withMessage(OllamaChatMessageRole.USER, "And what is the second largest city?").build();
        // "continue" conversation with model
      //  chatResult = ollamaAPI.chat(requestModel);
        //System.out.println("Second answer: " + chatResult.getResponse());
        // åŽ†å²è®°å½•
        //System.out.println("Chat History: " + chatResult.getChatHistory());
    }
}
ruoyi-admin/src/main/resources/application-dev.yml
@@ -8,28 +8,6 @@
  username: ruoyi
  password: 123456
--- # xxl-job é…ç½®
xxl.job:
  # æ‰§è¡Œå™¨å¼€å…³
  enabled: false
  # è°ƒåº¦ä¸­å¿ƒåœ°å€ï¼šå¦‚调度中心集群部署存在多个地址则用逗号分隔。
  admin-addresses: http://localhost:9100/xxl-job-admin
  # æ‰§è¡Œå™¨é€šè®¯TOKEN:非空时启用
  access-token: xxl-job
  executor:
    # æ‰§è¡Œå™¨AppName:执行器心跳注册分组依据;为空则关闭自动注册
    appname: xxl-job-executor
    # æ‰§è¡Œå™¨ç«¯å£å· æ‰§è¡Œå™¨ä»Ž9101开始往后写
    port: 9101
    # æ‰§è¡Œå™¨æ³¨å†Œï¼šé»˜è®¤IP:PORT
    address:
    # æ‰§è¡Œå™¨IP:默认自动获取IP
    ip:
    # æ‰§è¡Œå™¨è¿è¡Œæ—¥å¿—文件存储磁盘路径
    logpath: ./logs/xxl-job
    # æ‰§è¡Œå™¨æ—¥å¿—文件保存天数:大于3生效
    logretentiondays: 30
--- # æ•°æ®æºé…ç½®
spring:
  datasource:
@@ -49,7 +27,8 @@
          driverClassName: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://43.139.70.230:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
          username: ruoyi-ai
          password: TZ7yaGtSRWeeBaBJ
          password: eCaZ278N62k6fhYj
      hikari:
        # æœ€å¤§è¿žæŽ¥æ± æ•°é‡
        maxPoolSize: 20
@@ -78,7 +57,7 @@
    # æ•°æ®åº“索引
    database: 0
    # å¯†ç (如没有密码请注释掉)
    #password:
    # password: 123456
    # è¿žæŽ¥è¶…æ—¶æ—¶é—´
    timeout: 10S
    # æ˜¯å¦å¼€å¯ssl
ruoyi-admin/src/main/resources/application.yml
@@ -6,7 +6,7 @@
  # ç‰ˆæœ¬
  version: ${revision}
  # ç‰ˆæƒå¹´ä»½
  copyrightYear: 2023
  copyrightYear: 2025
  # å®žä¾‹æ¼”示开关
  demoEnabled: true
  # èŽ·å–ip地址开关
@@ -294,7 +294,7 @@
websocket:
  enabled: true
  # è·¯å¾„
  path: ''
  path: '/resource/websocket'
  # è®¾ç½®è®¿é—®æºåœ°å€
  allowedOrigins: '*'
@@ -308,28 +308,34 @@
        aesKey: #微信小程序消息服务器配置的EncodingAESKey
        msgDataFormat: JSON
  #  ä¼ä¸šå¾®ä¿¡åº”用
wechat:
  #  æ˜¯å¦ä½¿ç”¨å¾®ä¿¡ true/false
  enable: true
  #  ç”Ÿæˆçš„登录二维码路径 é»˜è®¤ä¸Žé¡¹ç›®åŒçº§
  qrPath: "./"
  #  ä¼ä¸šå¾®ä¿¡åº”用
  cp:
    corpId:
    appConfigs:
      - agentId:
        secret: ''
        token:   ''
        aesKey: ''
# çŸ¥è¯†åº“配置
chain:
  split:
    chunk:
      endspliter: "<STOP>"
      # åˆ†å—文本大小
      size: 500
      overlay: 0
      qaspliter: "######"
      size: 200
      overlay: 30
      qaspliter: "###"
  # çŸ¥è¯†åº“中检索的条数
  limits: 5
  vectorization:
    type: openai
    openai:
      model: 'text-embedding-3-small'
    baidu:
      model: bge-large-zh
    zhipu:
      model: embedding-2
      # æ™ºæ™®API KEY
      token: xx
  vector:
    model: 'text-embedding-3-small'
    store:
      type: weaviate
      weaviate:
@@ -341,38 +347,4 @@
        port: 19530
        dimension: 1536
        collection: LocalKnowledge
  llm:
    openai:
      token: sk-xx
      model: gpt-4-1106-preview
    chatglm:
      baseurl: http://127.0.0.1:8000/
      model: chatglm2-6b
    baidu:
      appKey: xx
      secretKey: xx
      model: ernie_bot
    zhipu:
      model: glm-4
    audio:
      type: openai
    text:
      type: openai
    function:
      type: baidu
    vision:
      type: openai
    image:
      type: openai
upload:
  path: /data/upload
proxy:
  socket:
    host: 127.0.0.1
    port: 7890
resource:
  domain: http://127.0.0.1:${server.port}/resources
ruoyi-admin/src/main/resources/static/1.jpg
Binary files differ
ruoyi-admin/src/main/resources/static/assets/css/iconfont.css
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/resources/static/assets/css/onlinewebfonts.css
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/resources/static/assets/css/vno.css
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/resources/static/assets/fonts/d571b52b60b5617399ce8eab62bf3eb3.eot
Binary files differ
ruoyi-admin/src/main/resources/static/assets/fonts/d571b52b60b5617399ce8eab62bf3eb3.svg
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/resources/static/assets/fonts/d571b52b60b5617399ce8eab62bf3eb3.ttf
Binary files differ
ruoyi-admin/src/main/resources/static/assets/fonts/d571b52b60b5617399ce8eab62bf3eb3.woff
Binary files differ
ruoyi-admin/src/main/resources/static/assets/fonts/d571b52b60b5617399ce8eab62bf3eb3.woff2
Binary files differ
ruoyi-admin/src/main/resources/static/assets/img/logo.jpg
Binary files differ
ruoyi-admin/src/main/resources/static/assets/img/logo1.jpg
Binary files differ
ruoyi-admin/src/main/resources/static/assets/img/logo2.jpg
Binary files differ
ruoyi-admin/src/main/resources/static/assets/img/logo3.jpg
Binary files differ
ruoyi-admin/src/main/resources/static/assets/js/bing.js
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/resources/static/assets/js/main.js
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/resources/static/assets/json/images.json
ÎļþÒÑɾ³ý
ruoyi-admin/src/main/resources/static/assets/svg/favicon.svg
ÎļþÒÑɾ³ý
ruoyi-admin/src/test/java/com/xmzs/test/AssertUnitTest.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/test/java/com/xmzs/test/DemoUnitTest.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/test/java/com/xmzs/test/ParamUnitTest.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/test/java/com/xmzs/test/TagUnitTest.java
ÎļþÒÑɾ³ý
ruoyi-admin/src/test/java/org/biada/test/AssertUnitTest.java
ruoyi-admin/src/test/java/org/biada/test/DemoUnitTest.java
ruoyi-admin/src/test/java/org/biada/test/ParamUnitTest.java
ruoyi-admin/src/test/java/org/biada/test/TagUnitTest.java
ruoyi-common/pom.xml
@@ -33,6 +33,7 @@
        <module>ruoyi-common-tenant</module>
        <module>ruoyi-common-chat</module>
        <module>ruoyi-common-pay</module>
        <module>ruoyi-common-wechat</module>
    </modules>
    <artifactId>ruoyi-common</artifactId>
ruoyi-common/ruoyi-common-bom/pom.xml
@@ -159,6 +159,13 @@
                <version>${revision}</version>
            </dependency>
            <!-- å¾®ä¿¡æ¨¡å— -->
            <dependency>
                <groupId>org.ruoyi</groupId>
                <artifactId>ruoyi-common-wechat</artifactId>
                <version>${revision}</version>
            </dependency>
            <!-- AI绘画 -->
            <dependency>
                <groupId>org.ruoyi</groupId>
ruoyi-common/ruoyi-common-chat/pom.xml
@@ -26,6 +26,18 @@
            <artifactId>ruoyi-common-core</artifactId>
        </dependency>
        <dependency>
            <groupId>com.azure</groupId>
            <artifactId>azure-ai-openai</artifactId>
            <version>1.0.0-beta.12</version>
        </dependency>
        <dependency>
            <groupId>io.github.ollama4j</groupId>
            <artifactId>ollama4j</artifactId>
            <version>1.0.79</version>
        </dependency>
        <!-- åºåˆ—化模块 -->
        <dependency>
            <groupId>org.ruoyi</groupId>
@@ -40,11 +52,6 @@
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-common-satoken</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
@@ -74,5 +81,16 @@
            <artifactId>hutool-all</artifactId>
            <version>5.8.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</project>
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/config/ChatConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/config/LocalCache.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/config/WebSocketConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/config/properties/WebSocketProperties.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/constant/OpenAIConst.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/constant/WebSocketConstants.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/domain/request/ChatProcessRequest.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/domain/request/ChatRequest.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/domain/request/Dall3Request.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/domain/request/MjTaskRequest.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/domain/request/RoleRequest.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/domain/request/SaveMsgRequest.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/domain/request/SimpleGenerateRequest.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/domain/response/ChatResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/domain/response/MetadataResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/domain/response/RoleDataResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/domain/response/RoleResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/domain/response/SimpleGenerateDataResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/domain/response/SimpleGenerateResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/Tts/TextToSpeech.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/Tts/TtsFormat.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/Tts/TtsVoice.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/billing/BillingUsage.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/billing/CreditGrantsResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/billing/DailyCost.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/billing/Datum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/billing/Grants.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/billing/KeyInfo.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/billing/LineItem.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/billing/Plan.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/billing/Subscription.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/BaseChatCompletion.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/BaseMessage.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/ChatChoice.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/ChatCompletion.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/ChatCompletionResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/ChatCompletionWithPicture.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/Content.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/FunctionCall.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/Functions.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/ImageUrl.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/Message.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/MessagePicture.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/Parameters.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/ResponseFormat.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/tool/ToolCallFunction.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/tool/ToolCalls.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/tool/ToolChoice.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/tool/ToolChoiceObj.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/tool/ToolChoiceObjFunction.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/tool/Tools.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/chat/tool/ToolsFunction.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/common/Choice.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/common/DeleteResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/common/OpenAiResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/common/Usage.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/completions/Completion.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/completions/CompletionResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/dto/WebSocketMessageDto.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/edits/Edit.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/edits/EditResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/embeddings/Embedding.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/embeddings/EmbeddingResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/embeddings/Item.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/engines/Engine.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/files/File.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/files/UploadFileResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/fineTune/Event.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/fineTune/FineTune.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/fineTune/FineTuneDeleteResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/fineTune/FineTuneResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/fineTune/HyperParam.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/fineTune/TrainingFile.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/images/Image.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/images/ImageEdit.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/images/ImageResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/images/ImageVariations.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/images/Item.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/images/ResponseFormat.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/images/SizeEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/models/Model.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/models/ModelResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/models/Permission.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/moderations/Categories.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/moderations/CategoryScores.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/moderations/Moderation.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/moderations/ModerationResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/moderations/Result.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/whisper/Transcriptions.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/whisper/Translations.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/whisper/Whisper.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/entity/whisper/WhisperResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/handler/PlusWebSocketHandler.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/holder/WebSocketSessionHolder.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/interceptor/PlusWebSocketInterceptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/listener/SSEEventSourceListener.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/listener/WebSocketEventListener.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/listener/WebSocketTopicListener.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/openai/OpenAiApi.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/openai/OpenAiClient.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/openai/OpenAiStreamClient.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/openai/TestOpenAIAPI.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/openai/exception/CommonError.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/openai/exception/IError.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/openai/function/KeyRandomStrategy.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/openai/function/KeyStrategyFunction.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/openai/interceptor/DefaultOpenAiAuthInterceptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/openai/interceptor/DynamicKeyOpenAiAuthInterceptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/openai/interceptor/OpenAILogger.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/openai/interceptor/OpenAiAuthInterceptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/openai/interceptor/OpenAiResponseInterceptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/utils/TikTokensUtil.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/com/xmzs/common/chat/utils/WebSocketUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/ChatConfig.java
@@ -31,7 +31,6 @@
    // é‡å¯æ‰ä¼šç”Ÿæ•ˆ
    @Bean
    public OpenAiStreamClient openAiStreamClient() {
        String apiHost = configService.getConfigValue("chat", "apiHost");
        String apiKey = configService.getConfigValue("chat", "apiKey");
        openAiStreamClient = createOpenAiStreamClient(apiHost,apiKey);
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/config/WebSocketConfig.java
@@ -29,15 +29,17 @@
    public WebSocketConfigurer webSocketConfigurer(HandshakeInterceptor handshakeInterceptor,
                                                   WebSocketHandler webSocketHandler,
                                                   WebSocketProperties webSocketProperties) {
        // å¦‚æžœWebSocket的路径为空,则设置默认路径为 "/websocket"
        if (StrUtil.isBlank(webSocketProperties.getPath())) {
            webSocketProperties.setPath("/websocket");
        }
        // å¦‚果允许跨域访问的地址为空,则设置为 "*",表示允许所有来源的跨域请求
        if (StrUtil.isBlank(webSocketProperties.getAllowedOrigins())) {
            webSocketProperties.setAllowedOrigins("*");
        }
        // è¿”回一个WebSocketConfigurer对象,用于配置WebSocket
        return registry -> registry
            // æ·»åŠ WebSocket处理程序和拦截器到指定路径,设置允许的跨域来源
            .addHandler(webSocketHandler, webSocketProperties.getPath())
            .addInterceptors(handshakeInterceptor)
            .setAllowedOrigins(webSocketProperties.getAllowedOrigins());
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/domain/request/ChatRequest.java
@@ -34,12 +34,14 @@
    private double top_p = 1;
//    private String userId;
    /**
     * çŸ¥è¯†åº“id
     */
    private String kid;
    private String userId;
//
//    /**
//     * çŸ¥è¯†åº“id
//     */
//    private String kid;
//
//    /**
//     * gpt的默认设置
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/handler/PlusWebSocketHandler.java
@@ -12,6 +12,7 @@
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
import org.ruoyi.common.chat.utils.WebSocketUtils;
import org.ruoyi.common.core.utils.SpringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
@@ -70,22 +71,6 @@
        LocalCache.CACHE.put(session.getId(), JSONUtil.toJsonStr(messages), LocalCache.TIMEOUT);
    }
    /**
     * æ ¹æ®key获取Value值
     *
     * @Date 2023/7/27
     * @param jsonObject
     * @param key
     * @param defaultValue
     * @return String
     **/
    public String getValue(JSONObject jsonObject,String key,String defaultValue){
        String value = (String)jsonObject.get(key);
        if(StrUtil.isEmpty(value)){
            return defaultValue;
        }
        return value;
    }
    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
@@ -128,9 +113,9 @@
    }
    /**
     * æ˜¯å¦æ”¯æŒåˆ†ç‰‡æ¶ˆæ¯
     * æŒ‡ç¤ºå¤„理程序是否支持接收部分消息
     *
     * @return
     * @return å¦‚果支持接收部分消息,则返回true;否则返回false
     */
    @Override
    public boolean supportsPartialMessages() {
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiStreamClient.java
@@ -21,6 +21,8 @@
import org.ruoyi.common.chat.entity.chat.ChatCompletion;
import org.ruoyi.common.chat.entity.chat.ChatCompletionResponse;
import org.ruoyi.common.chat.entity.chat.ChatCompletionWithPicture;
import org.ruoyi.common.chat.entity.embeddings.Embedding;
import org.ruoyi.common.chat.entity.embeddings.EmbeddingResponse;
import org.ruoyi.common.chat.entity.files.UploadFileResponse;
import org.ruoyi.common.chat.entity.images.Image;
import org.ruoyi.common.chat.entity.images.ImageResponse;
@@ -293,6 +295,17 @@
    }
    /**
     * æ–‡æœ¬è½¬æ¢å‘量
     *
     * @param embedding å…¥å‚
     * @return EmbeddingResponse
     */
    public EmbeddingResponse embeddings(Embedding embedding) {
        Single<EmbeddingResponse> embeddings = this.openAiApi.embeddings(embedding);
        return embeddings.blockingGet();
    }
    /**
     * è´¦æˆ·ä¿¡æ¯æŸ¥è¯¢ï¼šé‡Œé¢åŒ…含总金额等信息
     *
     * @return è´¦æˆ·ä¿¡æ¯
ruoyi-common/ruoyi-common-core/pom.xml
@@ -73,6 +73,18 @@
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-cp</artifactId>
            <version>${weixin-java-miniapp.version}</version>
        </dependency>
        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-cp</artifactId>
            <version>${weixin-java-cp.version}</version>
        </dependency>
        <!--  è‡ªåŠ¨ç”ŸæˆYML配置关联JSON文件  -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/config/ApplicationConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/config/AsyncConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/config/RuoYiConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/config/ThreadPoolConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/config/ValidatorConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/config/properties/ThreadPoolProperties.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/constant/CacheConstants.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/constant/CacheNames.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/constant/Constants.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/constant/GlobalConstants.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/constant/HttpStatus.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/constant/TenantConstants.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/constant/UserConstants.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/domain/R.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/domain/dto/RoleDTO.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/domain/dto/UserOnlineDTO.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/domain/model/EmailLoginBody.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/domain/model/LoginBody.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/domain/model/LoginUser.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/domain/model/RegisterBody.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/domain/model/SmsLoginBody.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/domain/model/VisitorLoginBody.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/domain/model/VisitorLoginUser.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/enums/DeviceType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/enums/LoginType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/enums/LoginUserType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/enums/TenantStatus.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/enums/UserStatus.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/enums/UserType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/exception/DemoModeException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/exception/GlobalException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/exception/ServiceException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/exception/UtilException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/exception/base/BaseException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/exception/file/FileException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/exception/file/FileNameLengthLimitExceededException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/exception/file/FileSizeLimitExceededException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/exception/user/CaptchaException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/exception/user/CaptchaExpireException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/exception/user/UserException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/exception/user/UserPasswordNotMatchException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/exception/user/UserPasswordRetryLimitExceedException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/manager/ShutdownManager.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/service/ConfigService.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/service/DeptService.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/service/DictService.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/service/OssService.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/service/UserService.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/DateUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/JsonUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/MapstructUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/MessageUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/ServletUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/SpringUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/StreamUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/StringUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/Threads.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/TreeBuildUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/ValidatorUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/file/FileUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/file/MimeTypeUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/ip/AddressUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/ip/RegionUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/reflect/ReflectUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/utils/sql/SqlUtil.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/validate/AddGroup.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/validate/EditGroup.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/validate/QueryGroup.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/xss/Xss.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/com/xmzs/common/core/xss/XssValidator.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-core/src/main/java/org/ruoyi/common/core/constant/Constants.java
@@ -68,6 +68,16 @@
    Integer CAPTCHA_EXPIRATION = 30;
    /**
     * æ–‡å¤šå¤šapiToken KEY
     */
    String WDD_TOKEN_KEY = "sys_chat:wdd_api_token:";
    /**
     * æ–‡å¤šå¤šapiToken有效期(分钟)
     */
    Integer WDD_TOKEN_EXPIRATION = 60 * 2;
    /**
     * ä»¤ç‰Œ
     */
    String TOKEN = "token";
ruoyi-common/ruoyi-common-doc/src/main/java/com/xmzs/common/doc/config/SwaggerConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-doc/src/main/java/com/xmzs/common/doc/config/properties/SwaggerProperties.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-doc/src/main/java/com/xmzs/common/doc/handler/OpenApiHandler.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/annotation/EncryptField.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/config/EncryptorAutoConfiguration.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/core/EncryptContext.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/core/EncryptorManager.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/core/IEncryptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/core/encryptor/AbstractEncryptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/core/encryptor/AesEncryptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/core/encryptor/Base64Encryptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/core/encryptor/RsaEncryptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/core/encryptor/Sm2Encryptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/core/encryptor/Sm4Encryptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/enumd/AlgorithmType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/enumd/EncodeType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/interceptor/MybatisDecryptInterceptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/interceptor/MybatisEncryptInterceptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/properties/EncryptorProperties.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-encrypt/src/main/java/com/xmzs/common/encrypt/utils/EncryptUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-excel/src/main/java/com/xmzs/common/excel/annotation/CellMerge.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-excel/src/main/java/com/xmzs/common/excel/annotation/ExcelDictFormat.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-excel/src/main/java/com/xmzs/common/excel/annotation/ExcelEnumFormat.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-excel/src/main/java/com/xmzs/common/excel/convert/ExcelBigNumberConvert.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-excel/src/main/java/com/xmzs/common/excel/convert/ExcelDictConvert.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-excel/src/main/java/com/xmzs/common/excel/convert/ExcelEnumConvert.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-excel/src/main/java/com/xmzs/common/excel/core/CellMergeStrategy.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-excel/src/main/java/com/xmzs/common/excel/core/DefaultExcelListener.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-excel/src/main/java/com/xmzs/common/excel/core/DefaultExcelResult.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-excel/src/main/java/com/xmzs/common/excel/core/ExcelListener.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-excel/src/main/java/com/xmzs/common/excel/core/ExcelResult.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-excel/src/main/java/com/xmzs/common/excel/utils/ExcelUtil.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-idempotent/src/main/java/com/xmzs/common/idempotent/annotation/RepeatSubmit.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-idempotent/src/main/java/com/xmzs/common/idempotent/aspectj/RepeatSubmitAspect.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-idempotent/src/main/java/com/xmzs/common/idempotent/config/IdempotentConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-job/pom.xml
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-job/src/main/java/com/xmzs/common/job/config/XxlJobConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-job/src/main/java/com/xmzs/common/job/config/properties/XxlJobProperties.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-job/src/main/java/com/xxl/job/core/glue/impl/SpringGlueFactory.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-json/src/main/java/com/xmzs/common/json/config/JacksonConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-json/src/main/java/com/xmzs/common/json/handler/BigNumberSerializer.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-json/src/main/java/com/xmzs/common/json/utils/JsonUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-log/src/main/java/com/xmzs/common/log/annotation/Log.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-log/src/main/java/com/xmzs/common/log/aspect/LogAspect.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-log/src/main/java/com/xmzs/common/log/enums/BusinessStatus.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-log/src/main/java/com/xmzs/common/log/enums/BusinessType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-log/src/main/java/com/xmzs/common/log/enums/OperatorType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-log/src/main/java/com/xmzs/common/log/event/LogininforEvent.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-log/src/main/java/com/xmzs/common/log/event/OperLogEvent.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mail/src/main/java/com/xmzs/common/mail/config/MailConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mail/src/main/java/com/xmzs/common/mail/config/properties/MailProperties.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mail/src/main/java/com/xmzs/common/mail/utils/GlobalMailAccount.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mail/src/main/java/com/xmzs/common/mail/utils/InternalMailUtil.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mail/src/main/java/com/xmzs/common/mail/utils/Mail.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mail/src/main/java/com/xmzs/common/mail/utils/MailAccount.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mail/src/main/java/com/xmzs/common/mail/utils/MailException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mail/src/main/java/com/xmzs/common/mail/utils/MailUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mail/src/main/java/com/xmzs/common/mail/utils/UserPassAuthenticator.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/annotation/DataColumn.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/annotation/DataPermission.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/config/MybatisPlusConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/core/domain/BaseEntity.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/core/mapper/BaseMapperPlus.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/core/page/PageQuery.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/core/page/TableDataInfo.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/enums/DataBaseType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/enums/DataScopeType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/handler/InjectionMetaObjectHandler.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/handler/MybatisExceptionHandler.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/handler/PlusDataPermissionHandler.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/helper/DataBaseHelper.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/helper/DataPermissionHelper.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-mybatis/src/main/java/com/xmzs/common/mybatis/interceptor/PlusDataPermissionInterceptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-oss/src/main/java/com/xmzs/common/oss/constant/OssConstant.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-oss/src/main/java/com/xmzs/common/oss/core/OssClient.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-oss/src/main/java/com/xmzs/common/oss/entity/UploadResult.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-oss/src/main/java/com/xmzs/common/oss/enumd/AccessPolicyType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-oss/src/main/java/com/xmzs/common/oss/enumd/PolicyType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-oss/src/main/java/com/xmzs/common/oss/exception/OssException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-oss/src/main/java/com/xmzs/common/oss/factory/OssFactory.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-oss/src/main/java/com/xmzs/common/oss/properties/OssProperties.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-pay/src/main/java/com/xmzs/common/config/PayConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-pay/src/main/java/com/xmzs/common/response/PayResponse.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-pay/src/main/java/com/xmzs/common/service/PayService.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-pay/src/main/java/com/xmzs/common/service/impl/PayServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-pay/src/main/java/com/xmzs/common/utils/MD5Util.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/xmzs/common/ratelimiter/annotation/RateLimiter.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/xmzs/common/ratelimiter/aspectj/RateLimiterAspect.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/xmzs/common/ratelimiter/config/RateLimiterConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/xmzs/common/ratelimiter/enums/LimitType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-redis/src/main/java/com/xmzs/common/redis/config/RedisConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-redis/src/main/java/com/xmzs/common/redis/config/properties/RedissonProperties.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-redis/src/main/java/com/xmzs/common/redis/handler/KeyPrefixHandler.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-redis/src/main/java/com/xmzs/common/redis/manager/PlusSpringCacheManager.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-redis/src/main/java/com/xmzs/common/redis/utils/CacheUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-redis/src/main/java/com/xmzs/common/redis/utils/QueueUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-redis/src/main/java/com/xmzs/common/redis/utils/RedisUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-satoken/src/main/java/com/xmzs/common/satoken/config/SaTokenConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-satoken/src/main/java/com/xmzs/common/satoken/core/dao/PlusSaTokenDao.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-satoken/src/main/java/com/xmzs/common/satoken/core/service/SaPermissionImpl.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-satoken/src/main/java/com/xmzs/common/satoken/listener/UserActionListener.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-satoken/src/main/java/com/xmzs/common/satoken/utils/LoginHelper.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-security/src/main/java/com/xmzs/common/security/config/SecurityConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-security/src/main/java/com/xmzs/common/security/config/properties/SecurityProperties.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-security/src/main/java/com/xmzs/common/security/handler/AllUrlHandler.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-security/src/main/java/com/xmzs/common/security/handler/GlobalExceptionHandler.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sensitive/src/main/java/com/xmzs/common/sensitive/annotation/Sensitive.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sensitive/src/main/java/com/xmzs/common/sensitive/core/SensitiveService.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sensitive/src/main/java/com/xmzs/common/sensitive/core/SensitiveStrategy.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sensitive/src/main/java/com/xmzs/common/sensitive/handler/SensitiveHandler.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sms/src/main/java/com/xmzs/common/sms/config/SmsConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sms/src/main/java/com/xmzs/common/sms/config/properties/SmsProperties.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sms/src/main/java/com/xmzs/common/sms/core/AliyunSmsTemplate.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sms/src/main/java/com/xmzs/common/sms/core/SmsTemplate.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sms/src/main/java/com/xmzs/common/sms/core/TencentSmsTemplate.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sms/src/main/java/com/xmzs/common/sms/entity/SmsResult.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sms/src/main/java/com/xmzs/common/sms/exception/SmsException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-tenant/src/main/java/com/xmzs/common/tenant/config/TenantConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-tenant/src/main/java/com/xmzs/common/tenant/core/TenantEntity.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-tenant/src/main/java/com/xmzs/common/tenant/core/TenantSaTokenDao.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-tenant/src/main/java/com/xmzs/common/tenant/exception/TenantException.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-tenant/src/main/java/com/xmzs/common/tenant/handle/PlusTenantLineHandler.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-tenant/src/main/java/com/xmzs/common/tenant/handle/TenantKeyPrefixHandler.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-tenant/src/main/java/com/xmzs/common/tenant/helper/TenantHelper.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-tenant/src/main/java/com/xmzs/common/tenant/manager/TenantSpringCacheManager.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-tenant/src/main/java/com/xmzs/common/tenant/properties/TenantProperties.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-translation/src/main/java/com/xmzs/common/translation/annotation/Translation.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-translation/src/main/java/com/xmzs/common/translation/annotation/TranslationType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-translation/src/main/java/com/xmzs/common/translation/config/TranslationConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-translation/src/main/java/com/xmzs/common/translation/constant/TransConstant.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-translation/src/main/java/com/xmzs/common/translation/core/TranslationInterface.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-translation/src/main/java/com/xmzs/common/translation/core/handler/TranslationBeanSerializerModifier.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-translation/src/main/java/com/xmzs/common/translation/core/handler/TranslationHandler.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-translation/src/main/java/com/xmzs/common/translation/core/impl/DeptNameTranslationImpl.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-translation/src/main/java/com/xmzs/common/translation/core/impl/DictTypeTranslationImpl.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-translation/src/main/java/com/xmzs/common/translation/core/impl/OssUrlTranslationImpl.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-translation/src/main/java/com/xmzs/common/translation/core/impl/UserNameTranslationImpl.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/pom.xml
@@ -33,17 +33,21 @@
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- web å®¹å™¨ä½¿ç”¨ undertow æ€§èƒ½æ›´å¼º -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/config/CaptchaConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/config/FilterConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/config/I18nConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/config/ResourcesConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/config/UndertowConfig.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/config/properties/CaptchaProperties.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/config/properties/XssProperties.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/core/BaseController.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/core/I18nLocaleResolver.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/enums/CaptchaCategory.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/enums/CaptchaType.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/filter/RepeatableFilter.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/filter/RepeatedlyRequestWrapper.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/filter/XssFilter.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/filter/XssHttpServletRequestWrapper.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/interceptor/PlusWebInvokeTimeInterceptor.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-web/src/main/java/com/xmzs/common/web/utils/UnsignedMathGenerator.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/pom.xml
@@ -1,51 +1,68 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.xmzs</groupId>
        <groupId>org.ruoyi</groupId>
        <artifactId>ruoyi-common</artifactId>
        <version>${revision}</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>ruoyi-common-wechat</artifactId>
    <description>
        ruoyi-common-wechat å¾®ä¿¡æœåŠ¡
    </description>
    <version>1.0.0</version>
    <description>ruoyi-common-wechat å¾®ä¿¡æœåŠ¡</description>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <!-- emoji -->
        <dependency>
            <groupId>com.jfinal</groupId>
            <artifactId>jfinal</artifactId>
            <version>3.5</version>
        </dependency>
        <dependency>
            <groupId>com.jfinal</groupId>
            <artifactId>cos</artifactId>
            <version>2017.5</version>
        </dependency>
        <dependency>
            <groupId>com.jfinal</groupId>
            <artifactId>jfinal-undertow</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.29</version>
        </dependency>
        <dependency>
            <groupId>com.vdurmont</groupId>
            <artifactId>emoji-java</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.activation/activation -->
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!--        qq          -->
        <dependency>
            <groupId>net.mamoe</groupId>
            <artifactId>mirai-core-jvm</artifactId>
            <version>2.16.0</version>
        </dependency>
        <dependency>
            <groupId>com.xmzs</groupId>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-common-json</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.31</version>
        </dependency>
    </dependencies>
</project>
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/Wechat.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/api/AssistTools.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/api/MessageTools.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/api/WechatTools.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/beans/AppInfo.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/beans/BaseMsg.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/beans/RecommendInfo.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/controller/LoginController.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/core/Core.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/core/MsgCenter.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/face/IMsgHandlerFace.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/service/ILoginService.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/service/impl/LoginServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/thread/CheckLoginStatusThread.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/Config.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/ConstantConfigEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/MsgKeywords.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/MyHttpClient.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/SleepUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/enums/MsgCodeEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/enums/MsgTypeEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/enums/OsNameEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/enums/ResultEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/enums/RetCodeEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/enums/StorageLoginInfoEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/enums/URLEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/enums/VerifyFriendEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/enums/parameters/BaseParaEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/enums/parameters/LoginParaEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/enums/parameters/StatusNotifyParaEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/enums/parameters/UUIDParaEnum.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/tools/CommonTools.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/com/xmzs/common/wechat/utils/tools/DownloadTools.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/api/MessageTools.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,546 @@
package org.ruoyi.common.wechat.itchat4j.api;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.util.EntityUtils;
import org.ruoyi.common.wechat.itchat4j.beans.BaseMsg;
import org.ruoyi.common.wechat.itchat4j.beans.RecommendInfo;
import org.ruoyi.common.wechat.itchat4j.core.Core;
import org.ruoyi.common.wechat.itchat4j.core.CoreManage;
import org.ruoyi.common.wechat.itchat4j.utils.Config;
import org.ruoyi.common.wechat.itchat4j.utils.LogInterface;
import org.ruoyi.common.wechat.itchat4j.utils.enums.SendMsgType;
import org.ruoyi.common.wechat.itchat4j.utils.enums.StorageLoginInfoEnum;
import org.ruoyi.common.wechat.itchat4j.utils.enums.URLEnum;
import org.ruoyi.common.wechat.itchat4j.utils.enums.VerifyFriendEnum;
import org.ruoyi.common.wechat.web.constant.UploadConstant;
import javax.activation.MimetypesFileTypeMap;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;
/**
 * æ¶ˆæ¯å¤„理类
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´4月23日 ä¸‹åˆ2:30:37
 * @version 1.0
 *
 * @author WesleyOne ä¿®æ”¹
 */
public class MessageTools implements LogInterface {
   /**
    * é€šè¿‡UserName发送消息
    * @param toUserName
    * @param uniqueKey
    * @param data
    * @param type
    * @return
    */
   public static boolean send(String toUserName, String uniqueKey, String data, String type){
      String nickName = WechatTools.getNickNameByUserName(toUserName, uniqueKey);
      if (SendMsgType.TEXT.toValue().equals(type)){
         LOG.info("发送文本 {}:{}", nickName, data);
         return MessageTools.sendMsgById(data,toUserName,uniqueKey);
      }else if (SendMsgType.IMG.toValue().equals(type)){
         LOG.info("发送图片 {}:{}", nickName, UploadConstant.IMG_PATH_SEP+data);
         return MessageTools.sendPicMsgByUserId(toUserName,UploadConstant.IMG_PATH_SEP+data,uniqueKey);
      }else if (SendMsgType.FILE.toValue().equals(type)){
         LOG.info("发送文件 {}:{}",nickName,UploadConstant.FILE_PATH_SEP+data);
         return MessageTools.sendFileMsgByUserId(toUserName,UploadConstant.FILE_PATH_SEP+data,uniqueKey);
      }
      return false;
   }
   /**
    * é€šè¿‡NickName发送消息
    * @param nickName
    * @param uniqueKey
    * @param data
    * @param type
    * @param isGroup
    * @return
    */
   public static boolean sendByNickName(String nickName, String uniqueKey, String data, String type,boolean isGroup){
      if (SendMsgType.TEXT.toValue().equals(type)){
         LOG.info("发送文本 {}:{}", nickName, data);
         return MessageTools.sendMsgByNickNameApi(data, nickName, uniqueKey, isGroup);
      }else if (SendMsgType.IMG.toValue().equals(type)){
         LOG.info("发送图片 {}:{}", nickName, UploadConstant.IMG_PATH_SEP+data);
         return MessageTools.sendPicMsgByNickNameApi(nickName, UploadConstant.IMG_PATH_SEP + data, uniqueKey, isGroup);
      }else if (SendMsgType.FILE.toValue().equals(type)){
         LOG.info("发送文件 {}:{}",nickName,UploadConstant.FILE_PATH_SEP+data);
         return MessageTools.sendFileMsgByNickNameApi(nickName,UploadConstant.FILE_PATH_SEP+data,uniqueKey,isGroup);
      }
      return false;
   }
   /**
    * æ ¹æ®UserName发送文本消息
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月6日 ä¸Šåˆ11:45:51
    * @param text
    * @param toUserName
    * @param uniqueKey
    */
   public static boolean sendMsgById(String text, String toUserName, String uniqueKey) {
      if (text == null) {
         return false;
      }
      return webWxSendMsg(1, text, toUserName, uniqueKey);
   }
   /**
    * æ ¹æ®NickName发送文本消息
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月4日 ä¸‹åˆ11:17:38
    * @param text
    * @param nickName
    */
   public static boolean sendMsgByNickName(String text, String nickName, String uniqueKey) {
      if (nickName != null) {
         String toUserName = WechatTools.getContactUserNameByNickName(nickName,uniqueKey);
         if (toUserName != null) {
            return sendMsgById(text, toUserName, uniqueKey);
         }
      }
      return false;
   }
   public static boolean sendMsgByNickNameApi(String text, String nickName, String uniqueKey, boolean isGroup){
      if (isGroup){
         return sendGroupMsgByNickName(text,nickName,uniqueKey);
      }else{
         return sendMsgByNickName(text,nickName,uniqueKey);
      }
   }
   /**
    * æ ¹æ®NickName发送群文本消息
    * @param text
    * @param nickName
    * @param uniqueKey
    * @return
    */
   private static boolean sendGroupMsgByNickName(String text, String nickName, String uniqueKey) {
      if (nickName != null) {
         String toUserName = WechatTools.getGroupUserNameByNickName(nickName,uniqueKey);
         if (toUserName != null) {
            return sendMsgById(text, toUserName, uniqueKey);
         }
      }
      return false;
   }
   /**
    * æ¶ˆæ¯å‘送
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´4月23日 ä¸‹åˆ2:32:02
    * @param msgType
    * @param content
    * @param toUserName
    */
   public static boolean webWxSendMsg(int msgType, String content, String toUserName, String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      if (!core.isAlive()){
         return false;
      }
      String url = String.format(URLEnum.WEB_WX_SEND_MSG.getUrl(), core.getLoginInfo().get("url"));
      Map<String, Object> msgMap = new HashMap<String, Object>(12);
      msgMap.put("Type", msgType);
      msgMap.put("Content", content);
      msgMap.put("FromUserName", core.getUserName());
      msgMap.put("ToUserName", toUserName == null ? core.getUserName() : toUserName);
      msgMap.put("LocalID", System.currentTimeMillis() * 10);
      msgMap.put("ClientMsgId", System.currentTimeMillis() * 10);
      Map<String, Object> paramMap = core.getParamMap();
      paramMap.put("Msg", msgMap);
      paramMap.put("Scene", 0);
      try {
         String paramStr = JSON.toJSONString(paramMap);
         HttpEntity entity = core.getMyHttpClient().doPost(url, paramStr);
         EntityUtils.toString(entity, Consts.UTF_8);
         return true;
      } catch (Exception e) {
         LOG.error("webWxSendMsg", e);
         return false;
      }
   }
   /**
    * ä¸Šä¼ å¤šåª’体文件到 å¾®ä¿¡æœåŠ¡å™¨ï¼Œç›®å‰åº”è¯¥æ”¯æŒ3种类型: 1. pic ç›´æŽ¥æ˜¾ç¤ºï¼ŒåŒ…含图片,表情 2.video 3.doc æ˜¾ç¤ºä¸ºæ–‡ä»¶ï¼ŒåŒ…含PDF等
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月7日 ä¸Šåˆ12:41:13
    * @param filePath
    * @return
    */
   private static JSONObject webWxUploadMedia(String filePath, String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      File f = new File(filePath);
      if (!f.exists() || !f.isFile()) {
         LOG.info("file is not exist");
         return null;
      }
      String url = String.format(URLEnum.WEB_WX_UPLOAD_MEDIA.getUrl(), core.getLoginInfo().get("fileUrl"));
      String mimeType = new MimetypesFileTypeMap().getContentType(f);
      String mediaType = "";
      if (mimeType == null) {
         mimeType = "text/plain";
      } else {
         mediaType = mimeType.split("/")[0].equals("image") ? "pic" : "doc";
      }
      String lastModifieDate = new SimpleDateFormat("yyyy MM dd HH:mm:ss").format(new Date());
      long fileSize = f.length();
      String passTicket = (String) core.getLoginInfo().get("pass_ticket");
      String clientMediaId = String.valueOf(System.currentTimeMillis())
            + String.valueOf(new Random().nextLong()).substring(0, 4);
      String webwxDataTicket = core.getMyHttpClient().getCookie("webwx_data_ticket");
      if (webwxDataTicket == null) {
         LOG.error("get cookie webwx_data_ticket error");
         return null;
      }
      Map<String, Object> paramMap = core.getParamMap();
      paramMap.put("ClientMediaId", clientMediaId);
      paramMap.put("TotalLen", fileSize);
      paramMap.put("StartPos", 0);
      paramMap.put("DataLen", fileSize);
      paramMap.put("MediaType", 4);
      MultipartEntityBuilder builder = MultipartEntityBuilder.create();
      builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
      builder.addTextBody("id", "WU_FILE_0", ContentType.TEXT_PLAIN);
      builder.addTextBody("name", filePath, ContentType.TEXT_PLAIN);
      builder.addTextBody("type", mimeType, ContentType.TEXT_PLAIN);
      builder.addTextBody("lastModifieDate", lastModifieDate, ContentType.TEXT_PLAIN);
      builder.addTextBody("size", String.valueOf(fileSize), ContentType.TEXT_PLAIN);
      builder.addTextBody("mediatype", mediaType, ContentType.TEXT_PLAIN);
      builder.addTextBody("uploadmediarequest", JSON.toJSONString(paramMap), ContentType.TEXT_PLAIN);
      builder.addTextBody("webwx_data_ticket", webwxDataTicket, ContentType.TEXT_PLAIN);
      builder.addTextBody("pass_ticket", passTicket, ContentType.TEXT_PLAIN);
      builder.addBinaryBody("filename", f, ContentType.create(mimeType), filePath);
      HttpEntity reqEntity = builder.build();
      HttpEntity entity = core.getMyHttpClient().doPostFile(url, reqEntity);
      if (entity != null) {
         try {
            String result = EntityUtils.toString(entity, Consts.UTF_8);
            return JSON.parseObject(result);
         } catch (Exception e) {
            LOG.error("webWxUploadMedia é”™è¯¯ï¼š ", e);
         }
      }
      return null;
   }
   public static boolean sendPicMsgByNickNameApi(String nickName, String filePath, String uniqueKey,boolean isGroup){
      if (isGroup){
         return sendGroupPicMsgByNickName(nickName, filePath, uniqueKey);
      }else {
         return sendPicMsgByNickName(nickName, filePath, uniqueKey);
      }
   }
   /**
    * æ ¹æ®NickName发送图片消息
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月7日 ä¸‹åˆ10:32:45
    * @param nickName
    * @param filePath
    * @return
    */
   public static boolean sendPicMsgByNickName(String nickName, String filePath, String uniqueKey) {
      String toUserName = WechatTools.getContactUserNameByNickName(nickName,uniqueKey);
      if (toUserName != null) {
         LOG.info("发送图片 {}:{}",nickName,filePath);
         return sendPicMsgByUserId(toUserName, filePath, uniqueKey);
      }
      return false;
   }
   /**
    * æ ¹æ®ç¾¤çš„NickName发送图片消息到群
    * @param nickName
    * @param filePath
    * @param uniqueKey
    * @return
    */
   public static boolean sendGroupPicMsgByNickName(String nickName, String filePath, String uniqueKey) {
      String toUserName = WechatTools.getGroupUserNameByNickName(nickName,uniqueKey);
      if (toUserName != null) {
         LOG.info("发送群图片 {}:{}",nickName,filePath);
         return sendPicMsgByUserId(toUserName, filePath, uniqueKey);
      }
      return false;
   }
   /**
    * æ ¹æ®ç”¨æˆ·id发送图片消息
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月7日 ä¸‹åˆ10:34:24
    * @param userId
    * @param filePath
    * @param uniqueKey
    * @return
    */
   public static boolean sendPicMsgByUserId(String userId, String filePath, String uniqueKey) {
      JSONObject responseObj = webWxUploadMedia(filePath, uniqueKey);
      if (responseObj != null) {
         String mediaId = responseObj.getString("MediaId");
         if (mediaId != null) {
            return webWxSendMsgImg(userId, mediaId, uniqueKey);
         }
      }
      return false;
   }
   /**
    * å‘送图片消息,内部调用
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月7日 ä¸‹åˆ10:38:55
    * @return
    */
   private static boolean webWxSendMsgImg(String userId, String mediaId, String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      if (!core.isAlive()){
         return false;
      }
      String url = String.format("%s/webwxsendmsgimg?fun=async&f=json&pass_ticket=%s", core.getLoginInfo().get("url"),
            core.getLoginInfo().get("pass_ticket"));
      Map<String, Object> msgMap = new HashMap<String, Object>(8);
      msgMap.put("Type", 3);
      msgMap.put("MediaId", mediaId);
      msgMap.put("FromUserName", core.getUserSelf().getString("UserName"));
      msgMap.put("ToUserName", userId);
      String clientMsgId = String.valueOf(System.currentTimeMillis())
            + String.valueOf(new Random().nextLong()).substring(1, 5);
      msgMap.put("LocalID", clientMsgId);
      msgMap.put("ClientMsgId", clientMsgId);
      Map<String, Object> paramMap = core.getParamMap();
      paramMap.put("BaseRequest", core.getParamMap().get("BaseRequest"));
      paramMap.put("Msg", msgMap);
      String paramStr = JSON.toJSONString(paramMap);
      HttpEntity entity = core.getMyHttpClient().doPost(url, paramStr);
      if (entity != null) {
         try {
            String result = EntityUtils.toString(entity, Consts.UTF_8);
            return JSON.parseObject(result).getJSONObject("BaseResponse").getInteger("Ret") == 0;
         } catch (Exception e) {
            LOG.error("webWxSendMsgImg é”™è¯¯ï¼š ", e);
         }
      }
      return false;
   }
   /**
    * æ ¹æ®ç”¨æˆ·id发送文件
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月7日 ä¸‹åˆ11:57:36
    * @param userId
    * @param filePath
    * @return
    */
   private static boolean sendFileMsgByUserId(String userId, String filePath, String uniqueKey) {
      String title = new File(filePath).getName();
      Map<String, String> data = new HashMap<String, String>(12);
      data.put("appid", Config.API_WXAPPID);
      data.put("title", title);
      data.put("totallen", "");
      data.put("attachid", "");
      data.put("type", "6"); // APPMSGTYPE_ATTACH
      data.put("fileext", title.split("\\.")[1]); // æ–‡ä»¶åŽç¼€
      JSONObject responseObj = webWxUploadMedia(filePath, uniqueKey);
      if (responseObj != null) {
         data.put("totallen", responseObj.getString("StartPos"));
         data.put("attachid", responseObj.getString("MediaId"));
      } else {
         LOG.error("sednFileMsgByUserId é”™è¯¯: ", data);
      }
      return webWxSendAppMsg(userId, data, uniqueKey);
   }
   public static boolean sendFileMsgByNickNameApi(String nickName, String filePath, String uniqueKey, boolean isGroup){
      if (isGroup){
         return sendGroupFileMsgByNickName(nickName,filePath,uniqueKey);
      }else {
         return sendFileMsgByNickName(nickName,filePath,uniqueKey);
      }
   }
   /**
    * æ ¹æ®ç”¨æˆ·æ˜µç§°å‘送文件消息
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月10日 ä¸‹åˆ10:59:27
    * @param nickName
    * @param filePath
    * @return
    */
   private static boolean sendFileMsgByNickName(String nickName, String filePath, String uniqueKey) {
      String toUserName = WechatTools.getContactUserNameByNickName(nickName,uniqueKey);
      if (toUserName != null) {
         LOG.info("发送文件 {}:{}",nickName,filePath);
         return sendFileMsgByUserId(toUserName, filePath, uniqueKey);
      }
      return false;
   }
   /**
    * æ ¹æ®ç¾¤æ˜µç§°å‘送文件消息
    * @param nickName
    * @param filePath
    * @param uniqueKey
    * @return
    */
   private static boolean sendGroupFileMsgByNickName(String nickName, String filePath, String uniqueKey) {
      String toUserName = WechatTools.getGroupUserNameByNickName(nickName,uniqueKey);
      if (toUserName != null) {
         LOG.info("发送文件 {}:{}",nickName,filePath);
         return sendFileMsgByUserId(toUserName, filePath, uniqueKey);
      }
      return false;
   }
   /**
    * å†…部调用
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月10日 ä¸Šåˆ12:21:28
    * @param userId
    * @param data
    * @param uniqueKey
    * @return
    */
   private static boolean webWxSendAppMsg(String userId, Map<String, String> data, String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      if (!core.isAlive()){
         return false;
      }
      String url = String.format("%s/webwxsendappmsg?fun=async&f=json&pass_ticket=%s", core.getLoginInfo().get("url"),
            core.getLoginInfo().get("pass_ticket"));
      String clientMsgId = String.valueOf(System.currentTimeMillis())
            + String.valueOf(new Random().nextLong()).substring(1, 5);
      String content = "<appmsg appid='wxeb7ec651dd0aefa9' sdkver=''><title>" + data.get("title")
            + "</title><des></des><action></action><type>6</type><content></content><url></url><lowurl></lowurl>"
            + "<appattach><totallen>" + data.get("totallen") + "</totallen><attachid>" + data.get("attachid")
            + "</attachid><fileext>" + data.get("fileext") + "</fileext></appattach><extinfo></extinfo></appmsg>";
      Map<String, Object> msgMap = new HashMap<String, Object>(12);
      msgMap.put("Type", data.get("type"));
      msgMap.put("Content", content);
      msgMap.put("FromUserName", core.getUserSelf().getString("UserName"));
      msgMap.put("ToUserName", userId);
      msgMap.put("LocalID", clientMsgId);
      msgMap.put("ClientMsgId", clientMsgId);
      /*
       * Map<String, Object> paramMap = new HashMap<String, Object>();
       *
       * @SuppressWarnings("unchecked") Map<String, Map<String, String>>
       * baseRequestMap = (Map<String, Map<String, String>>)
       * core.getLoginInfo() .get("baseRequest"); paramMap.put("BaseRequest",
       * baseRequestMap.get("BaseRequest"));
       */
      Map<String, Object> paramMap = core.getParamMap();
      paramMap.put("Msg", msgMap);
      paramMap.put("Scene", 0);
      String paramStr = JSON.toJSONString(paramMap);
      HttpEntity entity = core.getMyHttpClient().doPost(url, paramStr);
      if (entity != null) {
         try {
            String result = EntityUtils.toString(entity, Consts.UTF_8);
            return JSON.parseObject(result).getJSONObject("BaseResponse").getInteger("Ret") == 0;
         } catch (Exception e) {
            LOG.error("错误: ", e);
         }
      }
      return false;
   }
   /**
    * è¢«åŠ¨æ·»åŠ å¥½å‹
    *
    * @date 2017å¹´6月29日 ä¸‹åˆ10:08:43
    * @param msg
    * @param accept
    *            true æŽ¥å— false æ‹’绝
    */
   private static void addFriend(BaseMsg msg, boolean accept, String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      if (!accept) { // ä¸æ·»åŠ 
         return;
      }
      int status = VerifyFriendEnum.ACCEPT.getCode(); // æŽ¥å—好友请求
      RecommendInfo recommendInfo = msg.getRecommendInfo();
      String userName = recommendInfo.getUserName();
      String ticket = recommendInfo.getTicket();
      // æ›´æ–°å¥½å‹åˆ—表
      // TODO æ­¤å¤„需要更新好友列表
      // core.getContactList().add(msg.getJSONObject("RecommendInfo"));
      String url = String.format(URLEnum.WEB_WX_VERIFYUSER.getUrl(), core.getLoginInfo().get("url"),
            String.valueOf(System.currentTimeMillis() / 3158L), core.getLoginInfo().get("pass_ticket"));
      List<Map<String, Object>> verifyUserList = new ArrayList<Map<String, Object>>();
      Map<String, Object> verifyUser = new HashMap<String, Object>();
      verifyUser.put("Value", userName);
      verifyUser.put("VerifyUserTicket", ticket);
      verifyUserList.add(verifyUser);
      List<Integer> sceneList = new ArrayList<Integer>();
      sceneList.add(33);
      JSONObject body = new JSONObject();
      body.put("BaseRequest", core.getParamMap().get("BaseRequest"));
      body.put("Opcode", status);
      body.put("VerifyUserListSize", 1);
      body.put("VerifyUserList", verifyUserList);
      body.put("VerifyContent", "");
      body.put("SceneListCount", 1);
      body.put("SceneList", sceneList);
      body.put("skey", core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey()));
      String result = null;
      try {
         String paramStr = JSON.toJSONString(body);
         HttpEntity entity = core.getMyHttpClient().doPost(url, paramStr);
         result = EntityUtils.toString(entity, Consts.UTF_8);
      } catch (Exception e) {
         LOG.error("webWxSendMsg", e);
      }
      if (StringUtils.isBlank(result)) {
         LOG.error("被动添加好友失败");
      }
      LOG.debug(result);
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/api/WechatTools.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,352 @@
package org.ruoyi.common.wechat.itchat4j.api;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.ruoyi.common.wechat.itchat4j.core.Core;
import org.ruoyi.common.wechat.itchat4j.core.CoreManage;
import org.ruoyi.common.wechat.itchat4j.utils.LogInterface;
import org.ruoyi.common.wechat.itchat4j.utils.enums.StorageLoginInfoEnum;
import org.ruoyi.common.wechat.itchat4j.utils.enums.URLEnum;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * å¾®ä¿¡å°å·¥å…·ï¼Œå¦‚获好友列表,根据昵称查找好友或群等
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´5月4日 ä¸‹åˆ10:49:16
 * @version 1.0
 *
 * @author WesleyOne ä¿®æ”¹
 */
public class WechatTools  implements LogInterface {
   /**
    * è¿”回好友昵称列表
    * @param uniqueKey
    * @return
    */
   public static List<String> getContactNickNameList(String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      List<String> contactNickNameList = new ArrayList<String>();
      for (JSONObject o : core.getContactList()) {
         contactNickNameList.add(o.getString("NickName"));
         // é¡ºä¾¿åˆ·ä¸‹ç¼“å­˜
         core.getUserInfoMap().put(o.getString("NickName"),o);
         core.getUserInfoMap().put(o.getString("UserName"),o);
      }
      return contactNickNameList;
   }
   /**
    * è¿”回好友完整信息列表
    * @param uniqueKey
    * @return
    */
   public static List<JSONObject> getContactList(String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      return core.getContactList();
   }
   /**
    * è¿”回群列表
    * @param uniqueKey
    * @return
    */
   public static List<JSONObject> getGroupList(String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      return core.getGroupList();
   }
   /**
    * èŽ·å–ç¾¤NickName列表
    * @param uniqueKey
    * @return
    */
   public static List<String> getGroupNickNameList(String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      List<String> groupNickNameList = new ArrayList<String>();
      for (JSONObject o : core.getGroupList()) {
         groupNickNameList.add(o.getString("NickName"));
      }
      return groupNickNameList;
   }
   /**
    * èŽ·å–ç¾¤æ‰€æœ‰æˆå‘˜ä¿¡æ¯
    * @param groupId
    * @param uniqueKey
    * @return
    */
   public static JSONArray getGroupMemberByGroupId(String groupId, String uniqueKey){
      Core core = CoreManage.getInstance(uniqueKey);
      JSONObject jsonObject = core.getGroupInfoMap().get(groupId);
      if (jsonObject == null){
         return new JSONArray();
      }
      return jsonObject.getJSONArray("MemberList");
   }
   /**
    * é€šè¿‡ç¾¤æˆå‘˜ID获取昵称
    * @param groupId
    * @param uniqueKey
    * @param memberId
    * @return
    */
   public static String getMemberNickName(String groupId, String uniqueKey, String memberId){
      JSONArray members = getGroupMemberByGroupId(groupId, uniqueKey);
      int size = members.size();
      if (size > 0){
         for (int i=0;i<size;i++){
            JSONObject jsonObject = members.getJSONObject(i);
            if (memberId.equals(jsonObject.getString("UserName"))){
               return jsonObject.getString("NickName");
            }
         }
      }
      return "";
   }
   /**
    * é€€å‡ºå¾®ä¿¡
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月18日 ä¸‹åˆ11:56:54
    */
   public static void logout(String uniqueKey) {
      webWxLogout(uniqueKey);
   }
   private static boolean webWxLogout(String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      String url = String.format(URLEnum.WEB_WX_LOGOUT.getUrl(),
            core.getLoginInfo().get(StorageLoginInfoEnum.url.getKey()));
      List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
      params.add(new BasicNameValuePair("redirect", "1"));
      params.add(new BasicNameValuePair("type", "1"));
      params.add(
            new BasicNameValuePair("skey", (String) core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey())));
      try {
         HttpEntity entity = core.getMyHttpClient().doGet(url, params, false, null);
         String text = EntityUtils.toString(entity, Consts.UTF_8);
         return true;
      } catch (Exception e) {
         LOG.debug(e.getMessage());
      } finally {
         // å¼ºåˆ¶é€€å‡ºï¼Œæç¤ºç›¸å…³çº¿ç¨‹é€€å‡º
         core.setAlive(false);
      }
      return false;
   }
   public static void setUserInfo(String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      for (JSONObject o : core.getContactList()) {
         core.getUserInfoMap().put(o.getString("NickName"), o);
         core.getUserInfoMap().put(o.getString("UserName"), o);
      }
   }
   /**
    *
    * æ ¹æ®ç”¨æˆ·æ˜µç§°è®¾ç½®å¤‡æ³¨åç§°
    *
    * @date 2017å¹´5月27日 ä¸Šåˆ12:21:40
    * @param nickName
    * @param remName
    */
   public static void remarkNameByNickName(String nickName, String remName, String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      String url = String.format(URLEnum.WEB_WX_REMARKNAME.getUrl(), core.getLoginInfo().get("url"),
            core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey()));
      Map<String, Object> msgMap = new HashMap<String, Object>(8);
      Map<String, Object> msgMap_BaseRequest = new HashMap<String, Object>(8);
      msgMap.put("CmdId", 2);
      msgMap.put("RemarkName", remName);
      msgMap.put("UserName", core.getUserInfoMap().get(nickName).get("UserName"));
      msgMap_BaseRequest.put("Uin", core.getLoginInfo().get(StorageLoginInfoEnum.wxuin.getKey()));
      msgMap_BaseRequest.put("Sid", core.getLoginInfo().get(StorageLoginInfoEnum.wxsid.getKey()));
      msgMap_BaseRequest.put("Skey", core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey()));
      msgMap_BaseRequest.put("DeviceID", core.getLoginInfo().get(StorageLoginInfoEnum.deviceid.getKey()));
      msgMap.put("BaseRequest", msgMap_BaseRequest);
      try {
         String paramStr = JSON.toJSONString(msgMap);
         HttpEntity entity = core.getMyHttpClient().doPost(url, paramStr);
         // String result = EntityUtils.toString(entity, Consts.UTF_8);
         LOG.info("修改备注" + remName);
      } catch (Exception e) {
         LOG.error("remarkNameByUserName", e);
      }
   }
   /**
    * èŽ·å–å¾®ä¿¡åœ¨çº¿çŠ¶æ€
    *
    * @date 2017å¹´6月16日 ä¸Šåˆ12:47:46
    * @return
    */
   public static boolean getWechatStatus(String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      return core.isAlive();
   }
   /**
    *
    * @param userName
    * @param nickName
    * @return
    */
   private static JSONObject getContactByNickNameAndUserName(String userName, String nickName, String uniqueKey){
      Core core = CoreManage.getInstance(uniqueKey);
      // é€šè¿‡userName查询
      if (StringUtils.isNotEmpty(userName) && StringUtils.isEmpty(nickName)){
         for (JSONObject contact:core.getContactList()){
            if (userName.equals(contact.getString("UserName"))){
               return contact;
            }
         }
      }
      // é€šè¿‡ç¾¤æ˜µç§°æŸ¥è¯¢
      if (StringUtils.isNotEmpty(nickName) && StringUtils.isEmpty(userName)){
         for (JSONObject contact:core.getContactList()){
            if (nickName.equals(contact.getString("NickName"))){
               return contact;
            }
         }
      }
      // é€šè¿‡userName和昵称联合查
      if (StringUtils.isNotEmpty(userName) && StringUtils.isNotEmpty(nickName)){
         for (JSONObject contact:core.getContactList()){
            if (nickName.equals(contact.getString("NickName")) && userName.equals(contact.getString("UserName"))){
               return contact;
            }
         }
      }
      return null;
   }
   /**
    * é€šè¿‡ç¾¤id查找群昵称
    * @param userName
    * @return
    */
   public static String getContactNickNameByUserName(String userName, String uniqueKey){
      JSONObject contact = getContactByNickNameAndUserName(userName,null, uniqueKey);
      if (contact!=null && StringUtils.isNotEmpty(contact.getString("NickName"))){
         return contact.getString("NickName");
      }else{
         return "";
      }
   }
   /**
    * é€šè¿‡ç¾¤æ˜µç§°æŸ¥æ‰¾ç¾¤id
    * @param nickName
    * @return
    */
   public static String getContactUserNameByNickName(String nickName, String uniqueKey){
      JSONObject contact = getContactByNickNameAndUserName(null,nickName,uniqueKey);
      if (contact!=null && StringUtils.isNotEmpty(contact.getString("UserName"))){
         return contact.getString("UserName");
      }else{
         return null;
      }
   }
   /**
    * é€šè¿‡userName或昵称查找群信息
    * @param userName
    * @return
    */
   private static JSONObject getGroupByNickNameAndUserName(String userName, String nickName, String uniqueKey){
      Core core = CoreManage.getInstance(uniqueKey);
      // é€šè¿‡userName查询
      if (StringUtils.isNotEmpty(userName) && StringUtils.isEmpty(nickName)){
         for (JSONObject group:core.getGroupList()){
            if (userName.equals(group.getString("UserName"))){
               return group;
            }
         }
      }
      // é€šè¿‡ç¾¤æ˜µç§°æŸ¥è¯¢
      if (StringUtils.isNotEmpty(nickName) && StringUtils.isEmpty(userName)){
         for (JSONObject group:core.getGroupList()){
            if (nickName.equals(group.getString("NickName"))){
               return group;
            }
         }
      }
      // é€šè¿‡userName和昵称联合查
      if (StringUtils.isNotEmpty(userName) && StringUtils.isNotEmpty(nickName)){
         for (JSONObject group:core.getGroupList()){
            if (nickName.equals(group.getString("NickName")) && userName.equals(group.getString("UserName"))){
               return group;
            }
         }
      }
      return null;
   }
   /**
    * é€šè¿‡ç¾¤id查找群昵称
    * @param userName
    * @return
    */
   public static String getGroupNickNameByUserName(String userName, String uniqueKey){
      JSONObject group = getGroupByNickNameAndUserName(userName,null,uniqueKey);
      if (group!=null && StringUtils.isNotEmpty(group.getString("NickName"))){
         return group.getString("NickName");
      }else{
         return "";
      }
   }
   /**
    * é€šè¿‡ç¾¤æ˜µç§°æŸ¥æ‰¾ç¾¤id
    * @param nickName
    * @return
    */
   public static String getGroupUserNameByNickName(String nickName, String uniqueKey){
      JSONObject group = getGroupByNickNameAndUserName(null,nickName, uniqueKey);
      if (group!=null && StringUtils.isNotEmpty(group.getString("UserName"))){
         return group.getString("UserName");
      }else{
         return null;
      }
   }
   /**
    * é€šè¿‡UserName查找NickName
    * åªæŸ¥ç¾¤åå’Œå¥½å‹å
    * @param userName
    * @param uniqueKey
    * @return
    */
   public static String getNickNameByUserName(String userName, String uniqueKey){
      if (userName.startsWith("@@")){
         return getGroupNickNameByUserName(userName,uniqueKey);
      }else if (userName.startsWith("@")){
         return getContactNickNameByUserName(userName,uniqueKey);
      }else {
         return "";
      }
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/beans/AppInfo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
package org.ruoyi.common.wechat.itchat4j.beans;
import java.io.Serializable;
/**
 * AppInfo
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´7月3日 ä¸‹åˆ10:38:14
 * @version 1.0
 *
 */
public class AppInfo implements Serializable {
   /**
    *
    */
   private static final long serialVersionUID = 1L;
   private int type;
   private String appId;
   public int getType() {
      return type;
   }
   public void setType(int type) {
      this.type = type;
   }
   public String getAppId() {
      return appId;
   }
   public void setAppId(String appId) {
      this.appId = appId;
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/beans/BaseMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,330 @@
package org.ruoyi.common.wechat.itchat4j.beans;
import java.io.Serializable;
/**
 * æ”¶åˆ°çš„微信消息
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´7月3日 ä¸‹åˆ10:28:06
 * @version 1.0
 *
 */
public class BaseMsg implements Serializable {
   /**
    *
    */
   private static final long serialVersionUID = 1L;
   private int subMsgType;
   private int voiceLength;
   private String fileName;
   private int imgHeight;
   private String toUserName;
   private int hasProductId;
   private int imgStatus;
   private String url;
   private int imgWidth;
   private int forwardFlag;
   private int status;
   private String Ticket;
   /** æŽ¨èæ¶ˆæ¯æŠ¥æ–‡ **/
   private RecommendInfo recommendInfo;
   private long createTime;
   private String newMsgId;
   /** æ–‡æœ¬æ¶ˆæ¯å†…容 **/
   private String text;
   /** æ¶ˆæ¯ç±»åž‹ **/
   private int msgType;
   /** æ˜¯å¦ä¸ºç¾¤æ¶ˆæ¯ **/
   private boolean groupMsg;
   private String msgId;
   private int statusNotifyCode;
   private AppInfo appInfo;
   private int appMsgType;
   private String Type;
   private int playLength;
   private String mediaId;
   private String content;
   private String statusNotifyUserName;
   private boolean atMe;
   // ç¾¤å‘送者ID昵称
   private String sendMemberId;
   private String memberNickname;
   /** æ¶ˆæ¯å‘送者ID **/
   private String fromUserName;
   private String oriContent;
   private String fileSize;
   private String fromNickName;
   public int getSubMsgType() {
      return subMsgType;
   }
   public void setSubMsgType(int subMsgType) {
      this.subMsgType = subMsgType;
   }
   public int getVoiceLength() {
      return voiceLength;
   }
   public void setVoiceLength(int voiceLength) {
      this.voiceLength = voiceLength;
   }
   public String getFileName() {
      return fileName;
   }
   public void setFileName(String fileName) {
      this.fileName = fileName;
   }
   public int getImgHeight() {
      return imgHeight;
   }
   public void setImgHeight(int imgHeight) {
      this.imgHeight = imgHeight;
   }
   public String getToUserName() {
      return toUserName;
   }
   public void setToUserName(String toUserName) {
      this.toUserName = toUserName;
   }
   public int getHasProductId() {
      return hasProductId;
   }
   public void setHasProductId(int hasProductId) {
      this.hasProductId = hasProductId;
   }
   public int getImgStatus() {
      return imgStatus;
   }
   public void setImgStatus(int imgStatus) {
      this.imgStatus = imgStatus;
   }
   public String getUrl() {
      return url;
   }
   public void setUrl(String url) {
      this.url = url;
   }
   public int getImgWidth() {
      return imgWidth;
   }
   public void setImgWidth(int imgWidth) {
      this.imgWidth = imgWidth;
   }
   public int getForwardFlag() {
      return forwardFlag;
   }
   public void setForwardFlag(int forwardFlag) {
      this.forwardFlag = forwardFlag;
   }
   public int getStatus() {
      return status;
   }
   public void setStatus(int status) {
      this.status = status;
   }
   public String getTicket() {
      return Ticket;
   }
   public void setTicket(String ticket) {
      Ticket = ticket;
   }
   public RecommendInfo getRecommendInfo() {
      return recommendInfo;
   }
   public void setRecommendInfo(RecommendInfo recommendInfo) {
      this.recommendInfo = recommendInfo;
   }
   public long getCreateTime() {
      return createTime;
   }
   public void setCreateTime(long createTime) {
      this.createTime = createTime;
   }
   public String getNewMsgId() {
      return newMsgId;
   }
   public void setNewMsgId(String newMsgId) {
      this.newMsgId = newMsgId;
   }
   public String getText() {
      return text;
   }
   public void setText(String text) {
      this.text = text;
   }
   public int getMsgType() {
      return msgType;
   }
   public void setMsgType(int msgType) {
      this.msgType = msgType;
   }
   public boolean isGroupMsg() {
      return groupMsg;
   }
   public void setGroupMsg(boolean groupMsg) {
      this.groupMsg = groupMsg;
   }
   public String getMsgId() {
      return msgId;
   }
   public void setMsgId(String msgId) {
      this.msgId = msgId;
   }
   public int getStatusNotifyCode() {
      return statusNotifyCode;
   }
   public void setStatusNotifyCode(int statusNotifyCode) {
      this.statusNotifyCode = statusNotifyCode;
   }
   public AppInfo getAppInfo() {
      return appInfo;
   }
   public void setAppInfo(AppInfo appInfo) {
      this.appInfo = appInfo;
   }
   public int getAppMsgType() {
      return appMsgType;
   }
   public void setAppMsgType(int appMsgType) {
      this.appMsgType = appMsgType;
   }
   public String getType() {
      return Type;
   }
   public void setType(String type) {
      Type = type;
   }
   public int getPlayLength() {
      return playLength;
   }
   public void setPlayLength(int playLength) {
      this.playLength = playLength;
   }
   public String getMediaId() {
      return mediaId;
   }
   public void setMediaId(String mediaId) {
      this.mediaId = mediaId;
   }
   public String getContent() {
      return content;
   }
   public void setContent(String content) {
      this.content = content;
   }
   public String getStatusNotifyUserName() {
      return statusNotifyUserName;
   }
   public void setStatusNotifyUserName(String statusNotifyUserName) {
      this.statusNotifyUserName = statusNotifyUserName;
   }
   public String getFromUserName() {
      return fromUserName;
   }
   public void setFromUserName(String fromUserName) {
      this.fromUserName = fromUserName;
   }
   public String getOriContent() {
      return oriContent;
   }
   public void setOriContent(String oriContent) {
      this.oriContent = oriContent;
   }
   public String getFileSize() {
      return fileSize;
   }
   public void setFileSize(String fileSize) {
      this.fileSize = fileSize;
   }
   public String getMemberNickname() {
      return memberNickname;
   }
   public void setMemberNickname(String memberNickname) {
      this.memberNickname = memberNickname;
   }
   public String getFromNickName() {
      return fromNickName;
   }
   public void setFromNickName(String fromNickName) {
      this.fromNickName = fromNickName;
   }
   public String getSendMemberId() {
      return sendMemberId;
   }
   public void setSendMemberId(String sendMemberId) {
      this.sendMemberId = sendMemberId;
   }
   public boolean isAtMe() {
      return atMe;
   }
   public void setAtMe(boolean atMe) {
      this.atMe = atMe;
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/beans/BaseResponse.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package org.ruoyi.common.wechat.itchat4j.beans;
/**
 * @author WesleyOne
 * @create 2018/12/21
 */
@Deprecated
public class BaseResponse {
    private Integer Ret;
    private String ErrMsg;
    public Integer getRet() {
        return Ret;
    }
    public void setRet(Integer ret) {
        Ret = ret;
    }
    public String getErrMsg() {
        return ErrMsg;
    }
    public void setErrMsg(String errMsg) {
        ErrMsg = errMsg;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/beans/Member.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,306 @@
package org.ruoyi.common.wechat.itchat4j.beans;
import java.util.List;
/**
 * æˆå‘˜ä¿¡æ¯å¯¹è±¡
 *
 *  æ¥è‡ªèŽ·å–å¥½å‹åˆ—è¡¨
 *  /cgi-bin/mmwebwx-bin/webwxgetcontact
 * MemberList中单体
 * @author WesleyOne
 * @create 2018/12/21
 */
@Deprecated
public class Member {
    private String Alias;
    private Integer AppAccountFlag;
    private Integer AttrStatus;
    private Integer ChatRoomId;
    private String City;
    private Integer ContactFlag;
    /**
     * ç¾¤æ˜µç§°
     */
    private String DisplayName;
    private String EncryChatRoomId;
    private String HeadImgUrl;
    private Integer HideInputBarFlag;
    private Integer IsOwner;
    private String KeyWord;
    private Integer MemberCount;
    private List<Member> MemberList;
    private String NickName;
    private Integer OwnerUin;
    private String PYInitial;
    private String PYQuanPin;
    private String Province;
    /**
     * å¤‡æ³¨åã€é¦–拼、全拼
     */
    private String RemarkName;
    private String RemarkPYInitial;
    private String RemarkPYQuanPin;
    private Integer Sex;
    private String Signature;
    private Integer SnsFlag;
    private Integer StarFriend;
    private Integer Statues;
    private Integer Uin;
    private Integer UniFriend;
    private String UserName;
    /**
     * ç”¨æ¥åˆ¤æ–­æ˜¯å¦æ˜¯å…¬ä¼—号或服务号的字段
     */
    private String VerifyFlag;
    public String getAlias() {
        return Alias;
    }
    public void setAlias(String alias) {
        Alias = alias;
    }
    public Integer getAppAccountFlag() {
        return AppAccountFlag;
    }
    public void setAppAccountFlag(Integer appAccountFlag) {
        AppAccountFlag = appAccountFlag;
    }
    public Integer getAttrStatus() {
        return AttrStatus;
    }
    public void setAttrStatus(Integer attrStatus) {
        AttrStatus = attrStatus;
    }
    public Integer getChatRoomId() {
        return ChatRoomId;
    }
    public void setChatRoomId(Integer chatRoomId) {
        ChatRoomId = chatRoomId;
    }
    public String getCity() {
        return City;
    }
    public void setCity(String city) {
        City = city;
    }
    public Integer getContactFlag() {
        return ContactFlag;
    }
    public void setContactFlag(Integer contactFlag) {
        ContactFlag = contactFlag;
    }
    public String getDisplayName() {
        return DisplayName;
    }
    public void setDisplayName(String displayName) {
        DisplayName = displayName;
    }
    public String getEncryChatRoomId() {
        return EncryChatRoomId;
    }
    public void setEncryChatRoomId(String encryChatRoomId) {
        EncryChatRoomId = encryChatRoomId;
    }
    public String getHeadImgUrl() {
        return HeadImgUrl;
    }
    public void setHeadImgUrl(String headImgUrl) {
        HeadImgUrl = headImgUrl;
    }
    public Integer getHideInputBarFlag() {
        return HideInputBarFlag;
    }
    public void setHideInputBarFlag(Integer hideInputBarFlag) {
        HideInputBarFlag = hideInputBarFlag;
    }
    public Integer getIsOwner() {
        return IsOwner;
    }
    public void setIsOwner(Integer isOwner) {
        IsOwner = isOwner;
    }
    public String getKeyWord() {
        return KeyWord;
    }
    public void setKeyWord(String keyWord) {
        KeyWord = keyWord;
    }
    public Integer getMemberCount() {
        return MemberCount;
    }
    public void setMemberCount(Integer memberCount) {
        MemberCount = memberCount;
    }
    public List<Member> getMemberList() {
        return MemberList;
    }
    public void setMemberList(List<Member> memberList) {
        MemberList = memberList;
    }
    public String getNickName() {
        return NickName;
    }
    public void setNickName(String nickName) {
        NickName = nickName;
    }
    public Integer getOwnerUin() {
        return OwnerUin;
    }
    public void setOwnerUin(Integer ownerUin) {
        OwnerUin = ownerUin;
    }
    public String getPYInitial() {
        return PYInitial;
    }
    public void setPYInitial(String PYInitial) {
        this.PYInitial = PYInitial;
    }
    public String getPYQuanPin() {
        return PYQuanPin;
    }
    public void setPYQuanPin(String PYQuanPin) {
        this.PYQuanPin = PYQuanPin;
    }
    public String getProvince() {
        return Province;
    }
    public void setProvince(String province) {
        Province = province;
    }
    public String getRemarkName() {
        return RemarkName;
    }
    public void setRemarkName(String remarkName) {
        RemarkName = remarkName;
    }
    public String getRemarkPYInitial() {
        return RemarkPYInitial;
    }
    public void setRemarkPYInitial(String remarkPYInitial) {
        RemarkPYInitial = remarkPYInitial;
    }
    public String getRemarkPYQuanPin() {
        return RemarkPYQuanPin;
    }
    public void setRemarkPYQuanPin(String remarkPYQuanPin) {
        RemarkPYQuanPin = remarkPYQuanPin;
    }
    public Integer getSex() {
        return Sex;
    }
    public void setSex(Integer sex) {
        Sex = sex;
    }
    public String getSignature() {
        return Signature;
    }
    public void setSignature(String signature) {
        Signature = signature;
    }
    public Integer getSnsFlag() {
        return SnsFlag;
    }
    public void setSnsFlag(Integer snsFlag) {
        SnsFlag = snsFlag;
    }
    public Integer getStarFriend() {
        return StarFriend;
    }
    public void setStarFriend(Integer starFriend) {
        StarFriend = starFriend;
    }
    public Integer getStatues() {
        return Statues;
    }
    public void setStatues(Integer statues) {
        Statues = statues;
    }
    public Integer getUin() {
        return Uin;
    }
    public void setUin(Integer uin) {
        Uin = uin;
    }
    public Integer getUniFriend() {
        return UniFriend;
    }
    public void setUniFriend(Integer uniFriend) {
        UniFriend = uniFriend;
    }
    public String getUserName() {
        return UserName;
    }
    public void setUserName(String userName) {
        UserName = userName;
    }
    public String getVerifyFlag() {
        return VerifyFlag;
    }
    public void setVerifyFlag(String verifyFlag) {
        VerifyFlag = verifyFlag;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/beans/RecommendInfo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,146 @@
package org.ruoyi.common.wechat.itchat4j.beans;
import java.io.Serializable;
/**
 * RecommendInfo
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´7月3日 ä¸‹åˆ10:35:14
 * @version 1.0
 *
 */
public class RecommendInfo implements Serializable {
   /**
    *
    */
   private static final long serialVersionUID = 1L;
   private String ticket;
   private String userName;
   private int sex;
   private int attrStatus;
   private String city;
   private String nickName;
   private int scene;
   private String province;
   private String content;
   private String alias;
   private String signature;
   private int opCode;
   private int qQNum;
   private int verifyFlag;
   public String getTicket() {
      return ticket;
   }
   public void setTicket(String ticket) {
      this.ticket = ticket;
   }
   public String getUserName() {
      return userName;
   }
   public void setUserName(String userName) {
      this.userName = userName;
   }
   public int getSex() {
      return sex;
   }
   public void setSex(int sex) {
      this.sex = sex;
   }
   public int getAttrStatus() {
      return attrStatus;
   }
   public void setAttrStatus(int attrStatus) {
      this.attrStatus = attrStatus;
   }
   public String getCity() {
      return city;
   }
   public void setCity(String city) {
      this.city = city;
   }
   public String getNickName() {
      return nickName;
   }
   public void setNickName(String nickName) {
      this.nickName = nickName;
   }
   public int getScene() {
      return scene;
   }
   public void setScene(int scene) {
      this.scene = scene;
   }
   public String getProvince() {
      return province;
   }
   public void setProvince(String province) {
      this.province = province;
   }
   public String getContent() {
      return content;
   }
   public void setContent(String content) {
      this.content = content;
   }
   public String getAlias() {
      return alias;
   }
   public void setAlias(String alias) {
      this.alias = alias;
   }
   public String getSignature() {
      return signature;
   }
   public void setSignature(String signature) {
      this.signature = signature;
   }
   public int getOpCode() {
      return opCode;
   }
   public void setOpCode(int opCode) {
      this.opCode = opCode;
   }
   public int getqQNum() {
      return qQNum;
   }
   public void setqQNum(int qQNum) {
      this.qQNum = qQNum;
   }
   public int getVerifyFlag() {
      return verifyFlag;
   }
   public void setVerifyFlag(int verifyFlag) {
      this.verifyFlag = verifyFlag;
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/beans/SendMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
package org.ruoyi.common.wechat.itchat4j.beans;
import org.ruoyi.common.wechat.itchat4j.utils.enums.SendMsgType;
import java.io.Serializable;
/**
 * å‘送消息体
 * @author WesleyOne
 * @create 2019/1/7
 */
public class SendMsg implements Serializable {
    private String userName;
    private String nickName;
    private String message;
    private SendMsgType msgType;
    private boolean isGroup;
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getNickName() {
        return nickName;
    }
    public void setNickName(String nickName) {
        this.nickName = nickName;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    public SendMsgType getMsgType() {
        return msgType;
    }
    public void setMsgType(SendMsgType msgType) {
        this.msgType = msgType;
    }
    public boolean isGroup() {
        return isGroup;
    }
    public void setGroup(boolean group) {
        isGroup = group;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/beans/SyncKey.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
package org.ruoyi.common.wechat.itchat4j.beans;
import java.util.List;
/**
 * @author WesleyOne
 * @create 2018/12/21
 */
@Deprecated
public class SyncKey {
    private Integer Count;
    private List<KV> List;
    public Integer getCount() {
        return Count;
    }
    public void setCount(Integer count) {
        Count = count;
    }
    public java.util.List<KV> getList() {
        return List;
    }
    public void setList(java.util.List<KV> list) {
        List = list;
    }
    class KV{
        private Integer Key;
        private Long Val;
        public Integer getKey() {
            return Key;
        }
        public void setKey(Integer key) {
            Key = key;
        }
        public Long getVal() {
            return Val;
        }
        public void setVal(Long val) {
            Val = val;
        }
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/beans/User.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
package org.ruoyi.common.wechat.itchat4j.beans;
/*
AppAccountFlag: 0
ContactFlag: 0
HeadImgFlag: 1
HeadImgUrl: "/cgi-bin/mmwebwx-bin/webwxgeticon?seq=778915892&username=@7e6934104b3cf1f92dd11344c63a06833ae54bd43b34229b5cc472c4d05eba4a&skey=@crypt_a24169c_f4c07f70afe861da5e8a6e1947044b6e"
HideInputBarFlag: 0
NickName: "[è¡°]晓炜"
PYInitial: ""
PYQuanPin: ""
RemarkName: ""
RemarkPYInitial: ""
RemarkPYQuanPin: ""
Sex: 1
Signature: "人工智障"
SnsFlag: 49
StarFriend: 0
Uin: 902478981
UserName: "@7e6934104b3cf1f92dd11344c63a06833ae54bd43b34229b5cc472c4d05eba4a"
VerifyFlag: 0
WebWxPluginSwitch: 0
*/
/**
 * @author WesleyOne
 * @create 2018/12/21
 */
@Deprecated
public class User {
    private String AppAccountFlag;
    private String ContactFlag;
    private String HeadImgFlag;
    private String HeadImgUrl;
    private String HideInputBarFlag;
    private String NickName;
    private String PYInitial;
    private String PYQuanPin;
    private String RemarkName;
    private String RemarkPYInitial;
    private String RemarkPYQuanPin;
    private String Sex;
    /**
     * ç­¾å
     */
    private String Signature;
    private String SnsFlag;
    private String StarFriend;
    private String Uin;
    private String UserName;
    private String VerifyFlag;
    private String WebWxPluginSwitch;
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/beans/WebWxInit.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
package org.ruoyi.common.wechat.itchat4j.beans;
import java.util.List;
/**
 * @author WesleyOne
 * @create 2018/12/21
 */
@Deprecated
public class WebWxInit {
    private BaseResponse BaseResponse;
    private String ChatSet;
    private Long ClickReportInterval;
    private Long ClientVersion;
    private List<Member> ContactList;
    private Integer Count;
    private Integer GrayScale;
    private Integer InviteStartCount;
    /**
     * è®¢é˜…号字段省略
     * MPSubscribeMsgCount
     * MPSubscribeMsgList
     */
    private String SKey;
    private SyncKey SyncKey;
    private Long SystemTime;
    private User User;
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/client/HttpClientManage.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
package org.ruoyi.common.wechat.itchat4j.client;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.CookieStore;
import java.util.HashMap;
/**
 * å¤šå¼€è¯·æ±‚类管理
 * @author WesleyOne
 * @create 2018/12/15
 */
public class HttpClientManage {
    private static HashMap<String,SingleHttpClient> clientMap = new HashMap<>(32);
    public static SingleHttpClient getInstance(String uniqueKey){
        return getInstance(uniqueKey,null);
    }
    public static SingleHttpClient getInstance(String uniqueKey,CookieStore outCookieStore) {
        if (StringUtils.isEmpty(uniqueKey)){
            return null;
        }
        SingleHttpClient client;
        // outCookieStore不为空时也重新构造,主要用于热登录
        if (!clientMap.containsKey(uniqueKey) || clientMap.get(uniqueKey) == null || outCookieStore != null){
            client = SingleHttpClient.getInstance(outCookieStore);
            clientMap.put(uniqueKey, client);
        }
        return clientMap.get(uniqueKey);
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/client/SingleHttpClient.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,187 @@
package org.ruoyi.common.wechat.itchat4j.client;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.ruoyi.common.wechat.itchat4j.utils.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
 * @author WesleyOne
 * @create 2018/12/15
 */
public class SingleHttpClient {
    private Logger logger = LoggerFactory.getLogger("UTILLOG");
    private CloseableHttpClient httpClient ;
    private CookieStore cookieStore;
    private String uniqueKey;
    public String getCookie(String name) {
        List<Cookie> cookies = cookieStore.getCookies();
        for (Cookie cookie : cookies) {
            if (cookie.getName().equalsIgnoreCase(name)) {
                return cookie.getValue();
            }
        }
        return null;
    }
    private SingleHttpClient(CookieStore outCookieStore){
        if (outCookieStore == null){
            outCookieStore = new BasicCookieStore();
        }
        this.cookieStore = outCookieStore;
        httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).setRetryHandler(new DefaultHttpRequestRetryHandler(0,false)).build();
    }
    private SingleHttpClient(){
        this(null);
    }
    public static SingleHttpClient getInstance(CookieStore outCookieStore){
        return new SingleHttpClient(outCookieStore);
    }
    /**
     * å¤„理GET请求
     *
     * @author https://github.com/yaphone
     * @date 2017å¹´4月9日 ä¸‹åˆ7:06:19
     * @param url
     * @param params
     * @return
     */
    public HttpEntity doGet(String url, List<BasicNameValuePair> params, boolean redirect,
                            Map<String, String> headerMap) {
        HttpEntity entity = null;
        HttpGet httpGet = new HttpGet();
        try {
            if (params != null) {
                String paramStr = EntityUtils.toString(new UrlEncodedFormEntity(params, Consts.UTF_8));
                httpGet = new HttpGet(url + "?" + paramStr);
//                System.out.println(url + "?" + paramStr);
            } else {
                httpGet = new HttpGet(url);
            }
            if (!redirect) {
                // ç¦æ­¢é‡å®šå‘
                httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
            }
            httpGet.setHeader("User-Agent", Config.USER_AGENT);
            if (headerMap != null) {
                Set<Map.Entry<String, String>> entries = headerMap.entrySet();
                for (Map.Entry<String, String> entry : entries) {
                    httpGet.setHeader(entry.getKey(), entry.getValue());
                }
            }
            CloseableHttpResponse response = httpClient.execute(httpGet);
            entity = response.getEntity();
        } catch (ClientProtocolException e) {
            logger.error(e.getMessage());
        } catch (IOException e) {
            logger.error(e.getMessage());
        } catch (Exception e){
            logger.error(e.getMessage());
        }
        return entity;
    }
    /**
     * å¤„理POST请求
     *
     * @author https://github.com/yaphone
     * @date 2017å¹´4月9日 ä¸‹åˆ7:06:35
     * @param url
     * @param paramsStr
     * @return
     */
    public HttpEntity doPost(String url, String paramsStr) {
       return doPost(url,paramsStr,null);
    }
    public HttpEntity doPost(String url, String paramsStr, Map<String, String> headerMap) {
        HttpEntity entity = null;
        HttpPost httpPost = new HttpPost();
        try {
            StringEntity params = new StringEntity(paramsStr, Consts.UTF_8);
            httpPost = new HttpPost(url);
            httpPost.setEntity(params);
            httpPost.setHeader("Content-type", "application/json; charset=utf-8");
            httpPost.setHeader("User-Agent", Config.USER_AGENT);
            if (headerMap != null) {
                Set<Map.Entry<String, String>> entries = headerMap.entrySet();
                for (Map.Entry<String, String> entry : entries) {
                    httpPost.setHeader(entry.getKey(), entry.getValue());
                }
            }
            CloseableHttpResponse response = httpClient.execute(httpPost);
            entity = response.getEntity();
        } catch (ClientProtocolException e) {
            logger.error(e.getMessage());
        } catch (IOException e) {
            logger.error(e.getMessage());
        } catch (Exception e){
            logger.error(e.getMessage());
        }
        return entity;
    }
    /**
     * ä¸Šä¼ æ–‡ä»¶åˆ°æœåС噍
     *
     * @author https://github.com/yaphone
     * @date 2017å¹´5月7日 ä¸‹åˆ9:19:23
     * @param url
     * @param reqEntity
     * @return
     */
    public HttpEntity doPostFile(String url, HttpEntity reqEntity) {
        HttpEntity entity = null;
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("User-Agent", Config.USER_AGENT);
        httpPost.setEntity(reqEntity);
        try {
            CloseableHttpResponse response = httpClient.execute(httpPost);
            entity = response.getEntity();
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return entity;
    }
    public CookieStore getCookieStore() {
        return this.cookieStore;
    }
    public void setCookieStore(CookieStore cookieStore) {
        this.cookieStore = cookieStore;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/controller/LoginController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,148 @@
package org.ruoyi.common.wechat.itchat4j.controller;
import org.ruoyi.common.wechat.itchat4j.core.Core;
import org.ruoyi.common.wechat.itchat4j.core.CoreManage;
import org.ruoyi.common.wechat.itchat4j.core.MsgCenter;
import org.ruoyi.common.wechat.itchat4j.service.ILoginService;
import org.ruoyi.common.wechat.itchat4j.service.impl.LoginServiceImpl;
import org.ruoyi.common.wechat.itchat4j.utils.LogInterface;
import org.ruoyi.common.wechat.itchat4j.utils.SleepUtils;
import org.ruoyi.common.wechat.itchat4j.utils.enums.URLEnum;
import org.ruoyi.common.wechat.web.base.BaseException;
/**
 * ç™»é™†æŽ§åˆ¶å™¨
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´5月13日 ä¸‹åˆ12:56:07
 * @version 1.0
 *
 * @author WesleyOne ä¿®æ”¹
 */
public class LoginController  implements LogInterface {
   private ILoginService loginService;
   private String uniqueKey;
   private Core core;
   public LoginController(String uniqueKey){
      this.uniqueKey = uniqueKey;
      this.loginService = new LoginServiceImpl(uniqueKey);
      this.core = CoreManage.getInstance(uniqueKey);
   }
   /**
    * èŽ·å–äºŒç»´ç åœ°å€
    * é£Žé™©:已登录账号不可调用该接口,会移除当前core信息
    * @return
    */
   public String login_1() throws BaseException {
      if (core.isAlive()) {
         LOG.warn("微信已登陆");
         throw new BaseException("微信已登陆");
      }
      LOG.info("1.获取微信UUID");
      while (loginService.getUuid() == null) {
         LOG.warn("1.1. èŽ·å–å¾®ä¿¡UUID失败,一秒后重新获取");
         SleepUtils.sleep(1000);
      }
      LOG.info("2. èŽ·å–ç™»é™†äºŒç»´ç å›¾ç‰‡");
      return URLEnum.QRCODE_URL.getUrl() + core.getUuid();
   }
   /**
    * ç¡®è®¤ç™»å½•
    * @return
    */
   public boolean login_2(){
      boolean result = false;
      LOG.info("3. è¯·æ‰«æäºŒç»´ç å›¾ç‰‡ï¼Œå¹¶åœ¨æ‰‹æœºä¸Šç¡®è®¤");
      if (!core.isAlive()) {
         if (loginService.login()){
            core.setAlive(true);
            LOG.info(("3.1登陆成功"));
            result = true;
         }
      }
      return result;
   }
   /**
    * åŠ è½½æ•°æ®
    * @return
    */
   public boolean login_3() {
      boolean result = true;
      LOG.info("4.微信初始化");
      if (!loginService.webWxInit()) {
         LOG.info("4.1 å¾®ä¿¡åˆå§‹åŒ–异常");
         result = false;
      }
      if (result){
         LOG.info("5. å¼€å¯å¾®ä¿¡çŠ¶æ€é€šçŸ¥");
         loginService.wxStatusNotify();
         LOG.info(String.format("欢迎回来, %s", core.getNickName()));
         LOG.info("6.+++开启消息发送线程["+uniqueKey+"]+++");
         Thread sendThread = new Thread(core.getThreadGroup(), () -> MsgCenter.sendMsg(uniqueKey), "SEND-" + uniqueKey);
         sendThread.start();
         LOG.info("8. +++开始接收消息线程["+uniqueKey+"]+++");
         loginService.startReceiving();
         LOG.info("9. èŽ·å–è”ç³»äººä¿¡æ¯");
         loginService.webWxGetContact();
         LOG.info("10. èŽ·å–ç¾¤å¥½å‹åŠç¾¤å¥½å‹åˆ—è¡¨åŠç¼“å­˜");
         loginService.WebWxBatchGetContact();
      }
      if (!result){
         core.setAlive(false);
         return false;
      }
      core.setFinishInit(true);
      return true;
   }
   public boolean reboot(){
      core.setFinishInit(false);
      // é‡æ–°åŠ è½½æ•°æ®
      boolean result = true;
      LOG.info("1.刷新初始化信息");
      if (!loginService.webWxInit()) {
         LOG.info("1.1 å¾®ä¿¡åˆå§‹åŒ–异常");
         result = false;
      }
      if (result){
         LOG.info("2. åˆ·æ–°å¼€å¯å¾®ä¿¡çŠ¶æ€é€šçŸ¥");
         loginService.wxStatusNotify();
         LOG.info("3. åˆ·æ–°èŽ·å–è”ç³»äººä¿¡æ¯");
         loginService.webWxGetContact();
         LOG.info("4. åˆ·æ–°èŽ·å–ç¾¤å¥½å‹åŠç¾¤å¥½å‹åˆ—è¡¨");
         loginService.WebWxBatchGetContact();
      }
      if (!result){
         core.setAlive(false);
         return false;
      }
      core.setFinishInit(true);
      return true;
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/core/Core.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,371 @@
package org.ruoyi.common.wechat.itchat4j.core;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import org.ruoyi.common.wechat.itchat4j.beans.BaseMsg;
import org.ruoyi.common.wechat.itchat4j.beans.SendMsg;
import org.ruoyi.common.wechat.itchat4j.beans.User;
import org.ruoyi.common.wechat.itchat4j.client.HttpClientManage;
import org.ruoyi.common.wechat.itchat4j.client.SingleHttpClient;
import org.ruoyi.common.wechat.itchat4j.service.impl.LoginServiceImpl;
import org.ruoyi.common.wechat.itchat4j.utils.enums.parameters.BaseParaEnum;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * æ ¸å¿ƒå­˜å‚¨ç±»ï¼Œå…¨å±€åªä¿å­˜ä¸€ä»½ï¼Œå•例模式
 *
 * @author https://github.com/yaphone
 * @author WesleyOne ä¿®æ”¹
 * @version 1.0
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´4月23日 ä¸‹åˆ2:33:56
 */
public class Core {
    private Core() {
    }
    private Core(String uniqueKey) {
        this.uniqueKey = uniqueKey;
        this.myHttpClient = HttpClientManage.getInstance(this.uniqueKey);
        this.threadGroup = new ThreadGroup(this.uniqueKey);
    }
    protected static Core getInstance(String uniqueKey) {
        return new Core(uniqueKey);
    }
    private String uniqueKey;
    boolean alive = false;
    /**
     * ç®¡ç†å½“前机器人的所有业务线程
     */
    @JSONField(serialize = false)
    private ThreadGroup threadGroup;
    @JSONField(serialize = false)
    boolean isFinishInit = false;
    /**
     * login,webWxInit
     * ç™»å½•接口获取
     */
    private String indexUrl;
    private String userName;
    private String nickName;
    String uuid = null;
    /**
     * webWxInit
     * InviteStartCount
     * SyncKey
     * synckey éšç€æ¯æ¬¡èŽ·å–æœ€æ–°æ¶ˆæ¯åŽçš„è¿”å›žå€¼æ›´æ–°ï¼Œå…¶ç›®çš„åœ¨äºŽæ¯æ¬¡åŒæ­¥æ¶ˆæ¯åŽè®°å½•ä¸€ä¸ªå½“å‰åŒæ­¥çš„çŠ¶æ€
     */
    Map<String, Object> loginInfo = new HashMap<String, Object>();
    /**
     * webWxInit
     * ç™»é™†è´¦å·è‡ªèº«ä¿¡æ¯
     *
     * @see User
     */
    private JSONObject userSelf;
    /**
     * åˆå§‹åŒ–/cgi-bin/mmwebwx-bin/webwxinit
     * æœ€åŽä¸€æ¬¡æ”¶åˆ°æ­£å¸¸retcode的时间,秒为单位
     * <p>
     * synccheck刷新
     */
    private long lastNormalRetcodeTime;
    /**
     * synccheck和webWxSync容错次数,超过退出
     */
    int receivingRetryCount = 5;
    @JSONField(serialize = false)
    SingleHttpClient myHttpClient;
    public SingleHttpClient getMyHttpClient() {
        return HttpClientManage.getInstance(uniqueKey);
    }
    /**
     * åˆå§‹è¯æ—¶èŽ·å–è”ç³»äººæ—¶åˆ›å»º
     * @see LoginServiceImpl#webWxGetContact()
     */
    /**
     * memberList长度
     */
    @JSONField(serialize = false)
    private int memberCount = 0;
    /**
     * å¥½å‹+群聊+公众号+特殊账号
     * æ³¨æ„ï¼šä¸ä¸»åŠ¨æ’å…¥,获取时通过其他几个账号集合合并
     */
    @JSONField(serialize = false)
    private List<JSONObject> memberList = new ArrayList<JSONObject>();
    /**
     * å¥½å‹
     */
    @JSONField(serialize = false)
    private List<JSONObject> contactList = new ArrayList<JSONObject>();
    /**
     * ç¾¤
     */
    @JSONField(serialize = false)
    private List<JSONObject> groupList = new ArrayList<JSONObject>();
    /**
     * å…¬ä¼—号/服务号
     */
    @Deprecated
    @JSONField(serialize = false)
    private List<JSONObject> publicUsersList = new ArrayList<JSONObject>();
    /**
     * ç‰¹æ®Šè´¦å·
     */
    @JSONField(serialize = false)
    private List<JSONObject> specialUsersList = new ArrayList<JSONObject>();
    /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
    /**
     * synccheck和webWxSynct添加
     * å¼‚步接受消息存储
     */
    @JSONField(serialize = false)
    private List<BaseMsg> msgList = new ArrayList<>();
    /**
     * å¼‚步发送消息存储
     */
    @JSONField(serialize = false)
    private List<SendMsg> sendList = new ArrayList();
    /********************************
     * ç¼“存字段,用于快速查找
     ********************************/
    /**
     * å¾®ä¿¡æ˜µç§°ä¸èƒ½è¶…过16位,而ID比较长,干脆用一个Map
     * ç¾¤ID或昵称,群信息
     * æ³¨æ„:存在相同昵称会后者覆盖前者
     * <p>
     * WebWxBatchGetContact之后可以通过
     * .getJSONArray("MemberList")获取群成员列表
     */
    @JSONField(serialize = false)
    private Map<String, JSONObject> groupInfoMap = new HashMap<>(1024);
    /**
     * å¾®ä¿¡æ˜µç§°ä¸èƒ½è¶…过16位,而ID比较长,干脆用一个Map
     * çީ家ID或昵称,玩家信息
     * æ³¨æ„:存在相同昵称会后者覆盖前者
     */
    @JSONField(serialize = false)
    private Map<String, JSONObject> userInfoMap = new HashMap<>(1024);
    /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
    /**
     * è¯·æ±‚参数
     */
    @JSONField(serialize = false)
    public Map<String, Object> getParamMap() {
        return new HashMap<String, Object>(1) {
            /**
             *
             */
            private static final long serialVersionUID = 1L;
            {
                Map<String, String> map = new HashMap<>(16);
                for (BaseParaEnum baseRequest : BaseParaEnum.values()) {
                    map.put(baseRequest.para(), getLoginInfo().get(baseRequest.value()).toString());
                }
                put("BaseRequest", map);
            }
        };
    }
    public String getUniqueKey() {
        return uniqueKey;
    }
    public void setUniqueKey(String uniqueKey) {
        this.uniqueKey = uniqueKey;
    }
    public boolean isAlive() {
        return alive;
    }
    public void setAlive(boolean alive) {
        this.alive = alive;
        if (!alive) {
            this.isFinishInit = false;
        }
    }
    public String getIndexUrl() {
        return indexUrl;
    }
    public void setIndexUrl(String indexUrl) {
        this.indexUrl = indexUrl;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getNickName() {
        return nickName;
    }
    public void setNickName(String nickName) {
        this.nickName = nickName;
    }
    public String getUuid() {
        return uuid;
    }
    public void setUuid(String uuid) {
        this.uuid = uuid;
    }
    public Map<String, Object> getLoginInfo() {
        return loginInfo;
    }
    public void setLoginInfo(Map<String, Object> loginInfo) {
        this.loginInfo = loginInfo;
    }
    public JSONObject getUserSelf() {
        return userSelf;
    }
    public void setUserSelf(JSONObject userSelf) {
        this.userSelf = userSelf;
    }
    public long getLastNormalRetcodeTime() {
        return lastNormalRetcodeTime;
    }
    public void setLastNormalRetcodeTime(long lastNormalRetcodeTime) {
        this.lastNormalRetcodeTime = lastNormalRetcodeTime;
    }
    public int getReceivingRetryCount() {
        return receivingRetryCount;
    }
    public void setReceivingRetryCount(int receivingRetryCount) {
        this.receivingRetryCount = receivingRetryCount;
    }
    public int getMemberCount() {
        return getContactList().size() + getGroupList().size() + getPublicUsersList().size() + getSpecialUsersList().size();
    }
    public List<JSONObject> getMemberList() {
        List<JSONObject> memberList = new ArrayList<>();
        memberList.addAll(this.getContactList());
        memberList.addAll(this.getGroupList());
        memberList.addAll(this.getPublicUsersList());
        memberList.addAll(this.getSpecialUsersList());
        return memberList;
    }
    public List<JSONObject> getContactList() {
        return contactList;
    }
    public void setContactList(List<JSONObject> contactList) {
        this.contactList = contactList;
    }
    public List<JSONObject> getGroupList() {
        return groupList;
    }
    public void setGroupList(List<JSONObject> groupList) {
        this.groupList = groupList;
    }
    public List<JSONObject> getPublicUsersList() {
        return publicUsersList;
    }
    public void setPublicUsersList(List<JSONObject> publicUsersList) {
        this.publicUsersList = publicUsersList;
    }
    public List<JSONObject> getSpecialUsersList() {
        return specialUsersList;
    }
    public void setSpecialUsersList(List<JSONObject> specialUsersList) {
        this.specialUsersList = specialUsersList;
    }
    public List<BaseMsg> getMsgList() {
        return msgList;
    }
    public void setMsgList(List<BaseMsg> msgList) {
        this.msgList = msgList;
    }
    public Map<String, JSONObject> getGroupInfoMap() {
        return groupInfoMap;
    }
    public void setGroupInfoMap(Map<String, JSONObject> groupInfoMap) {
        this.groupInfoMap = groupInfoMap;
    }
    public Map<String, JSONObject> getUserInfoMap() {
        return userInfoMap;
    }
    public void setUserInfoMap(Map<String, JSONObject> userInfoMap) {
        this.userInfoMap = userInfoMap;
    }
    public boolean isFinishInit() {
        return isFinishInit;
    }
    public void setFinishInit(boolean finishInit) {
        isFinishInit = finishInit;
    }
    public ThreadGroup getThreadGroup() {
        return threadGroup;
    }
    public void setThreadGroup(ThreadGroup threadGroup) {
        this.threadGroup = threadGroup;
    }
    public List<SendMsg> getSendList() {
        return sendList;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/core/CoreManage.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,323 @@
package org.ruoyi.common.wechat.itchat4j.core;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.ruoyi.common.wechat.itchat4j.beans.SendMsg;
import org.ruoyi.common.wechat.itchat4j.client.HttpClientManage;
import org.ruoyi.common.wechat.itchat4j.controller.LoginController;
import org.ruoyi.common.wechat.itchat4j.utils.LogInterface;
import org.ruoyi.common.wechat.itchat4j.utils.enums.SendMsgType;
import org.ruoyi.common.wechat.itchat4j.utils.tools.CommonTools;
import java.io.*;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
/**
 * å¤šå¼€ç®¡ç†
 *
 * @author WesleyOne
 * @create 2018/12/13
 */
public class CoreManage implements LogInterface {
    static int MAX_CORE_NUM = 50;
    private static HashMap<String, Core> coreMap = new HashMap<>(MAX_CORE_NUM / 3 * 4 + 1);
    // æ˜¯å¦çƒ­åŠ è½½
    public static boolean USE_HOT_RELOAD = false;
    public static String HOT_RELOAD_DIR = "/Users/wesley/output/hotreload/wxwobot.hot";
    public static Core getInstance(String uniqueKey) {
        if (StringUtils.isEmpty(uniqueKey)) {
            return null;
        }
        Core core;
        if (!coreMap.containsKey(uniqueKey) || coreMap.get(uniqueKey) == null) {
            core = Core.getInstance(uniqueKey);
            coreMap.put(uniqueKey, core);
        }
        return coreMap.get(uniqueKey);
    }
    /**
     * ç§»é™¤
     *
     * @param uniqueKey
     */
    public static void remove(String uniqueKey) {
        if (coreMap.containsKey(uniqueKey)) {
            coreMap.remove(uniqueKey);
        }
    }
    /**
     * æŸ¥è¯¢æ˜¯å¦åœ¨çº¿
     *
     * @param uniqueKey
     * @return
     */
    public static boolean isActive(String uniqueKey) {
        if (StringUtils.isNotEmpty(uniqueKey) && coreMap.containsKey(uniqueKey) && coreMap.get(uniqueKey).isAlive()) {
            return true;
        }
        return false;
    }
    /**
     * æŒä¹…化
     */
    public static void persistence() {
        // æ ¼å¼åŒ–数据
        Collection<Core> valueCollection = coreMap.values();
        int size = valueCollection.size();
        // æ²¡æœ‰æ•°æ®ä¸æ“ä½œ
        if (size <= 0) {
            return;
        }
        LOG.info("登录数据持久化中");
        Iterator<Core> iterator = valueCollection.iterator();
        JSONArray jsonArray = new JSONArray();
        while (iterator.hasNext()) {
            Core core = iterator.next();
            if (core.isAlive()) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("core", core);
                jsonObject.put("cookies", core.getMyHttpClient().getCookieStore().getCookies());
                jsonArray.add(jsonObject);
            }
        }
        try {
            File file = new File(HOT_RELOAD_DIR);
            if (!file.exists()) {
                file.createNewFile();
            }
            // æ¯æ¬¡è¦†ç›–
            FileWriter fileWritter = new FileWriter(HOT_RELOAD_DIR, false);
            fileWritter.write(jsonArray.toJSONString());
            fileWritter.close();
            LOG.info("登录数据持久化完成");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * å¯åŠ¨åŠ è½½æŒä¹…åŒ–æ–‡ä»¶
     */
    public static void reload() {
        if (USE_HOT_RELOAD) {
            File file = new File(HOT_RELOAD_DIR);
            if (file.exists()) {
                LOG.info("登录数据热加载中");
                StringBuilder stringBuilder = new StringBuilder();
                try {
                    FileReader fr = new FileReader(HOT_RELOAD_DIR);
                    BufferedReader bf = new BufferedReader(fr);
                    String str;
                    // æŒ‰è¡Œè¯»å–字符串
                    while ((str = bf.readLine()) != null) {
                        stringBuilder.append(str);
                    }
                    bf.close();
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    return;
                }
                String result = stringBuilder.toString();
                if (StringUtils.isEmpty(result)) {
                    return;
                }
                JSONArray jsonArray = JSONArray.parseArray(result);
                int size = jsonArray.size();
                if (size > 0) {
                    // å°è£…成线程操作
                    for (int i = 0; i < size; i++) {
                        JSONObject jsonObject = jsonArray.getJSONObject(i);
                        ReloadThread reloadThread = new ReloadThread(jsonObject);
                        Thread thread = new Thread(reloadThread);
                        thread.start();
                    }
                }
                LOG.info("登录数据热加载完成");
            }
        }
    }
    private static class ReloadThread implements Runnable {
        private JSONObject reloadObject;
        public ReloadThread(JSONObject object) {
            this.reloadObject = object;
        }
        @Override
        public void run() {
            Core core = null;
            try {
                /**
                 * åˆå§‹åŒ–Core,
                 * 1.获取登入的状态信息并装入CoreManage
                 * 2.构建ThreadGroup
                 * 3.获取Cookies并装入HttpClientManage
                 * 4.获取信息及启动线程
                 */
                JSONObject jsonObject = this.reloadObject;
                core = jsonObject.getObject("core", Core.class);
                String uniqueKey = core.getUniqueKey();
                if (core.isAlive()) {
                    core.setThreadGroup(new ThreadGroup(uniqueKey));
                    coreMap.put(uniqueKey, core);
                    JSONArray cookiesJsonArray = jsonObject.getJSONArray("cookies");
                    int arraySize = cookiesJsonArray.size();
                    if (arraySize <= 0) {
                        return;
                    }
                    // è£…载原cookie信息,json解析cookie异常,干脆手动封装
                    BasicCookieStore cookieStore = new BasicCookieStore();
                    for (int ci = 0; ci < arraySize; ci++) {
                        JSONObject cookieJson = cookiesJsonArray.getJSONObject(ci);
                        String name = cookieJson.getString("name");
                        String value = cookieJson.getString("value");
                        String domain = cookieJson.getString("domain");
                        String path = cookieJson.getString("path");
                        Boolean persistent = cookieJson.getBoolean("persistent");
                        Boolean secure = cookieJson.getBoolean("secure");
                        Long expiryDate = cookieJson.getLong("expiryDate");
                        Integer version = cookieJson.getInteger("version");
                        BasicClientCookie cookie = new BasicClientCookie(name, value);
                        cookie.setDomain(domain);
                        cookie.setPath(path);
                        cookie.setSecure(secure);
                        cookie.setExpiryDate(new Date(expiryDate));
                        cookie.setVersion(version);
                        cookieStore.addCookie(cookie);
                    }
                    // å¿…须在构建client时就放入cookie
                    HttpClientManage.getInstance(uniqueKey, cookieStore);
                    //装载core信息及启动线程
                    LoginController login = new LoginController(uniqueKey);
                    if (!login.login_3()) {
                        // åŠ è½½å¤±è´¥é€€å‡º
                        core.setAlive(false);
                        return;
                    }
                    LOG.info("热登录成功: {}", uniqueKey);
                }
            } catch (Exception e) {
                e.printStackTrace();
                if (core != null) {
                    core.setAlive(false);
                    core = null;
                }
            }
        }
    }
    /**
     * å­˜æ”¾æ–°çš„群,昵称emoji处理
     *
     * @param core
     * @param jsonObject
     */
    public static void addNewGroup(Core core, JSONObject jsonObject) {
        String userName = jsonObject.getString("UserName");
        CommonTools.emojiFormatter2(jsonObject, "NickName");
        // åˆ é™¤é‡å¤çš„
        core.getGroupList().removeIf(group -> userName.equals(group.getString("UserName")));
        core.getGroupList().add(jsonObject);
        core.getGroupInfoMap().put(jsonObject.getString("NickName"), jsonObject);
        core.getGroupInfoMap().put(userName, jsonObject);
    }
    /**
     * å­˜æ”¾æ–°çš„联系人,昵称emoji处理
     *
     * @param core
     * @param jsonObject
     */
    public static void addNewContact(Core core, JSONObject jsonObject) {
        String userName = jsonObject.getString("UserName");
        CommonTools.emojiFormatter2(jsonObject, "NickName");
        // åˆ é™¤é‡å¤çš„
        core.getContactList().removeIf(contact -> userName.equals(contact.getString("UserName")));
        core.getContactList().add(jsonObject);
        core.getUserInfoMap().put(jsonObject.getString("NickName"), jsonObject);
        core.getUserInfoMap().put(userName, jsonObject);
    }
    /**
     * æ¶ˆæ¯ç»Ÿä¸€åŠ åˆ°é˜Ÿåˆ—é‡Œå¤„ç†1
     * ç”¨äºŽå·²çŸ¥UserName
     *
     * @param uniqueKey
     * @param toUserName
     * @param data
     * @param type
     */
    public static void addSendMsg4UserName(String uniqueKey, String toUserName, String data, SendMsgType type) {
        if (StringUtils.isEmpty(uniqueKey) || StringUtils.isEmpty(toUserName) || StringUtils.isEmpty(data) || type == null) {
            LOG.error("消息参数不完整 uk:{} un: {} data: {} ", uniqueKey, toUserName, data);
            return;
        }
        SendMsg sendMsg = new SendMsg();
        sendMsg.setUserName(toUserName);
        sendMsg.setMessage(data);
        sendMsg.setMsgType(type);
        boolean isGroup = true;
        if (toUserName != null && !toUserName.startsWith("@@")) {
            isGroup = false;
        }
        sendMsg.setGroup(isGroup);
        CoreManage.getInstance(uniqueKey).getSendList().add(sendMsg);
    }
    /**
     * æ¶ˆæ¯ç»Ÿä¸€åŠ åˆ°é˜Ÿåˆ—é‡Œå¤„ç†2
     * ç”¨äºŽå·²çŸ¥NickName
     *
     * @param uniqueKey
     * @param toNickName
     * @param data
     * @param type
     * @param isGroup
     */
    public static void addSendMsg4NickName(String uniqueKey, String toNickName, String data, SendMsgType type, Boolean isGroup) {
        if (StringUtils.isEmpty(uniqueKey) || StringUtils.isEmpty(toNickName) || StringUtils.isEmpty(data) || type == null) {
            LOG.error("消息参数不完整 uk:{} nn: {} data: {} ", uniqueKey, toNickName, data);
            return;
        }
        SendMsg sendMsg = new SendMsg();
        sendMsg.setNickName(toNickName);
        sendMsg.setMessage(data);
        sendMsg.setMsgType(type);
        sendMsg.setGroup(isGroup);
        CoreManage.getInstance(uniqueKey).getSendList().add(sendMsg);
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/core/MsgCenter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,273 @@
package org.ruoyi.common.wechat.itchat4j.core;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.ruoyi.common.wechat.itchat4j.api.MessageTools;
import org.ruoyi.common.wechat.itchat4j.api.WechatTools;
import org.ruoyi.common.wechat.itchat4j.beans.BaseMsg;
import org.ruoyi.common.wechat.itchat4j.beans.SendMsg;
import org.ruoyi.common.wechat.itchat4j.face.IMsgHandlerFace;
import org.ruoyi.common.wechat.itchat4j.utils.LogInterface;
import org.ruoyi.common.wechat.itchat4j.utils.MoreConfig;
import org.ruoyi.common.wechat.itchat4j.utils.enums.MsgCodeEnum;
import org.ruoyi.common.wechat.itchat4j.utils.enums.MsgTypeEnum;
import org.ruoyi.common.wechat.itchat4j.utils.enums.SendMsgType;
import org.ruoyi.common.wechat.itchat4j.utils.tools.CommonTools;
import java.util.ArrayList;
import java.util.List;
/**
 * æ¶ˆæ¯å¤„理中心
 *
 * @author https://github.com/yaphone
 * @author WesleyOne ä¿®æ”¹
 * @version 1.0
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´5月14日 ä¸‹åˆ12:47:50
 */
public class MsgCenter implements LogInterface {
    /**
     * æŽ¥æ”¶æ¶ˆæ¯ï¼Œæ”¾å…¥é˜Ÿåˆ—
     *
     * @param msgList
     * @return
     * @author https://github.com/yaphone
     * @date 2017å¹´4月23日 ä¸‹åˆ2:30:48
     */
    public static JSONArray produceMsg(JSONArray msgList, String uniqueKey) {
        Core core = CoreManage.getInstance(uniqueKey);
        JSONArray result = new JSONArray();
        // ç”¨äºŽæš‚存未知群ID,最后调用webwxbatchgetcontact获取
        List<String> unknowGroup = new ArrayList<>();
        for (int i = 0; i < msgList.size(); i++) {
            JSONObject m = msgList.getJSONObject(i);
            // æ˜¯å¦æ˜¯ç¾¤æ¶ˆæ¯
            boolean isGroupMsg = false;
            boolean isAtMe = false;
            if (m.getString("FromUserName").contains("@@") || m.getString("ToUserName").contains("@@")) {
                // ç¾¤èŠæ¶ˆæ¯
                isGroupMsg = true;
                if (m.getString("FromUserName").contains("@@")
                    && !core.getGroupInfoMap().containsKey(m.getString("FromUserName"))) {
                    unknowGroup.add(m.getString("FromUserName"));
                } else if (m.getString("ToUserName").contains("@@")
                    && !core.getGroupInfoMap().containsKey(m.getString("ToUserName"))) {
                    unknowGroup.add(m.getString("ToUserName"));
                }
                // ç¾¤æ¶ˆæ¯ä¸Žæ™®é€šæ¶ˆæ¯ä¸åŒçš„æ˜¯åœ¨å…¶æ¶ˆæ¯ä½“(Content)中会包含发送者id及":<br/>"消息,这里需要处理一下,去掉多余信息,只保留消息内容
                String splitCode = ":<br/>";
                if (m.getString("Content").contains(splitCode)) {
                    String source = m.getString("Content");
                    String content = source.substring(source.indexOf(splitCode) + splitCode.length());
                    String sendMemberId = source.substring(0, source.indexOf(splitCode));
                    m.put("Content", content);
                    m.put(MoreConfig.SEND_MEMBER_ID, sendMemberId);
                    if (content.contains("@" + core.getNickName())) {
                        isAtMe = true;
                    }
                }
            }
            m.put("groupMsg", isGroupMsg);
            m.put("atMe", isAtMe);
            // 1.文本消息
            if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_TEXT.getCode())) {
                if (m.getString("Url").length() != 0) {
                    // 1.1分享位置 ä¸å¤„理
                    continue;
//               String[] contents = m.getString("Content").split(":");
//               String data = "Map";
//               if (contents.length>0) {
//                  data = contents[0]+":"+m.getString("Url");
//               }
//               m.put("Type", MsgTypeEnum.MAP.getType());
//               m.put("Text", data);
//               LOG.warn("MAP_CONTENT: {},URL: {}",m.getString("Content"),m.getString("Url"));
                    /**
                     *   MAP_CONTENT: æ»¨å…´å°åŒº(东区):/cgi-bin/mmwebwx-bin/webwxgetpubliclinkimg?url=xxx&msgid=7525662842661720095&pictype=location,URL: http://apis.map.qq.com/uri/v1/geocoder?coord=30.191660,120.200508
                     */
                } else {
                    // 1.2 æ™®é€šæ–‡æœ¬
                    m.put("Type", MsgTypeEnum.TEXT.getType());
                    CommonTools.emojiFormatter2(m, "Content");
                    m.put("Text", m.getString("Content"));
                }
            } else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_IMAGE.getCode())
                || m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_EMOTICON.getCode())) {
                // 2.图片消息 ä¸å¤„理
                continue;
//            m.put("Type", MsgTypeEnum.PIC.getType());
            } else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_VOICE.getCode())) {
                // 3.语音消息 ä¸å¤„理
                continue;
//            m.put("Type", MsgTypeEnum.VOICE.getType());
            } else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_VERIFYMSG.getCode())) {
                // 4.好友确认消息 ä¸å¤„理
                continue;
                // MessageTools.addFriend(core, userName, 3, ticket); // ç¡®è®¤æ·»åŠ å¥½å‹
//            m.put("Type", MsgTypeEnum.VERIFYMSG.getType());
            } else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_SHARECARD.getCode())) {
                // 5.共享名片 ä¸å¤„理
//            m.put("Type", MsgTypeEnum.NAMECARD.getType());
            } else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_VIDEO.getCode())
                || m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_MICROVIDEO.getCode())) {
                // 6.视频 ä¸å¤„理
                continue;
//            m.put("Type", MsgTypeEnum.VIEDO.getType());
            } else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_MEDIA.getCode())) {
                // 7.分享链接 ä¸å¤„理
                continue;
//            m.put("Type", MsgTypeEnum.MEDIA.getType());
            } else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_STATUSNOTIFY.getCode())) {
                // å¾®ä¿¡åˆå§‹åŒ–消息   ç³»ç»Ÿ
                m.put("Type", MsgTypeEnum.SYS.getType());
            } else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_SYS.getCode())) {
                // ç³»ç»Ÿæ¶ˆæ¯   ç³»ç»Ÿ
                m.put("Type", MsgTypeEnum.SYS.getType());
            } else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_RECALLED.getCode())) {
                // æ’¤å›žæ¶ˆæ¯   ç³»ç»Ÿ  ä¸å¤„理
                continue;
//            m.put("Type", MsgTypeEnum.SYS.getType());
            } else {
                LOG.error("Useless msg: {} \n {}", m.getInteger("MsgType"), m.getString("Content"));
            }
            /**
             *   æ—¥å¿—
             *   æ˜¾ç¤ºæ”¶åˆ°çš„æ¶ˆæ¯
             */
            String nickName;
            String memberName = "";
            if (m.getBoolean("groupMsg")) {
                nickName = WechatTools.getGroupNickNameByUserName(m.getString("FromUserName"), uniqueKey);
                if (m.getString(MoreConfig.SEND_MEMBER_ID) != null) {
                    // èŽ·å–æˆå‘˜æ˜µç§°
                    memberName = WechatTools.getMemberNickName(m.getString("FromUserName"), uniqueKey, m.getString(MoreConfig.SEND_MEMBER_ID));
                    m.put(MoreConfig.SEND_MEMBER_NICKNAMW, memberName);
                }
            } else {
                nickName = WechatTools.getContactNickNameByUserName(m.getString("FromUserName"), uniqueKey);
            }
            m.put("fromNickName", nickName);
            LOG.info("收到【{}】=>【{}】消息,来自: {} å†…容:\n{} ",
                MsgCodeEnum.fromCode(m.getInteger("MsgType")) == null ? "未知类型" + m.getInteger("MsgType") : MsgCodeEnum.fromCode(m.getInteger("MsgType")).getType(),
                m.getString("Type"),
                nickName + " : " + memberName,
                StringUtils.isNotEmpty(m.getString("Content")) ? m.getString("Content") : "");
            result.add(m);
        }
        return result;
    }
    /**
     * å¾®ä¿¡æŽ¥æ”¶æ¶ˆæ¯å¤„理
     *
     * @param uniqueKey
     * @author https://github.com/yaphone
     * @date 2017å¹´5月14日 ä¸Šåˆ10:52:34
     */
    public static void handleMsg(String uniqueKey, IMsgHandlerFace msgHandler) {
        Core core = CoreManage.getInstance(uniqueKey);
        while (true) {
            if (!core.isAlive()) {
                LOG.info("停止消息处理");
                break;
            }
            if (core.getMsgList().size() > 0 && core.getMsgList().get(0).getContent() != null) {
                if (core.getMsgList().get(0).getContent().length() > 0) {
                    BaseMsg msg = core.getMsgList().get(0);
                    if (msg.getType() != null) {
                        try {
                            if (msg.getType().equals(MsgTypeEnum.TEXT.getType())) {
                                msgHandler.textMsgHandle(msg);
                            } else if (msg.getType().equals(MsgTypeEnum.PIC.getType())) {
                                msgHandler.picMsgHandle(msg);
                            } else if (msg.getType().equals(MsgTypeEnum.VOICE.getType())) {
                                msgHandler.voiceMsgHandle(msg);
                            } else if (msg.getType().equals(MsgTypeEnum.VIEDO.getType())) {
                                msgHandler.videoMsgHandle(msg);
                            } else if (msg.getType().equals(MsgTypeEnum.NAMECARD.getType())) {
                                msgHandler.nameCardMsgHandle(msg);
                            } else if (msg.getType().equals(MsgTypeEnum.SYS.getType())) {
                                msgHandler.sysMsgHandle(msg);
                            } else if (msg.getType().equals(MsgTypeEnum.VERIFYMSG.getType())) {
                                msgHandler.verifyAddFriendMsgHandle(msg);
                            } else if (msg.getType().equals(MsgTypeEnum.MEDIA.getType())) {
                                msgHandler.mediaMsgHandle(msg);
                            } else {
                                LOG.warn("暂未处理信息【{}】", msg.getType());
                            }
                        } catch (Exception e) {
                            LOG.error(e.getMessage(), e);
                        }
                    }
                }
                core.getMsgList().remove(0);
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                LOG.error("消息处理中断");
                break;
            }
        }
    }
    /**
     * ç»Ÿä¸€å‘送消息
     *
     * @param uniqueKey
     */
    public static void sendMsg(String uniqueKey) {
        Core core = CoreManage.getInstance(uniqueKey);
        while (true) {
            if (core == null || !core.isAlive()) {
                LOG.info("停止消息发送");
                break;
            }
            if (CollectionUtil.isNotEmpty(core.getSendList())) {
                SendMsg sendMsg = core.getSendList().get(0);
                try {
                    String userName = sendMsg.getUserName();
                    String nickName = sendMsg.getNickName();
                    String message = sendMsg.getMessage();
                    boolean isGroup = sendMsg.isGroup();
                    SendMsgType msgType = sendMsg.getMsgType();
                    if (StringUtils.isNotEmpty(message) && msgType != null) {
                        if (StringUtils.isNotEmpty(userName)) {
                            MessageTools.send(userName, uniqueKey, message, msgType.toValue());
                        } else if (StringUtils.isNotEmpty(nickName)) {
                            MessageTools.sendByNickName(nickName, uniqueKey, message, msgType.toValue(), isGroup);
                        } else {
                            LOG.error("无效发送消息: {}", JSONObject.toJSONString(sendMsg));
                        }
                    }
                } catch (Exception e) {
                    LOG.error(e.getMessage(), e);
                }
                core.getSendList().remove(0);
            }
            try {
                // æŽ§åˆ¶å‘送频率
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                LOG.error("消息发送中断");
                break;
            }
        }
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/face/IMsgHandlerFace.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,93 @@
package org.ruoyi.common.wechat.itchat4j.face;
import org.ruoyi.common.wechat.itchat4j.beans.BaseMsg;
/**
 * æ¶ˆæ¯å¤„理接口
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´4月20日 ä¸Šåˆ12:13:49
 * @version 1.0
 *
 * @author WesleyOne ä¿®æ”¹
 */
public interface IMsgHandlerFace {
   /**
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´4月20日 ä¸Šåˆ12:15:00
    * @param msg
    * @return
    */
   void textMsgHandle(BaseMsg msg);
   /**
    * å¤„理图片消息
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´4月21日 ä¸‹åˆ11:07:06
    * @param msg
    * @return
    */
   void picMsgHandle(BaseMsg msg);
   /**
    * å¤„理声音消息
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´4月22日 ä¸Šåˆ12:09:44
    * @param msg
    * @return
    */
   void voiceMsgHandle(BaseMsg msg);
   /**
    * å¤„理小视频消息
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´4月23日 ä¸‹åˆ12:19:50
    * @param msg
    * @return
    */
   void videoMsgHandle(BaseMsg msg);
   /**
    * å¤„理名片消息
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月1日 ä¸Šåˆ12:50:50
    * @param msg
    * @return
    */
   void nameCardMsgHandle(BaseMsg msg);
   /**
    * å¤„理系统消息
    *
    * @author Relyn
    * @date 2017å¹´6月21日17:43:51
    * @param msg
    * @return
    */
   void sysMsgHandle(BaseMsg msg);
   /**
    * å¤„理确认添加好友消息
    *
    * @date 2017å¹´6月28日 ä¸‹åˆ10:15:30
    * @param msg
    * @return
    */
   void verifyAddFriendMsgHandle(BaseMsg msg);
   /**
    * å¤„理收到的文件消息
    *
    * @date 2017å¹´7月21日 ä¸‹åˆ11:59:14
    * @param msg
    * @return
    */
   void mediaMsgHandle(BaseMsg msg);
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/service/ILoginService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,85 @@
package org.ruoyi.common.wechat.itchat4j.service;
/**
 * ç™»é™†æœåŠ¡æŽ¥å£
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´5月13日 ä¸Šåˆ12:07:21
 * @version 1.0
 *
 * @author WesleyOne ä¿®æ”¹
 */
public interface ILoginService {
   /**
    * ç™»é™†
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月13日 ä¸Šåˆ12:14:07
    * @return
    */
   boolean login();
   /**
    * èŽ·å–UUID
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月13日 ä¸Šåˆ12:21:40
    * @return
    */
   String getUuid();
   /**
    * èŽ·å–äºŒç»´ç å›¾ç‰‡
    * (直接获取图片链接,不下载文件)
    * @author https://github.com/yaphone
    * @date 2017å¹´5月13日 ä¸Šåˆ12:13:51
    * @param qrPath
    * @return
    */
   @Deprecated
   boolean getQR(String qrPath);
   /**
    * web初始化
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月13日 ä¸Šåˆ12:14:13
    * @return
    */
   boolean webWxInit();
   /**
    * å¾®ä¿¡çŠ¶æ€é€šçŸ¥
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月13日 ä¸Šåˆ12:14:24
    */
   void wxStatusNotify();
   /**
    * æŽ¥æ”¶æ¶ˆæ¯
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月13日 ä¸Šåˆ12:14:37
    */
   void startReceiving();
   /**
    * èŽ·å–å¾®ä¿¡è”ç³»äºº
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´5月13日 ä¸‹åˆ2:26:18
    */
   void webWxGetContact();
   /**
    * æ‰¹é‡èŽ·å–è”ç³»äººä¿¡æ¯
    *
    * @date 2017å¹´6月22日 ä¸‹åˆ11:24:35
    */
   void WebWxBatchGetContact();
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/service/impl/LoginServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,894 @@
package org.ruoyi.common.wechat.itchat4j.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.cookie.Cookie;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.ruoyi.common.wechat.itchat4j.beans.BaseMsg;
import org.ruoyi.common.wechat.itchat4j.beans.Member;
import org.ruoyi.common.wechat.itchat4j.beans.WebWxInit;
import org.ruoyi.common.wechat.itchat4j.core.Core;
import org.ruoyi.common.wechat.itchat4j.core.CoreManage;
import org.ruoyi.common.wechat.itchat4j.core.MsgCenter;
import org.ruoyi.common.wechat.itchat4j.service.ILoginService;
import org.ruoyi.common.wechat.itchat4j.utils.LogInterface;
import org.ruoyi.common.wechat.itchat4j.utils.SleepUtils;
import org.ruoyi.common.wechat.itchat4j.utils.enums.*;
import org.ruoyi.common.wechat.itchat4j.utils.enums.parameters.BaseParaEnum;
import org.ruoyi.common.wechat.itchat4j.utils.enums.parameters.LoginParaEnum;
import org.ruoyi.common.wechat.itchat4j.utils.enums.parameters.StatusNotifyParaEnum;
import org.ruoyi.common.wechat.itchat4j.utils.enums.parameters.UUIDParaEnum;
import org.ruoyi.common.wechat.itchat4j.utils.tools.CommonTools;
import org.w3c.dom.Document;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
/**
 * ç™»é™†æœåŠ¡å®žçŽ°ç±»
 *
 * @author https://github.com/yaphone
 * @author WesleyOne ä¿®æ”¹
 * @version 1.0
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´5月13日 ä¸Šåˆ12:09:35
 */
public class LoginServiceImpl implements ILoginService, LogInterface {
    private Core core;
    private String uniqueKey;
    public LoginServiceImpl(String uniqueKey) {
        this.uniqueKey = uniqueKey;
        this.core = CoreManage.getInstance(uniqueKey);
    }
    @Override
    public boolean login() {
        boolean isLogin = false;
        // ç»„装参数和URL
        List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
        params.add(new BasicNameValuePair(LoginParaEnum.LOGIN_ICON.para(), LoginParaEnum.LOGIN_ICON.value()));
        params.add(new BasicNameValuePair(LoginParaEnum.UUID.para(), core.getUuid()));
        params.add(new BasicNameValuePair(LoginParaEnum.TIP.para(), LoginParaEnum.TIP.value()));
        // long time = 4000;
        long startMillis = System.currentTimeMillis();
        boolean overTime = false;
        while (!isLogin && !overTime) {
            // é˜²æ­¢è¯·æ±‚重复时的问题
            if (core.isAlive()) {
                break;
            }
            long millis = System.currentTimeMillis();
            params.add(new BasicNameValuePair(LoginParaEnum.R.para(), String.valueOf(millis / 1579L)));
            params.add(new BasicNameValuePair(LoginParaEnum._1.para(), String.valueOf(millis)));
            HttpEntity entity = core.getMyHttpClient().doGet(URLEnum.LOGIN_URL.getUrl(), params, true, null);
            try {
                String result = EntityUtils.toString(entity);
                String status = checklogin(result);
                if (ResultEnum.SUCCESS.getCode().equals(status)) {
                    // å¤„理结果
                    if (processLoginInfo(result)) {
                        isLogin = true;
                        core.setAlive(isLogin);
                        break;
                    } else {
                        isLogin = false;
                        core.setAlive(isLogin);
                        // ç™»å…¥å¼‚常直接退出,防止死循环
                        break;
                    }
                }
                if (ResultEnum.WAIT_CONFIRM.getCode().equals(status)) {
                    LOG.info("请点击微信确认按钮,进行登陆");
                }
            } catch (Exception e) {
                LOG.error("微信登陆异常!", e);
                break;
            }
            // 3分钟超时不再请求
            SleepUtils.sleep(1000);
            overTime = (millis - startMillis) > 1000 * 180;
        }
        return isLogin;
    }
    @Override
    public String getUuid() {
        // ç»„装参数和URL
        List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
        params.add(new BasicNameValuePair(UUIDParaEnum.APP_ID.para(), UUIDParaEnum.APP_ID.value()));
        params.add(new BasicNameValuePair(UUIDParaEnum.FUN.para(), UUIDParaEnum.FUN.value()));
        params.add(new BasicNameValuePair(UUIDParaEnum.LANG.para(), UUIDParaEnum.LANG.value()));
        params.add(new BasicNameValuePair(UUIDParaEnum._1.para(), String.valueOf(System.currentTimeMillis())));
        HttpEntity entity = core.getMyHttpClient().doGet(URLEnum.UUID_URL.getUrl(), params, true, null);
        try {
            String result = EntityUtils.toString(entity);
            String regEx = "window.QRLogin.code = (\\d+); window.QRLogin.uuid = \"(\\S+?)\";";
            Matcher matcher = CommonTools.getMatcher(regEx, result);
            LOG.info(result);
            if (matcher.find()) {
                if ((ResultEnum.SUCCESS.getCode().equals(matcher.group(1)))) {
                    core.setUuid(matcher.group(2));
                }
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
        return core.getUuid();
    }
    @Deprecated
    @Override
    public boolean getQR(String qrPath) {
        return getQR(qrPath, false);
    }
    @Deprecated
    public boolean getQR(String qrPath, boolean open) {
        qrPath = qrPath + File.separator + "QR.jpg";
        String qrUrl = URLEnum.QRCODE_URL.getUrl() + core.getUuid();
        HttpEntity entity = core.getMyHttpClient().doGet(qrUrl, null, true, null);
        try {
            // æ–‡ä»¶å·²å­˜åœ¨å…ˆåˆ é™¤
            File file = new File(qrPath);
            if (file.exists() && file.isFile()) {
                file.delete();
            }
            // å†™å…¥äºŒç»´ç 
            OutputStream out = new FileOutputStream(qrPath);
            byte[] bytes = EntityUtils.toByteArray(entity);
            out.write(bytes);
            out.flush();
            out.close();
            if (open) {
                try {
                    CommonTools.printQr(qrPath); // æ‰“开登陆二维码图片
                } catch (Exception e) {
                    LOG.info(e.getMessage());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            LOG.error(e.getMessage(), e);
            return false;
        }
        return true;
    }
    /**
     * èŽ·å–è‡ªèº«ç™»å½•ä¿¡æ¯ç¼“å­˜
     *
     * @return
     */
    @Override
    public boolean webWxInit() {
        core.setAlive(true);
        core.setLastNormalRetcodeTime(System.currentTimeMillis());
        try {
            // ç»„装请求URL和参数
            String url = String.format(URLEnum.INIT_URL.getUrl(),
                core.getLoginInfo().get(StorageLoginInfoEnum.url.getKey()),
                System.currentTimeMillis() / 3158L,
                core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey()));
            Map<String, Object> paramMap = core.getParamMap();
            // è¯·æ±‚初始化接口
            HttpEntity entity = core.getMyHttpClient().doPost(url, JSONObject.toJSONString(paramMap), getPersistentCookieMap());
            String result = EntityUtils.toString(entity, Consts.UTF_8);
            /**
             * ç›¸å…³è¿”回信息,本项目未做封装
             * @see WebWxInit
             */
            JSONObject obj = JSON.parseObject(result);
            JSONObject user = obj.getJSONObject(StorageLoginInfoEnum.User.getKey());
            JSONObject syncKey = obj.getJSONObject(StorageLoginInfoEnum.SyncKey.getKey());
            core.getLoginInfo().put(StorageLoginInfoEnum.InviteStartCount.getKey(),
                obj.getInteger(StorageLoginInfoEnum.InviteStartCount.getKey()));
            core.getLoginInfo().put(StorageLoginInfoEnum.SyncKey.getKey(), syncKey);
            JSONArray syncArray = syncKey.getJSONArray("List");
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < syncArray.size(); i++) {
                sb.append(syncArray.getJSONObject(i).getString("Key") + "_"
                    + syncArray.getJSONObject(i).getString("Val") + "|");
            }
            // 1_661706053|2_661706420|3_661706415|1000_1494151022|
            String synckey = sb.toString();
            // 1_661706053|2_661706420|3_661706415|1000_1494151022
            core.getLoginInfo().put(StorageLoginInfoEnum.synckey.getKey(), synckey.substring(0, synckey.length() - 1));
            core.setUserName(user.getString("UserName"));
            core.setNickName(user.getString("NickName"));
            core.setUserSelf(obj.getJSONObject("User"));
            /**
             * TIP:
             * ContactList此处只是部分,不做处理,webwxgetcontact接口统一处理
             * MPSubscribeMsgList å…¬ä¼—号服务号也不处理
             */
        } catch (Exception e) {
            LOG.error("热登录出现该异常请忽略" + e.getMessage(), e);
            core.setAlive(false);
            return false;
        }
        return true;
    }
    @Override
    public void wxStatusNotify() {
        // ç»„装请求URL和参数
        String url = String.format(URLEnum.STATUS_NOTIFY_URL.getUrl(),
            core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey()));
        Map<String, Object> paramMap = core.getParamMap();
        paramMap.put(StatusNotifyParaEnum.CODE.para(), StatusNotifyParaEnum.CODE.value());
        paramMap.put(StatusNotifyParaEnum.FROM_USERNAME.para(), core.getUserName());
        paramMap.put(StatusNotifyParaEnum.TO_USERNAME.para(), core.getUserName());
        paramMap.put(StatusNotifyParaEnum.CLIENT_MSG_ID.para(), System.currentTimeMillis());
        String paramStr = JSON.toJSONString(paramMap);
        try {
            HttpEntity entity = core.getMyHttpClient().doPost(url, paramStr);
//         String result = EntityUtils.toString(entity, Consts.UTF_8);
//         LOG.info(result);
        } catch (Exception e) {
            LOG.error("微信状态通知接口失败!", e);
        }
    }
    @Override
    public void startReceiving() {
        core.setAlive(true);
        Thread thread = new Thread(core.getThreadGroup(), new Runnable() {
            int retryCount = 0;
            @Override
            public void run() {
                while (core.isAlive()) {
                    try {
                        long startTime = System.currentTimeMillis();
                        Map<String, String> resultMap = syncCheck();
                        LOG.info(JSONObject.toJSONString(resultMap));
                        String retcode = resultMap.get("retcode");
                        String selector = resultMap.get("selector");
                        RetCodeEnum retCodeEnum = RetCodeEnum.fromCode(retcode);
                        if (retCodeEnum != null) {
                            LOG.info(retCodeEnum.getType());
                            if (retcode.equals(RetCodeEnum.UNKOWN.getCode())) {
                                // é˜²æ­¢é¢‘繁请求
                                Thread.sleep(1000);
                                continue;
                            } else if (retcode.equals(RetCodeEnum.SUCCESS.getCode())) {
                                // ä¿®æ”¹æœ€åŽæ”¶åˆ°æ­£å¸¸æŠ¥æ–‡æ—¶é—´
                                core.setLastNormalRetcodeTime(System.currentTimeMillis());
                                SelectorEnum selectorEnum = SelectorEnum.fromCode(selector);
                                if (selectorEnum != null) {
                                    if (selector.equals(SelectorEnum.NORMAL.getCode())) {
                                        continue;
                                    } else if (selector.equals(SelectorEnum.NEW_MSG.getCode())) {
                                        // æœ‰æ–°æ¶ˆæ¯
//                                        processWebwxSync();
                                    } else if (selector.equals(SelectorEnum.ENTER_OR_LEAVE_CHAT.getCode())) {
//                                        processWebwxSync();
                                    } else if (selector.equals(SelectorEnum.MOD_CONTACT.getCode())) {
//                                        processWebwxSync();
                                    } else if (selector.equals(SelectorEnum.SELECTOR_3.getCode())) {
//                                        processWebwxSync();
//                                        continue;
                                    } else if (selector.equals(SelectorEnum.ADD_OR_DEL_CONTACT.getCode())) {
//                                        processWebwxSync();
                                    } else {
                                        LOG.error("UNKNOW SELECTOR CODE {}", selector);
                                    }
                                } else {
                                    // é˜²æ­¢æ–°ç±»åž‹ä¸å¤„理堆积
//                                    processWebwxSync();
                                }
                            } else if (retcode.equals(RetCodeEnum.NOT_LOGIN_CHECK.getCode()) ||
                                retcode.equals(RetCodeEnum.TICKET_ERROR.getCode()) ||
                                retcode.equals(RetCodeEnum.PARAM_ERROR.getCode()) ||
                                retcode.equals(RetCodeEnum.NOT_LOGIN_WARN.getCode()) ||
                                retcode.equals(RetCodeEnum.COOKIE_INVALID_ERROR.getCode()) ||
                                retcode.equals(RetCodeEnum.LOGIN_ENV_ERROR.getCode())) {
                                // çŠ¶æ€å¼‚å¸¸ç›´æŽ¥é€€å‡º
                                core.setAlive(false);
                                break;
                            } else {
                                // é˜²æ­¢é¢‘繁请求
                                Thread.sleep(1000);
                                break;
                            }
                        } else {
                            LOG.error("特殊retcode: {}", retcode);
                        }
                        // ç»Ÿç»Ÿå°è¯•获取新消息
                        processWebwxSync();
                        if (System.currentTimeMillis() - startTime < 1000 * 1) {
                            Thread.sleep(1000);
                        }
                    } catch (InterruptedException e0) {
                        LOG.error("线程中断");
                        core.setAlive(false);
                        break;
                    } catch (Exception e) {
                        LOG.error(e.getMessage());
                        retryCount += 1;
                        if (core.getReceivingRetryCount() < retryCount) {
                            core.setAlive(false);
                        } else {
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e1) {
                                LOG.error(e.getMessage());
                                break;
                            }
                        }
                    }
                }
            }
        }, "REC-" + uniqueKey);
        thread.start();
    }
    private void processWebwxSync() {
        JSONObject msgObj = webWxSync();
        if (msgObj != null) {
            Integer addMsgCount = msgObj.getInteger("AddMsgCount");
            Integer ModMsgCount = msgObj.getInteger("ModContactCount");
            Integer DelContactCount = msgObj.getInteger("DelContactCount");
            Integer ModChatRoomMemberCount = msgObj.getInteger("ModChatRoomMemberCount");
            if (addMsgCount > 0 || ModMsgCount > 0 || DelContactCount > 0 || ModChatRoomMemberCount > 0) {
                LOG.info("接收原文:{}", msgObj.toJSONString());
            }
            // ç”¨äºŽé€šçŸ¥èŽ·å–è¯¦ç»†è¯¦ç»†
            List<String> modUserName = new ArrayList<>();
            // å¤„理新消息
            try {
                if (addMsgCount > 0) {
                    JSONArray msgList = msgObj.getJSONArray("AddMsgList");
                    msgList = MsgCenter.produceMsg(msgList, uniqueKey);
                    for (int j = 0; j < msgList.size(); j++) {
                        BaseMsg baseMsg = JSON.toJavaObject(msgList.getJSONObject(j),
                            BaseMsg.class);
                        // TODO æ—¥å¿—
                        LOG.info("处理后对象:{}", JSON.toJSONString(baseMsg));
                        core.getMsgList().add(baseMsg);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            // å¤„理修改联系人或群成员
            try {
                if (ModMsgCount > 0) {
                    JSONArray list = msgObj.getJSONArray("ModContactList");
                    int size = list.size();
                    for (int j = 0; j < size; j++) {
                        String userName = list.getJSONObject(j).getString("UserName");
                        if (userName.startsWith("@@")) {
                            CoreManage.addNewGroup(core, list.getJSONObject(j));
                        } else if (userName.startsWith("@")) {
                            CoreManage.addNewContact(core, list.getJSONObject(j));
                        }
                        modUserName.add(userName);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            /**
             * æ²¡æœ‰èŽ·å–è¿‡æ•°æ®ï¼Œä¸çŸ¥é“å¹²å•¥ç”¨
             * DelContactCount: 0
             * DelContactList: []
             * ModChatRoomMemberCount: 0
             * ModChatRoomMemberList: []
             */
            // èŽ·å–è¯¦ç»†ä¿¡æ¯
            WebWxBatchGetContact(modUserName);
        }
    }
    @Override
    public void webWxGetContact() {
        String url = String.format(URLEnum.WEB_WX_GET_CONTACT.getUrl(),
            core.getLoginInfo().get(StorageLoginInfoEnum.url.getKey()));
        JSONArray member = new JSONArray();
        try {
            // å¾ªçŽ¯èŽ·å–seq直到为0,即获取全部好友列表 ==0:好友获取完毕 >0:好友未获取完毕,此时seq为已获取的字节数
            Long seq = 0L;
            do {
                // è®¾ç½®seq传参
                List<BasicNameValuePair> params = new ArrayList<>();
                params.add(new BasicNameValuePair("r", String.valueOf(System.currentTimeMillis())));
                params.add(new BasicNameValuePair("seq", String.valueOf(seq)));
                params.add(new BasicNameValuePair("skey", core.getLoginInfo().get(BaseParaEnum.Skey.value()).toString()));
                HttpEntity entity = core.getMyHttpClient().doGet(url, params, false, getPersistentCookieMap());
                String result = EntityUtils.toString(entity, Consts.UTF_8);
                JSONObject fullFriendsJsonList = JSON.parseObject(result);
                if (fullFriendsJsonList.get("Seq") != null) {
                    seq = fullFriendsJsonList.getLong("Seq");
                }
                // ç´¯åŠ å¥½å‹åˆ—è¡¨
                member.addAll(fullFriendsJsonList.getJSONArray(StorageLoginInfoEnum.MemberList.getKey()));
            } while (seq > 0);
            Iterator<?> iterator = member.iterator();
            while (iterator.hasNext()) {
                /**
                 * @see Member
                 */
                JSONObject o = (JSONObject) iterator.next();
                String userName = o.getString("UserName");
                if (StringUtils.isEmpty(userName)) {
                    LOG.error("{} å¥½å‹åˆ—表存在UserName空", core.getUniqueKey());
                    continue;
                }
                /**
                 * è‡ªå·±ä¿¡æ¯ä¸æ·»åŠ 
                 */
                if (userName.equals(core.getUserName())) {
                    continue;
                }
                /**
                 * å¼€å¤´@@           => ç¾¤èŠ
                 * å¼€å¤´@            => VerifyFlag   ->  == 0    å¥½å‹
                 *                                  -> != 0    å…¬ä¼—号、服务号
                 * ä¸å«@开头(其他) => ç‰¹æ®Šè´¦å·
                 */
                if (userName.startsWith("@@")) {
                    // ç¾¤èŠ
                    CoreManage.addNewGroup(core, o);
                } else if (userName.startsWith("@")) {
                    Integer verifyFlag = o.getInteger("VerifyFlag");
                    if (verifyFlag != null && verifyFlag == 0) {
                        // å¥½å‹
                        CoreManage.addNewContact(core, o);
                    } else {
                        // å…¬ä¼—号
                        core.getPublicUsersList().add(o);
                    }
                } else {
                    // ç‰¹æ®Šè´¦å·
                    core.getSpecialUsersList().add(o);
                }
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
        return;
    }
    /**
     * èŽ·å–ç¾¤å’Œå¥½å‹è¯¦ç»†ä¿¡æ¯
     * é¦–次加载用
     */
    @Override
    public void WebWxBatchGetContact() {
        Map<String, Object> paramMap = core.getParamMap();
        // å¤„理群成员信息
        int size = core.getGroupList().size();
        List<Map<String, String>> list = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            HashMap<String, String> map = new HashMap<>(4);
            map.put("UserName", core.getGroupList().get(i).getString("UserName"));
            map.put("EncryChatRoomId", "");
            list.add(map);
        }
        // å¤„理玩家
        int sizeUser = core.getContactList().size();
        for (int i = 0; i < sizeUser; i++) {
            HashMap<String, String> map = new HashMap<>(4);
            map.put("UserName", core.getContactList().get(i).getString("UserName"));
            map.put("EncryChatRoomId", "");
            list.add(map);
        }
        WebWxBatchGetContactMain(paramMap, list);
    }
    /**
     * èŽ·å–ç¾¤å’Œå¥½å‹è¯¦ç»†ä¿¡æ¯
     * è¿‡ç¨‹ä¸­é›¶æ•£æŸ¥è¯¢
     */
    public void WebWxBatchGetContact(List<String> userNameList) {
        if (CollectionUtil.isEmpty(userNameList)) {
            return;
        }
        String url = String.format(URLEnum.WEB_WX_BATCH_GET_CONTACT.getUrl(),
            core.getLoginInfo().get(StorageLoginInfoEnum.url.getKey()), System.currentTimeMillis(),
            core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey()));
        Map<String, Object> paramMap = core.getParamMap();
        // ä¸ºäº†èŽ·å–ç¾¤æˆå‘˜ä¿¡æ¯
        List<Map<String, String>> list = new ArrayList<>();
        int size = userNameList.size();
        for (int i = 0; i < size; i++) {
            HashMap<String, String> map = new HashMap<>(4);
            map.put("UserName", userNameList.get(i));
            map.put("EncryChatRoomId", "");
            list.add(map);
        }
        WebWxBatchGetContactMain(paramMap, list);
    }
    private void WebWxBatchGetContactMain(Map<String, Object> paramMap, List<Map<String, String>> list) {
        String url = String.format(URLEnum.WEB_WX_BATCH_GET_CONTACT.getUrl(),
            core.getLoginInfo().get(StorageLoginInfoEnum.url.getKey()), System.currentTimeMillis(),
            core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey()));
        int totalSize = list.size();
        int batchSize = 50;
        int num = totalSize / batchSize;
        if (totalSize % batchSize > 0) {
            num += 1;
        }
        for (int i = 0; i < num; i++) {
            int startNum = i * batchSize;
            int endNum = (i + 1) * batchSize;
            if (endNum > totalSize) {
                endNum = totalSize;
            }
            paramMap.put("Count", endNum - startNum);
            paramMap.put("List", list.subList(startNum, endNum));
            HttpEntity entity = core.getMyHttpClient().doPost(url, JSON.toJSONString(paramMap), getPersistentCookieMap());
            try {
                String text = EntityUtils.toString(entity, Consts.UTF_8);
                JSONObject obj = JSON.parseObject(text);
                JSONArray contactList = obj.getJSONArray("ContactList");
                int contactSize = contactList.size();
                if (contactSize > 0) {
                    for (int j = 0; j < contactSize; j++) {
                        String userName = contactList.getJSONObject(j).getString("UserName");
                        if (userName.startsWith("@@")) {
                            CoreManage.addNewGroup(core, contactList.getJSONObject(j));
                        } else if (userName.startsWith("@")) {
                            CoreManage.addNewContact(core, contactList.getJSONObject(j));
                        }
                    }
                }
            } catch (Exception e) {
                LOG.info(e.getMessage());
            }
        }
    }
    /**
     * æ£€æŸ¥ç™»é™†çŠ¶æ€
     *
     * @param result
     * @return
     */
    public String checklogin(String result) {
        String regEx = "window.code=(\\d+)";
        Matcher matcher = CommonTools.getMatcher(regEx, result);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }
    /**
     * å¤„理登陆信息
     *
     * @param loginContent
     * @author https://github.com/yaphone
     * @date 2017å¹´4月9日 ä¸‹åˆ12:16:26
     */
    private boolean processLoginInfo(String loginContent) {
        String regEx = "window.redirect_uri=\"(\\S+)\";";
        Matcher matcher = CommonTools.getMatcher(regEx, loginContent);
        if (matcher.find()) {
            String originalUrl = matcher.group(1);
            String url = originalUrl.substring(0, originalUrl.lastIndexOf('/'));
            core.getLoginInfo().put("url", url);
            Map<String, List<String>> possibleUrlMap = this.getPossibleUrlMap();
            Iterator<Entry<String, List<String>>> iterator = possibleUrlMap.entrySet().iterator();
            Entry<String, List<String>> entry;
            String fileUrl;
            String syncUrl;
            while (iterator.hasNext()) {
                entry = iterator.next();
                String indexUrl = entry.getKey();
                fileUrl = "https://" + entry.getValue().get(0) + "/cgi-bin/mmwebwx-bin";
                syncUrl = "https://" + entry.getValue().get(1) + "/cgi-bin/mmwebwx-bin";
                if (core.getLoginInfo().get("url").toString().contains(indexUrl)) {
                    core.setIndexUrl(indexUrl);
                    core.getLoginInfo().put("fileUrl", fileUrl);
                    core.getLoginInfo().put("syncUrl", syncUrl);
                    break;
                }
            }
            if (core.getLoginInfo().get("fileUrl") == null && core.getLoginInfo().get("syncUrl") == null) {
                core.getLoginInfo().put("fileUrl", url);
                core.getLoginInfo().put("syncUrl", url);
            }
            core.getLoginInfo().put("deviceid", "e" + String.valueOf(new Random().nextLong()).substring(1, 16)); // ç”Ÿæˆ15位随机数
            core.getLoginInfo().put("BaseRequest", new ArrayList<String>());
            String text = "";
            try {
                Map<String, String> header = new HashMap<>();
                header.put("client-version", "2.0.0");
                header.put("extspam", "Go8FCIkFEokFCggwMDAwMDAwMRAGGvAESySibk50w5Wb3uTl2c2h64jVVrV7gNs06GFlWplHQbY/5FfiO++1yH4ykCyNPWKXmco+wfQzK5R98D3so7rJ5LmGFvBLjGceleySrc3SOf2Pc1gVehzJgODeS0lDL3/I/0S2SSE98YgKleq6Uqx6ndTy9yaL9qFxJL7eiA/R3SEfTaW1SBoSITIu+EEkXff+Pv8NHOk7N57rcGk1w0ZzRrQDkXTOXFN2iHYIzAAZPIOY45Lsh+A4slpgnDiaOvRtlQYCt97nmPLuTipOJ8Qc5pM7ZsOsAPPrCQL7nK0I7aPrFDF0q4ziUUKettzW8MrAaiVfmbD1/VkmLNVqqZVvBCtRblXb5FHmtS8FxnqCzYP4WFvz3T0TcrOqwLX1M/DQvcHaGGw0B0y4bZMs7lVScGBFxMj3vbFi2SRKbKhaitxHfYHAOAa0X7/MSS0RNAjdwoyGHeOepXOKY+h3iHeqCvgOH6LOifdHf/1aaZNwSkGotYnYScW8Yx63LnSwba7+hESrtPa/huRmB9KWvMCKbDThL/nne14hnL277EDCSocPu3rOSYjuB9gKSOdVmWsj9Dxb/iZIe+S6AiG29Esm+/eUacSba0k8wn5HhHg9d4tIcixrxveflc8vi2/wNQGVFNsGO6tB5WF0xf/plngOvQ1/ivGV/C1Qpdhzznh0ExAVJ6dwzNg7qIEBaw+BzTJTUuRcPk92Sn6QDn2Pu3mpONaEumacjW4w6ipPnPw+g2TfywJjeEcpSZaP4Q3YV5HG8D6UjWA4GSkBKculWpdCMadx0usMomsSS/74QgpYqcPkmamB4nVv1JxczYITIqItIKjD35IGKAUwAA==");
                originalUrl = originalUrl + "&fun=new&version=v2&mod=desktop&lang=zh_CN";
                HttpEntity entity = core.getMyHttpClient().doGet(originalUrl, null, false, header);
                text = EntityUtils.toString(entity);
            } catch (Exception e) {
                LOG.info(e.getMessage());
                return false;
            }
            //add by é»˜éžé»˜ 2017-08-01 22:28:09
            //如果登录被禁止时,则登录返回的message内容不为空,下面代码则判断登录内容是否为空,不为空则退出程序
            String msg = getLoginMessage(text);
            if (!"".equals(msg)) {
                LOG.info(msg);
//            System.exit(0);
                return false;
            }
            Document doc = CommonTools.xmlParser(text);
            if (doc != null) {
                core.getLoginInfo().put(StorageLoginInfoEnum.skey.getKey(),
                    doc.getElementsByTagName(StorageLoginInfoEnum.skey.getKey()).item(0).getFirstChild()
                        .getNodeValue());
                core.getLoginInfo().put(StorageLoginInfoEnum.wxsid.getKey(),
                    doc.getElementsByTagName(StorageLoginInfoEnum.wxsid.getKey()).item(0).getFirstChild()
                        .getNodeValue());
                core.getLoginInfo().put(StorageLoginInfoEnum.wxuin.getKey(),
                    doc.getElementsByTagName(StorageLoginInfoEnum.wxuin.getKey()).item(0).getFirstChild()
                        .getNodeValue());
                core.getLoginInfo().put(StorageLoginInfoEnum.pass_ticket.getKey(),
                    doc.getElementsByTagName(StorageLoginInfoEnum.pass_ticket.getKey()).item(0).getFirstChild()
                        .getNodeValue());
            }
        }
        return true;
    }
    private Map<String, List<String>> getPossibleUrlMap() {
        Map<String, List<String>> possibleUrlMap = new HashMap<String, List<String>>();
        possibleUrlMap.put("wx.qq.com", new ArrayList<String>() {
            /**
             *
             */
            private static final long serialVersionUID = 1L;
            {
                add("file.wx.qq.com");
                add("webpush.wx.qq.com");
            }
        });
        possibleUrlMap.put("wx2.qq.com", new ArrayList<String>() {
            /**
             *
             */
            private static final long serialVersionUID = 1L;
            {
                add("file.wx2.qq.com");
                add("webpush.wx2.qq.com");
            }
        });
        possibleUrlMap.put("wx8.qq.com", new ArrayList<String>() {
            /**
             *
             */
            private static final long serialVersionUID = 1L;
            {
                add("file.wx8.qq.com");
                add("webpush.wx8.qq.com");
            }
        });
        possibleUrlMap.put("web2.wechat.com", new ArrayList<String>() {
            /**
             *
             */
            private static final long serialVersionUID = 1L;
            {
                add("file.web2.wechat.com");
                add("webpush.web2.wechat.com");
            }
        });
        possibleUrlMap.put("wechat.com", new ArrayList<String>() {
            /**
             *
             */
            private static final long serialVersionUID = 1L;
            {
                add("file.web.wechat.com");
                add("webpush.web.wechat.com");
            }
        });
        return possibleUrlMap;
    }
    /**
     * åŒæ­¥æ¶ˆæ¯ sync the messages
     *
     * @return
     * @author https://github.com/yaphone
     * @date 2017å¹´5月12日 ä¸Šåˆ12:24:55
     */
    private JSONObject webWxSync() {
        JSONObject result = null;
        String url = String.format(URLEnum.WEB_WX_SYNC_URL.getUrl(),
            core.getLoginInfo().get(StorageLoginInfoEnum.url.getKey()),
            core.getLoginInfo().get(StorageLoginInfoEnum.wxsid.getKey()),
            core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey()),
            core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey()));
        Map<String, Object> paramMap = core.getParamMap();
        paramMap.put(StorageLoginInfoEnum.SyncKey.getKey(),
            core.getLoginInfo().get(StorageLoginInfoEnum.SyncKey.getKey()));
        paramMap.put("rr", -System.currentTimeMillis() / 1000);
        String paramStr = JSON.toJSONString(paramMap);
        try {
            HttpEntity entity = core.getMyHttpClient().doPost(url, paramStr, getPersistentCookieMap());
            String text = EntityUtils.toString(entity, Consts.UTF_8);
            JSONObject obj = JSON.parseObject(text);
            if (obj.getJSONObject("BaseResponse").getInteger("Ret") != 0) {
                result = null;
            } else {
                result = obj;
                core.getLoginInfo().put(StorageLoginInfoEnum.SyncKey.getKey(), obj.getJSONObject("SyncCheckKey"));
                JSONArray syncArray = obj.getJSONObject(StorageLoginInfoEnum.SyncKey.getKey()).getJSONArray("List");
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < syncArray.size(); i++) {
                    sb.append(syncArray.getJSONObject(i).getString("Key") + "_"
                        + syncArray.getJSONObject(i).getString("Val") + "|");
                }
                String synckey = sb.toString();
                /**
                 * éšç€æ¯æ¬¡èŽ·å–æœ€æ–°æ¶ˆæ¯ï¼ˆå‚è§9)后的返回值更新,其目的在于每次同步消息后记录一个当前同步的状态
                 */
                core.getLoginInfo().put(StorageLoginInfoEnum.synckey.getKey(),
                    synckey.substring(0, synckey.length() - 1));// 1_656161336|2_656161626|3_656161313|11_656159955|13_656120033|201_1492273724|1000_1492265953|1001_1492250432|1004_1491805192
            }
        } catch (Exception e) {
            LOG.info(e.getMessage());
        }
        return result;
    }
    /**
     * æ£€æŸ¥æ˜¯å¦æœ‰æ–°æ¶ˆæ¯ check whether there's a message
     *
     * @return
     * @author https://github.com/yaphone
     * @date 2017å¹´4月16日 ä¸Šåˆ11:11:34
     */
    private Map<String, String> syncCheck() {
        Map<String, String> resultMap = new HashMap<String, String>();
        // ç»„装请求URL和参数
        String url = core.getLoginInfo().get(StorageLoginInfoEnum.syncUrl.getKey()) + URLEnum.SYNC_CHECK_URL.getUrl();
        List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
        for (BaseParaEnum baseRequest : BaseParaEnum.values()) {
            params.add(new BasicNameValuePair(baseRequest.para().toLowerCase(),
                core.getLoginInfo().get(baseRequest.value()).toString()));
        }
        params.add(new BasicNameValuePair("r", String.valueOf(System.currentTimeMillis())));
        params.add(new BasicNameValuePair("synckey", (String) core.getLoginInfo().get("synckey")));
        params.add(new BasicNameValuePair("_", String.valueOf(System.currentTimeMillis())));
        try {
            HttpEntity entity = core.getMyHttpClient().doGet(url, params, true, getPersistentCookieMap());
            if (entity == null) {
                resultMap.put("retcode", "9999");
                resultMap.put("selector", "9999");
                return resultMap;
            }
            String text = EntityUtils.toString(entity);
            String regEx = "window.synccheck=\\{retcode:\"(\\d+)\",selector:\"(\\d+)\"\\}";
            Matcher matcher = CommonTools.getMatcher(regEx, text);
            if (!matcher.find() || matcher.group(1).equals("2")) {
                LOG.info(String.format("Unexpected sync check result: %s", text));
            } else {
                resultMap.put("retcode", matcher.group(1));
                resultMap.put("selector", matcher.group(2));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultMap;
    }
    private Map<String, String> getPersistentCookieMap() {
        /**
         * ä»¥ä¸‹éƒ¨åˆ†ç¡®ä¿cookie存在header中,重启时需要强制手动添加,
         * TODO ä¸å¼ºåˆ¶åŠ é‡å¯ä¼šcookie失效,还不确定问题
         */
        String cookieStr = null;
        if (core != null && core.getMyHttpClient() != null && core.getMyHttpClient().getCookieStore() != null) {
            List<Cookie> cookies = core.getMyHttpClient().getCookieStore().getCookies();
            StringBuilder sb = new StringBuilder();
            if (CollectionUtil.isNotEmpty(cookies)) {
                for (Cookie ck : cookies) {
                    sb.append(ck.getName()).append('=').append(ck.getValue()).append(';');
                }
                cookieStr = sb.toString().substring(0, sb.toString().length() - 1);
            }
        }
        Map<String, String> headerMap = null;
        if (cookieStr != null) {
            headerMap = new HashMap<>(6);
            headerMap.put("Cookie", cookieStr);
        }
        /* ^-----------------------------------------------^ */
        return headerMap;
    }
    /**
     * è§£æžç™»å½•返回的消息,如果成功登录,则message为空
     *
     * @param result
     * @return
     */
    public String getLoginMessage(String result) {
        String[] strArr = result.split("<message>");
        String[] rs = strArr[1].split("</message>");
        if (rs != null && rs.length > 1) {
            return rs[0];
        }
        return "";
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/Config.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,78 @@
package org.ruoyi.common.wechat.itchat4j.utils;
import org.ruoyi.common.wechat.itchat4j.utils.enums.OsNameEnum;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
/**
 * é…ç½®ä¿¡æ¯
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´4月23日 ä¸‹åˆ2:26:21
 * @version 1.0
 *
 */
public class Config {
   public static final String API_WXAPPID = "API_WXAPPID";
   public static final String picDir = "D://org.ruoyi.common.wechat";
   public static final String VERSION = "1.2.18";
   public static final String BASE_URL = "https://login.weixin.qq.com";
   public static final String OS = "";
   public static final String DIR = "";
   public static final String DEFAULT_QR = "QR.jpg";
   public static final String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36";
   /**
    * ä»…仅用于参考
    */
   @Deprecated
   public static final ArrayList<String> API_SPECIAL_USER = new ArrayList<String>(Arrays.asList("filehelper", "weibo",
         "qqmail", "fmessage", "tmessage", "qmessage", "qqsync", "floatbottle", "lbsapp", "shakeapp", "medianote",
         "qqfriend", "readerapp", "blogapp", "facebookapp", "masssendapp", "meishiapp", "feedsapp", "voip",
         "blogappweixin", "brandsessionholder", "weixin", "weixinreminder", "officialaccounts", "wxitil",
         "notification_messages", "wxid_novlwrv3lqwv11", "gh_22b87fa7cb3c", "userexperience_alarm"));
   /**
    * èŽ·å–æ–‡ä»¶ç›®å½•
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´4月8日 ä¸‹åˆ10:27:42
    * @return
    */
   public static String getLocalPath() {
      String localPath = null;
      try {
         localPath = new File("").getCanonicalPath();
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
      return localPath;
   }
   /**
    * èŽ·å–ç³»ç»Ÿå¹³å°
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´4月8日 ä¸‹åˆ10:27:53
    */
   public static OsNameEnum getOsNameEnum() {
      String os = System.getProperty("os.name").toUpperCase();
      if (os.indexOf(OsNameEnum.DARWIN.toString()) >= 0) {
         return OsNameEnum.DARWIN;
      } else if (os.indexOf(OsNameEnum.WINDOWS.toString()) >= 0) {
         return OsNameEnum.WINDOWS;
      } else if (os.indexOf(OsNameEnum.LINUX.toString()) >= 0) {
         return OsNameEnum.LINUX;
      } else if (os.indexOf(OsNameEnum.MAC.toString()) >= 0) {
         return OsNameEnum.MAC;
      }
      return OsNameEnum.OTHER;
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/ConstantConfigEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
package org.ruoyi.common.wechat.itchat4j.utils;
/**
 * å¸¸é‡
 *
 * @author https=//github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´5月5日 ä¸‹åˆ11=29=04
 * @version 1.0
 *
 */
public class ConstantConfigEnum {
   public static final int APPMSGTYPE_TEXT = 1;
   public static final int APPMSGTYPE_IMG = 2;
   public static final int APPMSGTYPE_AUDIO = 3;
   public static final int APPMSGTYPE_VIDEO = 4;
   public static final int APPMSGTYPE_URL = 5;
   public static final int APPMSGTYPE_ATTACH = 6;
   public static final int APPMSGTYPE_OPEN = 7;
   public static final int APPMSGTYPE_EMOJI = 8;
   public static final int APPMSGTYPE_VOICE_REMIND = 9;
   public static final int APPMSGTYPE_SCAN_GOOD = 10;
   public static final int APPMSGTYPE_GOOD = 13;
   public static final int APPMSGTYPE_EMOTION = 15;
   public static final int APPMSGTYPE_CARD_TICKET = 16;
   public static final int APPMSGTYPE_REALTIME_SHARE_LOCATION = 17;
   // public static final int APPMSGTYPE_TRANSFERS = 2e3;
   public static final int APPMSGTYPE_RED_ENVELOPES = 2001;
   public static final int APPMSGTYPE_READER_TYPE = 100001;
   public static final int UPLOAD_MEDIA_TYPE_IMAGE = 1;
   public static final int UPLOAD_MEDIA_TYPE_VIDEO = 2;
   public static final int UPLOAD_MEDIA_TYPE_AUDIO = 3;
   public static final int UPLOAD_MEDIA_TYPE_ATTACHMENT = 4;
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/LogInterface.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package org.ruoyi.common.wechat.itchat4j.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * å…¬å…±æ—¥å¿—接口
 * @author WesleyOne
 * @create 2018/12/12
 */
public interface LogInterface {
    public final Logger LOG = LoggerFactory.getLogger("WXROBLOG");
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/MoreConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package org.ruoyi.common.wechat.itchat4j.utils;
/**
 * @author WesleyOne
 * @create 2018/12/19
 */
public class MoreConfig {
    //存储群聊成员ID的键标识
    public static final String SEND_MEMBER_ID = "sendMemberId";
    public static final String SEND_MEMBER_NICKNAMW = "memberNickname";
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/SleepUtils.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package org.ruoyi.common.wechat.itchat4j.utils;
/**
 * Created by xiaoxiaomo on 2017/5/6.
 */
public class SleepUtils {
    /**
     * æ¯«ç§’为单位
     * @param time
     */
    public static void sleep( long time ){
        try {
            Thread.sleep( time );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/MsgCodeEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,64 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
/**
 * æ¶ˆæ¯ç±»åž‹
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´4月23日 ä¸‹åˆ12:15:00
 * @version 1.0
 *
 */
public enum MsgCodeEnum {
   MSGTYPE_TEXT(1, "文本消息"),
   MSGTYPE_IMAGE(3, "图片消息"),
   MSGTYPE_VOICE(34, "语音消息"),
   MSGTYPE_VERIFYMSG(37, "好友请求"),
   MSGTYPE_POSSIBLEFRIEND_MSG(40, "POSSIBLEFRIEND_MSG"),
   MSGTYPE_SHARECARD(42, "分享名片"),
   MSGTYPE_VIDEO(43, "视频消息"),
   MSGTYPE_EMOTICON(47, "表情消息"),
   MSGTYPE_LOCATION(48, "位置消息"),
   MSGTYPE_MEDIA(49, "分享链接"),
   MSGTYPE_VOIPMSG(50, "VOIPMSG"),
   MSGTYPE_STATUSNOTIFY(51, "状态通知"),
   MSGTYPE_VOIPNOTIFY(52, "VOIPNOTIFY"),
   MSGTYPE_VOIPINVITE(53, "VOIPINVITE"),
   MSGTYPE_MICROVIDEO(62, "短视频消息"),
   MSGTYPE_SYSNOTICE(9999, "SYSNOTICE"),
   MSGTYPE_SYS(10000, "系统消息"),
   MSGTYPE_RECALLED(10002, "撤回消息")
   ;
   private static final Map<Integer, MsgCodeEnum> lookup = new HashMap<>();
   static {
      for (MsgCodeEnum s : EnumSet.allOf(MsgCodeEnum.class)){
         lookup.put(s.getCode(), s);
      }
   }
   public static MsgCodeEnum fromCode(int code) {
      return lookup.get(code);
   }
   private int code;
   private String type;
   MsgCodeEnum(int code, String type) {
      this.code = code;
      this.type = type;
   }
   public int getCode() {
      return code;
   }
   public String getType() {
      return type;
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/MsgTypeEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums;
/**
 * æ¶ˆæ¯ç±»åž‹æžšä¸¾ç±»
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´5月13日 ä¸‹åˆ11:53:00
 * @version 1.0
 *
 */
public enum MsgTypeEnum {
   TEXT("Text", "文本消息"),
   MAP("MAP", "地理位置"),
   PIC("Pic", "图片消息"),
   VOICE("Voice", "语音消息"),
   VIEDO("Viedo", "小视频消息"),
   NAMECARD("NameCard", "名片消息"),
   SYS("Sys", "系统消息"),
   VERIFYMSG("VerifyMsg", "添加好友"),
   // åœ°å€åˆ†äº«
   MEDIA("app", "文件消息");
   private String type;
   private String code;
   MsgTypeEnum(String type, String code) {
      this.type = type;
      this.code = code;
   }
   public String getType() {
      return type;
   }
   public String getCode() {
      return code;
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/OsNameEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums;
/**
 * ç³»ç»Ÿå¹³å°
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´4月8日 ä¸‹åˆ10:36:28
 * @version 1.0
 *
 */
public enum OsNameEnum {
   WINDOWS, LINUX, DARWIN, MAC, OTHER
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/ResultEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums;
import lombok.Getter;
/**
 * è¿”回结构枚举类
 * <p>
 * Created by xiaoxiaomo on 2017/5/6.
 */
@Getter
public enum ResultEnum {
    SUCCESS("200", "成功"),
    WAIT_CONFIRM("201", "请在手机上点击确认"),
    WAIT_SCAN("400", "请扫描二维码");
    private final String code;
    private final String msg;
    ResultEnum(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/RetCodeEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
public enum RetCodeEnum {
   UNKOWN("9999", "未知"),
   SUCCESS("0", "成功"),
   TICKET_ERROR("-14", "ticket错误"),
   PARAM_ERROR("1", "传入参数错误"),
   NOT_LOGIN_WARN("1100", "未登录提示"),
   NOT_LOGIN_CHECK("1101", "未检测到登录"),
   COOKIE_INVALID_ERROR("1102", "cookie值无效"),
   LOGIN_ENV_ERROR("1203", "当前登录环境异常,为了安全起见请不要在web端进行登录"),
   TOO_OFEN("1205", "操作频繁")
   ;
   private static final Map<String, RetCodeEnum> lookup = new HashMap<String, RetCodeEnum>();
   static {
      for (RetCodeEnum s : EnumSet.allOf(RetCodeEnum.class)){
         lookup.put(s.getCode(), s);
      }
   }
   public static RetCodeEnum fromCode(String code) {
      return lookup.get(code);
   }
   private String code;
   private String type;
   RetCodeEnum(String code, String type) {
      this.code = code;
      this.type = type;
   }
   public String getCode() {
      return code;
   }
   public String getType() {
      return type;
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/SelectorEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
/**
 * @author WesleyOne
 * @create 2018/12/21
 */
public enum SelectorEnum {
    UNKOWN("9999", "未知"),
    NORMAL("0", "正常"),
    NEW_MSG("2", "有新消息"),
    SELECTOR_3("3", "访问频繁#"),
    MOD_CONTACT("4", "有人修改了自己的昵称或你修改了别人的备注"),
    ADD_OR_DEL_CONTACT("6", "存在删除或者新增的好友信息"),
    ENTER_OR_LEAVE_CHAT("7", "进入或离开聊天界面");
    private static final Map<String, SelectorEnum> lookup = new HashMap<>();
    static {
        for (SelectorEnum s : EnumSet.allOf(SelectorEnum.class)) {
            lookup.put(s.getCode(), s);
        }
    }
    public static SelectorEnum fromCode(String code) {
        return lookup.get(code);
    }
    private String code;
    private String type;
    SelectorEnum(String code, String type) {
        this.code = code;
        this.type = type;
    }
    public String getCode() {
        return code;
    }
    public String getType() {
        return type;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/SendMsgType.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums;
import com.jfinal.plugin.activerecord.Record;
import java.util.*;
/**
 * å‘送类型
 * @author WesleyOne
 * @create 2018/12/14
 */
public enum SendMsgType {
    IMG("IMG","图片"),
    FILE("FILE","文件"),
    TEXT("TEXT","纯文本")
    ;
    private String value;
    private String name;
    SendMsgType(String value, String name) {
        this.value = value;
        this.name = name;
    }
    private static final Map<String, SendMsgType> lookup = new HashMap<>();
    public static List<Record> LIST_KV = new ArrayList<>();
    static {
        for (SendMsgType s : EnumSet.allOf(SendMsgType.class)){
            lookup.put(s.toValue(), s);
            LIST_KV.add(new Record().set("v",s.toValue()).set("n",s.toName()));
        }
    }
    /**
     * èŽ·å–æžšä¸¾çš„å€¼ï¼ˆæ•´æ•°å€¼ã€å­—ç¬¦ä¸²å€¼ç­‰ï¼‰
     * @return
     */
    public String toValue() {
        return this.value;
    }
    public String toName() {
        return this.name;
    }
    /**
     * æ ¹æ®å€¼ï¼ˆæ•´æ•°å€¼ã€å­—符串值等)获取相应的枚举类型
     * @param value
     * @return
     */
    public static SendMsgType fromValue(String value) {
        return lookup.get(value);
    }
    public boolean equal(SendMsgType type){
        if (type != null && this.toValue().equals(type.toValue())){
            return true;
        }
        return false;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/StorageLoginInfoEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
/**
 * Created by xiaoxiaomo on 2017/5/7.
 */
public enum StorageLoginInfoEnum {
    //URL
    url("url",new String()),
    fileUrl("fileUrl",new String()),
    syncUrl("syncUrl",new String()),
    //生成15位随机数
    deviceid("deviceid",new String()),
    //baseRequest
    skey("skey",new String()),
    wxsid("wxsid",new String()),
    wxuin("wxuin",new String()),
    pass_ticket("pass_ticket",new String()),
    InviteStartCount("InviteStartCount",new Integer(0)),
    // ç™»å½•用户登录时信息
    User("User",new JSONObject()),
    SyncKey("SyncKey",new JSONObject()),
    synckey("synckey",new String()),
    MemberCount("MemberCount",new String()),
    MemberList("MemberList",new JSONArray()),
    ;
    private String key;
    private Object type;
    StorageLoginInfoEnum(String key, Object type) {
        this.key = key;
        this.type = type;
    }
    public String getKey() {
        return key;
    }
    public Object getType() {
        return type;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/URLEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums;
/**
 * URL
 * Created by xiaoxiaomo on 2017/5/6.
 */
public enum URLEnum {
    BASE_URL("https://login.weixin.qq.com","基本的URL"),
    UUID_URL(BASE_URL.url+"/jslogin","UUIDLURL"),
    QRCODE_URL(BASE_URL.url+"/qrcode/","初始化URL"),
    STATUS_NOTIFY_URL(BASE_URL.url+"/webwxstatusnotify?lang=zh_CN&pass_ticket=%s","微信状态通知"),
    LOGIN_URL(BASE_URL.url+"/cgi-bin/mmwebwx-bin/login","登陆URL"),
    INIT_URL("%s/webwxinit?r=%s&pass_ticket=%s","初始化URL"),
    SYNC_CHECK_URL("/synccheck","检查心跳URL"),
    WEB_WX_SYNC_URL("%s/webwxsync?sid=%s&skey=%s&pass_ticket=%s&lang=zh_CN","web微信消息同步URL"),
    WEB_WX_GET_CONTACT("%s/webwxgetcontact","web微信获取联系人信息URL"),
    WEB_WX_SEND_MSG("%s/webwxsendmsg","发送消息URL"),
    WEB_WX_UPLOAD_MEDIA("%s/webwxuploadmedia?f=json", "上传文件到服务器"),
    WEB_WX_GET_MSG_IMG("%s/webwxgetmsgimg", "下载图片消息"),
    WEB_WX_GET_VOICE("%s/webwxgetvoice", "下载语音消息"),
    WEB_WX_GET_VIEDO("%s/webwxgetvideo", "下载语音消息"),
    WEB_WX_PUSH_LOGIN("%s/webwxpushloginurl", "不扫码登陆"),
    WEB_WX_LOGOUT("%s/webwxlogout", "退出微信"),
    WEB_WX_BATCH_GET_CONTACT("%s/webwxbatchgetcontact?type=ex&r=%s&lang=zh_CN&pass_ticket=%s", "查询群信息"),
   WEB_WX_REMARKNAME("%s/webwxoplog?lang=zh_CN&pass_ticket=%s", "修改好友备注"),
    WEB_WX_VERIFYUSER("%s/webwxverifyuser?r=%s&lang=zh_CN&pass_ticket=%s", "被动添加好友"),
    WEB_WX_GET_MEDIA("%s/webwxgetmedia", "下载文件")
    ;
    private String url;
    private String msg;
    URLEnum(String url, String msg) {
        this.url = url;
        this.msg = msg;
    }
    public String getUrl() {
        return url;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/VerifyFriendEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums;
/**
 * ç¡®è®¤æ·»åŠ å¥½å‹Enum
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´6月29日 ä¸‹åˆ9:47:14
 * @version 1.0
 *
 */
public enum VerifyFriendEnum {
   ADD(2, "添加"),
   ACCEPT(3, "接受");
   private int code;
   private String desc;
   private VerifyFriendEnum(int code, String desc) {
      this.code = code;
      this.desc = desc;
   }
   public int getCode() {
      return code;
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/parameters/BaseParaEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums.parameters;
/**
 *
 * åŸºæœ¬è¯·æ±‚参数
 * 1. webWxInit      åˆå§‹åŒ–
 * 2. wxStatusNotify å¾®ä¿¡çŠ¶æ€é€šçŸ¥
 *
 * <p>
 * Created by xiaoxiaomo on 2017/5/7.
 */
public enum BaseParaEnum {
    Uin("Uin", "wxuin"),
    Sid("Sid", "wxsid"),
    Skey("Skey", "skey"),
    DeviceID("DeviceID", "pass_ticket");
    private String para;
    private String value;
    BaseParaEnum(String para, String value) {
        this.para = para;
        this.value = value;
    }
    public String para() {
        return para;
    }
    public Object value() {
        return value;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/parameters/LoginParaEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums.parameters;
/**
 * ç™»é™†
 * <p>
 * Created by xiaoxiaomo on 2017/5/7.
 */
public enum LoginParaEnum {
    LOGIN_ICON("loginicon", "true"),
    UUID("uuid", ""),
    TIP("tip", "0"),
    R("r", ""),
    _1("_", "");
    private String para;
    private String value;
    LoginParaEnum(String para, String value) {
        this.para = para;
        this.value = value;
    }
    public String para() {
        return para;
    }
    public String value() {
        return value;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/parameters/StatusNotifyParaEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums.parameters;
/**
 * çŠ¶æ€é€šçŸ¥
 * <p>
 * Created by xiaoxiaomo on 2017/5/7.
 */
public enum StatusNotifyParaEnum {
    CODE("Code", "3"),
    FROM_USERNAME("FromUserName", ""),
    TO_USERNAME("ToUserName", ""),
    //时间戳
    CLIENT_MSG_ID("ClientMsgId", "");
    private String para;
    private String value;
    StatusNotifyParaEnum(String para, String value) {
        this.para = para;
        this.value = value;
    }
    public String para() {
        return para;
    }
    public String value() {
        return value;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/enums/parameters/UUIDParaEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package org.ruoyi.common.wechat.itchat4j.utils.enums.parameters;
/**
 * UUID
 * <p>
 * Created by xiaoxiaomo on 2017/5/7.
 */
public enum UUIDParaEnum {
    APP_ID("appid", "wx782c26e4c19acffb"),
    FUN("fun", "new"),
    LANG("lang", "zh_CN"),
    _1("_", "时间戳");
    private String para;
    private String value;
    UUIDParaEnum(String para, String value) {
        this.para = para;
        this.value = value;
    }
    public String para() {
        return para;
    }
    public String value() {
        return value;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/tools/CommonTools.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,301 @@
package org.ruoyi.common.wechat.itchat4j.utils.tools;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.vdurmont.emoji.EmojiParser;
import org.ruoyi.common.wechat.itchat4j.utils.Config;
import org.ruoyi.common.wechat.itchat4j.utils.enums.OsNameEnum;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * å¸¸ç”¨å·¥å…·ç±»
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´4月8日 ä¸‹åˆ10:59:55
 * @version 1.0
 *
 */
public class CommonTools {
   public static boolean printQr(String qrPath) {
      switch (Config.getOsNameEnum()) {
      case WINDOWS:
         if (Config.getOsNameEnum().equals(OsNameEnum.WINDOWS)) {
            Runtime runtime = Runtime.getRuntime();
            try {
               runtime.exec("cmd /c start " + qrPath);
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
         break;
      case MAC:
         if (Config.getOsNameEnum().equals(OsNameEnum.MAC)) {
            Runtime runtime = Runtime.getRuntime();
            try {
               runtime.exec("open " + qrPath);
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
         break;
      default:
         break;
      }
      return true;
   }
   public static boolean clearScreen() {
      switch (Config.getOsNameEnum()) {
      case WINDOWS:
         if (Config.getOsNameEnum().equals(OsNameEnum.WINDOWS)) {
            Runtime runtime = Runtime.getRuntime();
            try {
               runtime.exec("cmd /c " + "cls");
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
         break;
      default:
         break;
      }
      return true;
   }
   /**
    * æ­£åˆ™è¡¨è¾¾å¼å¤„理工具
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´4月9日 ä¸Šåˆ12:27:10
    * @return
    */
   public static Matcher getMatcher(String regEx, String text) {
      Pattern pattern = Pattern.compile(regEx);
      Matcher matcher = pattern.matcher(text);
      return matcher;
   }
   /**
    * xml解析器
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´4月9日 ä¸‹åˆ6:24:25
    * @param text
    * @return
    */
   public static Document xmlParser(String text) {
      Document doc = null;
      StringReader sr = new StringReader(text);
      InputSource is = new InputSource(sr);
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      try {
         DocumentBuilder builder = factory.newDocumentBuilder();
         doc = builder.parse(is);
      } catch (Exception e) {
         e.printStackTrace();
      }
      return doc;
   }
   public static JSONObject structFriendInfo(JSONObject userObj) {
      Map<String, Object> friendInfoTemplate = new HashMap<String, Object>();
      friendInfoTemplate.put("UserName", "");
      friendInfoTemplate.put("City", "");
      friendInfoTemplate.put("DisplayName", "");
      friendInfoTemplate.put("PYQuanPin", "");
      friendInfoTemplate.put("RemarkPYInitial", "");
      friendInfoTemplate.put("Province", "");
      friendInfoTemplate.put("KeyWord", "");
      friendInfoTemplate.put("RemarkName", "");
      friendInfoTemplate.put("PYInitial", "");
      friendInfoTemplate.put("EncryChatRoomId", "");
      friendInfoTemplate.put("Alias", "");
      friendInfoTemplate.put("Signature", "");
      friendInfoTemplate.put("NickName", "");
      friendInfoTemplate.put("RemarkPYQuanPin", "");
      friendInfoTemplate.put("HeadImgUrl", "");
      friendInfoTemplate.put("UniFriend", 0);
      friendInfoTemplate.put("Sex", 0);
      friendInfoTemplate.put("AppAccountFlag", 0);
      friendInfoTemplate.put("VerifyFlag", 0);
      friendInfoTemplate.put("ChatRoomId", 0);
      friendInfoTemplate.put("HideInputBarFlag", 0);
      friendInfoTemplate.put("AttrStatus", 0);
      friendInfoTemplate.put("SnsFlag", 0);
      friendInfoTemplate.put("MemberCount", 0);
      friendInfoTemplate.put("OwnerUin", 0);
      friendInfoTemplate.put("ContactFlag", 0);
      friendInfoTemplate.put("Uin", 0);
      friendInfoTemplate.put("StarFriend", 0);
      friendInfoTemplate.put("Statues", 0);
      friendInfoTemplate.put("MemberList", new ArrayList<Object>());
      JSONObject r = new JSONObject();
      Set<String> keySet = friendInfoTemplate.keySet();
      for (String key : keySet) {
         if (userObj.containsKey(key)) {
            r.put(key, userObj.get(key));
         } else {
            r.put(key, friendInfoTemplate.get(key));
         }
      }
      return r;
   }
   public static String getSynckey(JSONObject obj) {
      JSONArray obj2 = obj.getJSONArray("List");
      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < obj2.size(); i++) {
         JSONObject obj3 = (JSONObject) JSON.toJSON(obj2.get(i));
         sb.append(obj3.get("Val") + "|");
      }
      return sb.substring(0, sb.length() - 1); // 656159784|656159911|656159873|1491905341
   }
   public static JSONObject searchDictList(List<JSONObject> list, String key, String value) {
      JSONObject r = null;
      for (JSONObject i : list) {
         if (i.getString(key).equals(value)) {
            r = i;
            break;
         }
      }
      return r;
   }
   /**
    * å¤„理emoji表情
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´4月23日 ä¸‹åˆ2:39:04
    * @param d
    * @param k
    */
   public static void emojiFormatter(JSONObject d, String k) {
//      Matcher matcher = getMatcher("<span class=\"emoji emoji(.{1,10})\"></span>", d.getString(k));
      Matcher matcher = getMatcher("<span class=\"emoji emoji(.+?)\"></span>", d.getString(k));
      StringBuilder sb = new StringBuilder();
      String content = d.getString(k);
      int lastStart = 0;
      while (matcher.find()) {
         String str = matcher.group(1);
         if (str.length() == 6) {
         } else if (str.length() == 10) {
         } else {
            str = "&#x" + str + ";";
            String tmp = content.substring(lastStart, matcher.start());
            sb.append(tmp + str);
            lastStart = matcher.end();
         }
      }
      if (lastStart < content.length()) {
         sb.append(content.substring(lastStart));
      }
      if (sb.length() != 0) {
         d.put(k, EmojiParser.parseToUnicode(sb.toString()));
      } else {
         d.put(k, content);
      }
   }
   /**
    * è½¬åŒ–成alias
    * @param d
    * @param k
    */
   public static void emojiFormatter2(JSONObject d, String k) {
      Matcher matcher = getMatcher("<span class=\"emoji emoji(.+?)\"></span>", d.getString(k));
      StringBuilder sb = new StringBuilder();
      String content = d.getString(k);
      int lastStart = 0;
      while (matcher.find()) {
         String str = matcher.group(1);
         if (str.length() == 6) {
         } else if (str.length() == 10) {
         } else {
            str = "&#x" + str + ";";
            String tmp = content.substring(lastStart, matcher.start());
            sb.append(tmp + str);
            lastStart = matcher.end();
         }
      }
      if (lastStart < content.length()) {
         sb.append(content.substring(lastStart));
      }
      if (sb.length() != 0) {
         d.put(k, EmojiParser.parseToAliases(EmojiParser.parseToUnicode(sb.toString())));
      } else {
         d.put(k, content);
      }
   }
   /**
    * æ¶ˆæ¯æ ¼å¼åŒ–
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´4月23日 ä¸‹åˆ4:19:08
    * @param d
    * @param k
    */
   public static void msgFormatter(JSONObject d, String k) {
      d.put(k, d.getString(k).replace("<br/>", "\n"));
      emojiFormatter(d, k);
      // TODO ä¸Žemoji表情有部分兼容问题,目前暂未处理解码处理 d.put(k,
      // StringEscapeUtils.unescapeHtml4(d.getString(k)));
   }
   public static void main(String[] args) {
      String str2 = "三生三世<span class=\"emoji emoji1f46f\"></span>十三水<span class=\"emoji emoji1f440\"></span>";
      Matcher matcher = getMatcher("<span class=\"emoji emoji(.+?)\"></span>", str2);
      StringBuilder sb = new StringBuilder();
      String content = str2;
      int lastStart = 0;
      while (matcher.find()) {
         String str = matcher.group(1);
         if (str.length() == 6) {
         } else if (str.length() == 10) {
         } else {
            str = "&#x" + str + ";";
            String tmp = content.substring(lastStart, matcher.start());
            sb.append(tmp + str);
            lastStart = matcher.end();
         }
      }
      if (lastStart < content.length()) {
         sb.append(content.substring(lastStart));
      }
      if (sb.length() != 0) {
         System.out.println(EmojiParser.parseToUnicode(sb.toString()));
         System.out.println(EmojiParser.parseToAliases(EmojiParser.parseToUnicode(sb.toString())));
         System.out.println(EmojiParser.removeAllEmojis(sb.toString()));
      }
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/itchat4j/utils/tools/DownloadTools.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
package org.ruoyi.common.wechat.itchat4j.utils.tools;
import org.apache.http.HttpEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.ruoyi.common.wechat.itchat4j.beans.BaseMsg;
import org.ruoyi.common.wechat.itchat4j.core.Core;
import org.ruoyi.common.wechat.itchat4j.core.CoreManage;
import org.ruoyi.common.wechat.itchat4j.utils.LogInterface;
import org.ruoyi.common.wechat.itchat4j.utils.enums.MsgTypeEnum;
import org.ruoyi.common.wechat.itchat4j.utils.enums.URLEnum;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
/**
 * ä¸‹è½½å·¥å…·ç±»
 *
 * @author https://github.com/yaphone
 * @date åˆ›å»ºæ—¶é—´ï¼š2017å¹´4月21日 ä¸‹åˆ11:18:46
 * @version 1.0
 *
 */
public class DownloadTools  implements LogInterface {
   private static Logger logger = Logger.getLogger("UTILLOG");
   /**
    * å¤„理下载任务
    *
    * @author https://github.com/yaphone
    * @date 2017å¹´4月21日 ä¸‹åˆ11:00:25
    * @param msg
    * @param type
    * @param path
    * @return
    */
   public static Object getDownloadFn(BaseMsg msg, String type, String path, String uniqueKey) {
      Core core = CoreManage.getInstance(uniqueKey);
      Map<String, String> headerMap = new HashMap<String, String>();
      List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
      String url = "";
      if (type.equals(MsgTypeEnum.PIC.getType())) {
         url = String.format(URLEnum.WEB_WX_GET_MSG_IMG.getUrl(), (String) core.getLoginInfo().get("url"));
      } else if (type.equals(MsgTypeEnum.VOICE.getType())) {
         url = String.format(URLEnum.WEB_WX_GET_VOICE.getUrl(), (String) core.getLoginInfo().get("url"));
      } else if (type.equals(MsgTypeEnum.VIEDO.getType())) {
         headerMap.put("Range", "bytes=0-");
         url = String.format(URLEnum.WEB_WX_GET_VIEDO.getUrl(), (String) core.getLoginInfo().get("url"));
      } else if (type.equals(MsgTypeEnum.MEDIA.getType())) {
         headerMap.put("Range", "bytes=0-");
         url = String.format(URLEnum.WEB_WX_GET_MEDIA.getUrl(), (String) core.getLoginInfo().get("fileUrl"));
         params.add(new BasicNameValuePair("sender", msg.getFromUserName()));
         params.add(new BasicNameValuePair("mediaid", msg.getMediaId()));
         params.add(new BasicNameValuePair("filename", msg.getFileName()));
      }
      params.add(new BasicNameValuePair("msgid", msg.getNewMsgId()));
      params.add(new BasicNameValuePair("skey", (String) core.getLoginInfo().get("skey")));
      HttpEntity entity = core.getMyHttpClient().doGet(url, params, true, headerMap);
      try {
         OutputStream out = new FileOutputStream(path);
         byte[] bytes = EntityUtils.toByteArray(entity);
         out.write(bytes);
         out.flush();
         out.close();
      } catch (Exception e) {
         logger.info(e.getMessage());
         return false;
      }
      return null;
   };
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/annotation/UnCheckLogin.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
package org.ruoyi.common.wechat.web.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
 * ä¸æ£€æŸ¥ç™»å½•
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface UnCheckLogin {
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/base/BaseError.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
package org.ruoyi.common.wechat.web.base;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
/**
 * é”™è¯¯ç®¡ç†
 * @author WesleyOne
 * @create 2018/7/28
 */
public enum BaseError {
    UNPERMISSION("09","没有操作权限"),
    UNLOGIN("01","未登录或登录过期"),
    OPERATION_ERR("8899","操作失败!"),
    NORMAL_ERR("8999","参数异常"),
    SYSTEM_ERR("9999","系统异常");
    private String code;
    private String msg;
    BaseError(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    private static final Map<String, BaseError> lookup = new HashMap<String, BaseError>();
    static {
        for (BaseError s : EnumSet.allOf(BaseError.class))
            lookup.put(s.getMsg(), s);
    }
    /**
     * èŽ·å–æžšä¸¾çš„å€¼ï¼ˆæ•´æ•°å€¼ã€å­—ç¬¦ä¸²å€¼ç­‰ï¼‰
     * @return
     */
    public String getCode() {
        return this.code;
    }
    public String getMsg() {
        return this.msg;
    }
    /**
     * æ ¹æ®å€¼ï¼ˆæ•´æ•°å€¼ã€å­—符串值等)获取相应的枚举类型
     * @param code
     * @return
     */
    public static BaseError fromValue(String code) {
        return lookup.get(code);
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/base/BaseException.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
package org.ruoyi.common.wechat.web.base;
import java.io.Serializable;
/**
 * ç»Ÿä¸€å¼‚常对象
 * @author WesleyOne
 * @create 2018/7/28
 */
public class BaseException extends Exception implements Serializable {
    private static final long serialVersionUID = 2007525058641283836L;
    private String code;
    public BaseException(String code, String msg) {
        super(msg);
        this.code = code;
    }
    public BaseException(BaseError baseError) {
        super(baseError.getMsg());
        this.code = baseError.getCode();
    }
    public BaseException(String msg) {
        super(msg);
        this.code = BaseError.NORMAL_ERR.getCode();
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/base/BaseResponse.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,85 @@
package org.ruoyi.common.wechat.web.base;
/**
 * @author WesleyOne
 * @create 2018/7/28
 */
public class BaseResponse<T> {
    public static BaseResponse OK = new BaseResponse();
    private String code = "00";
    private String message = "操作成功";
    private T data;
    public BaseResponse() {
    }
    public BaseResponse(T data) {
        this.data = data;
    }
    public BaseResponse(String code, String message) {
        this.code = code;
        this.message = message;
    }
    public static BaseResponse success(){
        return new BaseResponse();
    }
    public static BaseResponse success(Object o){
        return new BaseResponse(o);
    }
    public static BaseResponse error(String code,String msg){
        BaseResponse r = new BaseResponse();
        r.setCode(code);
        r.setMessage(msg);
        return r;
    }
    public static BaseResponse error(BaseError baseError){
        BaseResponse r = new BaseResponse();
        r.setCode(baseError.getCode());
        r.setMessage(baseError.getMsg());
        return r;
    }
    /**
     * æœªç™»å½•返回
     * @return
     */
    public static BaseResponse unLogin(){
        BaseResponse r = new BaseResponse();
        r.setCode(BaseError.UNLOGIN.getCode());
        r.setMessage(BaseError.UNLOGIN.getMsg());
        return r;
    }
    /**
     * æ— æƒé™è¿”回
     * @return
     */
    public static BaseResponse unPermission(){
        BaseResponse r = new BaseResponse();
        r.setCode(BaseError.UNPERMISSION.getCode());
        r.setMessage(BaseError.UNPERMISSION.getMsg());
        return r;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/cache/UserSession.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package org.ruoyi.common.wechat.web.cache;
import org.ruoyi.common.wechat.web.utils.LRUCache;
import java.util.LinkedHashMap;
/**
 * ç®€å•的本地会话存储
 * @author WesleyOne
 * @create 2018/9/25
 */
public class UserSession {
    public static LinkedHashMap<String,String> USERSESSION_CACHE = new LRUCache<String, String>(64);
    public static void addUserSession(String username,String userSession){
        USERSESSION_CACHE.put(username,userSession);
    }
    public static void delUserSession(String username){
        USERSESSION_CACHE.remove(username);
    }
    public static boolean checkUserSession(String username,String userSession){
        String s = USERSESSION_CACHE.get(username);
        if (userSession!=null&&userSession.equals(s)){
            return true;
        }
        return false;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/common/MyConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,153 @@
package org.ruoyi.common.wechat.web.common;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.wall.WallFilter;
import com.jfinal.config.*;
import com.jfinal.json.FastJsonFactory;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.dialect.MysqlDialect;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.server.undertow.UndertowServer;
import com.jfinal.template.Engine;
import com.jfinal.template.source.ClassPathSourceFactory;
import org.ruoyi.common.wechat.itchat4j.core.CoreManage;
import org.ruoyi.common.wechat.web.constant.UploadConstant;
import org.ruoyi.common.wechat.web.interceptor.ExceptionInterceptor;
import org.ruoyi.common.wechat.web.model._MappingKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
/**
 * JFinal项目的核心配置
 * è¯¦æƒ…查看官方文档
 * https://www.jfinal.com/doc
 *
 * @author WesleyOne
 */
public class MyConfig extends JFinalConfig {
   public final Logger LOG = LoggerFactory.getLogger(this.getClass());
   public static void main(String[] args) {
      UndertowServer.start(MyConfig.class, 8180, true);
   }
   /**
    * é…ç½®å¸¸é‡
    */
   @Override
   public void configConstant(Constants me) {
      PropKit.use("appConfig.properties");
      me.setDevMode(PropKit.getBoolean("devMode", false));
      //上传的文件的最大50M
      me.setMaxPostSize(10 * 1024 * 1024);
      me.setEncoding("UTF-8");
      me.setJsonFactory(new FastJsonFactory());
      me.setError404View("/WEB-INF/templates/404.html");
   }
   /**
    * é…ç½®è·¯ç”±
    */
   @Override
   public void configRoute(Routes me) {
      me.add(new MyRoute());
      me.add(new OutRoute());
   }
   @Override
   public void configEngine(Engine me) {
      me.setDevMode(PropKit.use("appConfig.properties").getBoolean("devMode", false));
      me.addSharedFunction("/WEB-INF/templates/bs4temp/layout.html");
      me.addSharedObject("imgDomain" , UploadConstant.IMG_URL);
      me.addSharedObject("filedomain" , UploadConstant.FILE_URL);
   }
   /**
    * é…ç½®æ’ä»¶
    */
   @Override
   public void configPlugin(Plugins me) {
      // é…ç½® druid æ•°æ®åº“连接池插件
      DruidPlugin druidPlugin = createDruidPlugin();
      druidPlugin.addFilter(new StatFilter());
      WallFilter wall = new WallFilter();
      wall.setDbType("mysql");
      druidPlugin.addFilter(wall);
      druidPlugin.setInitialSize(1);
      me.add(druidPlugin);
      // é…ç½®ActiveRecord插件
      ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
      _MappingKit.mapping(arp);
      arp.setDialect(new MysqlDialect());
      arp.setShowSql(PropKit.use("appConfig.properties").getBoolean("devMode", false));
      arp.getEngine().setSourceFactory(new ClassPathSourceFactory());
      me.add(arp);
   }
   public static DruidPlugin createDruidPlugin() {
      return new DruidPlugin(PropKit.get("jdbcUrl"), PropKit.get("user"), PropKit.get("password").trim());
   }
   /**
    * é…ç½®å…¨å±€æ‹¦æˆªå™¨
    */
   @Override
   public void configInterceptor(Interceptors me) {
      me.add(new ExceptionInterceptor());
   }
   /**
    * é…ç½®å¤„理器
    */
   @Override
   public void configHandler(Handlers me) {
   }
   @Override
   public void afterJFinalStart() {
      System.setProperty("jsse.enableSNIExtension", "false");
      // æ£€æŸ¥æ–‡ä»¶å¤¹(/热登录/下载根目录)是否存在
        checkFileExist();
      // çƒ­ç™»é™†æ“ä½œ
      CoreManage.reload();
   }
    @Override
   public void beforeJFinalStop() {
      CoreManage.persistence();
   }
    /**
     * æ£€æŸ¥æ–‡ä»¶å¤¹(/热登录/下载根目录)是否存在
     */
    private void checkFileExist() {
        String hotReloadDir = PropKit.get("hotReloadDir");
        String downloadPath = PropKit.get("download_path");
        String logPath = PropKit.get("log_path");
        File hotReloadFile = new File(hotReloadDir);
        if (!hotReloadFile.exists()){
            if (!hotReloadFile.mkdirs()) {
                LOG.error("热加载文件夹创建失败[{}]",hotReloadDir);
            }
        }
        File downloadFile = new File(downloadPath);
        if (!downloadFile.exists()){
            if (!downloadFile.mkdirs()) {
                LOG.error("下载文件夹创建失败[{}]",downloadPath);
            }
        }
        File logFile = new File(logPath);
        if (!logFile.exists()){
            if (!logFile.mkdirs()) {
                LOG.error("日志文件夹创建失败[{}]",logPath);
            }
        }
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/common/MyRoute.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package org.ruoyi.common.wechat.web.common;
import com.jfinal.config.Routes;
import org.ruoyi.common.wechat.web.controller.*;
import org.ruoyi.common.wechat.web.interceptor.VisitLogInterceptor;
/**
 * ç®¡ç†åŽå°è·¯ç”±ç»Ÿä¸€ç®¡ç†
 * @author wesleyOne
 */
public class MyRoute extends Routes {
   @Override
   public void config() {
      //设置视图根目录
      setBaseViewPath("/WEB-INF/templates");
      //设置拦截器,前面的先执行
      addInterceptor(new VisitLogInterceptor());
      //添加路由
      add("/", IndexController.class);
      add("/rob",RobotController.class);
      add("/robwk",RobotWorkController.class);
      add("/relate",RelateController.class);
      add("/kw",KeyWordController.class);
      add("/upload",UploadController.class);
      add("/tool",ToolController.class);
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/common/OutRoute.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package org.ruoyi.common.wechat.web.common;
import com.jfinal.config.Routes;
import org.ruoyi.common.wechat.web.controller.ExtendController;
import org.ruoyi.common.wechat.web.interceptor.VisitLogInterceptor4down;
/**
 * å¯¹å¤–路由统一管理
 * @author WesleyOne
 * @create 2018/9/25
 */
public class OutRoute extends Routes {
    @Override
    public void config() {
        //设置视图根目录
        setBaseViewPath("/WEB-INF/templates");
        addInterceptor(new VisitLogInterceptor4down());
        //添加路由
        add("/ext", ExtendController.class);
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/constant/ConfigKeys.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package org.ruoyi.common.wechat.web.constant;
/**
 * @author WesleyOne
 * @create 2018/12/13
 */
public class ConfigKeys {
    /**
     * é»˜è®¤å…¨å±€å…³é”®å­—回复用昵称,该字段超过16字符防止与用户昵称冲突
     *
     * http://kf.qq.com/touch/wxappfaq/150910F322eY150910eIV32Q.html?platform=14
     * å¾®ä¿¡æ˜µç§°è®¾ç½®è§„则
     * æœ€å¤šå¯è®¾ç½®16个汉字,可设置含有中文、英文、数字、符号组合的昵称,但不建议设置特殊字符。
     * æ¸©é¦¨æç¤ºï¼š1个符号相当于一个汉字,2个数字/英文相当于1个汉字;
     */
    public static final String DEAFAULT_KEYWORD = "默认全局关键字回复用昵称-请勿修改";
    public static final String DEAFAULT_WELCOME = "默认群欢迎新人用-请勿修改";
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/constant/UploadConstant.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package org.ruoyi.common.wechat.web.constant;
import com.jfinal.kit.PathKit;
import java.io.File;
public class UploadConstant {
    public static final String IMG_FOLD = "img";
    public static final String FILE_FOLD = "file";
    public static final String IMG_URL = "/"+IMG_FOLD+"/";
    public static final String FILE_URL = "/"+FILE_FOLD+"/";
    public static final String IMG_PATH = PathKit.getWebRootPath()+ File.separator +IMG_FOLD;
    public static final String FILE_PATH = PathKit.getWebRootPath()+ File.separator +FILE_FOLD;
    public static final String IMG_PATH_SEP = IMG_PATH + File.separator;
    public static final String FILE_PATH_SEP = FILE_PATH + File.separator;
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/controller/ExtendController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,125 @@
package org.ruoyi.common.wechat.web.controller;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.ruoyi.common.wechat.itchat4j.core.CoreManage;
import org.ruoyi.common.wechat.itchat4j.utils.enums.SendMsgType;
import org.ruoyi.common.wechat.web.model.WxRobRelation;
import org.ruoyi.common.wechat.web.utils.IpUtil;
/**
 * å¯¹å¤–接口
 * @author WesleyOne
 * @create 2018/12/16
 */
public class ExtendController extends _BaseController {
    /**
     * å¯¹å¤–通用规则发消息
     * å‚æ•°:
     * ok       å¤–接唯一码
     * msg     æ¶ˆæ¯åˆ—表
     *         ç±»åž‹å‚考@see     org.ruoyi.common.wechat.itchat4j.utils.enums.SendMsgType
     *          TEXT     æ–‡æœ¬æ¶ˆæ¯ä¸²
     *          IMG      å›¾ç‰‡åä¸²ï¼ˆéœ€è¦åŽå°-通用工具-上传获取)
     *          FILE     æ–‡ä»¶åä¸²ï¼ˆéœ€è¦åŽå°-通用工具-上传获取)
     *  ä¾‹å­:
     *  {"ok":"test123",
     *   "msg":[
     *       {"type":"TEXT","body":"我是消息体"},
     *       {"type":"IMG","body":"ty6yLk3X_1545142908614.jpg"},
     *       {"type":"FILE","body":"ty6yLk3X_1545142537914.txt"},
     *   ]
     *  }
     *
     *  è¯´æ˜Ž:
     *      å‘送顺序按照列表顺序从前往后发
     *
     * è¿”回:
     * 00   æˆåŠŸ
     * 01   å¤–接码不存在
     * 02   å¤–接码失效
     * 03   IP未通过审核
     *
     */
    public void sendMsg(){
        JSONObject postParam = getPostParam();
        String outKey = postParam.getString("ok");
        String msgStr = postParam.getString("msg");
        JSONArray msgs = JSONArray.parseArray(msgStr);
        if (StringUtils.isEmpty(outKey)){
            setCode("01");
            setMsg("外接码不存在");
            renderJson();
            return;
        }
        WxRobRelation relationRecord = WxRobRelation.dao.findFirst("SELECT * FROM wx_rob_relation WHERE out_key = ? LIMIT 1", outKey);
        /**
         * æ ¡éªŒIP
         * 1.配置空则拒绝所有
         * 2.存在0.0.0.0不校验
         */
        String whiteList = relationRecord.getWhiteList();
        if (StringUtils.isEmpty(whiteList) || !relationRecord.getEnable()){
            setCode("02");
            setMsg("外接码失效或未配置白名单");
            renderJson();
            return;
        }
        String allPassIp = "0.0.0.0";
        // ä¸æ˜¯å®Œå…¨å¼€æ”¾IP并且访问IP不存在
        if (!whiteList.contains(allPassIp)){
            String outRealIp = IpUtil.getRealIp(getRequest());
            if (!whiteList.contains(outRealIp)){
                setCode("03");
                setMsg("IP未通过审核");
                renderJson();
                return;
            }
        }
        String uniqueKey = relationRecord.getUniqueKey();
        // æŸ¥çœ‹æœºå™¨æ˜¯å¦åŠ è½½å®Œæˆ
        if (!CoreManage.getInstance(uniqueKey).isAlive() || !CoreManage.getInstance(uniqueKey).isFinishInit()){
            setCode("05");
            setMsg("机器未准备完成");
            renderJson();
            return;
        }
        /**
         * æ·»åŠ åˆ°æ¶ˆæ¯é˜Ÿåˆ—
         */
        Boolean toGroup = relationRecord.getToGroup();
        String nickName = relationRecord.getNickName();
        // å•次请求最大消息数
        int maxMessages = 10;
        int msgLength = msgs.size();
        if (msgLength<maxMessages){
            maxMessages = msgLength;
        }
        // åˆ°è¿™ä¸€æ­¥é»˜è®¤è¿”回成功
        boolean result = true;
        for (int i=0;i<maxMessages;i++){
            JSONObject message = msgs.getJSONObject(i);
            String type = message.getString("type");
            String body = message.getString("body");
            CoreManage.addSendMsg4NickName(uniqueKey,nickName,body,SendMsgType.fromValue(type),toGroup);
        }
        if (!result){
            setOperateErr();
        }
        renderJson();
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/controller/IndexController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,99 @@
package org.ruoyi.common.wechat.web.controller;
import com.jfinal.kit.PropKit;
import org.apache.commons.lang3.RandomStringUtils;
import org.ruoyi.common.wechat.web.annotation.UnCheckLogin;
import org.ruoyi.common.wechat.web.cache.UserSession;
import java.util.UUID;
/**
 * @author WesleyOne
 * @create 2018/7/27
 */
public class IndexController extends _BaseController {
    public static final String WX_ROB_LOGIN_ = "WX_ROB_LOGIN_";
    public void index(){
        setAttr("username",getCookie("uid"));
        setAttr("imgdomain",PropKit.get("imgDomain"));
        renderTemplate("index.html");
    }
    @UnCheckLogin
    public void login(){
        redirect("/",false);
        // æµ‹è¯•免登录
        if (PropKit.getBoolean("devMode")){
            redirect("/loginPost?username=wxwobot&password=wxwobot",true);
            return;
        }
        renderTemplate("login.html");
    }
    /**
     * ç™»å…¥
     */
    @UnCheckLogin
    public void loginPost(){
        String sid = UUID.randomUUID().toString();
        UserSession.addUserSession("wxwobot",sid);
        addCookie("uid","wxwobot",-1);
        addCookie("sid",sid,-1);
        redirect("/",false);
        //return;
//        String username = getPara("username");
//        String password = getPara("password");
//        if (vldParamNull(username,"用户名不能为空")||
//                vldParamNull(password,"密码不能为空")){
//            return;
//        }
//
//        // èŽ·å–çœŸå®žå¯†ç ã€‚æ­¤å¤„ä¸ºäº†æ–¹ä¾¿ç›´æŽ¥ä»Žé…ç½®æ–‡ä»¶é‡ŒèŽ·å–
//        String pass = PropKit.use("passport.properties").get(username);
//        // æ¸…楚缓存,可以修改配置文件直接修改
//        PropKit.useless("passport.properties");
//
//        if (StringUtils.isNotEmpty(password) && pass != null && pass.equals(MD5Util.MD5Encrypt(password))){
//
//            //String sid = UUID.randomUUID().toString();
//            UserSession.addUserSession(username,sid);
//            addCookie("uid",username,-1);
//            addCookie("sid",sid,-1);
//            redirect("/",false);
//            return;
//        }else {
//            setAttr("error","账号密码不正确");
//            renderTemplate("login.html");
//        }
    }
    @UnCheckLogin
    public void logout(){
        String uid = getUid();
        if (uid!=null){
            UserSession.delUserSession(uid);
        }
        redirect("/login",false);
    }
    /**
     * æ¸¸å®¢ç™»å½•
     */
    @UnCheckLogin
    public void visitLogin() {
        String visitName = RandomStringUtils.randomAlphabetic(5);
        String sid = UUID.randomUUID().toString();
        UserSession.addUserSession(visitName,sid);
        addCookie("uid",visitName,-1);
        addCookie("sid",sid,-1);
        redirect("/",false);
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/controller/KeyWordController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,191 @@
package org.ruoyi.common.wechat.web.controller;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.render.JsonRender;
import org.apache.commons.lang3.StringUtils;
import org.ruoyi.common.wechat.itchat4j.api.WechatTools;
import org.ruoyi.common.wechat.web.enums.KeyMsgValueType;
import org.ruoyi.common.wechat.web.model.WxRobKeyword;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
 * TODO å…³é”®è¯æ“ä½œ
 * @author WesleyOne
 * @create 2018/12/16
 */
public class KeyWordController extends _BaseController{
    public void index(){
        String uniqueKey = getPara("uk");
        if (StringUtils.isNotEmpty(uniqueKey)){
            setAttr("search_uk",uniqueKey);
        }
        setAttr("keys",KeyMsgValueType.LIST_KV);
        renderTemplate("index.html");
    }
    public void list(){
        int rows = getParaToInt("limit", 10);
        int pageNum = getPageNum(getParaToInt("offset", 1), rows);
        String uniqueKey = getPara("uniqueKey");
        String keyData = getPara("keyData");
        String nickName = getPara("nickName");
        String typeData = getPara("typeData");
        Boolean enable = getParaToBoolean("enable");
        Boolean togrp = getParaToBoolean("togrp");
        String where = " where 1=1 ";
        if (StringUtils.isNotEmpty(uniqueKey)){
            where += " and unique_key = '"+uniqueKey + "' ";
        }
        if (StringUtils.isNotEmpty(keyData)) {
            where += " and key_data LIKE '" + keyData + "%' ";
        }
        if (StringUtils.isNotEmpty(nickName)) {
            where += " and nick_name LIKE '" + nickName + "%' ";
        }
        if (KeyMsgValueType.fromValue(typeData) != null){
            where += " and type_data = '" + typeData + "' ";
        }
        if (enable != null){
            where += " and enable = " + (enable?1:0);
        }
        if (togrp != null){
            where += " and to_group = " + (togrp?1:0);
        }
        Page<WxRobKeyword> page = WxRobKeyword.dao.paginate(pageNum, rows, "select * ",
                " from wx_rob_keyword "+where);
        setAttrs(buildPagination(page.getList(), page.getTotalRow()));
        render(new JsonRender().forIE());
    }
    public void editIndex(){
        Integer kid = getParaToInt("kid");
        WxRobKeyword kwRecord;
        boolean isEdit = true;
        List<String> groupNickNames = new ArrayList<>();
        if (kid != null){
            kwRecord = WxRobKeyword.dao.findById(kid);
        }else{
            isEdit = false;
            kwRecord = new WxRobKeyword();
            String uniqueKey = getPara("uk");
            if (StringUtils.isNotEmpty(uniqueKey)){
                kwRecord.setUniqueKey(uniqueKey);
                groupNickNames.addAll(WechatTools.getGroupNickNameList(uniqueKey));
            }
            // é»˜è®¤æ˜¾ç¤ºæ–‡æœ¬
            kwRecord.setTypeData(KeyMsgValueType.TEXT.toValue());
        }
        setAttr("isEdit",isEdit);
        setAttr("form",kwRecord);
        setAttr("keys",KeyMsgValueType.LIST_KV);
        setAttr("groupNickNames",groupNickNames);
        renderTemplate("editIndex.html");
    }
    /**
     * æ–°å¢žä¿®æ”¹
     */
    public void editKeyWord(){
        JSONObject postParam = getPostParam();
        Long id = postParam.getLong("kid");
        String uniqueKey = postParam.getString("uniqueKey");
        String keyData = postParam.getString("keyData");
        String valueData = postParam.getString("valueData");
        String nickName = postParam.getString("nickName");
        String typeData = postParam.getString("typeData");
        Boolean enable = postParam.getBoolean("enable");
        Boolean toGroup = postParam.getBoolean("toGroup");
        WxRobKeyword editRecord = new WxRobKeyword();
        if (StringUtils.isNotEmpty(keyData)){
            editRecord.setKeyData(keyData);
        }
        if (StringUtils.isNotEmpty(valueData)){
            editRecord.setValueData(valueData);
        }
        if (StringUtils.isNotEmpty(nickName)){
            editRecord.setNickName(nickName);
        }
        if (KeyMsgValueType.fromValue(typeData) != null){
            editRecord.setTypeData(typeData);
        }else {
            editRecord.setTypeData(KeyMsgValueType.TEXT.toValue());
        }
        if (enable != null){
            editRecord.setEnable(enable);
        }
        if (toGroup != null){
            editRecord.setToGroup(toGroup);
        }
        if (id != null){
            editRecord.setId(id);
            boolean update = editRecord.update();
            if (update){
                setMsg("修改成功");
            }else{
                setOperateErr("修改失败");
            }
        }else{
            // æ ¡éªŒ
            editRecord.setUniqueKey(uniqueKey);
            editRecord.setCreateTime(new Date());
            editRecord.setEnable(true);
            if (vldParamNull(editRecord.getUniqueKey(),"唯一码不能为空")){
                return;
            }
            if (vldParamNull(editRecord.getKeyData(),"关键字不能为空")){
                return;
            }
            if (vldParamNull(editRecord.getValueData(),"内容不能为空")){
                return;
            }
            if (vldParamNull(editRecord.getTypeData(),"内容类型不能为空")){
                return;
            }
            if (vldParamNull(editRecord.getNickName(),"昵称不能为空")){
                return;
            }
            if (vldParamNull(editRecord.getToGroup(),"群聊好友未选择")){
                return;
            }
            boolean save = editRecord.save();
            if (save){
                setMsg("新增成功");
            }else{
                setOperateErr("新增失败");
            }
        }
        renderJson();
    }
    /**
     * åˆ é™¤å…³é”®å­—
     */
    public void delKeyWord(){
        String kid = getPara("kid");
        boolean delete = WxRobKeyword.dao.deleteById(kid);
        if (delete){
            setMsg("删除成功");
        }else{
            setOperateErr("删除失败");
        }
        renderJson();
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/controller/RelateController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,179 @@
package org.ruoyi.common.wechat.web.controller;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.render.JsonRender;
import org.apache.commons.lang3.StringUtils;
import org.ruoyi.common.wechat.itchat4j.api.WechatTools;
import org.ruoyi.common.wechat.web.model.WxRobRelation;
import org.ruoyi.common.wechat.web.utils.UUIDShortUtil;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
 * TODO å…³è”配置
 * @author WesleyOne
 * @create 2018/12/16
 */
public class RelateController extends _BaseController {
    public void index(){
        String outKey = getPara("ok");
        if (StringUtils.isNotEmpty(outKey)){
            setAttr("search_ok",outKey);
        }
        String searchUk = getPara("uk");
        if (StringUtils.isNotEmpty(searchUk)){
            setAttr("search_uk",searchUk);
        }
        renderTemplate("index.html");
    }
    public void list(){
        int rows = getParaToInt("limit", 10);
        int pageNum = getPageNum(getParaToInt("offset", 1), rows);
        String outKey = getPara("outKey");
        String uniqueKey = getPara("uniqueKey");
        String nickName = getPara("nickName");
        Boolean enable = getParaToBoolean("enable");
        Boolean togrp = getParaToBoolean("togrp");
        String where = " where 1=1 ";
        if (StringUtils.isNotEmpty(outKey)) {
            where += " and out_key = '" + outKey + "' ";
        }
        if (StringUtils.isNotEmpty(uniqueKey)){
            where += " and unique_key = '"+uniqueKey + "' ";
        }
        if (StringUtils.isNotEmpty(nickName)) {
            where += " and nick_name LIKE '" + nickName + "%' ";
        }
        if (enable != null){
            where += " and enable = " + (enable?1:0);
        }
        if (togrp != null){
            where += " and to_group = " + (togrp?1:0);
        }
        Page<WxRobRelation> page = WxRobRelation.dao.paginate(pageNum, rows, "select * ",
                " from wx_rob_relation "+where);
        setAttrs(buildPagination(page.getList(), page.getTotalRow()));
        render(new JsonRender().forIE());
    }
    public void editIndex(){
        Integer kid = getParaToInt("kid");
        WxRobRelation wxRobRelation;
        boolean isEdit = true;
        List<String> groupNickNames = new ArrayList<>();
        if (kid != null){
            wxRobRelation = WxRobRelation.dao.findById(kid);
        }else{
            isEdit = false;
            wxRobRelation = new WxRobRelation();
            String uniqueKey = getPara("uk");
            String nickName = getPara("nk");
            Boolean toGroup = getParaToBoolean("tgb");
            if (StringUtils.isNotEmpty(uniqueKey)){
                wxRobRelation.setUniqueKey(uniqueKey);
                groupNickNames.addAll(WechatTools.getGroupNickNameList(uniqueKey));
            }
            if (StringUtils.isNotEmpty(nickName)){
                wxRobRelation.setNickName(nickName);
            }
            if (toGroup != null){
                wxRobRelation.setToGroup(toGroup);
            }else{
                wxRobRelation.setToGroup(true);
            }
        }
        setAttr("isEdit",isEdit);
        setAttr("form",wxRobRelation);
        setAttr("groupNickNames",groupNickNames);
        renderTemplate("editIndex.html");
    }
    /**
     * ç¼–辑外部id关联
     */
    public void editRelate(){
        JSONObject postParam = getPostParam();
        Long id = postParam.getLong("kid");
        String uniqueKey = postParam.getString("uniqueKey");
        String nickName = postParam.getString("nickName");
        String whiteList = postParam.getString("whiteList");
        Boolean enable = postParam.getBoolean("enable");
        Boolean toGroup = postParam.getBoolean("toGroup");
        WxRobRelation editRecord = new WxRobRelation();
        if (StringUtils.isNotEmpty(nickName)){
            editRecord.setNickName(nickName);
        }
        if (enable != null){
            editRecord.setEnable(enable);
        }
        if (toGroup != null){
            editRecord.setToGroup(toGroup);
        }
        if (StringUtils.isNotEmpty(whiteList)){
            editRecord.setWhiteList(whiteList);
        }
        if (id != null){
            editRecord.setId(id);
            boolean update = editRecord.update();
            if (update){
                setMsg("修改成功");
            }else{
                setOperateErr("修改失败");
            }
        }else{
            // æ ¡éªŒ
            editRecord.setUniqueKey(uniqueKey);
            editRecord.setCreateTime(new Date());
            editRecord.setEnable(true);
            if (vldParamNull(editRecord.getUniqueKey(),"唯一码不能为空")){
                return;
            }
            if (vldParamNull(editRecord.getNickName(),"昵称不能为空")){
                return;
            }
            if (vldParamNull(editRecord.getToGroup(),"群聊好友未选择")){
                return;
            }
            boolean isSuccess = false;
            int maxTime = 5;
            while (!isSuccess && maxTime >0){
                String outKey = UUIDShortUtil.generateShortUuid();
                editRecord.setOutKey(outKey);
                isSuccess = editRecord.save();
                maxTime--;
            }
            if (isSuccess){
                setMsg("新增成功");
            }else{
                setOperateErr("新增失败");
            }
        }
        renderJson();
    }
    /**
     * åˆ é™¤å¤–部id关联
     */
    public void delRelate(){
        String kid = getPara("kid");
        boolean delete = WxRobRelation.dao.deleteById(kid);
        if (delete){
            setMsg("删除成功");
        }else{
            setOperateErr("删除失败");
        }
        renderJson();
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/controller/RobotController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,223 @@
package org.ruoyi.common.wechat.web.controller;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.render.JsonRender;
import org.apache.commons.lang3.StringUtils;
import org.ruoyi.common.wechat.itchat4j.core.Core;
import org.ruoyi.common.wechat.itchat4j.core.CoreManage;
import org.ruoyi.common.wechat.web.base.BaseException;
import org.ruoyi.common.wechat.web.model.WxRobConfig;
import org.ruoyi.common.wechat.web.utils.UUIDShortUtil;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
 * æœºå™¨äººç›¸å…³ç®¡ç†æŽ¥å£
 * @author WesleyOne
 * @create 2018/12/16
 */
public class RobotController extends _BaseController {
    /**
     * æœºå™¨äººé¡µé¢
     */
    public void index(){
        renderTemplate("index.html");
    }
    /**
     * æœºå™¨äººåˆ—表
     * åˆ†é¡µï¼Œæœç´¢æ¡ä»¶
     */
    public void list(){
        int rows = getParaToInt("limit", 10);
        int pageNum = getPageNum(getParaToInt("offset", 1), rows);
        String searchUniqueKey = getPara("uniqueKey");
        String remark = getPara("remark");
        Boolean enable = getParaToBoolean("enable");
        String where = " where 1=1 ";
        if (StringUtils.isNotEmpty(searchUniqueKey)){
            where += " and unique_key = '"+searchUniqueKey + "' ";
        }
        if (StringUtils.isNotEmpty(remark)) {
            where += " and remark like '" + remark + "%' ";
        }
        if (enable != null){
            where += " and enable = " + (enable?1:0);
        }
        Page<WxRobConfig> page = WxRobConfig.dao.paginate(pageNum, rows, "select * ",
                " from wx_rob_config "+where);
        //其他处理
        List<WxRobConfig> dataList = page.getList();
        if (CollectionUtil.isNotEmpty(dataList)){
            for (WxRobConfig conf: dataList){
                // èŽ·å–æœºå™¨äººçŠ¶æ€
                String uniqueKey = conf.getUniqueKey();
                conf.setActive(CoreManage.isActive(uniqueKey));
            }
        }
        setAttrs(buildPagination(dataList, page.getTotalRow()));
        render(new JsonRender().forIE());
    }
    /**
     * æœºå™¨äººé¡µé¢
     */
    public void addIndex(){
        renderTemplate("addIndex.html");
    }
    /**
     * æ·»åŠ æœºå™¨äºº
     */
    public void addRob(){
        JSONObject postParam = getPostParam();
        String remark = postParam.getString("remark");
        if (vldParamNull(remark,"微信号不能为空")){
            return;
        }
        Record remarkRecord = Db.findFirst("SELECT remark FROM wx_rob_config WHERE remark = ? LIMIT 1", remark);
        if (vldParamNull(remarkRecord != null,"备注已存在")){
            return;
        }
        WxRobConfig bean = new WxRobConfig();
        bean.setRemark(remark)
                .setCreateTime(new Date())
                .setUpdateTime(new Date())
                .setToFriend(false)
                .setToGroup(true)
                .setFromOut(false)
                .setDefaultFriend(false)
                .setDefaultGroup(false);
        boolean isSuccess = false;
        int maxTime = 5;
        while (!isSuccess && maxTime >0){
            String uniKey = UUIDShortUtil.generateShortUuid();
            bean.setUniqueKey(uniKey);
            isSuccess = bean.save();
            maxTime--;
        }
        if (!isSuccess){
            setOperateErr();
        }else{
            setData(bean);
        }
        renderJson();
    }
    /**
     * æœºå™¨äººå¯åŠ¨ç¦æ­¢å¼€å…³ï¼Œå‘é€ç¾¤èŠå¼€å…³ï¼Œå‘é€å¥½å‹å¼€å…³,对外接口消息开关
     */
    public void change(){
        JSONObject postParam = getPostParam();
        Long id = postParam.getLong("rid");
        String type = postParam.getString("type");
        Boolean state = postParam.getBoolean("state");
        if (id == null || StringUtils.isEmpty(type) || state == null){
            setOperateErr();
            renderJson();
            return;
        }
        WxRobConfig config = new WxRobConfig();
        config.setId(id);
        if ("enable".equals(type)){
            config.setEnable(state);
        }else if ("tofrd".equals(type)){
            config.setToFriend(state);
        }else if ("togrp".equals(type)){
            config.setToGroup(state);
        }else if ("fromout".equals(type)) {
            config.setFromOut(state);
        }else if ("default_group".equals(type)){
            config.setDefaultGroup(state);
        }else if ("default_friend".equals(type)){
            config.setDefaultFriend(state);
        }else {
            setOperateErr("非法操作");
            render(new JsonRender().forIE());
            return;
        }
        config.setUpdateTime(new Date());
        boolean update = config.update();
        if (!update){
            setOperateErr();
        }else{
            setData(update);
        }
        renderJson();
    }
    /**
     * ä¿®æ”¹å¤‡æ³¨
     */
    public void changeRemark(){
        JSONObject postParam = getPostParam();
        Long id = postParam.getLong("rid");
        String remark = postParam.getString("remark");
        if (vldParamNull(id,"ID不能为空")){
            return;
        }
        if (vldParamNull(remark,"备注不能为空")){
            return;
        }
        Record remarkRecord = Db.findFirst("SELECT remark FROM wx_rob_config WHERE remark = ? LIMIT 1", remark);
        if (vldParamNull(remarkRecord != null,"备注已存在")){
            return;
        }
        WxRobConfig config = new WxRobConfig();
        config.setId(id);
        config.setRemark(remark);
        boolean update = config.update();
        if (!update){
            setOperateErr();
        }else{
            setData(update);
        }
        renderJson();
    }
    /**
     * å‘送页面
     */
    public void sendIndex() throws BaseException {
        String uniqueKey = getUniqueKey();
        Core core = CoreManage.getInstance(uniqueKey);
        List<JSONObject> sourceSendList = new ArrayList<>();
        sourceSendList.addAll( core.getGroupList());
        sourceSendList.addAll( core.getContactList());
        List<JSONObject> targetList = new ArrayList<>();
        JSONObject filehelper = new JSONObject();
        filehelper.put("UserName","filehelper");
        filehelper.put("NickName","文件传输助手");
        targetList.add(filehelper);
        for (JSONObject jsonObject : sourceSendList) {
            JSONObject newObject = new JSONObject();
            if (StringUtils.isEmpty(jsonObject.getString("NickName"))){
                continue;
            }
            newObject.put("NickName",jsonObject.getString("NickName"));
            newObject.put("UserName",jsonObject.getString("UserName"));
            targetList.add(newObject);
        }
        setAttr("uniqueKey",uniqueKey);
        setAttr("targetList",targetList);
        renderTemplate("sendIndex.html");
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/controller/RobotWorkController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,179 @@
package org.ruoyi.common.wechat.web.controller;
import com.alibaba.fastjson.JSONObject;
import org.ruoyi.common.wechat.itchat4j.api.WechatTools;
import org.ruoyi.common.wechat.itchat4j.controller.LoginController;
import org.ruoyi.common.wechat.itchat4j.core.CoreManage;
import org.ruoyi.common.wechat.itchat4j.service.impl.LoginServiceImpl;
import org.ruoyi.common.wechat.itchat4j.utils.enums.SendMsgType;
import org.ruoyi.common.wechat.web.base.BaseException;
import java.io.IOException;
import java.util.List;
/**
 * @author WesleyOne
 * @create 2018/12/16
 */
public class RobotWorkController extends _BaseController {
    /**
     * èŽ·å–çŠ¶æ€
     * @throws BaseException
     */
    public void getStatus() throws BaseException {
        String uniqueKey = getUniqueKey();
        boolean wechatStatus = WechatTools.getWechatStatus(uniqueKey);
        setData(wechatStatus);
        renderJson();
    }
    /**
     * ç™»å½•第一步,获取二维码链接
     * @throws BaseException
     */
    public void getQr() throws BaseException, IOException {
        String uniqueKey = getUniqueKey();
        LoginController login = new LoginController(uniqueKey);
        String qrSrc = login.login_1();
        setData(qrSrc);
        renderJson();
    }
    /**
     * ç™»å½•第二步,确认登录状态
     * @throws BaseException
     */
    public void login() throws BaseException {
        String uniqueKey = getUniqueKey();
        LoginController login = new LoginController(uniqueKey);
        boolean result = login.login_2();
        if (result){
        }else{
            setOperateErr();
        }
        renderJson();
    }
    /**
     * ç™»å½•第三步,确认登录及初始化信息
     * @throws BaseException
     */
    public void init() throws BaseException {
        String uniqueKey = getUniqueKey();
        LoginController login = new LoginController(uniqueKey);
        boolean loginResult = login.login_3();
        if (loginResult){
            setMsg("登录成功");
        }else{
            setMsg("登录失败,关闭二维码后重新打开");
        }
        renderJson();
    }
    /**
     * é€€å‡º
     * @throws BaseException
     */
    public void logout() throws BaseException {
        String uniqueKey = getUniqueKey();
        WechatTools.logout(uniqueKey);
        renderJson();
    }
    /**
     * èŽ·å–ç¾¤æ˜µç§°
     */
    public void getGroupNickNames() throws BaseException {
        String uniqueKey = getUniqueKey();
        List<String> groupNickNameList = WechatTools.getGroupNickNameList(uniqueKey);
        setData(groupNickNameList);
        renderJson();
    }
    /**
     * èŽ·å–å¥½å‹æ˜µç§°
     */
    public void getContactNickNames() throws BaseException {
        String uniqueKey = getUniqueKey();
        List<String> contactNickNameList = WechatTools.getContactNickNameList(uniqueKey);
        setData(contactNickNameList);
        renderJson();
    }
    public void getGroups() throws BaseException {
        String uniqueKey = getUniqueKey();
        List<JSONObject> groupList = WechatTools.getGroupList(uniqueKey);
        setData(groupList);
        renderJson();
    }
    public void getContacts() throws BaseException {
        String uniqueKey = getUniqueKey();
        List<JSONObject> contactList = WechatTools.getContactList(uniqueKey);
        setData(contactList);
        renderJson();
    }
    public void getCore() throws BaseException {
        String uniqueKey = getUniqueKey();
        setData(CoreManage.getInstance(uniqueKey));
        renderJson();
    }
    /**
     * å¼ºåˆ¶åˆ·æ–°é€šè®¯å½•
     */
    public void gct() throws BaseException {
        String uniqueKey = getUniqueKey();
        LoginServiceImpl loginService = new LoginServiceImpl(uniqueKey);
        loginService.webWxGetContact();
        renderJson();
    }
    /**
     * åˆ·æ–°é€šè®¯å½•详情
     * @throws BaseException
     */
    public void ggp() throws BaseException {
        String uniqueKey = getUniqueKey();
        LoginServiceImpl loginService = new LoginServiceImpl(uniqueKey);
        loginService.WebWxBatchGetContact();
        renderJson();
    }
    /**
     * é‡å¯
     * @throws BaseException
     */
    public void reboot() throws BaseException {
        String uniqueKey = getUniqueKey();
        LoginController login = new LoginController(uniqueKey);
        boolean loginResult = login.reboot();
        setData(loginResult);
        renderJson();
    }
    /**
     * æ‰‹åŠ¨å¤‡ä»½çƒ­ç™»å½•ä¿¡æ¯
     */
    public void manualCopy(){
        CoreManage.persistence();
        renderJson();
    }
    public void testSend() throws BaseException {
        JSONObject postParam = getPostParam();
        String uniqueKey = postParam.getString("uniqueKey");
        String data = postParam.getString("valueData");
        String userName = postParam.getString("userName");
        String typeData = postParam.getString("typeData");
        CoreManage.addSendMsg4UserName(uniqueKey,userName,data, SendMsgType.fromValue(typeData));
        renderJson();
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/controller/ToolController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package org.ruoyi.common.wechat.web.controller;
/**
 * é€šç”¨å·¥å…·
 * @author WesleyOne
 * @create 2018/12/24
 */
public class ToolController extends _BaseController {
    public void index(){
        renderTemplate("index.html");
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/controller/UploadController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
package org.ruoyi.common.wechat.web.controller;
import com.jfinal.upload.UploadFile;
import org.ruoyi.common.wechat.web.constant.UploadConstant;
import java.io.File;
/**
 * @author WesleyOne
 * @create 2018/12/14
 */
public class UploadController extends _BaseController {
    public void img2local(){
        UploadFile file = getFile();
        String fn = getPara("fn", "");
        String originalFileName = file.getOriginalFileName();
        int i = file.getOriginalFileName().lastIndexOf(".")+1;
        String fileType = originalFileName.substring(i);
        String fileName = fn + "_" + System.currentTimeMillis() + "." + fileType;
        String newFilePath = UploadConstant.IMG_PATH+File.separator+fileName;
        file.getFile().renameTo(new File(newFilePath));
        setAttr("name",fileName);
        renderJson();
    }
    public void file2local(){
        UploadFile file = getFile();
        String fn = getPara("fn", "");
        String originalFileName = file.getOriginalFileName();
        int i = file.getOriginalFileName().lastIndexOf(".")+1;
        String fileType = originalFileName.substring(i);
        String fileName = fn + "_" + System.currentTimeMillis() + "." + fileType;
        String newFilePath = UploadConstant.FILE_PATH+File.separator+fileName;
        file.getFile().renameTo(new File(newFilePath));
        setAttr("name",fileName);
        renderJson();
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/controller/_BaseController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,199 @@
package org.ruoyi.common.wechat.web.controller;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.core.Controller;
import com.jfinal.core.NotAction;
import com.jfinal.kit.HttpKit;
import com.jfinal.kit.StrKit;
import org.apache.commons.lang3.StringUtils;
import org.ruoyi.common.wechat.web.base.BaseError;
import org.ruoyi.common.wechat.web.base.BaseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.Cookie;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author WesleyOne
 * @create 2018/7/27
 */
public class _BaseController extends Controller {
    public final Logger LOG = LoggerFactory.getLogger(this.getClass());
    /**
     * é€šç”¨éªŒè¯
     * @param result    true说明验证不通过
     * @param code
     * @param errorMsg
     */
    @NotAction
    public boolean vldParam(boolean result, String code, String errorMsg){
        if (result){
            setAttr("code",code);
            setAttr("message",errorMsg);
            this.renderJson();
            return true;
        }
        return false;
    }
    @NotAction
    public boolean vldParam(boolean result, BaseError baseError){
        if (result){
            return vldParam(true,baseError.getCode(),baseError.getMsg());
        }
        return false;
    }
    @NotAction
    public boolean vldParam(boolean result, String errMsg){
        if (result){
            return vldParam(true,BaseError.NORMAL_ERR.getCode(),errMsg);
        }
        return false;
    }
    /**
     * å‚数非空判断
     * @param paramValue
     * @param baseError
     * @return
     */
    @NotAction
    public boolean vldParamNull(String paramValue, BaseError baseError){
        if (StrKit.isBlank(paramValue)) {
            return vldParam(true,baseError.getCode(),baseError.getMsg());
        }
        return false;
    }
    @NotAction
    public boolean vldParamNull(String paramValue, String errMsg){
        if (StrKit.isBlank(paramValue)) {
            return vldParam(true,BaseError.NORMAL_ERR.getCode(),errMsg);
        }
        return false;
    }
    /**
     * å‚数非空判断
     * @param paramValue
     * @param baseError
     * @return
     */
    @NotAction
    public boolean vldParamNull(Object paramValue, BaseError baseError){
        if (paramValue == null) {
            return vldParam(true,baseError.getCode(),baseError.getMsg());
        }
        return false;
    }
    @NotAction
    public boolean vldParamNull(Object paramValue, String errMsg){
        if (paramValue == null) {
            return vldParam(true,BaseError.NORMAL_ERR.getCode(),errMsg);
        }
        return false;
    }
    @NotAction
    public void setData(Object o){
        this.setAttr("data",o);
    }
    @NotAction
    public void setCount(Object o){
        this.setAttr("_count",o);
    }
    @NotAction
    public void setCode(String code){
        this.setAttr("code",code);
    }
    @NotAction
    public void setMsg(String msg){
        this.setAttr("message",msg);
    }
    @NotAction
    public void setOperateErr(String msg){
        this.setAttr("code",BaseError.OPERATION_ERR.getCode());
        this.setAttr("message",msg);
    }
    @NotAction
    public void setOperateErr(){
        this.setAttr("code",BaseError.OPERATION_ERR.getCode());
        this.setAttr("message",BaseError.OPERATION_ERR.getMsg());
    }
    @NotAction
    public void setDeleteErr(){
        this.setAttr("code",BaseError.OPERATION_ERR.getCode());
        this.setAttr("message",BaseError.OPERATION_ERR.getMsg());
    }
    @NotAction
    public void addCookie(String key,String value,int second) {
        Cookie cookie = new Cookie(key,value);
        cookie.setMaxAge(second);
        cookie.setPath("/");
        setCookie(cookie);
    }
    @NotAction
    public JSONObject getPostParam(){
        String jsonString= HttpKit.readData(getRequest());
        return JSONObject.parseObject(jsonString);
    }
    @NotAction
    public String getUid(){
        return this.getCookie("uid");
    }
    /**
     * åˆ†é¡µå¤„理
     * @param list
     * @param count
     * @return
     */
    @SuppressWarnings("rawtypes")
    @NotAction
    protected Map<String, Object> buildPagination(List list, Integer count) {
        return buildPagination(list, count, null);
    }
    @SuppressWarnings("rawtypes")
    @NotAction
    protected Map<String, Object> buildPagination(List list, Integer count,
                                                  List<Map<String, Object>> footer) {
        Map<String, Object> map = new HashMap<String, Object>(4);
        map.put("total", count);
        map.put("rows", list);
        if (footer != null){
            map.put("footer", footer);
        }
        return map;
    }
    @NotAction
    protected static int getPageNum(int pageNum,int rows){
        int pageNumber = pageNum / rows + 1;
        return pageNumber;
    }
    /**
     * èŽ·å–UniqueKey
     * @return
     */
    @NotAction
    public String getUniqueKey() throws BaseException {
        String uniqueKey = getPara("_ck", "");
        if (StringUtils.isEmpty(uniqueKey)){
            throw new BaseException("机器唯一码为空");
        }
        return uniqueKey;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/enums/KeyMsgValueType.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
package org.ruoyi.common.wechat.web.enums;
import com.jfinal.plugin.activerecord.Record;
import java.util.*;
public enum KeyMsgValueType {
    IMG("IMG", "图片"),
    FILE("FILE", "文件"),
    TEXT("TEXT", "纯文本");
    private String value;
    private String name;
    KeyMsgValueType(String value, String name) {
        this.value = value;
        this.name = name;
    }
    private static final Map<String, KeyMsgValueType> lookup = new HashMap<>();
    public static List<Record> LIST_KV = new ArrayList<>();
    static {
        for (KeyMsgValueType s : EnumSet.allOf(KeyMsgValueType.class)) {
            lookup.put(s.toValue(), s);
            LIST_KV.add(new Record().set("v", s.toValue()).set("n", s.toName()));
        }
    }
    public String toValue() {
        return this.value;
    }
    public String toName() {
        return this.name;
    }
    public static KeyMsgValueType fromValue(String value) {
        return lookup.get(value);
    }
    public boolean equal(KeyMsgValueType type) {
        return type != null && this.toValue().equals(type.toValue());
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/interceptor/ExceptionInterceptor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
package org.ruoyi.common.wechat.web.interceptor;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import org.ruoyi.common.wechat.web.base.BaseError;
import org.ruoyi.common.wechat.web.base.BaseException;
import org.ruoyi.common.wechat.web.base.BaseResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * å…¨å±€å¼‚常拦截
 * @author WesleyOne
 * @create 2018/7/28
 */
public class ExceptionInterceptor implements Interceptor {
    private static final Logger LOG   = LoggerFactory.getLogger(ExceptionInterceptor.class);
    @Override
    public void intercept(Invocation me) {
        try {
            me.getController().setAttr("code","00");
            me.getController().setAttr("message","操作成功");
            me.invoke();
        }
        catch (Exception e) {
            LOG.error(e.getMessage(),e);
            BaseResponse resp = new BaseResponse();
            Throwable cause = e.getCause();
            String ajax = me.getController().getRequest().getHeader("X-Requested-With");
            //判断ajax请求还是页面请求
            if ("XMLHttpRequest".equals(ajax)){
                if (cause instanceof BaseException) {
                    resp.setCode(((BaseException) cause).getCode());
                    resp.setMessage(cause.getMessage());
                } else{
                    resp.setCode(BaseError.SYSTEM_ERR.getCode());
                    resp.setMessage(BaseError.SYSTEM_ERR.getMsg());
                }
                me.getController().renderJson(resp);
                return;
            }else{
                //默认系统500页面,添加第二个参数可自行添加500页面
                me.getController().renderError(500);
                return;
            }
        }
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/interceptor/VisitLogInterceptor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,79 @@
package org.ruoyi.common.wechat.web.interceptor;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import org.ruoyi.common.wechat.web.annotation.UnCheckLogin;
import org.ruoyi.common.wechat.web.cache.UserSession;
import org.ruoyi.common.wechat.web.utils.IpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
 * ç®¡ç†åŽå°æ“ä½œæ—¥å¿—
 * @author admin
 */
public class VisitLogInterceptor implements Interceptor {
   public static final Logger LOG = LoggerFactory.getLogger(VisitLogInterceptor.class);
   @Override
   public void intercept(Invocation inv) {
      String requestUrl = inv.getActionKey();
      String uid = inv.getController().getCookie("uid");
      String sid = inv.getController().getCookie("sid");
      String ip = IpUtil.getRealIp(inv.getController().getRequest());
        LOG.info("{} - {} - {} æ“ä½œäº† {}",ip,uid,sid,requestUrl);
      inv.getController().setAttr("active",inv.getController().getControllerKey());
      //找到不需要登录的action
      Class controllerClass = inv.getController().getClass();
      UnCheckLogin methodOwn = getControllerMethodUnLoginOwn(controllerClass, inv.getMethodName());
      if (methodOwn != null) {
         LOG.info("不需要登录,requestUrl=" + requestUrl);
         inv.invoke();
         return;
      }
      boolean isLogin = UserSession.checkUserSession(uid,sid);
      if (!isLogin){
         //未登入
         inv.getController().redirect("/login",false);
         return;
      }
      long start = System.currentTimeMillis();
      inv.invoke();
      long l = System.currentTimeMillis() - start;
      if (l > 1000*2){
         LOG.warn("请求 {} ,连接时长 {} ms",requestUrl,l);
      }
   }
   //--------------以下是内部方法-----------
   private UnCheckLogin getControllerMethodUnLoginOwn(Class controllerClass, String methodName) {
      for (Method method : controllerClass.getMethods()) {
         if (methodName.equals(method.getName())) {
            return getUnLogin(method);
         }
      }
      return null;
   }
   private UnCheckLogin getUnLogin(Method method) {
      Annotation[] annotations = method.getAnnotations();
      for (Annotation annt : annotations) {
         if (annt instanceof UnCheckLogin) {
            UnCheckLogin own = (UnCheckLogin) annt;
            return own;
         }
      }
      return null;
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/interceptor/VisitLogInterceptor4down.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
package org.ruoyi.common.wechat.web.interceptor;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import org.ruoyi.common.wechat.web.utils.IpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * å¯¹å¤–接口访问日志
 * @author WesleyOne
 * @create 2018/9/25
 */
public class VisitLogInterceptor4down implements Interceptor {
    public static final Logger LOG = LoggerFactory.getLogger(VisitLogInterceptor4down.class);
    @Override
    public void intercept(Invocation inv) {
        String ip = IpUtil.getRealIp(inv.getController().getRequest());
        StringBuffer requestURL = inv.getController().getRequest().getRequestURL();
        String queryString = inv.getController().getRequest().getQueryString();
        LOG.info("{} æ“ä½œäº† {} {}",ip,requestURL,queryString);
        inv.invoke();
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/model/WxRobConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package org.ruoyi.common.wechat.web.model;
import org.ruoyi.common.wechat.web.model.base.BaseWxRobConfig;
/**
 * Generated by JFinal.
 */
@SuppressWarnings("serial")
public class WxRobConfig extends BaseWxRobConfig<WxRobConfig> {
    public static final WxRobConfig dao = new WxRobConfig().dao();
    private boolean isActive;
    public boolean isActive() {
        return isActive;
    }
    public void setActive(boolean active) {
        isActive = active;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/model/WxRobKeyword.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
package org.ruoyi.common.wechat.web.model;
import org.ruoyi.common.wechat.web.model.base.BaseWxRobKeyword;
/**
 * Generated by JFinal.
 */
@SuppressWarnings("serial")
public class WxRobKeyword extends BaseWxRobKeyword<WxRobKeyword> {
    public static final WxRobKeyword dao = new WxRobKeyword().dao();
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/model/WxRobRelation.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
package org.ruoyi.common.wechat.web.model;
import org.ruoyi.common.wechat.web.model.base.BaseWxRobRelation;
/**
 * Generated by JFinal.
 */
@SuppressWarnings("serial")
public class WxRobRelation extends BaseWxRobRelation<WxRobRelation> {
    public static final WxRobRelation dao = new WxRobRelation().dao();
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/model/_JFinalDemoGenerator.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,72 @@
package org.ruoyi.common.wechat.web.model;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.dialect.MysqlDialect;
import com.jfinal.plugin.activerecord.generator.Generator;
import com.jfinal.plugin.druid.DruidPlugin;
import org.ruoyi.common.wechat.web.common.MyConfig;
import javax.sql.DataSource;
/**
 * æœ¬ demo ä»…表达最为粗浅的 jfinal ç”¨æ³•,更为有价值的实用的企业级用法
 * è¯¦è§ JFinal ä¿±ä¹éƒ¨: http://jfinal.com/club
 *
 * åœ¨æ•°æ®åº“表有任何变动时,运行一下 main æ–¹æ³•,极速响应变化进行代码重构
 */
public class _JFinalDemoGenerator {
//   public static DataSource getDataSource() {
////      PropKit.use("appConfig.properties");
////      DruidPlugin druidPlugin =  new DruidPlugin(PropKit.get("jdbcUrl"), PropKit.get("user"), PropKit.get("password").trim(),PropKit.get("jdbcDriverSqlServe"));
////      DruidPlugin druidPlugin = new DruidPlugin("jdbc:mysql://127.0.0.1:3306/wxwobot?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull","root", "root");
//      DruidPlugin druidPlugin = new DruidPlugin("jdbc:mysql://localhost:3306/wxwobot?characterEncoding=utf8&useSSL=false&zeroDateTimeBehavior=convertToNull",
//            "root", "root");
//      druidPlugin.start();
//      return druidPlugin.getDataSource();
//   }
   public static DataSource getDataSource() {
      DruidPlugin druidPlugin = MyConfig.createDruidPlugin();
      druidPlugin.start();
      return druidPlugin.getDataSource();
   }
   public static void main(String[] args) {
      PropKit.use("appConfig.properties");
      // base model æ‰€ä½¿ç”¨çš„包名
      String baseModelPackageName = "org.ruoyi.common.wechat.web.model.base";
      // base model æ–‡ä»¶ä¿å­˜è·¯å¾„
      String baseModelOutputDir = PathKit.getWebRootPath() + "/src/main/java/org.ruoyi.common.wechat/web/model/base";
      // model æ‰€ä½¿ç”¨çš„包名 (MappingKit é»˜è®¤ä½¿ç”¨çš„包名)
      String modelPackageName = "org.ruoyi.common.wechat.web.model";
      // model æ–‡ä»¶ä¿å­˜è·¯å¾„ (MappingKit ä¸Ž DataDictionary æ–‡ä»¶é»˜è®¤ä¿å­˜è·¯å¾„)
      String modelOutputDir = baseModelOutputDir + "/..";
      // åˆ›å»ºç”Ÿæˆå™¨
      Generator generator = new Generator(getDataSource(), baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir);
      // è®¾ç½®æ˜¯å¦ç”Ÿæˆé“¾å¼ setter æ–¹æ³•
      generator.setGenerateChainSetter(false);
      // æ·»åŠ ä¸éœ€è¦ç”Ÿæˆçš„è¡¨å
      generator.addExcludedTable();
      // è®¾ç½®æ˜¯å¦åœ¨ Model ä¸­ç”Ÿæˆ dao å¯¹è±¡
      generator.setGenerateDaoInModel(false);
      // è®¾ç½®æ˜¯å¦ç”Ÿæˆé“¾å¼ setter æ–¹æ³•
      generator.setGenerateChainSetter(true);
      // è®¾ç½®æ˜¯å¦ç”Ÿæˆå­—典文件
      generator.setGenerateDataDictionary(false);
      // è®¾ç½®éœ€è¦è¢«ç§»é™¤çš„表名前缀用于生成modelName。例如表名 "osc_user",移除前缀 "osc_"后生成的model名为 "User"而非 OscUser
//      generator.setRemovedTableNamePrefixes("t_");
      generator.setDialect(new MysqlDialect());
      // ç”Ÿæˆ
      generator.generate();
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/model/_MappingKit.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package org.ruoyi.common.wechat.web.model;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
/**
 * Generated by JFinal, do not modify this file.
 * <pre>
 * Example:
 * public void configPlugin(Plugins me) {
 *     ActiveRecordPlugin arp = new ActiveRecordPlugin(...);
 *     _MappingKit.mapping(arp);
 *     me.add(arp);
 * }
 * </pre>
 */
public class _MappingKit {
   public static void mapping(ActiveRecordPlugin arp) {
      arp.addMapping("wx_rob_config", "id", WxRobConfig.class);
      arp.addMapping("wx_rob_keyword", "id", WxRobKeyword.class);
      arp.addMapping("wx_rob_relation", "id", WxRobRelation.class);
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/model/base/BaseWxRobConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,111 @@
package org.ruoyi.common.wechat.web.model.base;
import com.jfinal.plugin.activerecord.IBean;
import com.jfinal.plugin.activerecord.Model;
/**
 * Generated by JFinal, do not modify this file.
 */
@SuppressWarnings({"serial", "unchecked"})
public abstract class BaseWxRobConfig<M extends BaseWxRobConfig<M>> extends Model<M> implements IBean {
   public M setId(Long id) {
      set("id", id);
      return (M)this;
   }
   public Long getId() {
      return getLong("id");
   }
   public M setUniqueKey(String uniqueKey) {
      set("unique_key", uniqueKey);
      return (M)this;
   }
   public String getUniqueKey() {
      return getStr("unique_key");
   }
   public M setRemark(String remark) {
      set("remark", remark);
      return (M)this;
   }
   public String getRemark() {
      return getStr("remark");
   }
   public M setCreateTime(java.util.Date createTime) {
      set("create_time", createTime);
      return (M)this;
   }
   public java.util.Date getCreateTime() {
      return get("create_time");
   }
   public M setUpdateTime(java.util.Date updateTime) {
      set("update_time", updateTime);
      return (M)this;
   }
   public java.util.Date getUpdateTime() {
      return get("update_time");
   }
   public M setToFriend(Boolean toFriend) {
      set("to_friend", toFriend);
      return (M)this;
   }
   public Boolean getToFriend() {
      return get("to_friend");
   }
   public M setToGroup(Boolean toGroup) {
      set("to_group", toGroup);
      return (M)this;
   }
   public Boolean getToGroup() {
      return get("to_group");
   }
   public M setDefaultFriend(Boolean defaultFriend) {
      set("default_friend", defaultFriend);
      return (M)this;
   }
   public Boolean getDefaultFriend() {
      return get("default_friend");
   }
   public M setDefaultGroup(Boolean defaultGroup) {
      set("default_group", defaultGroup);
      return (M)this;
   }
   public Boolean getDefaultGroup() {
      return get("default_group");
   }
   public M setFromOut(Boolean fromOut) {
      set("from_out", fromOut);
      return (M)this;
   }
   public Boolean getFromOut() {
      return get("from_out");
   }
   public M setEnable(Boolean enable) {
      set("enable", enable);
      return (M)this;
   }
   public Boolean getEnable() {
      return get("enable");
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/model/base/BaseWxRobKeyword.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,93 @@
package org.ruoyi.common.wechat.web.model.base;
import com.jfinal.plugin.activerecord.IBean;
import com.jfinal.plugin.activerecord.Model;
/**
 * Generated by JFinal, do not modify this file.
 */
@SuppressWarnings({"serial", "unchecked"})
public abstract class BaseWxRobKeyword<M extends BaseWxRobKeyword<M>> extends Model<M> implements IBean {
   public M setId(Long id) {
      set("id", id);
      return (M)this;
   }
   public Long getId() {
      return getLong("id");
   }
   public M setUniqueKey(String uniqueKey) {
      set("unique_key", uniqueKey);
      return (M)this;
   }
   public String getUniqueKey() {
      return getStr("unique_key");
   }
   public M setKeyData(String keyData) {
      set("key_data", keyData);
      return (M)this;
   }
   public String getKeyData() {
      return getStr("key_data");
   }
   public M setValueData(String valueData) {
      set("value_data", valueData);
      return (M)this;
   }
   public String getValueData() {
      return getStr("value_data");
   }
   public M setTypeData(String typeData) {
      set("type_data", typeData);
      return (M)this;
   }
   public String getTypeData() {
      return getStr("type_data");
   }
   public M setNickName(String nickName) {
      set("nick_name", nickName);
      return (M)this;
   }
   public String getNickName() {
      return getStr("nick_name");
   }
   public M setToGroup(Boolean toGroup) {
      set("to_group", toGroup);
      return (M)this;
   }
   public Boolean getToGroup() {
      return get("to_group");
   }
   public M setEnable(Boolean enable) {
      set("enable", enable);
      return (M)this;
   }
   public Boolean getEnable() {
      return get("enable");
   }
   public M setCreateTime(java.util.Date createTime) {
      set("create_time", createTime);
      return (M)this;
   }
   public java.util.Date getCreateTime() {
      return get("create_time");
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/model/base/BaseWxRobRelation.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,84 @@
package org.ruoyi.common.wechat.web.model.base;
import com.jfinal.plugin.activerecord.IBean;
import com.jfinal.plugin.activerecord.Model;
/**
 * Generated by JFinal, do not modify this file.
 */
@SuppressWarnings({"serial", "unchecked"})
public abstract class BaseWxRobRelation<M extends BaseWxRobRelation<M>> extends Model<M> implements IBean {
   public M setId(Long id) {
      set("id", id);
      return (M)this;
   }
   public Long getId() {
      return getLong("id");
   }
   public M setOutKey(String outKey) {
      set("out_key", outKey);
      return (M)this;
   }
   public String getOutKey() {
      return getStr("out_key");
   }
   public M setUniqueKey(String uniqueKey) {
      set("unique_key", uniqueKey);
      return (M)this;
   }
   public String getUniqueKey() {
      return getStr("unique_key");
   }
   public M setNickName(String nickName) {
      set("nick_name", nickName);
      return (M)this;
   }
   public String getNickName() {
      return getStr("nick_name");
   }
   public M setToGroup(Boolean toGroup) {
      set("to_group", toGroup);
      return (M)this;
   }
   public Boolean getToGroup() {
      return get("to_group");
   }
   public M setEnable(Boolean enable) {
      set("enable", enable);
      return (M)this;
   }
   public Boolean getEnable() {
      return get("enable");
   }
   public M setWhiteList(String whiteList) {
      set("white_list", whiteList);
      return (M)this;
   }
   public String getWhiteList() {
      return getStr("white_list");
   }
   public M setCreateTime(java.util.Date createTime) {
      set("create_time", createTime);
      return (M)this;
   }
   public java.util.Date getCreateTime() {
      return get("create_time");
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/utils/Base64Util.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package org.ruoyi.common.wechat.web.utils;
import org.apache.commons.codec.binary.Base64;
/**
 * @author WesleyOne
 * @create 2018/12/19
 */
public class Base64Util {
    /**
     * ç¼–码
     * @param source
     * @return
     */
    public static String encode(String source){
        byte[] result = Base64.encodeBase64(source.getBytes());
        return result.toString();
    }
    /**
     * è§£ç 
     * @param source
     * @return
     */
    public static String decode(String source){
        byte[] result = Base64.decodeBase64(source);
        return result.toString();
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/utils/IpUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
package org.ruoyi.common.wechat.web.utils;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
/**
 * @author WesleyOne
 * @create 2018/11/5
 */
public class IpUtil {
    /**
     * èŽ·å–ç”¨æˆ·çœŸå®žIP(在安防或多层代理场景下)
     * @param request
     * @return
     */
    public static String getRealIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
            //多次反向代理后会有多个ip值,第一个ip才是真实ip
            int index = ip.indexOf(",");
            if(index != -1){
                return ip.substring(0,index);
            }
        }
        ip = request.getHeader("X-Real-IP");
        if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
            return ip;
        }
        return request.getRemoteAddr();
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/utils/LRUCache.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
package org.ruoyi.common.wechat.web.utils;
import java.util.LinkedHashMap;
/**
 * @author WesleyOne
 * @create 2018/12/12
 */
public class LRUCache<K,V> extends LinkedHashMap<K,V> {
    private static final long serialVersionUID = 1L;
    protected int maxElements;
    public LRUCache(int maxSize)
    {
        super(maxSize * 4 / 3 , 0.75F, true);
        maxElements = maxSize;
    }
    @Override
    protected boolean removeEldestEntry(java.util.Map.Entry eldest)
    {
        return size() > maxElements;
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/utils/MD5Util.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
package org.ruoyi.common.wechat.web.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Util {
   private static String byteArrayToHexString(byte b[]) {
      StringBuffer resultSb = new StringBuffer();
      for (int i = 0; i < b.length; i++){
         resultSb.append(byteToHexString(b[i]));
      }
      return resultSb.toString();
   }
   private static String byteToHexString(byte b) {
      int n = b;
      if (n < 0){
         n += 256;
      }
      int d1 = n / 16;
      int d2 = n % 16;
      return hexDigits[d1] + hexDigits[d2];
   }
   public static String MD5Encode(String origin, String charsetname) {
      String resultString = null;
      try {
         resultString = new String(origin);
         MessageDigest md = MessageDigest.getInstance("MD5");
         if (charsetname == null || "".equals(charsetname)){
            resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
         } else{
            resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
         }
      } catch (Exception exception) {
      }
      return resultString;
   }
   private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
   public static String MD5Encrypt(String str) {
      String s = str;
      if (s == null) {
         return null;
      }
      String value = null;
      MessageDigest md5 = null;
      try {
         md5 = MessageDigest.getInstance("MD5");
      } catch (NoSuchAlgorithmException ex) {
      }
      //sun.misc.BASE64Encoder baseEncoder = new sun.misc.BASE64Encoder();
      return value;
   }
   public static void main(String[] args) {
      System.out.println(MD5Encrypt("wxwobot"));
   }
}
ruoyi-common/ruoyi-common-wechat/src/main/java/org/ruoyi/common/wechat/web/utils/UUIDShortUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
package org.ruoyi.common.wechat.web.utils;
import java.util.UUID;
/**
 *
 * @author internet
 * @create 2018/12/17
 */
public class UUIDShortUtil {
    private static String[] chars = new String[] { "a", "b", "c", "d", "e", "f",
            "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
            "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
            "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
            "W", "X", "Y", "Z" };
    /**
     * çŸ­8位
     * @return
     */
    public static String generateShortUuid() {
        StringBuffer shortBuffer = new StringBuffer();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        for (int i = 0; i < 8; i++) {
            String str = uuid.substring(i * 4, i * 4 + 4);
            int x = Integer.parseInt(str, 16);
            shortBuffer.append(chars[x % 0x3E]);
        }
        return shortBuffer.toString();
    }
}
ruoyi-common/ruoyi-common-wechat/src/main/resources/appConfig.properties
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
jdbcUrl = ${pro.jdbc.agent.url}
user = ${pro.jdbc.agent.username}
password = ${pro.jdbc.agent.password}
devMode = ${pro.devMode}
hotReloadDir = ${pro.hotreload.realpath}
download_path = ${pro.download.path}
log_path = ${log.file.path}
ruoyi-common/ruoyi-common-wechat/src/main/resources/passport.properties
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
wxwobot = C9ah2BEPliU2EzPV/VAn9Q==
ruoyi-common/ruoyi-common-wechat/src/main/resources/undertow.txt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
# é…ç½® undertow
undertow.devMode=${pro.undertow.devMode}
undertow.host=${pro.domain.host}
undertow.port=${pro.domain.port}
undertow.contextPath=/
undertow.resourcePath=webapp, io.wxwobot.admin/src/main/webapp, src/main/webapp
# å¼€å¯ gzip åŽ‹ç¼©
undertow.gzip.enable=true
# é…ç½®åŽ‹ç¼©çº§åˆ«ï¼Œé»˜è®¤å€¼ -1。 å¯é…ç½® 1 åˆ° 9。 1 æ‹¥æœ‰æœ€å¿«åŽ‹ç¼©é€Ÿåº¦ï¼Œ9 æ‹¥æœ‰æœ€é«˜åŽ‹ç¼©çŽ‡
undertow.gzip.level=-1
# è§¦å‘压缩的最小内容长度
undertow.gzip.minLength=1024
# session è¿‡æœŸæ—¶é—´ï¼Œæ³¨æ„å•位是秒
undertow.session.timeout=1800
# æ”¯æŒ session çƒ­åŠ è½½ï¼Œé¿å…ä¾èµ–äºŽ session çš„登录型项目反复登录,默认值为 true。仅用于 devMode,生产环境无影响
undertow.session.hotSwap=true
# ä¸‹é¢ä¸¤è¡Œå‘½ä»¤ç”Ÿæˆå¯†é’¥åº“
# keytool -genkeypair -validity 3650 -alias club -keyalg RSA -keystore club.jks
# keytool -importkeystore -srckeystore club.jks -destkeystore club.pfx -deststoretype PKCS12
# ç”Ÿæˆè¿‡ç¨‹ä¸­æç¤ºè¾“å…¥ "名字与姓氏" æ—¶è¾“å…¥ localhost。生产环境从阿里云下载 tomcat ç±»åž‹çš„密钥库
#
# æ›´è¯¦ç»†çš„ https/ssl é…ç½®è§ jfinal å®˜æ–¹æ–‡æ¡£ ï¼šhttp://www.jfinal.com/doc/1-4
#
# æ˜¯å¦å¼€å¯ ssl
undertow.ssl.enable=false
# ssl ç›‘听端口号,部署环境设置为 443
undertow.ssl.port=443
# å¯†é’¥åº“类型,建议使用 PKCS12
undertow.ssl.keyStoreType=PKCS12
# å¯†é’¥åº“文件
undertow.ssl.keyStore=demo.pfx
# å¯†é’¥åº“密码
undertow.ssl.keyStorePassword=111111
# ssl å¼€å¯æ—¶ï¼Œæ˜¯å¦å¼€å¯ http2。检测该配置是否生效在 chrome åœ°å€æ ä¸­è¾“å…¥: chrome://net-internals/#http2
undertow.http2.enable=true
# ssl å¼€å¯æ—¶ï¼Œhttp è¯·æ±‚是否重定向到 https
# undertow.http.toHttps=false
# ssl å¼€å¯æ—¶ï¼Œæ˜¯å¦å…³é—­ http
# undertow.http.disable=false
ruoyi-modules/pom.xml
@@ -20,6 +20,8 @@
        <module>ruoyi-demo</module>
        <module>ruoyi-fusion</module>
        <module>ruoyi-system</module>
        <module>ruoyi-live</module>
        <module>ruoyi-knowledge</module>
    </modules>
</project>
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/MailController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/RedisCacheController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/RedisLockController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/RedisPubSubController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/RedisRateLimiterController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/SmsController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/Swagger3DemoController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/TestBatchController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/TestDemoController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/TestEncryptController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/TestExcelController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/TestI18nController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/TestSensitiveController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/TestTreeController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/queue/BoundedQueueController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/queue/DelayedQueueController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/queue/PriorityDemo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/controller/queue/PriorityQueueController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/domain/TestDemo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/domain/TestDemoEncrypt.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/domain/TestTree.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/domain/bo/TestDemoBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/domain/bo/TestDemoImportVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/domain/bo/TestTreeBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/domain/package-info.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/domain/vo/TestDemoVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/domain/vo/TestTreeVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/mapper/TestDemoEncryptMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/mapper/TestDemoMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/mapper/TestTreeMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/mapper/package-info.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/service/ITestDemoService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/service/ITestTreeService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/service/impl/TestDemoServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/service/impl/TestTreeServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/service/impl/package-info.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/com/xmzs/demo/service/package-info.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-fusion/pom.xml
@@ -11,7 +11,7 @@
    <artifactId>ruoyi-fusion</artifactId>
    <description>
       AI绘画
       ä¸‰æ–¹API接入
    </description>
    <properties>
@@ -29,10 +29,7 @@
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
@@ -114,6 +111,10 @@
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-system</artifactId>
        </dependency>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-knowledge</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-modules/ruoyi-fusion/src/main/java/org/ruoyi/fusion/controller/ChatController.java
@@ -17,7 +17,9 @@
import org.ruoyi.common.mybatis.core.page.PageQuery;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.satoken.utils.LoginHelper;
import org.ruoyi.knowledge.service.EmbeddingService;
import org.ruoyi.system.domain.bo.ChatMessageBo;
import org.ruoyi.system.domain.request.translation.TranslationRequest;
import org.ruoyi.system.domain.vo.ChatMessageVo;
import org.ruoyi.system.service.IChatMessageService;
import org.ruoyi.system.service.ISseService;
@@ -46,12 +48,16 @@
    private final IChatMessageService chatMessageService;
    private final EmbeddingService embeddingService;
    /**
     * èŠå¤©æŽ¥å£
     */
    @PostMapping("/send")
    @ResponseBody
    public SseEmitter sseChat(@RequestBody @Valid ChatRequest chatRequest, HttpServletRequest request) {
        if (chatRequest.getModel().startsWith("ollama")) {
            return ISseService.ollamaChat(chatRequest);
        }
        return ISseService.sseChat(chatRequest,request);
    }
@@ -89,6 +95,17 @@
        return ISseService.textToSpeed(textToSpeech);
    }
    /**
     * æ–‡æœ¬ç¿»è¯‘
     *
     * @param
     */
    @PostMapping("/translation")
    @ResponseBody
    public String translation(@RequestBody TranslationRequest translationRequest) {
        return ISseService.translation(translationRequest);
    }
    @PostMapping("/dall3")
    @ResponseBody
    public R<List<Item>> dall3(@RequestBody @Valid Dall3Request request) {
ruoyi-modules/ruoyi-fusion/src/main/java/org/ruoyi/fusion/controller/CoverController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
package org.ruoyi.fusion.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.ruoyi.common.core.domain.R;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.web.core.BaseController;
import org.ruoyi.system.domain.vo.cover.CoverParamVo;
import org.ruoyi.system.domain.vo.cover.CoverVo;
import org.ruoyi.system.domain.vo.cover.CoverCallbackVo;
import org.ruoyi.system.domain.vo.cover.MusicVo;
import org.ruoyi.system.service.ICoverService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
 * ç»˜å£°ç¾ŽéŸ³-翻唱
 *
 * @author NSL
 * @since  2024-12-25
 */
@Api(tags = "歌曲翻唱")
@RequiredArgsConstructor
@RestController
@RequestMapping("/cover")
public class CoverController extends BaseController {
    private final ICoverService coverService;
    @ApiOperation(value = "查找歌曲")
    @GetMapping("/searchMusic")
    public R<List<MusicVo>> searchMusic(String musicName) {
        return R.ok(coverService.searchMusic(musicName));
    }
    @ApiOperation(value = "翻唱歌曲")
    @PostMapping("/saveCoverTask")
    public R<Void> saveCoverTask(@RequestBody CoverParamVo coverParamVo) {
        coverService.saveCoverTask(coverParamVo);
        return R.ok("翻唱歌曲处理中请等待10分钟-30分钟,翻唱结果请到翻唱记录中查询!");
    }
    @ApiOperation(value = "查询翻唱记录")
    @PostMapping("/searchCoverRecord")
    public R<TableDataInfo<CoverVo>> searchCoverRecord(@RequestBody PageQuery pageQuery) {
        return R.ok(coverService.searchCoverRecord(pageQuery));
    }
    @ApiOperation(value = "翻唱回调接口")
    @PostMapping("/callback")
    public R<Void> callback(@RequestBody CoverCallbackVo coverCallbackVo) {
        coverService.callback(coverCallbackVo);
        return R.ok();
    }
}
ruoyi-modules/ruoyi-fusion/src/main/java/org/ruoyi/fusion/controller/LumaController.java
@@ -32,6 +32,7 @@
    @PostMapping("/generations/")
    public String generateVideo(@RequestBody GenerateLuma generateLuma) {
        OkHttpUtil okHttpUtil = okHttpConfig.getOkHttpUtil("luma");
        chatCostService.taskDeduct("luma", "文生视频", NumberUtils.toDouble(okHttpConfig.getGenerate(), 0.3));
        String generateJson = JSONUtil.toJsonStr(generateLuma);
        String url = "luma/generations";
ruoyi-modules/ruoyi-fusion/src/main/java/org/ruoyi/fusion/controller/PptController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,79 @@
package org.ruoyi.fusion.controller;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.ruoyi.common.core.domain.R;
import org.ruoyi.common.web.core.BaseController;
import org.ruoyi.system.domain.vo.ppt.*;
import org.ruoyi.system.service.IPptService;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
/**
 * AI_PPT
 *
 * @author NSL
 * @since 2024-12-30
 */
@Api(tags = "AI-PPT")
@RequiredArgsConstructor
@RestController
@RequestMapping("/ppt")
public class PptController extends BaseController {
    private final IPptService pptService;
    @ApiOperation(value = "获取API Token")
    @GetMapping("/getApiToken")
    public R<String> getApiToken() {
        return R.ok(pptService.getApiToken());
    }
    @ApiOperation(value = "同步流式生成 PPT")
    @PostMapping("/syncStreamGeneratePpt")
    public R<Void> syncStreamGeneratePpt(String title) {
        pptService.syncStreamGeneratePpt(title);
        return R.ok();
    }
    @ApiOperation(value = "查询所有PPT列表")
    @PostMapping("/selectPptList")
    public R<Void> selectPptList(@RequestBody PptAllQueryDto pptQueryVo) {
        pptService.selectPptList(pptQueryVo);
        return R.ok();
    }
    @ApiOperation(value = "生成大纲")
    @PostMapping(value = "/generateOutline", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
    public SseEmitter generateOutline(@RequestBody PptGenerateOutlineDto generateOutlineDto) {
        return pptService.generateOutline(generateOutlineDto);
    }
    @ApiOperation(value = "生成大纲内容")
    @PostMapping(value = "/generateContent", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
    public SseEmitter generateOutline(@RequestBody PptGenerateContentDto generateContentDto) {
        return pptService.generateContent(generateContentDto);
    }
    @ApiOperation(value = "分页查询 PPT æ¨¡æ¿")
    @PostMapping("/getTemplates")
    public R<JSONObject> getPptTemplates(@RequestBody PptTemplateQueryDto pptQueryVo) {
        return R.ok(pptService.getPptTemplates(pptQueryVo));
    }
    @ApiOperation(value = "生成 PPT")
    @PostMapping("/generatePptx")
    public R<JSONObject> generatePptx(@RequestBody PptGeneratePptxDto pptQueryVo) {
        return R.ok(pptService.generatePptx(pptQueryVo));
    }
    @ApiOperation(value = "生成PPT成功回调接口")
    @PostMapping("/successCallback")
    public R<Void> successCallback() {
        pptService.successCallback();
        return R.ok();
    }
}
ruoyi-modules/ruoyi-fusion/src/main/java/org/ruoyi/fusion/controller/VoiceController.java
@@ -1,31 +1,19 @@
package org.ruoyi.fusion.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.ruoyi.common.core.domain.R;
import org.ruoyi.common.core.validate.EditGroup;
import org.ruoyi.common.log.annotation.Log;
import org.ruoyi.common.log.enums.BusinessType;
import org.ruoyi.common.satoken.utils.LoginHelper;
import org.ruoyi.common.web.core.BaseController;
import org.ruoyi.system.domain.bo.VoiceRoleBo;
import org.ruoyi.system.domain.vo.VoiceRoleVo;
import org.ruoyi.system.request.RoleListDto;
import org.ruoyi.system.request.RoleRequest;
import org.ruoyi.system.request.SimpleGenerateRequest;
import org.ruoyi.system.response.SimpleGenerateDataResponse;
import org.ruoyi.system.response.rolelist.RoleListVO;
import org.ruoyi.system.service.IVoiceRoleService;
import org.springframework.validation.annotation.Validated;
import org.ruoyi.system.response.rolelist.ChatAppStoreVO;
import org.ruoyi.system.service.IChatAppStoreService;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
 * é…éŸ³è§’色
 * åº”用市场
 *
 * @author Lion Li
 * @date 2024-03-19
@@ -35,63 +23,7 @@
@RequestMapping("/system/voice")
public class VoiceController extends BaseController {
    private final IVoiceRoleService voiceRoleService;
    /**
     * æŸ¥è¯¢é…éŸ³è§’色列表
     */
    @GetMapping("/list")
    public List<VoiceRoleVo> list(VoiceRoleBo bo) {
        if(LoginHelper.getUserId() == null){
            return new ArrayList<>();
        }
        bo.setCreateBy(LoginHelper.getUserId());
        return voiceRoleService.queryList(bo);
    }
    /**
     * èŽ·å–é…éŸ³è§’è‰²è¯¦ç»†ä¿¡æ¯
     *
     * @param id ä¸»é”®
     */
    @SaCheckPermission("system:role:query")
    @GetMapping("/{id}")
    public R<VoiceRoleVo> getInfo(@NotNull(message = "主键不能为空")
                                       @PathVariable Long id) {
        return R.ok(voiceRoleService.queryById(id));
    }
    /**
     * æ–°å¢žé…éŸ³è§’色
     */
    @Log(title = "配音角色", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    public R<Void> add(@RequestBody RoleRequest roleRequest) {
        return toAjax(voiceRoleService.insertByBo(roleRequest));
    }
    /**
     * ä¿®æ”¹é…éŸ³è§’色
     */
    @SaCheckPermission("system:role:edit")
    @Log(title = "配音角色", businessType = BusinessType.UPDATE)
    @PutMapping()
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody VoiceRoleBo bo) {
        return toAjax(voiceRoleService.updateByBo(bo));
    }
    /**
     * åˆ é™¤é…éŸ³è§’色
     *
     * @param ids ä¸»é”®ä¸²
     */
    @Log(title = "配音角色", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
                          @PathVariable Long[] ids) {
        return toAjax(voiceRoleService.deleteWithValidByIds(List.of(ids), true));
    }
    private final IChatAppStoreService voiceRoleService;
    /**
     * å®žæ—¶è¯­éŸ³ç”Ÿæˆ
@@ -105,7 +37,7 @@
     * è§’色市场
     */
    @GetMapping("/roleList")
    public R<List<RoleListVO>> roleList() {
    public R<List<ChatAppStoreVO>> roleList() {
        return R.ok(voiceRoleService.roleList());
    }
ruoyi-modules/ruoyi-generator/pom.xml
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/java/com/xmzs/generator/config/GenConfig.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/java/com/xmzs/generator/constant/GenConstants.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/java/com/xmzs/generator/controller/GenController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/java/com/xmzs/generator/domain/GenTable.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/java/com/xmzs/generator/domain/GenTableColumn.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/java/com/xmzs/generator/mapper/GenTableColumnMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/java/com/xmzs/generator/mapper/GenTableMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/java/com/xmzs/generator/service/GenTableServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/java/com/xmzs/generator/service/IGenTableService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/java/com/xmzs/generator/util/GenUtils.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/java/com/xmzs/generator/util/VelocityInitializer.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/java/com/xmzs/generator/util/VelocityUtils.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/generator.yml
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/mapper/package-info.md
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/js/api.js.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/oracle/sql.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/postgres/sql.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sql.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sqlserver/sql.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/api.ts.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-job/pom.xml
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-job/src/main/java/com/xmzs/job/service/SampleService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-knowledge/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,200 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.ruoyi</groupId>
        <artifactId>ruoyi-modules</artifactId>
        <version>${revision}</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>ruoyi-knowledge</artifactId>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>webjars-locator-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>sockjs-client</artifactId>
            <version>1.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>3.3.7</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.1.1-1</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.10</version>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor.netty</groupId>
            <artifactId>reactor-netty-core</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>io.projectreactor.netty</groupId>
            <artifactId>reactor-netty-http</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.theokanning.openai-gpt3-java</groupId>
            <artifactId>api</artifactId>
            <version>0.18.0</version>
        </dependency>
        <dependency>
            <groupId>com.theokanning.openai-gpt3-java</groupId>
            <artifactId>client</artifactId>
            <version>0.18.0</version>
        </dependency>
        <dependency>
            <groupId>com.theokanning.openai-gpt3-java</groupId>
            <artifactId>service</artifactId>
            <version>0.18.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- é˜¿é‡ŒJSON解析器 -->
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.24</version>
        </dependency>
        <dependency>
            <groupId>com.knuddels</groupId>
            <artifactId>jtokkit</artifactId>
            <version>0.5.0</version>
        </dependency>
        <dependency>
            <groupId>io.weaviate</groupId>
            <artifactId>client</artifactId>
            <version>4.0.0</version>  <!-- Check latest version -->
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>3.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.27</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.retrofit2</groupId>
            <artifactId>converter-jackson</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>io.milvus</groupId>
            <artifactId>milvus-sdk-java</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.6</version>
        </dependency>
        <dependency>
            <groupId>com.belerweb</groupId>
            <artifactId>pinyin4j</artifactId>
            <version>2.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-system</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/CodeFileLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
package org.ruoyi.knowledge.chain.loader;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.knowledge.chain.split.TextSplitter;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class CodeFileLoader implements ResourceLoader{
    private final TextSplitter textSplitter;
    @Override
    public String getContent(InputStream inputStream) {
        StringBuffer stringBuffer = new StringBuffer();
        try (InputStreamReader reader = new InputStreamReader(inputStream);
             BufferedReader bufferedReader = new BufferedReader(reader)){
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuffer.append(line).append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuffer.toString();
    }
    @Override
    public List<String> getChunkList(String content){
        return textSplitter.split(content);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/CsvFileLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.ruoyi.knowledge.chain.loader;
import java.io.InputStream;
import java.util.List;
public class CsvFileLoader implements ResourceLoader{
    @Override
    public String getContent(InputStream inputStream) {
        return null;
    }
    @Override
    public List<String> getChunkList(String content) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/FolderLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.ruoyi.knowledge.chain.loader;
import java.io.InputStream;
import java.util.List;
public class FolderLoader implements ResourceLoader{
    @Override
    public String getContent(InputStream inputStream) {
        return null;
    }
    @Override
    public List<String> getChunkList(String content) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/GithubLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.ruoyi.knowledge.chain.loader;
import java.io.InputStream;
import java.util.List;
public class GithubLoader implements ResourceLoader{
    @Override
    public String getContent(InputStream inputStream) {
        return null;
    }
    @Override
    public List<String> getChunkList(String content) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/JsonFileLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.ruoyi.knowledge.chain.loader;
import java.io.InputStream;
import java.util.List;
public class JsonFileLoader implements ResourceLoader{
    @Override
    public String getContent(InputStream inputStream) {
        return null;
    }
    @Override
    public List<String> getChunkList(String content) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/MarkDownFileLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
package org.ruoyi.knowledge.chain.loader;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.knowledge.chain.split.TextSplitter;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class MarkDownFileLoader implements ResourceLoader{
    private final TextSplitter textSplitter;
    @Override
    public String getContent(InputStream inputStream) {
        StringBuffer stringBuffer = new StringBuffer();
        try (InputStreamReader reader = new InputStreamReader(inputStream);
             BufferedReader bufferedReader = new BufferedReader(reader)){
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuffer.append(line).append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuffer.toString();
    }
    @Override
    public List<String> getChunkList(String content){
        return textSplitter.split(content);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/PdfFileLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
package org.ruoyi.knowledge.chain.loader;
import lombok.AllArgsConstructor;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.ruoyi.knowledge.chain.split.TextSplitter;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
@Component
@AllArgsConstructor
public class PdfFileLoader implements ResourceLoader{
    private final TextSplitter characterTextSplitter;
    @Override
    public String getContent(InputStream inputStream) {
        PDDocument document = null;
        try {
            document = PDDocument.load(inputStream);
            PDFTextStripper textStripper = new PDFTextStripper();
            String content = textStripper.getText(document);
            return content;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public List<String> getChunkList(String content) {
        return characterTextSplitter.split(content);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/ResourceLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package org.ruoyi.knowledge.chain.loader;
import java.io.InputStream;
import java.util.List;
/**
 * èµ„源载入
 */
public interface ResourceLoader {
    String getContent(InputStream inputStream);
    List<String> getChunkList(String content);
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/ResourceLoaderFactory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
package org.ruoyi.knowledge.chain.loader;
import lombok.AllArgsConstructor;
import org.ruoyi.knowledge.chain.split.CharacterTextSplitter;
import org.ruoyi.knowledge.chain.split.CodeTextSplitter;
import org.ruoyi.knowledge.chain.split.MarkdownTextSplitter;
import org.ruoyi.knowledge.chain.split.TokenTextSplitter;
import org.ruoyi.knowledge.constant.FileType;
import org.springframework.stereotype.Component;
@AllArgsConstructor
@Component
public class ResourceLoaderFactory {
    private final CharacterTextSplitter characterTextSplitter;
    private final CodeTextSplitter codeTextSplitter;
    private final MarkdownTextSplitter markdownTextSplitter;
    private final TokenTextSplitter tokenTextSplitter;
    public ResourceLoader getLoaderByFileType(String fileType){
        if (FileType.isTextFile(fileType)){
            return new TextFileLoader(characterTextSplitter);
        } else if (FileType.isWord(fileType)) {
            return new WordLoader(characterTextSplitter);
        } else if (FileType.isPdf(fileType)) {
            return new PdfFileLoader(characterTextSplitter);
        } else if (FileType.isMdFile(fileType)) {
            return new MarkDownFileLoader(markdownTextSplitter);
        }else if (FileType.isCodeFile(fileType)) {
            return new CodeFileLoader(codeTextSplitter);
        }else {
            return new TextFileLoader(characterTextSplitter);
        }
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/TextFileLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
package org.ruoyi.knowledge.chain.loader;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.knowledge.chain.split.TextSplitter;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class TextFileLoader implements ResourceLoader{
    private final TextSplitter textSplitter;
    @Override
    public String getContent(InputStream inputStream) {
        StringBuffer stringBuffer = new StringBuffer();
        try (InputStreamReader reader = new InputStreamReader(inputStream, "UTF-8");
             BufferedReader bufferedReader = new BufferedReader(reader)){
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuffer.append(line).append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuffer.toString();
    }
    @Override
    public List<String> getChunkList(String content){
        return textSplitter.split(content);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/loader/WordLoader.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
package org.ruoyi.knowledge.chain.loader;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.ruoyi.knowledge.chain.split.TextSplitter;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class WordLoader implements ResourceLoader{
    private final TextSplitter textSplitter;
    @Override
    public String getContent(InputStream inputStream) {
        XWPFDocument document = null;
        try {
            document = new XWPFDocument(inputStream);
            XWPFWordExtractor extractor = new XWPFWordExtractor(document);
            String content = extractor.getText();
            return content;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public List<String> getChunkList(String content) {
        return textSplitter.split(content);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/retrieve/PromptRetrieverProperties.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package org.ruoyi.knowledge.chain.retrieve;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class PromptRetrieverProperties {
    /**
     * ä»ŽçŸ¥è¯†åº“中检索的条数,limits åº”大于 num
     */
    @Value("${chain.limits}")
    private int limits;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/CharacterTextSplitter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
package org.ruoyi.knowledge.chain.split;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
@Primary
public class CharacterTextSplitter implements TextSplitter{
    private final SplitterProperties splitterProperties;
    @Override
    public List<String> split(String content) {
        List<String> chunkList = new ArrayList<>();
        if (content.contains(splitterProperties.getEndspliter())){
            // æŒ‰è‡ªå®šä¹‰åˆ†éš”符切分
            String[] chunks = content.split(splitterProperties.getEndspliter());
            chunkList.addAll(Arrays.asList(chunks));
        }else {
            int indexMin = 0;
            int len = content.length();
            int i = 0;
            int right = 0;
            while (true) {
                if (len > right ){
                    int begin = i*splitterProperties.getSize() - splitterProperties.getOverlay();
                    if (begin < indexMin){
                        begin = indexMin;
                    }
                    int end = splitterProperties.getSize()*(i+1) + splitterProperties.getOverlay();
                    if (end > len){
                        end = len;
                    }
                    String chunk = content.substring(begin,end);
                    chunkList.add(chunk);
                    i++;
                    right = right + splitterProperties.getSize();
                }else {
                    break;
                }
            }
        }
        return chunkList;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/CodeTextSplitter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package org.ruoyi.knowledge.chain.split;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class CodeTextSplitter implements TextSplitter{
    @Override
    public List<String> split(String content) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/MarkdownTextSplitter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package org.ruoyi.knowledge.chain.split;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class MarkdownTextSplitter implements TextSplitter{
    @Override
    public List<String> split(String content) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/SplitterProperties.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package org.ruoyi.knowledge.chain.split;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "chain.split.chunk")
public class SplitterProperties {
    /**
     * åˆ†æ®µæ ‡è¯†ç¬¦
     */
    private String endspliter;
    /**
     * æé—®åˆ†æ®µæ ‡è¯†ç¬¦
     */
    private String qaspliter;
    /**
     * åˆ†å—文本大小
     */
    private int size;
    /**
     * ç›¸é‚»å—之间重叠的字符数(避免边界信息丢失)
     */
    private int overlay;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/TextSplitter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
package org.ruoyi.knowledge.chain.split;
import java.util.List;
/**
 * æ–‡æœ¬åˆ‡åˆ†
 */
public interface TextSplitter {
    List<String> split(String content);
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/split/TokenTextSplitter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package org.ruoyi.knowledge.chain.split;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@AllArgsConstructor
@Slf4j
public class TokenTextSplitter implements TextSplitter{
    @Override
    public List<String> split(String content) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/OpenAiVectorization.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
package org.ruoyi.knowledge.chain.vectorizer;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.common.chat.config.ChatConfig;
import org.ruoyi.common.chat.entity.embeddings.Embedding;
import org.ruoyi.common.chat.entity.embeddings.EmbeddingResponse;
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@Component
@Slf4j
@RequiredArgsConstructor
public class OpenAiVectorization implements Vectorization {
    @Value("${chain.vector.model}")
    private String embeddingModel;
    @Getter
    private OpenAiStreamClient openAiStreamClient;
    private final ChatConfig chatConfig;
    @Override
    public List<List<Double>> batchVectorization(List<String> chunkList) {
        openAiStreamClient = chatConfig.getOpenAiStreamClient();
        Embedding embedding = Embedding.builder()
            .input(chunkList)
            .model(embeddingModel)
            .build();
        EmbeddingResponse embeddings = openAiStreamClient.embeddings(embedding);
        List<List<Double>> vectorList = new ArrayList<>();
        embeddings.getData().forEach(data -> {
            List<BigDecimal> vector = data.getEmbedding();
            List<Double> doubleVector = new ArrayList<>();
            for (BigDecimal bd : vector) {
                doubleVector.add(bd.doubleValue());
            }
            vectorList.add(doubleVector);
        });
        return vectorList;
    }
    @Override
    public List<Double> singleVectorization(String chunk) {
        List<String> chunkList = new ArrayList<>();
        chunkList.add(chunk);
        List<List<Double>> vectorList = batchVectorization(chunkList);
        return vectorList.get(0);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/Vectorization.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
package org.ruoyi.knowledge.chain.vectorizer;
import java.util.List;
/**
 * å‘量化
 */
public interface Vectorization {
    List<List<Double>> batchVectorization(List<String> chunkList);
    List<Double> singleVectorization(String chunk);
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/VectorizationFactory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
package org.ruoyi.knowledge.chain.vectorizer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
 * æ–‡æœ¬å‘量化
 * @author huangkh
 */
@Component
@Slf4j
public class VectorizationFactory {
    private final OpenAiVectorization openAiVectorization;
    public VectorizationFactory(OpenAiVectorization openAiVectorization) {
        this.openAiVectorization = openAiVectorization;
    }
    public Vectorization getEmbedding(){
        return openAiVectorization;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorizer/VectorizationWrapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package org.ruoyi.knowledge.chain.vectorizer;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
@Primary
@AllArgsConstructor
public class VectorizationWrapper implements Vectorization{
    private final VectorizationFactory vectorizationFactory;
    @Override
    public List<List<Double>> batchVectorization(List<String> chunkList) {
        Vectorization embedding = vectorizationFactory.getEmbedding();
        return embedding.batchVectorization(chunkList);
    }
    @Override
    public List<Double> singleVectorization(String chunk) {
        Vectorization embedding = vectorizationFactory.getEmbedding();
        return embedding.singleVectorization(chunk);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/MilvusVectorStore.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,244 @@
package org.ruoyi.knowledge.chain.vectorstore;
import io.milvus.client.MilvusServiceClient;
import io.milvus.grpc.DataType;
import io.milvus.grpc.SearchResults;
import io.milvus.param.ConnectParam;
import io.milvus.param.IndexType;
import io.milvus.param.MetricType;
import io.milvus.param.R;
import io.milvus.param.collection.CreateCollectionParam;
import io.milvus.param.collection.DropCollectionParam;
import io.milvus.param.collection.FieldType;
import io.milvus.param.collection.LoadCollectionParam;
import io.milvus.param.dml.DeleteParam;
import io.milvus.param.dml.InsertParam;
import io.milvus.param.dml.SearchParam;
import io.milvus.param.index.CreateIndexParam;
import io.milvus.param.partition.CreatePartitionParam;
import io.milvus.response.QueryResultsWrapper;
import io.milvus.response.SearchResultsWrapper;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Service
@Slf4j
public class MilvusVectorStore implements VectorStore{
    @Value("${chain.vector.store.milvus.host}")
    private String milvusHost;
    @Value("${chain.vector.store.milvus.port}")
    private Integer milvausPort;
    @Value("${chain.vector.store.milvus.dimension}")
    private Integer dimension;
    @Value("${chain.vector.store.milvus.collection}")
    private String collectionName;
    private MilvusServiceClient milvusServiceClient;
    @PostConstruct
    public void init(){
        milvusServiceClient = new MilvusServiceClient(
                ConnectParam.newBuilder()
                        .withHost(milvusHost)
                        .withPort(milvausPort)
                        .withDatabaseName("default")
                        .build()
        );
    }
    private void createSchema(String kid) {
        FieldType primaryField = FieldType.newBuilder()
                .withName("row_id")
                .withDataType(DataType.Int64)
                .withPrimaryKey(true)
                .withAutoID(true)
                .build();
        FieldType contentField = FieldType.newBuilder()
                .withName("content")
                .withDataType(DataType.VarChar)
                .withMaxLength(1000)
                .build();
        FieldType kidField = FieldType.newBuilder()
                .withName("kid")
                .withDataType(DataType.VarChar)
                .withMaxLength(20)
                .build();
        FieldType docIdField = FieldType.newBuilder()
                .withName("docId")
                .withDataType(DataType.VarChar)
                .withMaxLength(20)
                .build();
        FieldType fidField = FieldType.newBuilder()
                .withName("fid")
                .withDataType(DataType.VarChar)
                .withMaxLength(20)
                .build();
        FieldType vectorField = FieldType.newBuilder()
                .withName("fv")
                .withDataType(DataType.FloatVector)
                .withDimension(dimension)
                .build();
        CreateCollectionParam createCollectionReq = CreateCollectionParam.newBuilder()
                .withCollectionName(collectionName + kid)
                .withDescription("local knowledge")
                .addFieldType(primaryField)
                .addFieldType(contentField)
                .addFieldType(kidField)
                .addFieldType(docIdField)
                .addFieldType(fidField)
                .addFieldType(vectorField)
                .build();
        milvusServiceClient.createCollection(createCollectionReq);
        // åˆ›å»ºå‘量的索引
        IndexType INDEX_TYPE = IndexType.IVF_FLAT;
        String INDEX_PARAM = "{\"nlist\":1024}";
        milvusServiceClient.createIndex(
                CreateIndexParam.newBuilder()
                        .withCollectionName(collectionName + kid)
                        .withFieldName("fv")
                        .withIndexType(INDEX_TYPE)
                        .withMetricType(MetricType.IP)
                        .withExtraParam(INDEX_PARAM)
                        .withSyncMode(Boolean.FALSE)
                        .build()
        );
    }
    @Override
    public void newSchema(String kid) {
        createSchema(kid);
    }
    @Override
    public void removeByKidAndFid(String kid, String fid) {
        milvusServiceClient.delete(
                DeleteParam.newBuilder()
                        .withCollectionName(collectionName + kid)
                        .withExpr("fid == " + fid)
                        .build()
        );
    }
    @Override
    public void storeEmbeddings(List<String> chunkList, List<List<Double>> vectorList, String kid, String docId, List<String> fidList) {
        if (StringUtils.isNotBlank(docId)){
            milvusServiceClient.createPartition(
                    CreatePartitionParam.newBuilder()
                            .withCollectionName(collectionName + kid)
                            .withPartitionName(docId)
                            .build()
            );
        }
        List<List<Float>> vectorFloatList = new ArrayList<>();
        List<String> kidList = new ArrayList<>();
        List<String> docIdList = new ArrayList<>();
        for (int i = 0; i < chunkList.size(); i++) {
            List<Double> vector = vectorList.get(i);
            List<Float> vfList = new ArrayList<>();
            for (int j = 0; j < vector.size(); j++) {
                Double value = vector.get(j);
                vfList.add(value.floatValue());
            }
            vectorFloatList.add(vfList);
            kidList.add(kid);
            docIdList.add(docId);
        }
        List<InsertParam.Field> fields = new ArrayList<>();
        fields.add(new InsertParam.Field("content", chunkList));
        fields.add(new InsertParam.Field("kid", kidList));
        fields.add(new InsertParam.Field("docId", docIdList));
        fields.add(new InsertParam.Field("fid", fidList));
        fields.add(new InsertParam.Field("fv", vectorFloatList));
        InsertParam insertParam = InsertParam.newBuilder()
                .withCollectionName(collectionName + kid)
                .withPartitionName(docId)
                .withFields(fields)
                .build();
        milvusServiceClient.insert(insertParam);
        // milvus在将数据装载到内存后才能进行向量计算
        milvusServiceClient.loadCollection(LoadCollectionParam.newBuilder().withCollectionName(collectionName + kid).build());
    }
    @Override
    public void removeByDocId(String kid, String docId) {
        milvusServiceClient.delete(
                DeleteParam.newBuilder()
                        .withCollectionName(collectionName + kid)
                        .withExpr("1 == 1")
                        .withPartitionName(docId)
                        .build()
        );
    }
    @Override
    public void removeByKid(String kid) {
        milvusServiceClient.dropCollection(
                DropCollectionParam.newBuilder()
                        .withCollectionName(collectionName + kid)
                        .build()
        );
    }
    @Override
    public List<String> nearest(List<Double> queryVector, String kid) {
        List<String> search_output_fields = Arrays.asList("content","fv");
        List<Float> fv = new ArrayList<>();
        for (int i = 0; i < queryVector.size(); i++) {
            fv.add(queryVector.get(i).floatValue());
        }
        List<List<Float>> vectors = new ArrayList<>();
        vectors.add(fv);
        String search_param = "{\"nprobe\":10, \"offset\":0}";
        SearchParam searchParam = SearchParam.newBuilder()
                .withCollectionName(collectionName + kid)
                .withMetricType(MetricType.IP)
                .withOutFields(search_output_fields)
                .withTopK(10)
                .withVectors(vectors)
                .withVectorFieldName("fv")
                .withParams(search_param)
                .build();
        R<SearchResults> respSearch = milvusServiceClient.search(searchParam);
        SearchResultsWrapper wrapperSearch = new SearchResultsWrapper(respSearch.getData().getResults());
        List<QueryResultsWrapper.RowRecord> rowRecords = wrapperSearch.getRowRecords();
        List<String> resultList = new ArrayList<>();
        if (resultList!=null && resultList.size() > 0){
            for (int i = 0; i < rowRecords.size(); i++) {
                String content = rowRecords.get(i).get("content").toString();
                resultList.add(content);
            }
        }
        return resultList;
    }
    /**
     * milvus ä¸æ”¯æŒé€šè¿‡æ–‡æœ¬æ£€ç´¢ç›¸ä¼¼æ€§
     * @param query
     * @param kid
     * @return
     */
    @Override
    public List<String> nearest(String query, String kid) {
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/VectorStore.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package org.ruoyi.knowledge.chain.vectorstore;
import java.util.List;
/**
 * å‘量存储
 */
public interface VectorStore {
    void storeEmbeddings(List<String> chunkList,List<List<Double>> vectorList, String kid, String docId,List<String> fidList);
    void removeByDocId(String kid,String docId);
    void removeByKid(String kid);
    List<String> nearest(List<Double> queryVector,String kid);
    List<String> nearest(String query,String kid);
    void newSchema(String kid);
    void removeByKidAndFid(String kid, String fid);
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/VectorStoreFactory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package org.ruoyi.knowledge.chain.vectorstore;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class VectorStoreFactory {
    @Value("${chain.vector.store.type}")
    private String type;
    private final WeaviateVectorStore weaviateVectorStore;
    private final MilvusVectorStore milvusVectorStore;
    public VectorStoreFactory(WeaviateVectorStore weaviateVectorStore, MilvusVectorStore milvusVectorStore) {
        this.weaviateVectorStore = weaviateVectorStore;
        this.milvusVectorStore = milvusVectorStore;
    }
    public VectorStore getVectorStore(){
        if ("weaviate".equals(type)){
            return weaviateVectorStore;
        }else if ("milvus".equals(type)){
            return milvusVectorStore;
        }
        return null;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/VectorStoreWrapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
package org.ruoyi.knowledge.chain.vectorstore;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@Slf4j
@Primary
@AllArgsConstructor
public class VectorStoreWrapper implements VectorStore{
    private final VectorStoreFactory vectorStoreFactory;
    @Override
    public void storeEmbeddings(List<String> chunkList, List<List<Double>> vectorList, String kid, String docId, List<String> fidList) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        vectorStore.storeEmbeddings(chunkList, vectorList,  kid,  docId, fidList);
    }
    @Override
    public void removeByDocId(String kid, String docId) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        vectorStore.removeByDocId(kid,docId);
    }
    @Override
    public void removeByKid(String kid) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        vectorStore.removeByKid(kid);
    }
    @Override
    public List<String> nearest(List<Double> queryVector, String kid) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        return vectorStore.nearest(queryVector,kid);
    }
    @Override
    public List<String> nearest(String query, String kid) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        return vectorStore.nearest(query, kid);
    }
    @Override
    public void newSchema(String kid) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        vectorStore.newSchema(kid);
    }
    @Override
    public void removeByKidAndFid(String kid, String fid) {
        VectorStore vectorStore = vectorStoreFactory.getVectorStore();
        vectorStore.removeByKidAndFid(kid, fid);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/chain/vectorstore/WeaviateVectorStore.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,372 @@
package org.ruoyi.knowledge.chain.vectorstore;
import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson2.JSONObject;
import com.google.gson.internal.LinkedTreeMap;
import io.weaviate.client.Config;
import io.weaviate.client.WeaviateClient;
import io.weaviate.client.base.Result;
import io.weaviate.client.v1.data.model.WeaviateObject;
import io.weaviate.client.v1.data.replication.model.ConsistencyLevel;
import io.weaviate.client.v1.filters.Operator;
import io.weaviate.client.v1.filters.WhereFilter;
import io.weaviate.client.v1.graphql.model.GraphQLResponse;
import io.weaviate.client.v1.graphql.query.argument.NearTextArgument;
import io.weaviate.client.v1.graphql.query.argument.NearVectorArgument;
import io.weaviate.client.v1.graphql.query.fields.Field;
import io.weaviate.client.v1.misc.model.Meta;
import io.weaviate.client.v1.misc.model.ReplicationConfig;
import io.weaviate.client.v1.misc.model.ShardingConfig;
import io.weaviate.client.v1.misc.model.VectorIndexConfig;
import io.weaviate.client.v1.schema.model.DataType;
import io.weaviate.client.v1.schema.model.Property;
import io.weaviate.client.v1.schema.model.Schema;
import io.weaviate.client.v1.schema.model.WeaviateClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.ruoyi.knowledge.chain.retrieve.PromptRetrieverProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@Slf4j
public class WeaviateVectorStore implements VectorStore{
    @Value("${chain.vector.store.weaviate.protocol}")
    private String protocol;
    @Value("${chain.vector.store.weaviate.host}")
    private String host;
    @Value("${chain.vector.store.weaviate.classname}")
    private String className;
    private final PromptRetrieverProperties promptRetrieverProperties;
    public WeaviateVectorStore(PromptRetrieverProperties promptRetrieverProperties) {
        this.promptRetrieverProperties = promptRetrieverProperties;
    }
    public WeaviateClient getClient(){
        Config config = new Config(protocol, host);
        WeaviateClient client = new WeaviateClient(config);
        return client;
    }
    public Result<Meta> getMeta(){
        WeaviateClient client = getClient();
        Result<Meta> meta = client.misc().metaGetter().run();
        if (meta.getError() == null) {
            System.out.printf("meta.hostname: %s\n", meta.getResult().getHostname());
            System.out.printf("meta.version: %s\n", meta.getResult().getVersion());
            System.out.printf("meta.modules: %s\n", meta.getResult().getModules());
        } else {
            System.out.printf("Error: %s\n", meta.getError().getMessages());
        }
        return meta;
    }
    public Result<Schema> getSchemas(){
        WeaviateClient client = getClient();
        Result<Schema> result = client.schema().getter().run();
        if (result.hasErrors()) {
            System.out.println(result.getError());
        }else {
            System.out.println(result.getResult());
        }
        return result;
    }
    public Result<Boolean> createSchema(String kid){
        WeaviateClient client = getClient();
        VectorIndexConfig vectorIndexConfig = VectorIndexConfig.builder()
            .distance("cosine")
            .cleanupIntervalSeconds(300)
            .efConstruction(128)
            .maxConnections(64)
            .vectorCacheMaxObjects(500000L)
            .ef(-1)
            .skip(false)
            .dynamicEfFactor(8)
            .dynamicEfMax(500)
            .dynamicEfMin(100)
            .flatSearchCutoff(40000)
            .build();
        ShardingConfig shardingConfig = ShardingConfig.builder()
            .desiredCount(3)
            .desiredVirtualCount(128)
            .function("murmur3")
            .key("_id")
            .strategy("hash")
            .virtualPerPhysical(128)
            .build();
        ReplicationConfig replicationConfig = ReplicationConfig.builder()
            .factor(1)
            .build();
        JSONObject classModuleConfigValue = new JSONObject();
        classModuleConfigValue.put("vectorizeClassName",false);
        JSONObject classModuleConfig = new JSONObject();
        classModuleConfig.put("text2vec-transformers",classModuleConfigValue);
        JSONObject propertyModuleConfigValueSkipTrue = new JSONObject();
        propertyModuleConfigValueSkipTrue.put("vectorizePropertyName",false);
        propertyModuleConfigValueSkipTrue.put("skip",true);
        JSONObject propertyModuleConfigSkipTrue = new JSONObject();
        propertyModuleConfigSkipTrue.put("text2vec-transformers",propertyModuleConfigValueSkipTrue);
        JSONObject propertyModuleConfigValueSkipFalse = new JSONObject();
        propertyModuleConfigValueSkipFalse.put("vectorizePropertyName",false);
        propertyModuleConfigValueSkipFalse.put("skip",false);
        JSONObject propertyModuleConfigSkipFalse = new JSONObject();
        propertyModuleConfigSkipFalse.put("text2vec-transformers",propertyModuleConfigValueSkipFalse);
        WeaviateClass clazz = WeaviateClass.builder()
            .className(className + kid)
            .description("local knowledge")
            .vectorIndexType("hnsw")
            .vectorizer("text2vec-transformers")
            .shardingConfig(shardingConfig)
            .vectorIndexConfig(vectorIndexConfig)
            .replicationConfig(replicationConfig)
            .moduleConfig(classModuleConfig)
            .properties(new ArrayList() {{
                add(Property.builder()
                        .dataType(new ArrayList(){ { add(DataType.TEXT); } })
                        .name("content")
                        .description("The content of the local knowledge,for search")
                        .moduleConfig(propertyModuleConfigSkipFalse)
                        .build());
                add(Property.builder()
                        .dataType(new ArrayList(){ { add(DataType.TEXT); } })
                        .name("kid")
                        .description("The knowledge id of the local knowledge,for search")
                        .moduleConfig(propertyModuleConfigSkipTrue)
                        .build());
                add(Property.builder()
                        .dataType(new ArrayList(){ { add(DataType.TEXT); } })
                        .name("docId")
                        .description("The doc id of the local knowledge,for search")
                        .moduleConfig(propertyModuleConfigSkipTrue)
                        .build());
                add(Property.builder()
                        .dataType(new ArrayList(){ { add(DataType.TEXT); } })
                        .name("fid")
                        .description("The fragment id of the local knowledge,for search")
                        .moduleConfig(propertyModuleConfigSkipTrue)
                        .build());
                add(Property.builder()
                        .dataType(new ArrayList(){ { add(DataType.TEXT); } })
                        .name("uuid")
                        .description("The uuid id of the local knowledge fragment(same with id properties),for search")
                        .moduleConfig(propertyModuleConfigSkipTrue)
                        .build());
            } })
            .build();
        Result<Boolean> result = client.schema().classCreator().withClass(clazz).run();
        if (result.hasErrors()) {
            System.out.println(result.getError());
        }
        System.out.println(result.getResult());
            return result;
    }
    @Override
    public void newSchema(String kid) {
        createSchema(kid);
    }
    @Override
    public void removeByKidAndFid(String kid, String fid) {
        List<String> resultList = new ArrayList<>();
        WeaviateClient client = getClient();
        Field fieldId = Field.builder().name("uuid").build();
        WhereFilter where = WhereFilter.builder()
                .path(new String[]{ "fid" })
                .operator(Operator.Equal)
                .valueString(fid)
                .build();
        Result<GraphQLResponse> result = client.graphQL().get()
                .withClassName(className + kid)
                .withFields(fieldId)
                .withWhere(where)
                .run();
        LinkedTreeMap<String,Object> t = (LinkedTreeMap<String, Object>) result.getResult().getData();
        LinkedTreeMap<String,ArrayList<LinkedTreeMap>> l = (LinkedTreeMap<String, ArrayList<LinkedTreeMap>>) t.get("Get");
        ArrayList<LinkedTreeMap> m = l.get(className + kid);
        for (LinkedTreeMap linkedTreeMap : m){
            String uuid = linkedTreeMap.get("uuid").toString();
            resultList.add(uuid);
        }
        for (String uuid : resultList) {
            Result<Boolean> deleteResult = client.data().deleter()
                    .withID(uuid)
                    .withClassName(className + kid)
                    .withConsistencyLevel(ConsistencyLevel.ALL)  // default QUORUM
                    .run();
        }
    }
    @Override
    public void storeEmbeddings(List<String> chunkList, List<List<Double>> vectorList,String kid, String docId,List<String> fidList) {
        WeaviateClient client = getClient();
        for (int i = 0; i < chunkList.size(); i++) {
            if (vectorList != null) {
                List<Double> vector = vectorList.get(i);
                Float[] vf = new Float[vector.size()];
                for (int j = 0; j < vector.size(); j++) {
                    Double value = vector.get(j);
                    vf[j] = value.floatValue();
                }
                Map<String, Object> dataSchema = new HashMap<>();
                dataSchema.put("content", chunkList.get(i));
                dataSchema.put("kid", kid);
                dataSchema.put("docId", docId);
                dataSchema.put("fid", fidList.get(i));
                String uuid = UUID.randomUUID(true).toString();
                dataSchema.put("uuid", uuid);
                Result<WeaviateObject> result = client.data().creator()
                        .withClassName(className + kid)
                        .withID(uuid)
                        .withVector(vf)
                        .withProperties(dataSchema)
                        .run();
            }
        }
    }
    @Override
    public void removeByDocId(String kid,String docId) {
        List<String> resultList = new ArrayList<>();
        WeaviateClient client = getClient();
        Field fieldId = Field.builder().name("uuid").build();
        WhereFilter where = WhereFilter.builder()
            .path(new String[]{ "docId" })
            .operator(Operator.Equal)
            .valueString(docId)
            .build();
        Result<GraphQLResponse> result = client.graphQL().get()
            .withClassName(className + kid)
            .withFields(fieldId)
            .withWhere(where)
            .run();
        LinkedTreeMap<String,Object> t = (LinkedTreeMap<String, Object>) result.getResult().getData();
        LinkedTreeMap<String,ArrayList<LinkedTreeMap>> l = (LinkedTreeMap<String, ArrayList<LinkedTreeMap>>) t.get("Get");
        ArrayList<LinkedTreeMap> m = l.get(className + kid);
        for (LinkedTreeMap linkedTreeMap : m){
            String uuid = linkedTreeMap.get("uuid").toString();
            resultList.add(uuid);
        }
        for (String uuid : resultList) {
            Result<Boolean> deleteResult = client.data().deleter()
                .withID(uuid)
                .withClassName(className + kid)
                .withConsistencyLevel(ConsistencyLevel.ALL)  // default QUORUM
                .run();
        }
    }
    @Override
    public void removeByKid(String kid) {
        WeaviateClient client = getClient();
        Result<Boolean> result = client.schema().classDeleter().withClassName(className + kid).run();
        if (result.hasErrors()) {
            System.out.println("删除schema失败" + result.getError());
        }else {
            System.out.println("删除schema成功" + result.getResult());
        }
        log.info("drop schema by kid, result = {}",result);
    }
    @Override
    public List<String> nearest(List<Double> queryVector,String kid) {
        if (StringUtils.isBlank(kid)){
            return new ArrayList<String>();
        }
        List<String> resultList = new ArrayList<>();
        Float[] vf = new Float[queryVector.size()];
        for (int j = 0; j < queryVector.size(); j++) {
            Double value = queryVector.get(j);
            vf[j] = value.floatValue();
        }
        WeaviateClient client = getClient();
        Field contentField = Field.builder().name("content").build();
        Field _additional = Field.builder()
                .name("_additional")
                .fields(new Field[]{
                        Field.builder().name("distance").build()
                }).build();
        NearVectorArgument nearVector = NearVectorArgument.builder()
                .vector(vf)
                .distance(1.6f) // certainty = 1f - distance /2f
                .build();
        Result<GraphQLResponse> result = client.graphQL().get()
                .withClassName(className + kid)
                .withFields(contentField,_additional)
                .withNearVector(nearVector)
                .withLimit(promptRetrieverProperties.getLimits())
                .run();
        LinkedTreeMap<String,Object> t = (LinkedTreeMap<String, Object>) result.getResult().getData();
        LinkedTreeMap<String,ArrayList<LinkedTreeMap>> l = (LinkedTreeMap<String, ArrayList<LinkedTreeMap>>) t.get("Get");
        ArrayList<LinkedTreeMap> m = l.get(className + kid);
        for (LinkedTreeMap linkedTreeMap : m){
            String content = linkedTreeMap.get("content").toString();
            resultList.add(content);
        }
        return resultList;
    }
    @Override
    public List<String> nearest(String query,String kid) {
        if (StringUtils.isBlank(kid)){
            return new ArrayList<String>();
        }
        List<String> resultList = new ArrayList<>();
        WeaviateClient client = getClient();
        Field contentField = Field.builder().name("content").build();
        Field _additional = Field.builder()
                .name("_additional")
                .fields(new Field[]{
                        Field.builder().name("distance").build()
                }).build();
        NearTextArgument nearText = client.graphQL().arguments().nearTextArgBuilder()
                .concepts(new String[]{ query })
                .distance(1.6f) // certainty = 1f - distance /2f
                .build();
        Result<GraphQLResponse> result = client.graphQL().get()
                .withClassName(className + kid)
                .withFields(contentField,_additional)
                .withNearText(nearText)
                .withLimit(promptRetrieverProperties.getLimits())
                .run();
        LinkedTreeMap<String,Object> t = (LinkedTreeMap<String, Object>) result.getResult().getData();
        LinkedTreeMap<String,ArrayList<LinkedTreeMap>> l = (LinkedTreeMap<String, ArrayList<LinkedTreeMap>>) t.get("Get");
        ArrayList<LinkedTreeMap> m = l.get(className + kid);
        for (LinkedTreeMap linkedTreeMap : m){
            String content = linkedTreeMap.get("content").toString();
            resultList.add(content);
        }
        return resultList;
    }
    public Result<Boolean> deleteSchema(String kid) {
        WeaviateClient client = getClient();
        Result<Boolean> result = client.schema().classDeleter().withClassName(className+ kid).run();
        if (result.hasErrors()) {
            System.out.println(result.getError());
        }else {
            System.out.println(result.getResult());
        }
        return result;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/constant/FileType.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,91 @@
package org.ruoyi.knowledge.constant;
public class FileType {
    public static final String TXT = "txt";
    public static final String CSV = "csv";
    public static final String MD = "md";
    public static final String DOC = "doc";
    public static final String DOCX = "docx";
    public static final String PDF = "pdf";
    public static final String LOG = "log";
    public static final String XML = "xml";
    public static final String JAVA = "java";
    public static final String HTML = "html";
    public static final String HTM = "htm";
    public static final String CSS = "css";
    public static final String JS = "js";
    public static final String PY = "py";
    public static final String CPP = "cpp";
    public static final String SQL = "sql";
    public static final String PHP = "php";
    public static final String RUBY = "ruby";
    public static final String C = "c";
    public static final String H = "h";
    public static final String HPP = "hpp";
    public static final String SWIFT = "swift";
    public static final String TS = "ts";
    public static final String RUST = "rs";
    public static final String PERL = "perl";
    public static final String SHELL = "shell";
    public static final String BAT = "bat";
    public static final String CMD = "cmd";
    public static final String PROPERTIES = "properties";
    public static final String INI = "ini";
    public static final String YAML = "yaml";
    public static final String YML = "yml";
    public static boolean isTextFile(String type){
        if (type.equalsIgnoreCase(TXT) || type.equalsIgnoreCase(CSV) || type.equalsIgnoreCase(PROPERTIES)
                || type.equalsIgnoreCase(INI) || type.equalsIgnoreCase(YAML) || type.equalsIgnoreCase(YML)
                || type.equalsIgnoreCase(LOG) || type.equalsIgnoreCase(XML)){
            return true;
        }
        else {
            return false;
        }
    }
    public static boolean isCodeFile(String type){
        if (type.equalsIgnoreCase(JAVA) || type.equalsIgnoreCase(HTML) || type.equalsIgnoreCase(HTM) || type.equalsIgnoreCase(JS) || type.equalsIgnoreCase(PY)
                || type.equalsIgnoreCase(CPP) || type.equalsIgnoreCase(SQL) || type.equalsIgnoreCase(PHP) || type.equalsIgnoreCase(RUBY)
                || type.equalsIgnoreCase(C) || type.equalsIgnoreCase(H) || type.equalsIgnoreCase(HPP) || type.equalsIgnoreCase(SWIFT)
                || type.equalsIgnoreCase(TS) || type.equalsIgnoreCase(RUST) || type.equalsIgnoreCase(PERL) || type.equalsIgnoreCase(SHELL)
                || type.equalsIgnoreCase(BAT) || type.equalsIgnoreCase(CMD) || type.equalsIgnoreCase(CSS)){
            return true;
        }
        else {
            return false;
        }
    }
    public static boolean isMdFile(String type){
        if (type.equalsIgnoreCase(MD)){
            return true;
        }
        else {
            return false;
        }
    }
    public static boolean isWord(String type){
        if (type.equalsIgnoreCase(DOC) || type.equalsIgnoreCase(DOCX)){
            return true;
        }
        else {
            return false;
        }
    }
    public static boolean isPdf(String type){
        if (type.equalsIgnoreCase(PDF)){
            return true;
        }
        else {
            return false;
        }
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/KnowledgeAttach.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
package org.ruoyi.knowledge.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
 * çŸ¥è¯†åº“附件对象 knowledge_attach
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@Data
@TableName("knowledge_attach")
public class KnowledgeAttach implements Serializable {
    @TableId(value = "id")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    private String kid;
    /**
     * æ–‡æ¡£ID
     */
    private String docId;
    /**
     * æ–‡æ¡£åç§°
     */
    private String docName;
    /**
     * æ–‡æ¡£ç±»åž‹
     */
    private String docType;
    /**
     * æ–‡æ¡£å†…容
     */
    private String content;
    /**
     * åˆ›å»ºè€…
     */
    private String createBy;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    private Date createTime;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/KnowledgeFragment.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
package org.ruoyi.knowledge.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
 * çŸ¥è¯†ç‰‡æ®µå¯¹è±¡ knowledge_fragment
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@Data
@TableName("knowledge_fragment")
public class KnowledgeFragment implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    @TableId(value = "id")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    private String kid;
    /**
     * æ–‡æ¡£ID
     */
    private String docId;
    /**
     * çŸ¥è¯†ç‰‡æ®µID
     */
    private String fid;
    /**
     * ç‰‡æ®µç´¢å¼•下标
     */
    private Integer idx;
    /**
     * æ–‡æ¡£å†…容
     */
    private String content;
    /**
     * åˆ›å»ºè€…
     */
    private String createBy;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    private Date createTime;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/KnowledgeInfo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
package org.ruoyi.knowledge.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
 * çŸ¥è¯†åº“对象 knowledge_info
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@Data
@TableName("knowledge_info")
public class KnowledgeInfo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     *
     */
    @TableId(value = "id")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    private String kid;
    /**
     * ç”¨æˆ·ID
     */
    private Long uid;
    /**
     * çŸ¥è¯†åº“名称
     */
    private String kname;
    /**
     * æè¿°
     */
    private String description;
    /**
     * åˆ›å»ºè€…
     */
    private String createBy;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    private Date createTime;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/bo/KnowledgeAttachBo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
package org.ruoyi.knowledge.domain.bo;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import org.ruoyi.knowledge.domain.KnowledgeAttach;
/**
 * çŸ¥è¯†åº“附件业务对象 knowledge_attach
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = KnowledgeAttach.class, reverseConvertGenerate = false)
public class KnowledgeAttachBo extends BaseEntity {
    @NotNull(message = "不能为空")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    @NotBlank(message = "知识库ID不能为空")
    private String kid;
    /**
     * æ–‡æ¡£ID
     */
    @NotBlank(message = "文档ID不能为空")
    private String docId;
    /**
     * æ–‡æ¡£åç§°
     */
    @NotBlank(message = "文档名称不能为空")
    private String docName;
    /**
     * æ–‡æ¡£ç±»åž‹
     */
    @NotBlank(message = "文档类型不能为空")
    private String docType;
    /**
     * æ–‡æ¡£å†…容
     */
    @NotBlank(message = "文档内容不能为空")
    private String content;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/bo/KnowledgeFragmentBo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
package org.ruoyi.knowledge.domain.bo;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import org.ruoyi.knowledge.domain.KnowledgeFragment;
/**
 * çŸ¥è¯†ç‰‡æ®µä¸šåŠ¡å¯¹è±¡ knowledge_fragment
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = KnowledgeFragment.class, reverseConvertGenerate = false)
public class KnowledgeFragmentBo extends BaseEntity {
    /**
     *
     */
    @NotNull(message = "不能为空")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    @NotBlank(message = "知识库ID不能为空")
    private String kid;
    /**
     * æ–‡æ¡£ID
     */
    @NotBlank(message = "文档ID不能为空")
    private String docId;
    /**
     * çŸ¥è¯†ç‰‡æ®µID
     */
    @NotBlank(message = "知识片段ID不能为空")
    private String fid;
    /**
     * ç‰‡æ®µç´¢å¼•下标
     */
    @NotNull(message = "片段索引下标不能为空")
    private Long idx;
    /**
     * æ–‡æ¡£å†…容
     */
    @NotBlank(message = "文档内容不能为空")
    private String content;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/bo/KnowledgeInfoBo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
package org.ruoyi.knowledge.domain.bo;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
import org.ruoyi.knowledge.domain.KnowledgeInfo;
/**
 * çŸ¥è¯†åº“业务对象 knowledge_info
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = KnowledgeInfo.class, reverseConvertGenerate = false)
public class KnowledgeInfoBo extends BaseEntity {
    /**
     *
     */
    @NotNull(message = "不能为空")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    @NotBlank(message = "知识库ID不能为空")
    private String kid;
    /**
     * ç”¨æˆ·ID
     */
    @NotNull(message = "用户ID不能为空")
    private Long uid;
    /**
     * çŸ¥è¯†åº“名称
     */
    @NotBlank(message = "知识库名称不能为空")
    private String kname;
    /**
     * æè¿°
     */
    @NotBlank(message = "描述不能为空")
    private String description;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/req/KnowledgeInfoUploadRequest.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package org.ruoyi.knowledge.domain.req;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
@Data
public class KnowledgeInfoUploadRequest {
    private String kid;
    private MultipartFile file;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/request.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,4 @@
package org.ruoyi.knowledge.domain;
public class request {
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/vo/KnowledgeAttachVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
package org.ruoyi.knowledge.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.ruoyi.knowledge.domain.KnowledgeAttach;
import java.io.Serial;
import java.io.Serializable;
/**
 * çŸ¥è¯†åº“附件视图对象 knowledge_attach
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = KnowledgeAttach.class)
public class KnowledgeAttachVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     *
     */
    @ExcelProperty(value = "")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    @ExcelProperty(value = "知识库ID")
    private String kid;
    /**
     * æ–‡æ¡£ID
     */
    @ExcelProperty(value = "文档ID")
    private String docId;
    /**
     * æ–‡æ¡£åç§°
     */
    @ExcelProperty(value = "文档名称")
    private String docName;
    /**
     * æ–‡æ¡£ç±»åž‹
     */
    @ExcelProperty(value = "文档类型")
    private String docType;
    /**
     * æ–‡æ¡£å†…容
     */
    @ExcelProperty(value = "文档内容")
    private String content;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/vo/KnowledgeFragmentVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
package org.ruoyi.knowledge.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.ruoyi.knowledge.domain.KnowledgeFragment;
import java.io.Serial;
import java.io.Serializable;
/**
 * çŸ¥è¯†ç‰‡æ®µè§†å›¾å¯¹è±¡ knowledge_fragment
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = KnowledgeFragment.class)
public class KnowledgeFragmentVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     *
     */
    @ExcelProperty(value = "")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    @ExcelProperty(value = "知识库ID")
    private String kid;
    /**
     * æ–‡æ¡£ID
     */
    @ExcelProperty(value = "文档ID")
    private String docId;
    /**
     * çŸ¥è¯†ç‰‡æ®µID
     */
    @ExcelProperty(value = "知识片段ID")
    private String fid;
    /**
     * ç‰‡æ®µç´¢å¼•下标
     */
    @ExcelProperty(value = "片段索引下标")
    private Long idx;
    /**
     * æ–‡æ¡£å†…容
     */
    @ExcelProperty(value = "文档内容")
    private String content;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/domain/vo/KnowledgeInfoVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
package org.ruoyi.knowledge.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.ruoyi.knowledge.domain.KnowledgeInfo;
import java.io.Serial;
import java.io.Serializable;
/**
 * çŸ¥è¯†åº“视图对象 knowledge_info
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = KnowledgeInfo.class)
public class KnowledgeInfoVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     *
     */
    @ExcelProperty(value = "")
    private Long id;
    /**
     * çŸ¥è¯†åº“ID
     */
    @ExcelProperty(value = "知识库ID")
    private String kid;
    /**
     * ç”¨æˆ·ID
     */
    @ExcelProperty(value = "用户ID")
    private Long uid;
    /**
     * çŸ¥è¯†åº“名称
     */
    @ExcelProperty(value = "知识库名称")
    private String kname;
    /**
     * æè¿°
     */
    @ExcelProperty(value = "描述")
    private String description;
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/mapper/KnowledgeAttachMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
package org.ruoyi.knowledge.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
import org.ruoyi.knowledge.domain.KnowledgeAttach;
import org.ruoyi.knowledge.domain.vo.KnowledgeAttachVo;
/**
 * çŸ¥è¯†åº“附件Mapper接口
 *
 * @author Lion Li
 * @date 2024-10-21
 */
public interface KnowledgeAttachMapper extends BaseMapperPlus<KnowledgeAttach, KnowledgeAttachVo> {
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/mapper/KnowledgeFragmentMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
package org.ruoyi.knowledge.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
import org.ruoyi.knowledge.domain.KnowledgeFragment;
import org.ruoyi.knowledge.domain.vo.KnowledgeFragmentVo;
/**
 * çŸ¥è¯†ç‰‡æ®µMapper接口
 *
 * @author Lion Li
 * @date 2024-10-21
 */
public interface KnowledgeFragmentMapper extends BaseMapperPlus<KnowledgeFragment, KnowledgeFragmentVo> {
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/mapper/KnowledgeInfoMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
package org.ruoyi.knowledge.mapper;
import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus;
import org.ruoyi.knowledge.domain.KnowledgeInfo;
import org.ruoyi.knowledge.domain.vo.KnowledgeInfoVo;
/**
 * çŸ¥è¯†åº“Mapper接口
 *
 * @author Lion Li
 * @date 2024-10-21
 */
public interface KnowledgeInfoMapper extends BaseMapperPlus<KnowledgeInfo, KnowledgeInfoVo> {
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/EmbeddingService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package org.ruoyi.knowledge.service;
import java.util.List;
public interface EmbeddingService {
    void storeEmbeddings(List<String> chunkList, String kid, String docId,List<String> fidList);
    void removeByDocId(String kid,String docId);
    void removeByKid(String kid);
    List<Double> getQueryVector(String query);
    void createSchema(String kid);
    void removeByKidAndFid(String kid, String fid);
    void saveFragment(String kid, String docId, String fid, String content);
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/IKnowledgeAttachService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
package org.ruoyi.knowledge.service;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.knowledge.domain.bo.KnowledgeAttachBo;
import org.ruoyi.knowledge.domain.vo.KnowledgeAttachVo;
import java.util.Collection;
import java.util.List;
/**
 * çŸ¥è¯†åº“附件Service接口
 *
 * @author Lion Li
 * @date 2024-10-21
 */
public interface IKnowledgeAttachService {
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“附件
     */
    KnowledgeAttachVo queryById(Long id);
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“附件列表
     */
    TableDataInfo<KnowledgeAttachVo> queryPageList(KnowledgeAttachBo bo, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“附件列表
     */
    List<KnowledgeAttachVo> queryList(KnowledgeAttachBo bo);
    /**
     * æ–°å¢žçŸ¥è¯†åº“附件
     */
    Boolean insertByBo(KnowledgeAttachBo bo);
    /**
     * ä¿®æ”¹çŸ¥è¯†åº“附件
     */
    Boolean updateByBo(KnowledgeAttachBo bo);
    /**
     * æ ¡éªŒå¹¶æ‰¹é‡åˆ é™¤çŸ¥è¯†åº“附件信息
     */
    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
    /**
     * åˆ é™¤çŸ¥è¯†é™„ä»¶
     *
     * @return
     */
    void removeKnowledgeAttach(String kid);
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/IKnowledgeFragmentService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
package org.ruoyi.knowledge.service;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.knowledge.domain.bo.KnowledgeFragmentBo;
import org.ruoyi.knowledge.domain.vo.KnowledgeFragmentVo;
import java.util.Collection;
import java.util.List;
/**
 * çŸ¥è¯†ç‰‡æ®µService接口
 *
 * @author Lion Li
 * @date 2024-10-21
 */
public interface IKnowledgeFragmentService {
    /**
     * æŸ¥è¯¢çŸ¥è¯†ç‰‡æ®µ
     */
    KnowledgeFragmentVo queryById(Long id);
    /**
     * æŸ¥è¯¢çŸ¥è¯†ç‰‡æ®µåˆ—表
     */
    TableDataInfo<KnowledgeFragmentVo> queryPageList(KnowledgeFragmentBo bo, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢çŸ¥è¯†ç‰‡æ®µåˆ—表
     */
    List<KnowledgeFragmentVo> queryList(KnowledgeFragmentBo bo);
    /**
     * æ–°å¢žçŸ¥è¯†ç‰‡æ®µ
     */
    Boolean insertByBo(KnowledgeFragmentBo bo);
    /**
     * ä¿®æ”¹çŸ¥è¯†ç‰‡æ®µ
     */
    Boolean updateByBo(KnowledgeFragmentBo bo);
    /**
     * æ ¡éªŒå¹¶æ‰¹é‡åˆ é™¤çŸ¥è¯†ç‰‡æ®µä¿¡æ¯
     */
    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/IKnowledgeInfoService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
package org.ruoyi.knowledge.service;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.knowledge.domain.KnowledgeAttach;
import org.ruoyi.knowledge.domain.bo.KnowledgeAttachBo;
import org.ruoyi.knowledge.domain.bo.KnowledgeInfoBo;
import org.ruoyi.knowledge.domain.req.KnowledgeInfoUploadRequest;
import org.ruoyi.knowledge.domain.vo.KnowledgeInfoVo;
import java.util.Collection;
import java.util.List;
/**
 * çŸ¥è¯†åº“Service接口
 *
 * @author Lion Li
 * @date 2024-10-21
 */
public interface IKnowledgeInfoService {
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“
     */
    KnowledgeInfoVo queryById(Long id);
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“列表
     */
    TableDataInfo<KnowledgeInfoVo> queryPageList(KnowledgeInfoBo bo, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“列表
     */
    List<KnowledgeInfoVo> queryList(KnowledgeInfoBo bo);
    /**
     * ä¿®æ”¹çŸ¥è¯†åº“
     */
    Boolean updateByBo(KnowledgeInfoBo bo);
    /**
     * æ–°å¢žçŸ¥è¯†åº“
     */
    void saveOne(KnowledgeInfoBo bo);
    /**
     * ä¸Šä¼ é™„ä»¶
     */
    void upload(KnowledgeInfoUploadRequest request);
    /**
     * åˆ é™¤çŸ¥è¯†åº“
     */
    void removeKnowledge(String id);
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/impl/EmbeddingServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
package org.ruoyi.knowledge.service.impl;
import lombok.AllArgsConstructor;
import org.ruoyi.knowledge.chain.vectorizer.Vectorization;
import org.ruoyi.knowledge.chain.vectorstore.VectorStore;
import org.ruoyi.knowledge.service.EmbeddingService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
@AllArgsConstructor
public class EmbeddingServiceImpl implements EmbeddingService {
    private final VectorStore vectorStore;
    private final Vectorization vectorization;
    /**
     * ä¿å­˜å‘量数据库
     * @param chunkList         æ–‡æ¡£æŒ‰è¡Œåˆ‡åˆ†çš„片段
     * @param kid               çŸ¥è¯†åº“ID
     * @param docId             æ–‡æ¡£ID
     */
    @Override
    public void storeEmbeddings(List<String> chunkList, String kid, String docId,List<String> fidList) {
        List<List<Double>> vectorList = vectorization.batchVectorization(chunkList);
        vectorStore.storeEmbeddings(chunkList,vectorList,kid,docId,fidList);
    }
    @Override
    public void removeByDocId(String kid,String docId) {
        vectorStore.removeByDocId(kid,docId);
    }
    @Override
    public void removeByKid(String kid) {
        vectorStore.removeByKid(kid);
    }
    @Override
    public List<Double> getQueryVector(String query) {
        List<Double> queryVector = vectorization.singleVectorization(query);
        return queryVector;
    }
    @Override
    public void createSchema(String kid) {
        vectorStore.newSchema(kid);
    }
    @Override
    public void removeByKidAndFid(String kid, String fid) {
        vectorStore.removeByKidAndFid(kid,fid);
    }
    @Override
    public void saveFragment(String kid, String docId, String fid, String content) {
        List<String> chunkList = new ArrayList<>();
        List<String> fidList = new ArrayList<>();
        chunkList.add(content);
        fidList.add(fid);
        storeEmbeddings(chunkList,kid,docId,fidList);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/impl/KnowledgeAttachServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,125 @@
package org.ruoyi.knowledge.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.knowledge.domain.KnowledgeAttach;
import org.ruoyi.knowledge.domain.bo.KnowledgeAttachBo;
import org.ruoyi.knowledge.domain.vo.KnowledgeAttachVo;
import org.ruoyi.knowledge.mapper.KnowledgeAttachMapper;
import org.ruoyi.knowledge.mapper.KnowledgeFragmentMapper;
import org.ruoyi.knowledge.service.IKnowledgeAttachService;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * çŸ¥è¯†åº“附件Service业务层处理
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@RequiredArgsConstructor
@Service
public class KnowledgeAttachServiceImpl implements IKnowledgeAttachService {
    private final KnowledgeAttachMapper baseMapper;
    private final KnowledgeFragmentMapper fragmentMapper;
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“附件
     */
    @Override
    public KnowledgeAttachVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“附件列表
     */
    @Override
    public TableDataInfo<KnowledgeAttachVo> queryPageList(KnowledgeAttachBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<KnowledgeAttach> lqw = buildQueryWrapper(bo);
        Page<KnowledgeAttachVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“附件列表
     */
    @Override
    public List<KnowledgeAttachVo> queryList(KnowledgeAttachBo bo) {
        LambdaQueryWrapper<KnowledgeAttach> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }
    private LambdaQueryWrapper<KnowledgeAttach> buildQueryWrapper(KnowledgeAttachBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<KnowledgeAttach> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getKid()), KnowledgeAttach::getKid, bo.getKid());
        lqw.eq(StringUtils.isNotBlank(bo.getDocId()), KnowledgeAttach::getDocId, bo.getDocId());
        lqw.like(StringUtils.isNotBlank(bo.getDocName()), KnowledgeAttach::getDocName, bo.getDocName());
        lqw.eq(StringUtils.isNotBlank(bo.getDocType()), KnowledgeAttach::getDocType, bo.getDocType());
        lqw.eq(StringUtils.isNotBlank(bo.getContent()), KnowledgeAttach::getContent, bo.getContent());
        return lqw;
    }
    /**
     * æ–°å¢žçŸ¥è¯†åº“附件
     */
    @Override
    public Boolean insertByBo(KnowledgeAttachBo bo) {
        KnowledgeAttach add = MapstructUtils.convert(bo, KnowledgeAttach.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }
    /**
     * ä¿®æ”¹çŸ¥è¯†åº“附件
     */
    @Override
    public Boolean updateByBo(KnowledgeAttachBo bo) {
        KnowledgeAttach update = MapstructUtils.convert(bo, KnowledgeAttach.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }
    /**
     * ä¿å­˜å‰çš„æ•°æ®æ ¡éªŒ
     */
    private void validEntityBeforeSave(KnowledgeAttach entity){
        //TODO åšä¸€äº›æ•°æ®æ ¡éªŒ,如唯一约束
    }
    /**
     * æ‰¹é‡åˆ é™¤çŸ¥è¯†åº“附件
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO åšä¸€äº›ä¸šåŠ¡ä¸Šçš„æ ¡éªŒ,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }
    @Override
    public void removeKnowledgeAttach(String kid) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("kid", kid);
        baseMapper.deleteByMap(map);
        fragmentMapper.deleteByMap(map);
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/impl/KnowledgeFragmentServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,113 @@
package org.ruoyi.knowledge.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.knowledge.domain.KnowledgeFragment;
import org.ruoyi.knowledge.domain.bo.KnowledgeFragmentBo;
import org.ruoyi.knowledge.domain.vo.KnowledgeFragmentVo;
import org.ruoyi.knowledge.mapper.KnowledgeFragmentMapper;
import org.ruoyi.knowledge.service.IKnowledgeFragmentService;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
 * çŸ¥è¯†ç‰‡æ®µService业务层处理
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@RequiredArgsConstructor
@Service
public class KnowledgeFragmentServiceImpl implements IKnowledgeFragmentService {
    private final KnowledgeFragmentMapper baseMapper;
    /**
     * æŸ¥è¯¢çŸ¥è¯†ç‰‡æ®µ
     */
    @Override
    public KnowledgeFragmentVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†ç‰‡æ®µåˆ—表
     */
    @Override
    public TableDataInfo<KnowledgeFragmentVo> queryPageList(KnowledgeFragmentBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<KnowledgeFragment> lqw = buildQueryWrapper(bo);
        lqw.eq(KnowledgeFragment::getDocId, bo.getDocId());
        Page<KnowledgeFragmentVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†ç‰‡æ®µåˆ—表
     */
    @Override
    public List<KnowledgeFragmentVo> queryList(KnowledgeFragmentBo bo) {
        LambdaQueryWrapper<KnowledgeFragment> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }
    private LambdaQueryWrapper<KnowledgeFragment> buildQueryWrapper(KnowledgeFragmentBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<KnowledgeFragment> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getKid()), KnowledgeFragment::getKid, bo.getKid());
        lqw.eq(StringUtils.isNotBlank(bo.getDocId()), KnowledgeFragment::getDocId, bo.getDocId());
        lqw.eq(StringUtils.isNotBlank(bo.getFid()), KnowledgeFragment::getFid, bo.getFid());
        lqw.eq(bo.getIdx() != null, KnowledgeFragment::getIdx, bo.getIdx());
        lqw.eq(StringUtils.isNotBlank(bo.getContent()), KnowledgeFragment::getContent, bo.getContent());
        return lqw;
    }
    /**
     * æ–°å¢žçŸ¥è¯†ç‰‡æ®µ
     */
    @Override
    public Boolean insertByBo(KnowledgeFragmentBo bo) {
        KnowledgeFragment add = MapstructUtils.convert(bo, KnowledgeFragment.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }
    /**
     * ä¿®æ”¹çŸ¥è¯†ç‰‡æ®µ
     */
    @Override
    public Boolean updateByBo(KnowledgeFragmentBo bo) {
        KnowledgeFragment update = MapstructUtils.convert(bo, KnowledgeFragment.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }
    /**
     * ä¿å­˜å‰çš„æ•°æ®æ ¡éªŒ
     */
    private void validEntityBeforeSave(KnowledgeFragment entity){
        //TODO åšä¸€äº›æ•°æ®æ ¡éªŒ,如唯一约束
    }
    /**
     * æ‰¹é‡åˆ é™¤çŸ¥è¯†ç‰‡æ®µ
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO åšä¸€äº›ä¸šåŠ¡ä¸Šçš„æ ¡éªŒ,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }
}
ruoyi-modules/ruoyi-knowledge/src/main/java/org/ruoyi/knowledge/service/impl/KnowledgeInfoServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,218 @@
package org.ruoyi.knowledge.service.impl;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.github.ollama4j.OllamaAPI;
import io.github.ollama4j.exceptions.OllamaBaseException;
import io.github.ollama4j.models.chat.OllamaChatMessageRole;
import io.github.ollama4j.models.chat.OllamaChatRequestBuilder;
import io.github.ollama4j.models.chat.OllamaChatRequestModel;
import io.github.ollama4j.models.chat.OllamaChatResult;
import lombok.RequiredArgsConstructor;
import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.satoken.utils.LoginHelper;
import org.ruoyi.knowledge.chain.loader.ResourceLoader;
import org.ruoyi.knowledge.chain.loader.ResourceLoaderFactory;
import org.ruoyi.knowledge.domain.KnowledgeAttach;
import org.ruoyi.knowledge.domain.KnowledgeFragment;
import org.ruoyi.knowledge.domain.KnowledgeInfo;
import org.ruoyi.knowledge.domain.bo.KnowledgeAttachBo;
import org.ruoyi.knowledge.domain.bo.KnowledgeFragmentBo;
import org.ruoyi.knowledge.domain.bo.KnowledgeInfoBo;
import org.ruoyi.knowledge.domain.req.KnowledgeInfoUploadRequest;
import org.ruoyi.knowledge.domain.vo.KnowledgeInfoVo;
import org.ruoyi.knowledge.mapper.KnowledgeAttachMapper;
import org.ruoyi.knowledge.mapper.KnowledgeFragmentMapper;
import org.ruoyi.knowledge.mapper.KnowledgeInfoMapper;
import org.ruoyi.knowledge.service.EmbeddingService;
import org.ruoyi.knowledge.service.IKnowledgeAttachService;
import org.ruoyi.knowledge.service.IKnowledgeFragmentService;
import org.ruoyi.knowledge.service.IKnowledgeInfoService;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
/**
 * çŸ¥è¯†åº“Service业务层处理
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@RequiredArgsConstructor
@Service
public class KnowledgeInfoServiceImpl implements IKnowledgeInfoService {
    private final KnowledgeInfoMapper baseMapper;
    private final EmbeddingService embeddingService;
    private final ResourceLoaderFactory resourceLoaderFactory;
    private final KnowledgeFragmentMapper fragmentMapper;
    private final KnowledgeAttachMapper attachMapper;
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“
     */
    @Override
    public KnowledgeInfoVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“列表
     */
    @Override
    public TableDataInfo<KnowledgeInfoVo> queryPageList(KnowledgeInfoBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<KnowledgeInfo> lqw = buildQueryWrapper(bo);
        Page<KnowledgeInfoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    /**
     * æŸ¥è¯¢çŸ¥è¯†åº“列表
     */
    @Override
    public List<KnowledgeInfoVo> queryList(KnowledgeInfoBo bo) {
        LambdaQueryWrapper<KnowledgeInfo> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }
    private LambdaQueryWrapper<KnowledgeInfo> buildQueryWrapper(KnowledgeInfoBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<KnowledgeInfo> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getKid()), KnowledgeInfo::getKid, bo.getKid());
        lqw.eq(bo.getUid() != null, KnowledgeInfo::getUid, bo.getUid());
        lqw.like(StringUtils.isNotBlank(bo.getKname()), KnowledgeInfo::getKname, bo.getKname());
        lqw.eq(StringUtils.isNotBlank(bo.getDescription()), KnowledgeInfo::getDescription, bo.getDescription());
        return lqw;
    }
    /**
     * ä¿®æ”¹çŸ¥è¯†åº“
     */
    @Override
    public Boolean updateByBo(KnowledgeInfoBo bo) {
        KnowledgeInfo update = MapstructUtils.convert(bo, KnowledgeInfo.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }
    /**
     * ä¿å­˜å‰çš„æ•°æ®æ ¡éªŒ
     */
    private void validEntityBeforeSave(KnowledgeInfo entity){
        //TODO åšä¸€äº›æ•°æ®æ ¡éªŒ,如唯一约束
    }
    @Override
    public void saveOne(KnowledgeInfoBo bo) {
        KnowledgeInfo knowledgeInfo = MapstructUtils.convert(bo, KnowledgeInfo.class);
        if (StringUtils.isBlank(bo.getKid())){
            String kid = RandomUtil.randomString(10);
            if (knowledgeInfo != null) {
                knowledgeInfo.setKid(kid);
                knowledgeInfo.setUid(LoginHelper.getLoginUser().getUserId());
            }
            baseMapper.insert(knowledgeInfo);
            embeddingService.createSchema(kid);
        }else {
            baseMapper.updateById(knowledgeInfo);
        }
    }
    @Override
    public void upload(KnowledgeInfoUploadRequest request) {
        storeContent(request.getFile(), request.getKid());
    }
    public void storeContent(MultipartFile file, String kid) {
        String fileName = file.getOriginalFilename();
        List<String> chunkList = new ArrayList<>();
        KnowledgeAttach knowledgeAttach = new KnowledgeAttach();
        knowledgeAttach.setKid(kid);
        String docId = RandomUtil.randomString(10);
        knowledgeAttach.setDocId(docId);
        knowledgeAttach.setDocName(fileName);
        knowledgeAttach.setDocType(fileName.substring(fileName.lastIndexOf(".")+1));
        String content = "";
        ResourceLoader resourceLoader = resourceLoaderFactory.getLoaderByFileType(knowledgeAttach.getDocType());
        List<String> fids = new ArrayList<>();
        try {
            content = resourceLoader.getContent(file.getInputStream());
            chunkList = resourceLoader.getChunkList(content);
            for (int i = 0; i < chunkList.size(); i++) {
                String fid = RandomUtil.randomString(16);
                fids.add(fid);
                KnowledgeFragment knowledgeFragment = new KnowledgeFragment();
                knowledgeFragment.setKid(kid);
                knowledgeFragment.setDocId(docId);
                knowledgeFragment.setFid(fid);
                knowledgeFragment.setIdx(i);
               // String text = convertTextBlockToPretrainData(chunkList.get(i));
                knowledgeFragment.setContent(chunkList.get(i));
                knowledgeFragment.setCreateTime(new Date());
                fragmentMapper.insert(knowledgeFragment);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        knowledgeAttach.setContent(content);
        knowledgeAttach.setCreateTime(new Date());
        attachMapper.insert(knowledgeAttach);
        embeddingService.storeEmbeddings(chunkList,kid,docId,fids);
    }
    @Override
    public void removeKnowledge(String id) {
        Map<String,Object> map = new HashMap<>();
        map.put("kid",id);
        // åˆ é™¤çŸ¥è¯†åº“
        baseMapper.deleteByMap(map);
        // åˆ é™¤é™„件和知识片段
        fragmentMapper.deleteByMap(map);
        attachMapper.deleteByMap(map);
        // åˆ é™¤å‘量库信息
        embeddingService.removeByKid(id);
    }
    /**
     * å°†æ–‡æœ¬å—转换为预训练数据
     * @param chunk è§£æžæ–‡æœ¬å—
     */
    public String convertTextBlockToPretrainData(String chunk){
            String host = "http://localhost:11434/";
            OllamaAPI ollama = new OllamaAPI(host);
            OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance("qwen2.5:7b");
            // è®¾ç½®è¶…æ—¶æ—¶é—´
            ollama.setRequestTimeoutSeconds(100);
            // create first user question
            String json = "instruction:用户指令,根据语义提取一个关键词;input:用户输入,根据语义提取多个关键词;output:输出文本内容";
            OllamaChatRequestModel requestModel = builder.withMessage
                (OllamaChatMessageRole.USER, "文本:"+chunk+"理解文本内容,并且将文本内容转换为:"+json+",输出JSON格式,不要包含其他无关内容,内部使用无需脱敏")
            .build();
            // start conversation with model
            OllamaChatResult chatResult = null;
            try {
                chatResult = ollama.chat(requestModel);
            } catch (Exception e) {
                System.out.println("解析失败!");
            }
            return chatResult.getResponse();
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
<!--
  ~ MIT License
  ~
  ~ Copyright (c) 2023 OrdinaryRoad
  ~
  ~ Permission is hereby granted, free of charge, to any person obtaining a copy
  ~ of this software and associated documentation files (the "Software"), to deal
  ~ in the Software without restriction, including without limitation the rights
  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  ~ copies of the Software, and to permit persons to whom the Software is
  ~ furnished to do so, subject to the following conditions:
  ~
  ~ The above copyright notice and this permission notice shall be included in all
  ~ copies or substantial portions of the Software.
  ~
  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  ~ SOFTWARE.
  -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.ruoyi</groupId>
        <artifactId>live-chat-client-commons</artifactId>
        <version>${revision}</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>live-chat-client-commons-base</artifactId>
    <name>ordinaryroad-live-chat-client-commons-base</name>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/constant/Constants.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.constant;
/**
 * @author mjz
 * @date 2023/8/26
 */
public class Constants {
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/exception/BaseException.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.exception;
/**
 * @author mjz
 * @date 2023/9/5
 */
public class BaseException extends RuntimeException {
    public BaseException() {
    }
    public BaseException(String message) {
        super(message);
    }
    public BaseException(String message, Throwable cause) {
        super(message, cause);
    }
    public BaseException(Throwable cause) {
        super(cause);
    }
    public BaseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/listener/IBaseConnectionListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.listener;
/**
 * è¿žæŽ¥å›žè°ƒ
 *
 * @author mjz
 * @date 2023/8/26
 */
public interface IBaseConnectionListener<T> {
    /**
     * è¿žæŽ¥å»ºç«‹æˆåŠŸ
     */
    default void onConnected(T t) {
        // ignore
    }
    /**
     * è¿žæŽ¥å»ºç«‹å¤±è´¥
     *
     * @param t
     */
    default void onConnectFailed(T t) {
        // ignore
    }
    /**
     * è¿žæŽ¥æ–­å¼€
     *
     * @param t
     */
    default void onDisconnected(T t) {
        // ignore
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/listener/IBaseMsgListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,149 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.listener;
import tech.ordinaryroad.live.chat.client.commons.base.msg.BaseCmdMsg;
import tech.ordinaryroad.live.chat.client.commons.base.msg.BaseMsg;
import tech.ordinaryroad.live.chat.client.commons.base.msg.ICmdMsg;
import tech.ordinaryroad.live.chat.client.commons.base.msg.IMsg;
/**
 * Base消息回调
 *
 * @author mjz
 * @date 2023/8/26
 */
public interface IBaseMsgListener<T, CmdEnum extends Enum<CmdEnum>> {
    /**
     * æ”¶åˆ°æ¶ˆæ¯ï¼ˆæ‰€æœ‰æ¶ˆæ¯ï¼‰
     *
     * @param msg IMsg
     */
    default void onMsg(T t, IMsg msg) {
        this.onMsg(msg);
    }
    default void onMsg(IMsg msg) {
        // ignore
    }
    /**
     * æ”¶åˆ°cmd消息(所有cmd)
     *
     * @param cmd    CmdEnum
     * @param cmdMsg BaseCmdMsg
     */
    default void onCmdMsg(T t, CmdEnum cmd, ICmdMsg<CmdEnum> cmdMsg) {
        this.onCmdMsg(cmd, cmdMsg);
    }
    default void onCmdMsg(CmdEnum cmd, ICmdMsg<CmdEnum> cmdMsg) {
        // ignore
    }
    /**
     * æ”¶åˆ°å…¶ä»–cmd消息(存在Enum,但Listener没有对应的回调)
     *
     * @param cmd    CmdEnum
     * @param cmdMsg BaseCmdMsg
     */
    default void onOtherCmdMsg(T t, CmdEnum cmd, ICmdMsg<CmdEnum> cmdMsg) {
        this.onOtherCmdMsg(cmd, cmdMsg);
    }
    default void onOtherCmdMsg(CmdEnum cmd, ICmdMsg<CmdEnum> cmdMsg) {
        // ignore
    }
    /**
     * æ”¶åˆ°æœªçŸ¥cmd消息
     *
     * @param cmdString å®žé™…收到的cmd字符串
     * @param msg       BaseMsg
     */
    default void onUnknownCmd(T t, String cmdString, IMsg msg) {
        this.onUnknownCmd(cmdString, msg);
    }
    default void onUnknownCmd(String cmdString, IMsg msg) {
        // ignore
    }
    /**
     * æ”¶åˆ°cmd消息(所有cmd)
     *
     * @param cmd    CmdEnum
     * @param cmdMsg BaseCmdMsg
     * @deprecated use {@link #onCmdMsg(T, Enum, ICmdMsg)}
     */
    default void onCmdMsg(T t, CmdEnum cmd, BaseCmdMsg<CmdEnum> cmdMsg) {
        this.onCmdMsg(cmd, cmdMsg);
    }
    /**
     * @deprecated use {@link #onCmdMsg(Enum, ICmdMsg)}
     */
    default void onCmdMsg(CmdEnum cmd, BaseCmdMsg<CmdEnum> cmdMsg) {
        // ignore
    }
    /**
     * æ”¶åˆ°å…¶ä»–cmd消息(存在Enum,但Listener没有对应的回调)
     *
     * @param cmd    CmdEnum
     * @param cmdMsg BaseCmdMsg
     * @deprecated use {@link #onOtherCmdMsg(T, Enum, ICmdMsg)}
     */
    default void onOtherCmdMsg(T t, CmdEnum cmd, BaseCmdMsg<CmdEnum> cmdMsg) {
        this.onOtherCmdMsg(cmd, cmdMsg);
    }
    /**
     * @deprecated use {@link #onOtherCmdMsg(Enum, ICmdMsg)}
     */
    default void onOtherCmdMsg(CmdEnum cmd, BaseCmdMsg<CmdEnum> cmdMsg) {
        // ignore
    }
    /**
     * æ”¶åˆ°æœªçŸ¥cmd消息
     *
     * @param cmdString å®žé™…收到的cmd字符串
     * @param msg       BaseMsg
     * @deprecated use {@link #onUnknownCmd(T, String, IMsg)}
     */
    default void onUnknownCmd(T t, String cmdString, BaseMsg msg) {
        this.onUnknownCmd(cmdString, msg);
    }
    /**
     * @deprecated use {@link #onUnknownCmd(String, IMsg)}
     */
    default void onUnknownCmd(String cmdString, BaseMsg msg) {
        // ignore
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/listener/IDanmuMsgListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,46 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.listener;
/**
 * å¼¹å¹•消息回调
 *
 * @author mjz
 * @since 0.0.6
 */
public interface IDanmuMsgListener<T, DanmuMsg> {
    /**
     * æ”¶åˆ°å¼¹å¹•
     */
    default void onDanmuMsg(T t, DanmuMsg msg) {
        this.onDanmuMsg(msg);
    }
    default void onDanmuMsg(DanmuMsg msg) {
        // ignore
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/listener/IEnterRoomMsgListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.listener;
/**
 * è¿›å…¥æˆ¿é—´æ¶ˆæ¯å›žè°ƒ
 *
 * @author mjz
 * @date 2023/12/14
 * @since 0.0.16
 */
public interface IEnterRoomMsgListener<T, EnterRoomMsg> {
    /**
     * ç”¨æˆ·è¿›å…¥æˆ¿é—´
     */
    default void onEnterRoomMsg(T t, EnterRoomMsg msg) {
        this.onEnterRoomMsg(msg);
    }
    default void onEnterRoomMsg(EnterRoomMsg msg) {
        // ignore
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/listener/IGiftMsgListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.listener;
/**
 * ç¤¼ç‰©æ¶ˆæ¯å›žè°ƒ
 *
 * @author mjz
 * @since 0.0.8
 */
public interface IGiftMsgListener<T, GiftMsg> {
    /**
     * æ”¶åˆ°ç¤¼ç‰©
     */
    default void onGiftMsg(T t, GiftMsg msg) {
        this.onGiftMsg(msg);
    }
    default void onGiftMsg(GiftMsg msg) {
        // ignore
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/listener/ILikeMsgListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,46 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.listener;
/**
 * ç‚¹èµžæ¶ˆæ¯å›žè°ƒ
 *
 * @author mjz
 * @since 0.2.0
 */
public interface ILikeMsgListener<T, LikeMsg> {
    /**
     * æ”¶åˆ°ç‚¹èµž
     */
    default void onLikeMsg(T t, LikeMsg msg) {
        this.onLikeMsg(msg);
    }
    default void onLikeMsg(LikeMsg msg) {
        // ignore
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/listener/ISuperChatMsgListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.listener;
/**
 * é†’目留言消息回调
 *
 * @author mjz
 * @date 2023/9/24
 * @since 0.0.11
 */
public interface ISuperChatMsgListener<T, SuperChatMsg> {
    /**
     * æ”¶åˆ°é†’目留言
     */
    default void onSuperChatMsg(T t, SuperChatMsg msg) {
        this.onSuperChatMsg(msg);
    }
    default void onSuperChatMsg(SuperChatMsg msg) {
        // ignore
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/msg/BaseCmdMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.msg;
/**
 * @author mjz
 * @date 2023/8/26
 */
public abstract class BaseCmdMsg<CmdEnum extends Enum<CmdEnum>> extends BaseMsg
        implements ICmdMsg<CmdEnum> {
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/msg/BaseMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.msg;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import tech.ordinaryroad.live.chat.client.commons.base.exception.BaseException;
import java.util.HashMap;
import java.util.Map;
/**
 * @author mjz
 * @date 2023/8/26
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public abstract class BaseMsg implements IMsg {
    public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
    /**
     * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
     */
    private final Map<String, JsonNode> unknownProperties = new HashMap<>();
    @JsonAnyGetter
    public Map<String, JsonNode> getUnknownProperties() {
        return unknownProperties;
    }
    @JsonAnySetter
    public void setOther(String key, JsonNode value) {
        this.unknownProperties.put(key, value);
    }
    @Override
    public String toString() {
        try {
            return OBJECT_MAPPER.writeValueAsString(this);
        } catch (JsonProcessingException e) {
            throw new BaseException(e);
        }
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/msg/ICmdMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.msg;
/**
 * @author mjz
 * @date 2023/10/2
 */
public interface ICmdMsg<CmdEnum extends Enum<CmdEnum>> extends IMsg {
    String getCmd();
    void setCmd(String cmd);
    CmdEnum getCmdEnum();
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/msg/IDanmuMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.msg;
/**
 * @author mjz
 * @date 2023/9/8
 */
public interface IDanmuMsg extends IMsg {
    /**
     * ç²‰ä¸ç‰Œåç§°
     */
    String getBadgeName();
    /**
     * ç²‰ä¸ç‰Œç­‰çº§
     */
    byte getBadgeLevel();
    /**
     * å¼¹å¹•发送者id
     */
    String getUid();
    /**
     * å¼¹å¹•发送者用户名
     */
    String getUsername();
    /**
     * å¼¹å¹•发送者头像地址
     *
     * @since 0.0.11
     */
    default String getUserAvatar() {
        return null;
    }
    /**
     * å¼¹å¹•内容
     */
    String getContent();
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/msg/IEnterRoomMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.msg;
/**
 * å…¥æˆ¿æ¶ˆæ¯
 *
 * @author mjz
 * @date 2023/12/26
 * @since 0.0.16
 */
public interface IEnterRoomMsg extends IMsg {
    /**
     * ç²‰ä¸ç‰Œåç§°
     */
    String getBadgeName();
    /**
     * ç²‰ä¸ç‰Œç­‰çº§
     */
    byte getBadgeLevel();
    /**
     * ç”¨æˆ·id
     */
    String getUid();
    /**
     * ç”¨æˆ·å
     */
    String getUsername();
    /**
     * å¤´åƒåœ°å€
     */
    default String getUserAvatar() {
        return null;
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/msg/IGiftMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,100 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.msg;
/**
 * @author mjz
 * @date 2023/9/8
 */
public interface IGiftMsg extends IMsg {
    /**
     * ç²‰ä¸ç‰Œåç§°
     */
    default String getBadgeName() {
        return "";
    }
    /**
     * ç²‰ä¸ç‰Œç­‰çº§
     */
    default byte getBadgeLevel() {
        return 0;
    }
    /**
     * å‘送方id
     */
    String getUid();
    /**
     * å‘送方用户名
     */
    String getUsername();
    /**
     * å‘送方头像地址
     *
     * @since 0.0.11
     */
    default String getUserAvatar() {
        return null;
    }
    /**
     * ç¤¼ç‰©åç§°
     */
    String getGiftName();
    /**
     * ç¤¼ç‰©å›¾åƒåœ°å€
     */
    String getGiftImg();
    /**
     * ç¤¼ç‰©id
     */
    String getGiftId();
    /**
     * ç¤¼ç‰©æ•°é‡
     */
    int getGiftCount();
    /**
     * å•个礼物价格
     */
    int getGiftPrice();
    /**
     * æŽ¥æ”¶æ–¹id
     */
    String getReceiveUid();
    /**
     * æŽ¥æ”¶æ–¹ç”¨æˆ·å
     */
    String getReceiveUsername();
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/msg/ILikeMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,71 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.msg;
/**
 * @author mjz
 * @date 2024/1/31
 * @since 0.2.0
 */
public interface ILikeMsg extends IMsg {
    /**
     * ç²‰ä¸ç‰Œåç§°
     */
    default String getBadgeName(){
        return "";
    }
    /**
     * ç²‰ä¸ç‰Œç­‰çº§
     */
    default byte getBadgeLevel(){
        return 0;
    }
    /**
     * ç‚¹èµžè€…id
     */
    String getUid();
    /**
     * ç‚¹èµžè€…用户名
     */
    String getUsername();
    /**
     * ç‚¹èµžè€…头像地址
     */
    default String getUserAvatar() {
        return null;
    }
    /**
     * ç‚¹èµžæ•°
     */
    default int getClickCount() {
        return 1;
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/msg/IMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.msg;
import java.io.Serializable;
/**
 * @author mjz
 * @date 2023/8/26
 */
public interface IMsg extends Serializable {
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-base/src/main/java/tech/ordinaryroad/live/chat/client/commons/base/msg/ISuperChatMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.base.msg;
/**
 * é†’目留言
 *
 * @author mjz
 * @date 2023/9/22
 */
public interface ISuperChatMsg extends IDanmuMsg {
    /**
     * é†’目留言持续时间,单位秒
     */
    int getDuration();
    @Override
    default String getBadgeName() {
        return "";
    }
    @Override
    default byte getBadgeLevel() {
        return 0;
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-client/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,55 @@
<!--
  ~ MIT License
  ~
  ~ Copyright (c) 2023 OrdinaryRoad
  ~
  ~ Permission is hereby granted, free of charge, to any person obtaining a copy
  ~ of this software and associated documentation files (the "Software"), to deal
  ~ in the Software without restriction, including without limitation the rights
  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  ~ copies of the Software, and to permit persons to whom the Software is
  ~ furnished to do so, subject to the following conditions:
  ~
  ~ The above copyright notice and this permission notice shall be included in all
  ~ copies or substantial portions of the Software.
  ~
  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  ~ SOFTWARE.
  -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.ruoyi</groupId>
        <artifactId>live-chat-client-commons</artifactId>
        <version>${revision}</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <packaging>jar</packaging>
    <artifactId>live-chat-client-commons-client</artifactId>
    <name>live-chat-client-commons-client</name>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>live-chat-client-commons-base</artifactId>
        </dependency>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>live-chat-client-commons-util</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-client/src/main/java/tech/ordinaryroad/live/chat/client/commons/client/BaseLiveChatClient.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,200 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.client;
import lombok.Getter;
import tech.ordinaryroad.live.chat.client.commons.base.listener.IBaseMsgListener;
import tech.ordinaryroad.live.chat.client.commons.client.config.BaseLiveChatClientConfig;
import tech.ordinaryroad.live.chat.client.commons.client.enums.ClientStatusEnums;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
/**
 * @author mjz
 * @date 2023/8/26
 */
public abstract class BaseLiveChatClient<
        Config extends BaseLiveChatClientConfig,
        MsgListener extends IBaseMsgListener<?, ?>
        > implements IBaseLiveChatClient<MsgListener> {
    private final Config config;
    @Getter
    private volatile ClientStatusEnums status = ClientStatusEnums.NEW;
    protected PropertyChangeSupport statusChangeSupport = new PropertyChangeSupport(status);
    protected volatile boolean cancelReconnect = false;
    protected final List<MsgListener> msgListeners = Collections.synchronizedList(new ArrayList<>());
    protected BaseLiveChatClient(Config config) {
        this.config = config;
    }
    public Config getConfig() {
        return config;
    }
    @Override
    public void connect(Runnable success) {
        this.connect(success, null);
    }
    @Override
    public void connect() {
        this.connect(null, null);
    }
    @Override
    public void disconnect(boolean cancelReconnect) {
        this.cancelReconnect = cancelReconnect;
        this.disconnect();
    }
    @Override
    public void send(Object msg) {
        this.send(msg, null, null);
    }
    @Override
    public void send(Object msg, Runnable success) {
        this.send(msg, success, null);
    }
    @Override
    public void send(Object msg, Consumer<Throwable> failed) {
        this.send(msg, null, failed);
    }
    @Override
    public void sendDanmu(Object danmu) {
        this.sendDanmu(danmu, null, null);
    }
    @Override
    public void sendDanmu(Object danmu, Runnable success) {
        this.sendDanmu(danmu, success, null);
    }
    @Override
    public void sendDanmu(Object danmu, Consumer<Throwable> failed) {
        this.sendDanmu(danmu, null, failed);
    }
    @Override
    public void clickLike(int count) {
        this.clickLike(count, null, null);
    }
    @Override
    public void clickLike(int count, Runnable success) {
        this.clickLike(count, success, null);
    }
    @Override
    public void clickLike(int count, Consumer<Throwable> failed) {
        this.clickLike(count, null, failed);
    }
    protected abstract void tryReconnect();
    protected abstract String getWebSocketUriString();
    /**
     * åˆ¤æ–­æ˜¯å¦å¤„于某个状态,或者处于后续状态
     *
     * @param status {@link ClientStatusEnums}
     * @return false: è¿˜æ²¡æœ‰åˆ°è¾¾è¯¥çŠ¶æ€
     */
    protected boolean checkStatus(ClientStatusEnums status) {
        return this.status.getCode() >= Objects.requireNonNull(status).getCode();
    }
    protected void setStatus(ClientStatusEnums status) {
        ClientStatusEnums oldStatus = this.status;
        if (oldStatus != status) {
            this.status = status;
            this.statusChangeSupport.firePropertyChange("status", oldStatus, status);
        }
    }
    public void addStatusChangeListener(PropertyChangeListener listener) {
        this.statusChangeSupport.addPropertyChangeListener(listener);
    }
    public void removeStatusChangeListener(PropertyChangeListener listener) {
        this.statusChangeSupport.removePropertyChangeListener(listener);
    }
    @Override
    public void destroy() {
        for (PropertyChangeListener propertyChangeListener : this.statusChangeSupport.getPropertyChangeListeners()) {
            this.statusChangeSupport.removePropertyChangeListener(propertyChangeListener);
        }
        this.msgListeners.clear();
    }
    @Override
    public boolean addMsgListener(MsgListener msgListener) {
        if (msgListener == null) {
            return false;
        }
        return this.msgListeners.add(msgListener);
    }
    @Override
    public boolean addMsgListeners(List<MsgListener> msgListeners) {
        if (msgListeners == null || msgListeners.isEmpty()) {
            return false;
        }
        return this.msgListeners.addAll(msgListeners);
    }
    @Override
    public boolean removeMsgListener(MsgListener msgListener) {
        if (msgListener == null) {
            return false;
        }
        return this.msgListeners.remove(msgListener);
    }
    @Override
    public boolean removeMsgListeners(List<MsgListener> msgListeners) {
        if (msgListeners == null || msgListeners.isEmpty()) {
            return false;
        }
        return this.msgListeners.removeAll(msgListeners);
    }
    @Override
    public void removeAllMsgListeners() {
        this.msgListeners.clear();
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-client/src/main/java/tech/ordinaryroad/live/chat/client/commons/client/IBaseLiveChatClient.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,135 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.client;
import tech.ordinaryroad.live.chat.client.commons.base.listener.IBaseMsgListener;
import java.util.List;
import java.util.function.Consumer;
/**
 * @author mjz
 * @date 2023/9/5
 */
public interface IBaseLiveChatClient<MsgListener extends IBaseMsgListener<?, ?>> {
    void init();
    boolean addMsgListener(MsgListener msgListener);
    boolean addMsgListeners(List<MsgListener> msgListeners);
    boolean removeMsgListener(MsgListener msgListener);
    boolean removeMsgListeners(List<MsgListener> msgListeners);
    void removeAllMsgListeners();
    void connect(Runnable success, Consumer<Throwable> failed);
    void connect(Runnable success);
    void connect();
    /**
     * æ‰‹åŠ¨æ–­å¼€è¿žæŽ¥
     *
     * @param cancelReconnect å–消本次的自动重连(如果启用自动重连)
     */
    void disconnect(boolean cancelReconnect);
    void disconnect();
    void destroy();
    void send(Object msg);
    void send(Object msg, Runnable success, Consumer<Throwable> failed);
    void send(Object msg, Runnable success);
    void send(Object msg, Consumer<Throwable> failed);
    /**
     * å‘送弹幕
     *
     * @param danmu å¼¹å¹•内容
     * @since 0.0.6
     */
    void sendDanmu(Object danmu);
    /**
     * å‘送弹幕
     *
     * @param danmu å¼¹å¹•内容
     * @since 0.0.6
     */
    void sendDanmu(Object danmu, Runnable success, Consumer<Throwable> failed);
    /**
     * å‘送弹幕
     *
     * @param danmu å¼¹å¹•内容
     * @since 0.0.6
     */
    void sendDanmu(Object danmu, Runnable success);
    /**
     * å‘送弹幕
     *
     * @param danmu å¼¹å¹•内容
     * @since 0.0.6
     */
    void sendDanmu(Object danmu, Consumer<Throwable> failed);
    /**
     * ä¸ºç›´æ’­é—´ç‚¹èµž
     *
     * @since 0.2.0
     */
    void clickLike(int count);
    /**
     * ä¸ºç›´æ’­é—´ç‚¹èµž
     *
     * @since 0.2.0
     */
    void clickLike(int count, Runnable success, Consumer<Throwable> failed);
    /**
     * ä¸ºç›´æ’­é—´ç‚¹èµž
     *
     * @since 0.2.0
     */
    void clickLike(int count, Runnable success);
    /**
     * ä¸ºç›´æ’­é—´ç‚¹èµž
     *
     * @since 0.2.0
     */
    void clickLike(int count, Consumer<Throwable> failed);
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-client/src/main/java/tech/ordinaryroad/live/chat/client/commons/client/config/BaseLiveChatClientConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,139 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.client.config;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import tech.ordinaryroad.live.chat.client.commons.base.exception.BaseException;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
/**
 * ç›´æ’­é—´å¼¹å¹•客户端配置
 *
 * @author mjz
 * @date 2023/8/26
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder(toBuilder = true)
public abstract class BaseLiveChatClientConfig {
    protected PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
    public static final long DEFAULT_HEARTBEAT_INITIAL_DELAY = 15;
    public static final long DEFAULT_HEARTBEAT_PERIOD = 25;
    public static final long DEFAULT_MIN_SEND_DANMU_PERIOD = 3000L;
    private String websocketUri;
    /**
     * æµè§ˆå™¨ä¸­çš„Cookie
     */
    private String cookie;
    /**
     * ç›´æ’­é—´id
     */
    private Object roomId;
    /**
     * æ˜¯å¦å¯ç”¨è‡ªåŠ¨é‡è¿ž
     */
    @Builder.Default
    private boolean autoReconnect = Boolean.TRUE;
    /**
     * é‡è¯•延迟时间(秒),默认5s后重试
     */
    @Builder.Default
    private int reconnectDelay = 5;
    /**
     * é¦–次发送心跳包的延迟时间(秒)
     */
    @Builder.Default
    private long heartbeatInitialDelay = DEFAULT_HEARTBEAT_INITIAL_DELAY;
    /**
     * å¿ƒè·³åŒ…发送周期(秒)
     */
    @Builder.Default
    private long heartbeatPeriod = DEFAULT_HEARTBEAT_PERIOD;
    /**
     * æœ€å°å‘送弹幕时间间隔(毫秒)
     */
    @Builder.Default
    private long minSendDanmuPeriod = DEFAULT_MIN_SEND_DANMU_PERIOD;
    public void setCookie(String cookie) {
        String oldValue = this.cookie;
        this.cookie = cookie;
        this.propertyChangeSupport.firePropertyChange("cookie", oldValue, cookie);
    }
    public void setRoomId(Object roomId) {
        if (!(roomId instanceof Number || roomId instanceof String)) {
            throw new BaseException("房间ID仅支持数字或字符串,所传参数类型:" + roomId.getClass() + "值:" + roomId);
        }
        Object oldValue = this.roomId;
        this.roomId = roomId;
        this.propertyChangeSupport.firePropertyChange("roomId", oldValue, roomId);
    }
    public void setWebsocketUri(String websocketUri) {
        String oldValue = this.websocketUri;
        this.websocketUri = websocketUri;
        this.propertyChangeSupport.firePropertyChange("websocketUri", oldValue, websocketUri);
    }
    public void setMinSendDanmuPeriod(long minSendDanmuPeriod) {
        long oldValue = this.minSendDanmuPeriod;
        this.minSendDanmuPeriod = minSendDanmuPeriod;
        this.propertyChangeSupport.firePropertyChange("minSendDanmuPeriod", oldValue, minSendDanmuPeriod);
    }
    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        this.propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
    }
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        this.propertyChangeSupport.addPropertyChangeListener(listener);
    }
    public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        this.propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
    }
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        this.propertyChangeSupport.removePropertyChangeListener(listener);
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-client/src/main/java/tech/ordinaryroad/live/chat/client/commons/client/enums/ClientStatusEnums.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,83 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.client.enums;
/**
 * @author mjz
 * @date 2023/8/26
 */
public enum ClientStatusEnums {
    /**
     * æ–°åˆ›å»º
     */
    NEW(0),
    /**
     * å·²åˆå§‹åŒ–
     */
    INITIALIZED(1),
    /**
     * è¿žæŽ¥ä¸­
     */
    CONNECTING(100),
    /**
     * é‡æ–°è¿žæŽ¥ä¸­
     */
    RECONNECTING(101),
    /**
     * å·²è¿žæŽ¥
     */
    CONNECTED(200),
    /**
     * è¿žæŽ¥å¤±è´¥
     */
    CONNECT_FAILED(401),
    /**
     * å·²æ–­å¼€è¿žæŽ¥
     */
    DISCONNECTED(400),
    /**
     * å·²é”€æ¯
     */
    DESTROYED(-1),
    ;
    public int getCode() {
        return code;
    }
    ClientStatusEnums(int order) {
        this.code = order;
    }
    private final int code;
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-util/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.ruoyi</groupId>
        <artifactId>live-chat-client-commons</artifactId>
        <version>${revision}</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <packaging>jar</packaging>
    <artifactId>live-chat-client-commons-util</artifactId>
    <name>live-chat-client-commons-util</name>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-util/src/main/java/tech/ordinaryroad/live/chat/client/commons/util/OrLiveChatCookieUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,80 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import java.net.HttpCookie;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
 * @author mjz
 * @date 2023/8/27
 */
public class OrLiveChatCookieUtil {
    public static String toString(List<HttpCookie> cookies) {
        if (CollUtil.isEmpty(cookies)) {
            return StrUtil.EMPTY;
        }
        return cookies.stream().map(httpCookie -> {
            httpCookie.setVersion(0);
            return httpCookie.toString();
        }).collect(Collectors.joining("; "));
    }
    public static Map<String, String> parseCookieString(String cookies) {
        Map<String, String> map = new HashMap<>();
        if (StrUtil.isNotBlank(cookies) && !StrUtil.isNullOrUndefined(cookies)) {
            try {
                String[] split = cookies.split("; ");
                for (String s : split) {
                    String[] split1 = s.split("=");
                    map.put(split1[0], split1[1]);
                }
            } catch (Exception e) {
                throw new RuntimeException("cookie解析失败 " + cookies, e);
            }
        }
        return map;
    }
    public static String getCookieByName(Map<String, String> cookieMap, String name, Supplier<String> supplier) {
        String str = MapUtil.getStr(cookieMap, name);
        return str == null ? supplier.get() : str;
    }
    public static String getCookieByName(String cookie, String name, Supplier<String> supplier) {
        String str = MapUtil.getStr(parseCookieString(cookie), name);
        return str == null ? supplier.get() : str;
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-util/src/main/java/tech/ordinaryroad/live/chat/client/commons/util/OrLiveChatNumberUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.util;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
/**
 * @author mjz
 * @date 2023/12/2
 */
public class OrLiveChatNumberUtil extends NumberUtil {
    public static long parseLong(Object object){
        return NumberUtil.parseLong(StrUtil.toStringOrNull(object));
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-util/src/main/java/tech/ordinaryroad/live/chat/client/commons/util/OrLiveChatReflectUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.util;
import cn.hutool.core.util.ReflectUtil;
import java.lang.reflect.Method;
/**
 * @author mjz
 * @date 2023/8/28
 */
public class OrLiveChatReflectUtil extends ReflectUtil {
    public static Method getGetterMethod(Class<?> objectClass, String key) {
        Method method;
        if (key.startsWith("is")) {
            method = ReflectUtil.getMethodByNameIgnoreCase(objectClass, key);
            if (method == null) {
                ReflectUtil.getMethodByNameIgnoreCase(objectClass, "get" + key);
            }
        } else {
            method = ReflectUtil.getMethodByNameIgnoreCase(objectClass, "get" + key);
        }
        return method;
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/live-chat-client-commons-util/src/main/java/tech/ordinaryroad/live/chat/client/commons/util/OrLocalDateTimeUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.commons.util;
import cn.hutool.core.date.LocalDateTimeUtil;
import java.time.ZoneId;
import java.time.ZonedDateTime;
/**
 * @author mjz
 * @date 2023/9/7
 */
public class OrLocalDateTimeUtil extends LocalDateTimeUtil {
    public static ZoneId ZONE_ID_CTT = ZoneId.of(ZoneId.SHORT_IDS.get("CTT"));
    /**
     * èŽ·å–ä¸­å›½æ ‡å‡†æ—¶é—´çš„å½“å‰æ—¶é—´æˆ³ï¼ˆæ¯«ç§’ï¼‰
     */
    public static long zonedCurrentTimeMillis() {
        ZonedDateTime now = ZonedDateTime.now(ZONE_ID_CTT);
        return now.toEpochSecond() * 1000 + now.getNano() / 1_000_000;
    }
    /**
     * èŽ·å–ä¸­å›½æ ‡å‡†æ—¶é—´çš„å½“å‰æ—¶é—´æˆ³ï¼ˆç§’ï¼‰
     */
    public static long zonedCurrentTimeSecs() {
        return ZonedDateTime.now(ZONE_ID_CTT).toEpochSecond();
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-commons/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
<!--
  ~ MIT License
  ~
  ~ Copyright (c) 2023 OrdinaryRoad
  ~
  ~ Permission is hereby granted, free of charge, to any person obtaining a copy
  ~ of this software and associated documentation files (the "Software"), to deal
  ~ in the Software without restriction, including without limitation the rights
  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  ~ copies of the Software, and to permit persons to whom the Software is
  ~ furnished to do so, subject to the following conditions:
  ~
  ~ The above copyright notice and this permission notice shall be included in all
  ~ copies or substantial portions of the Software.
  ~
  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  ~ SOFTWARE.
  -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.ruoyi</groupId>
        <artifactId>ruoyi-live</artifactId>
        <version>${revision}</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <packaging>pom</packaging>
    <artifactId>live-chat-client-commons</artifactId>
    <modules>
        <module>live-chat-client-commons-base</module>
        <module>live-chat-client-commons-util</module>
        <module>live-chat-client-commons-client</module>
    </modules>
</project>
ruoyi-modules/ruoyi-live/live-chat-client-servers/live-chat-client-servers-netty-client/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,55 @@
<!--
  ~ MIT License
  ~
  ~ Copyright (c) 2023 OrdinaryRoad
  ~
  ~ Permission is hereby granted, free of charge, to any person obtaining a copy
  ~ of this software and associated documentation files (the "Software"), to deal
  ~ in the Software without restriction, including without limitation the rights
  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  ~ copies of the Software, and to permit persons to whom the Software is
  ~ furnished to do so, subject to the following conditions:
  ~
  ~ The above copyright notice and this permission notice shall be included in all
  ~ copies or substantial portions of the Software.
  ~
  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  ~ SOFTWARE.
  -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.ruoyi</groupId>
        <artifactId>live-chat-client-servers</artifactId>
        <version>${revision}</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <packaging>jar</packaging>
    <artifactId>live-chat-client-servers-netty-client</artifactId>
    <name>live-chat-client-servers-netty</name>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>live-chat-client-commons-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>live-chat-client-servers-netty</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-modules/ruoyi-live/live-chat-client-servers/live-chat-client-servers-netty-client/src/main/java/tech/ordinaryroad/live/chat/client/servers/netty/client/base/BaseNettyClient.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,349 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.servers.netty.client.base;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.stream.ChunkedWriteHandler;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import tech.ordinaryroad.live.chat.client.commons.base.exception.BaseException;
import tech.ordinaryroad.live.chat.client.commons.base.listener.IBaseConnectionListener;
import tech.ordinaryroad.live.chat.client.commons.base.listener.IBaseMsgListener;
import tech.ordinaryroad.live.chat.client.commons.base.msg.IMsg;
import tech.ordinaryroad.live.chat.client.commons.client.BaseLiveChatClient;
import tech.ordinaryroad.live.chat.client.commons.client.enums.ClientStatusEnums;
import tech.ordinaryroad.live.chat.client.servers.netty.client.config.BaseNettyClientConfig;
import tech.ordinaryroad.live.chat.client.servers.netty.handler.base.BaseBinaryFrameHandler;
import tech.ordinaryroad.live.chat.client.servers.netty.handler.base.BaseConnectionHandler;
import javax.net.ssl.SSLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
 * @author mjz
 * @date 2023/8/26
 */
@Slf4j
public abstract class BaseNettyClient
        <Config extends BaseNettyClientConfig,
                CmdEnum extends Enum<CmdEnum>,
                Msg extends IMsg,
                MsgListener extends IBaseMsgListener<BinaryFrameHandler, CmdEnum>,
                ConnectionHandler extends BaseConnectionHandler<ConnectionHandler>,
                BinaryFrameHandler extends BaseBinaryFrameHandler<BinaryFrameHandler, CmdEnum, Msg, MsgListener>
                >
        extends BaseLiveChatClient<Config, MsgListener> {
    @Getter
    private final EventLoopGroup workerGroup;
    @Getter
    private final Bootstrap bootstrap = new Bootstrap();
    private BinaryFrameHandler binaryFrameHandler;
    private ConnectionHandler connectionHandler;
    private IBaseConnectionListener<ConnectionHandler> connectionListener;
    private Channel channel;
    @Getter
    private URI websocketUri;
    protected IBaseConnectionListener<ConnectionHandler> clientConnectionListener;
    /**
     * æŽ§åˆ¶å¼¹å¹•发送频率
     */
    private volatile long lastSendDanmuTimeInMillis;
    public abstract ConnectionHandler initConnectionHandler(IBaseConnectionListener<ConnectionHandler> clientConnectionListener);
    public abstract BinaryFrameHandler initBinaryFrameHandler();
    protected BaseNettyClient(Config config, EventLoopGroup workerGroup, IBaseConnectionListener<ConnectionHandler> connectionListener) {
        super(config);
        this.workerGroup = workerGroup;
        this.connectionListener = connectionListener;
    }
    public void onConnected(ConnectionHandler connectionHandler) {
        this.setStatus(ClientStatusEnums.CONNECTED);
        if (this.connectionListener != null) {
            this.connectionListener.onConnected(connectionHandler);
        }
    }
    public void onConnectFailed(ConnectionHandler connectionHandler) {
        this.setStatus(ClientStatusEnums.CONNECT_FAILED);
        tryReconnect();
        if (this.connectionListener != null) {
            this.connectionListener.onConnectFailed(connectionHandler);
        }
    }
    public void onDisconnected(ConnectionHandler connectionHandler) {
        this.setStatus(ClientStatusEnums.DISCONNECTED);
        tryReconnect();
        if (this.connectionListener != null) {
            this.connectionListener.onDisconnected(connectionHandler);
        }
    }
    @Override
    public void init() {
        if (checkStatus(ClientStatusEnums.INITIALIZED)) {
            return;
        }
        try {
            this.websocketUri = new URI(getWebSocketUriString());
            SslContext sslCtx = SslContextBuilder.forClient().build();
            this.clientConnectionListener = new IBaseConnectionListener<ConnectionHandler>() {
                @Override
                public void onConnected(ConnectionHandler connectionHandler) {
                    BaseNettyClient.this.onConnected(connectionHandler);
                }
                @Override
                public void onConnectFailed(ConnectionHandler connectionHandler) {
                    BaseNettyClient.this.onConnectFailed(connectionHandler);
                }
                @Override
                public void onDisconnected(ConnectionHandler connectionHandler) {
                    BaseNettyClient.this.onDisconnected(connectionHandler);
                }
            };
            this.binaryFrameHandler = this.initBinaryFrameHandler();
            this.connectionHandler = this.initConnectionHandler(this.clientConnectionListener);
            this.bootstrap.group(this.workerGroup)
                    // åˆ›å»ºChannel
                    .channel(NioSocketChannel.class)
                    .remoteAddress(this.websocketUri.getHost(), getInetPort())
                    .option(ChannelOption.TCP_NODELAY, true)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    // Channel配置
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            // è´£ä»»é“¾
                            ChannelPipeline pipeline = ch.pipeline();
                            // æ”¾åˆ°ç¬¬ä¸€ä½ addFirst æ”¯æŒwss链接服务端
                            pipeline.addFirst(sslCtx.newHandler(ch.alloc(), BaseNettyClient.this.websocketUri.getHost(), getInetPort()));
                            // æ·»åŠ ä¸€ä¸ªhttp的编解码器
                            pipeline.addLast(new HttpClientCodec());
                            // æ·»åŠ ä¸€ä¸ªç”¨äºŽæ”¯æŒå¤§æ•°æ®æµçš„æ”¯æŒ
                            pipeline.addLast(new ChunkedWriteHandler());
                            // æ·»åŠ ä¸€ä¸ªèšåˆå™¨ï¼Œè¿™ä¸ªèšåˆå™¨ä¸»è¦æ˜¯å°†HttpMessage聚合成FullHttpRequest/Response
                            pipeline.addLast(new HttpObjectAggregator(BaseNettyClient.this.getConfig().getAggregatorMaxContentLength()));
                            // è¿žæŽ¥å¤„理器
                            pipeline.addLast(BaseNettyClient.this.connectionHandler);
                            // å¼¹å¹•处理器
                            pipeline.addLast(BaseNettyClient.this.binaryFrameHandler);
                        }
                    });
            this.setStatus(ClientStatusEnums.INITIALIZED);
        } catch (URISyntaxException e) {
            throw new BaseException(e);
        } catch (SSLException e) {
            throw new BaseException(e);
        }
    }
    private int getInetPort() {
        int port = this.websocketUri.getPort();
        return port == -1 ? "wss".equalsIgnoreCase(websocketUri.getScheme()) ? 443 : 80 : port;
    }
    @Override
    public void connect(Runnable success, Consumer<Throwable> failed) {
        if (this.cancelReconnect) {
            this.cancelReconnect = false;
        }
        if (!checkStatus(ClientStatusEnums.INITIALIZED)) {
            return;
        }
        if (getStatus() == ClientStatusEnums.CONNECTED) {
            return;
        }
        if (getStatus() != ClientStatusEnums.RECONNECTING) {
            this.setStatus(ClientStatusEnums.CONNECTING);
        }
        this.bootstrap.connect().addListener((ChannelFutureListener) connectFuture -> {
            if (connectFuture.isSuccess()) {
                if (log.isDebugEnabled()) {
                    log.debug("连接建立成功!");
                }
                this.channel = connectFuture.channel();
                // ç›‘听是否握手成功
                this.connectionHandler.getHandshakeFuture().addListener((ChannelFutureListener) handshakeFuture -> {
                    try {
                        connectionHandler.sendAuthRequest(channel);
                        if (success != null) {
                            success.run();
                        }
                    } catch (Exception e) {
                        log.error("认证包发送失败,断开连接", e);
                        this.disconnect();
                    }
                });
            } else {
                log.error("连接建立失败", connectFuture.cause());
                this.onConnectFailed(this.connectionHandler);
                if (failed != null) {
                    failed.accept(connectFuture.cause());
                }
            }
        });
    }
    @Override
    public void disconnect() {
        if (this.channel == null) {
            return;
        }
        this.channel.close();
    }
    @Override
    protected void tryReconnect() {
        if (this.cancelReconnect) {
            this.cancelReconnect = false;
            return;
        }
        if (!getConfig().isAutoReconnect()) {
            return;
        }
        if (log.isWarnEnabled()) {
            log.warn("{}s后将重新连接 {}", getConfig().getReconnectDelay(), getConfig().getRoomId());
        }
        workerGroup.schedule(() -> {
            this.setStatus(ClientStatusEnums.RECONNECTING);
            this.connect();
        }, getConfig().getReconnectDelay(), TimeUnit.SECONDS);
    }
    @Override
    public void send(Object msg, Runnable success, Consumer<Throwable> failed) {
        ChannelFuture future = this.channel.writeAndFlush(msg);
        if (success != null || failed != null) {
            future.addListener((ChannelFutureListener) channelFuture -> {
                if (channelFuture.isSuccess()) {
                    if (success != null) {
                        success.run();
                    }
                } else {
                    if (failed != null) {
                        failed.accept(channelFuture.cause());
                    }
                }
            });
        }
    }
    @Override
    public void destroy() {
        super.destroy();
        // é”€æ¯æ—¶ä¸éœ€è¦é‡è¿ž
        this.cancelReconnect = true;
        workerGroup.shutdownGracefully().addListener(future -> {
            if (future.isSuccess()) {
                this.setStatus(ClientStatusEnums.DESTROYED);
            } else {
                throw new BaseException("client销毁失败", future.cause());
            }
        });
    }
    @Override
    protected String getWebSocketUriString() {
        return getConfig().getWebsocketUri();
    }
    @Override
    protected void setStatus(ClientStatusEnums status) {
        if (log.isDebugEnabled()) {
            if (getStatus() != status) {
                log.debug("{} çŠ¶æ€å˜åŒ– {} => {}\n", getClass().getSimpleName(), getStatus(), status);
            }
        }
        super.setStatus(status);
    }
    @Override
    public void sendDanmu(Object danmu, Runnable success, Consumer<Throwable> failed) {
        throw new BaseException("暂未支持该功能");
    }
    @Override
    public void clickLike(int count, Runnable success, Consumer<Throwable> failed) {
        throw new BaseException("暂未支持该功能");
    }
    /**
     * å‘送弹幕前判断是否可以发送
     *
     * @param checkConnected æ˜¯å¦æ£€æŸ¥Client连接状态
     */
    protected boolean checkCanSendDanmu(boolean checkConnected) {
        if (checkConnected && getStatus() != ClientStatusEnums.CONNECTED) {
            throw new BaseException("连接未建立,无法发送弹幕");
        }
        if (System.currentTimeMillis() - this.lastSendDanmuTimeInMillis <= getConfig().getMinSendDanmuPeriod()) {
            if (log.isWarnEnabled()) {
                log.warn("发送弹幕频率过快,忽略该次发送");
            }
            return false;
        }
        return true;
    }
    protected boolean checkCanSendDanmu() {
        return checkCanSendDanmu(true);
    }
    /**
     * å‘送弹幕后调用该方法
     */
    protected void finishSendDanmu() {
        this.lastSendDanmuTimeInMillis = System.currentTimeMillis();
        if (log.isDebugEnabled()) {
            log.debug("弹幕发送完成");
        }
    }
    public void iteratorMsgListeners(Consumer<MsgListener> consumer) {
        binaryFrameHandler.iteratorMsgListeners(consumer);
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-servers/live-chat-client-servers-netty-client/src/main/java/tech/ordinaryroad/live/chat/client/servers/netty/client/config/BaseNettyClientConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.servers.netty.client.config;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import tech.ordinaryroad.live.chat.client.commons.client.config.BaseLiveChatClientConfig;
import java.net.URI;
/**
 * @author mjz
 * @date 2023/8/26
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder(toBuilder = true)
public abstract class BaseNettyClientConfig extends BaseLiveChatClientConfig {
    /**
     * èšåˆå™¨å…è®¸çš„æœ€å¤§æ¶ˆæ¯ä½“长度,默认 64*1024 byte
     *
     * @see HttpObjectAggregator#HttpObjectAggregator(int)
     */
    @Builder.Default
    private int aggregatorMaxContentLength = 64 * 1024;
    /**
     * WebSocketClientHandshaker最大消息体长度,默认 64*1024 byte
     *
     * @see WebSocketClientHandshakerFactory#newHandshaker(URI, WebSocketVersion, String, boolean, HttpHeaders, int)
     */
    @Builder.Default
    private int maxFramePayloadLength = 64 * 1024;
}
ruoyi-modules/ruoyi-live/live-chat-client-servers/live-chat-client-servers-netty-client/src/main/java/tech/ordinaryroad/live/chat/client/servers/netty/client/handler/BaseNettyClientBinaryFrameHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.servers.netty.client.handler;
import lombok.Getter;
import tech.ordinaryroad.live.chat.client.commons.base.listener.IBaseMsgListener;
import tech.ordinaryroad.live.chat.client.commons.base.msg.IMsg;
import tech.ordinaryroad.live.chat.client.servers.netty.client.base.BaseNettyClient;
import tech.ordinaryroad.live.chat.client.servers.netty.handler.base.BaseBinaryFrameHandler;
import java.util.List;
/**
 * BaseClientBinaryFrameHandler
 *
 * @author mjz
 * @date 2023/8/30
 */
public abstract class BaseNettyClientBinaryFrameHandler<
        Client extends BaseNettyClient<?, ?, ?, ?, ?, ?>,
        BinaryFrameHandler extends BaseBinaryFrameHandler<BinaryFrameHandler, CmdEnum, Msg, MsgListener>,
        CmdEnum extends Enum<CmdEnum>,
        Msg extends IMsg,
        MsgListener extends IBaseMsgListener<BinaryFrameHandler, CmdEnum>>
        extends BaseBinaryFrameHandler<BinaryFrameHandler, CmdEnum, Msg, MsgListener> {
    @Getter
    protected final Client client;
    public BaseNettyClientBinaryFrameHandler(List<MsgListener> msgListeners, Client client, long roomId) {
        super(msgListeners, roomId);
        this.client = client;
    }
    public BaseNettyClientBinaryFrameHandler(List<MsgListener> msgListeners, Client client) {
        super(msgListeners, client.getConfig().getRoomId());
        this.client = client;
    }
    public BaseNettyClientBinaryFrameHandler(List<MsgListener> msgListeners, long roomId) {
        super(msgListeners, roomId);
        this.client = null;
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-servers/live-chat-client-servers-netty-client/src/main/java/tech/ordinaryroad/live/chat/client/servers/netty/client/handler/BaseNettyClientConnectionHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.servers.netty.client.handler;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import lombok.Getter;
import tech.ordinaryroad.live.chat.client.commons.base.listener.IBaseConnectionListener;
import tech.ordinaryroad.live.chat.client.servers.netty.client.base.BaseNettyClient;
import tech.ordinaryroad.live.chat.client.servers.netty.handler.base.BaseConnectionHandler;
/**
 * BaseClientConnectionHandler
 *
 * @author mjz
 * @date 2023/8/27
 */
public abstract class BaseNettyClientConnectionHandler<
        Client extends BaseNettyClient<?, ?, ?, ?, ?, ?>,
        ConnectionHandler extends BaseConnectionHandler<ConnectionHandler>>
        extends BaseConnectionHandler<ConnectionHandler> {
    @Getter
    protected final Client client;
    public BaseNettyClientConnectionHandler(WebSocketClientHandshaker handshaker, Client client, IBaseConnectionListener<ConnectionHandler> listener) {
        super(handshaker, listener);
        this.client = client;
    }
    public BaseNettyClientConnectionHandler(WebSocketClientHandshaker handshaker, Client client) {
        this(handshaker, client, null);
    }
    public BaseNettyClientConnectionHandler(WebSocketClientHandshaker handshaker, IBaseConnectionListener<ConnectionHandler> listener) {
        super(handshaker, listener);
        this.client = null;
    }
    public BaseNettyClientConnectionHandler(WebSocketClientHandshaker handshaker, long roomId) {
        super(handshaker, null);
        this.client = null;
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-servers/live-chat-client-servers-netty/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
<!--
  ~ MIT License
  ~
  ~ Copyright (c) 2023 OrdinaryRoad
  ~
  ~ Permission is hereby granted, free of charge, to any person obtaining a copy
  ~ of this software and associated documentation files (the "Software"), to deal
  ~ in the Software without restriction, including without limitation the rights
  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  ~ copies of the Software, and to permit persons to whom the Software is
  ~ furnished to do so, subject to the following conditions:
  ~
  ~ The above copyright notice and this permission notice shall be included in all
  ~ copies or substantial portions of the Software.
  ~
  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  ~ SOFTWARE.
  -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.ruoyi</groupId>
        <artifactId>live-chat-client-servers</artifactId>
        <version>${revision}</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <packaging>jar</packaging>
    <artifactId>live-chat-client-servers-netty</artifactId>
    <name>live-chat-client-servers-netty</name>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>live-chat-client-commons-base</artifactId>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-modules/ruoyi-live/live-chat-client-servers/live-chat-client-servers-netty/src/main/java/tech/ordinaryroad/live/chat/client/servers/netty/frame/base/BaseBinaryWebSocketFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.servers.netty.frame.base;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
/**
 * @author mjz
 * @date 2023/1/5
 */
public abstract class BaseBinaryWebSocketFrame extends BinaryWebSocketFrame {
    public BaseBinaryWebSocketFrame(ByteBuf byteBuf) {
        super(byteBuf);
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-servers/live-chat-client-servers-netty/src/main/java/tech/ordinaryroad/live/chat/client/servers/netty/handler/base/BaseBinaryFrameHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,184 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.servers.netty.handler.base;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import tech.ordinaryroad.live.chat.client.commons.base.listener.IBaseMsgListener;
import tech.ordinaryroad.live.chat.client.commons.base.msg.BaseCmdMsg;
import tech.ordinaryroad.live.chat.client.commons.base.msg.BaseMsg;
import tech.ordinaryroad.live.chat.client.commons.base.msg.ICmdMsg;
import tech.ordinaryroad.live.chat.client.commons.base.msg.IMsg;
import java.util.List;
import java.util.function.Consumer;
/**
 * æ¶ˆæ¯å¤„理器
 *
 * @author mjz
 * @date 2023/1/4
 */
@Slf4j
public abstract class BaseBinaryFrameHandler<
        T extends BaseBinaryFrameHandler<?, ?, ?, ?>,
        CmdEnum extends Enum<CmdEnum>,
        Msg extends IMsg,
        MsgListener extends IBaseMsgListener<T, CmdEnum>
        > extends SimpleChannelInboundHandler<BinaryWebSocketFrame>
        implements IBaseMsgListener<T, CmdEnum> {
    @Getter
    private final Object roomId;
    protected final List<MsgListener> msgListeners;
    public BaseBinaryFrameHandler(List<MsgListener> msgListeners, Object roomId) {
        this.msgListeners = msgListeners;
        this.roomId = roomId;
        if (this.msgListeners == null || this.msgListeners.isEmpty()) {
            if (log.isDebugEnabled()) {
                log.debug("listener not set");
            }
        }
    }
    /**
     * è§£ç æ”¶åˆ°çš„二进制流
     *
     * @param byteBuf ByteBuf
     * @return List<Msg>
     */
    protected abstract List<Msg> decode(ByteBuf byteBuf);
    @SuppressWarnings("unchecked")
    protected void channelRead0(ChannelHandlerContext ctx, BinaryWebSocketFrame message) {
        ByteBuf byteBuf = message.content();
        List<Msg> msgList = this.decode(byteBuf);
        if (msgList == null || msgList.isEmpty()) {
            if (log.isDebugEnabled()) {
                log.debug("msgList is empty");
            }
            return;
        }
        for (Msg msg : msgList) {
            this.onMsg((T) BaseBinaryFrameHandler.this, msg);
            if (msg instanceof ICmdMsg<?>) {
                ICmdMsg<?> cmdMsg = (ICmdMsg<?>) msg;
                Enum<?> cmdEnum = cmdMsg.getCmdEnum();
                if (cmdEnum == null) {
                    this.onUnknownCmd((T) BaseBinaryFrameHandler.this, cmdMsg.getCmd(), cmdMsg);
                } else {
                    this.onCmdMsg((T) BaseBinaryFrameHandler.this, (CmdEnum) cmdEnum, (ICmdMsg<CmdEnum>) cmdMsg);
                }
            }
            if (msg instanceof BaseCmdMsg<?>) {
                BaseCmdMsg<?> cmdMsg = (BaseCmdMsg<?>) msg;
                Enum<?> cmdEnum = cmdMsg.getCmdEnum();
                if (cmdEnum == null) {
                    this.onUnknownCmd((T) BaseBinaryFrameHandler.this, cmdMsg.getCmd(), cmdMsg);
                } else {
                    this.onCmdMsg((T) BaseBinaryFrameHandler.this, (CmdEnum) cmdEnum, (BaseCmdMsg<CmdEnum>) cmdMsg);
                }
            }
        }
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if (cause.getCause() instanceof UnrecognizedPropertyException) {
            log.error("缺少字段:{}", cause.getMessage());
        } else {
            super.exceptionCaught(ctx, cause);
        }
    }
    @Override
    public void onMsg(T t, IMsg msg) {
        IBaseMsgListener.super.onMsg(t, msg);
        iteratorMsgListeners(msgListener -> msgListener.onMsg(t, msg));
    }
    /**
     * é‡å†™è¯¥æ–¹æ³•,判断CMD,或者调用{@link IBaseMsgListener#onOtherCmdMsg(Object, Enum, ICmdMsg)}
     *
     * @param t      BaseBinaryFrameHandler
     * @param cmd    CmdEnum
     * @param cmdMsg BaseMsg
     */
    @Override
    public void onCmdMsg(T t, CmdEnum cmd, ICmdMsg<CmdEnum> cmdMsg) {
        IBaseMsgListener.super.onCmdMsg(t, cmd, cmdMsg);
        iteratorMsgListeners(msgListener -> msgListener.onCmdMsg(t, cmd, cmdMsg));
    }
    @Override
    public void onUnknownCmd(T t, String cmdString, IMsg msg) {
        IBaseMsgListener.super.onUnknownCmd(t, cmdString, msg);
        iteratorMsgListeners(msgListener -> msgListener.onUnknownCmd(t, cmdString, msg));
    }
    @SuppressWarnings("ForLoopReplaceableByForEach")
    public void iteratorMsgListeners(Consumer<MsgListener> consumer) {
        if (msgListeners.isEmpty()) {
            return;
        }
        for (int i = 0; i < msgListeners.size(); i++) {
            consumer.accept(msgListeners.get(i));
        }
    }
    @Override
    public void onCmdMsg(T t, CmdEnum cmd, BaseCmdMsg<CmdEnum> cmdMsg) {
        IBaseMsgListener.super.onCmdMsg(t, cmd, cmdMsg);
        iteratorMsgListeners(msgListener -> msgListener.onCmdMsg(t, cmd, cmdMsg));
    }
    @Override
    public void onUnknownCmd(T t, String cmdString, BaseMsg msg) {
        IBaseMsgListener.super.onUnknownCmd(t, cmdString, msg);
        iteratorMsgListeners(msgListener -> msgListener.onUnknownCmd(t, cmdString, msg));
    }
    public String getRoomIdAsString() {
        if (this.roomId == null) {
            return "";
        }
        return this.roomId.toString();
    }
    public long getRoomIdAsLong() {
        String roomIdAsString = this.getRoomIdAsString();
        if (roomIdAsString.trim().isEmpty()) {
            return 0L;
        }
        return Long.parseLong(roomIdAsString);
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-servers/live-chat-client-servers-netty/src/main/java/tech/ordinaryroad/live/chat/client/servers/netty/handler/base/BaseConnectionHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,168 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.servers.netty.handler.base;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketHandshakeException;
import io.netty.handler.ssl.SslCloseCompletionEvent;
import io.netty.handler.ssl.SslHandshakeCompletionEvent;
import io.netty.util.concurrent.ScheduledFuture;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import tech.ordinaryroad.live.chat.client.commons.base.listener.IBaseConnectionListener;
import java.util.concurrent.TimeUnit;
/**
 * è¿žæŽ¥å¤„理器
 *
 * @author mjz
 * @date 2023/8/21
 */
@Slf4j
public abstract class BaseConnectionHandler<ConnectionHandler extends BaseConnectionHandler<?>> extends SimpleChannelInboundHandler<FullHttpResponse> {
    private final WebSocketClientHandshaker handshaker;
    @Getter
    private ChannelPromise handshakeFuture;
    private final IBaseConnectionListener<ConnectionHandler> listener;
    /**
     * å®¢æˆ·ç«¯å‘送心跳包
     */
    private ScheduledFuture<?> scheduledFuture = null;
    public BaseConnectionHandler(WebSocketClientHandshaker handshaker, IBaseConnectionListener<ConnectionHandler> listener) {
        this.handshaker = handshaker;
        this.listener = listener;
    }
    public BaseConnectionHandler(WebSocketClientHandshaker handshaker) {
        this(handshaker, null);
    }
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        this.handshakeFuture = ctx.newPromise();
    }
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        this.handshaker.handshake(ctx.channel());
    }
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception {
        // åˆ¤æ–­æ˜¯å¦æ­£ç¡®æ¡æ‰‹
        if (this.handshaker.isHandshakeComplete()) {
            handshakeSuccessfully(ctx, msg);
        } else {
            try {
                handshakeSuccessfully(ctx, msg);
            } catch (WebSocketHandshakeException e) {
                handshakeFailed(msg, e);
            }
        }
    }
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("userEventTriggered {}", evt.getClass());
        }
        if (evt instanceof SslHandshakeCompletionEvent) {
            heartbeatCancel();
            heartbeatStart(ctx);
            if (this.listener != null) {
                listener.onConnected((ConnectionHandler) BaseConnectionHandler.this);
            }
        } else if (evt instanceof SslCloseCompletionEvent) {
            heartbeatCancel();
            if (this.listener != null) {
                listener.onDisconnected((ConnectionHandler) BaseConnectionHandler.this);
            }
        } else {
            log.error("待处理 {}", evt.getClass());
        }
        super.userEventTriggered(ctx, evt);
    }
    /**
     * å¼€å§‹å‘送心跳包
     */
    private void heartbeatStart(ChannelHandlerContext ctx) {
        scheduledFuture = ctx.executor().scheduleAtFixedRate(() -> {
            sendHeartbeat(ctx);
        }, getHeartbeatInitialDelay(), getHeartbeatPeriod(), TimeUnit.SECONDS);
    }
    /**
     * å–消发送心跳包
     */
    private void heartbeatCancel() {
        if (null != scheduledFuture && !scheduledFuture.isCancelled()) {
            scheduledFuture.cancel(true);
            scheduledFuture = null;
        }
    }
    protected abstract void sendHeartbeat(ChannelHandlerContext ctx);
    public abstract void sendAuthRequest(Channel channel);
    protected abstract long getHeartbeatPeriod();
    protected abstract long getHeartbeatInitialDelay();
    private void handshakeSuccessfully(ChannelHandlerContext ctx, FullHttpResponse msg) {
        if (log.isDebugEnabled()) {
            log.debug("握手完成!");
        }
        this.handshaker.finishHandshake(ctx.channel(), msg);
        this.handshakeFuture.setSuccess();
    }
    private void handshakeFailed(FullHttpResponse msg, WebSocketHandshakeException e) {
        log.error("握手失败!status:" + msg.status(), e);
        this.handshakeFuture.setFailure(e);
        if (listener != null) {
            this.listener.onConnectFailed((ConnectionHandler) this);
        }
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("exceptionCaught", cause);
        if (!this.handshakeFuture.isDone()) {
            this.handshakeFuture.setFailure(cause);
        }
        ctx.close();
    }
}
ruoyi-modules/ruoyi-live/live-chat-client-servers/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
<!--
  ~ MIT License
  ~
  ~ Copyright (c) 2023 OrdinaryRoad
  ~
  ~ Permission is hereby granted, free of charge, to any person obtaining a copy
  ~ of this software and associated documentation files (the "Software"), to deal
  ~ in the Software without restriction, including without limitation the rights
  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  ~ copies of the Software, and to permit persons to whom the Software is
  ~ furnished to do so, subject to the following conditions:
  ~
  ~ The above copyright notice and this permission notice shall be included in all
  ~ copies or substantial portions of the Software.
  ~
  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  ~ SOFTWARE.
  -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.ruoyi</groupId>
        <artifactId>ruoyi-live</artifactId>
        <version>${revision}</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <packaging>pom</packaging>
    <artifactId>live-chat-client-servers</artifactId>
    <name>live-chat-client-servers</name>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <modules>
        <module>live-chat-client-servers-netty</module>
        <module>live-chat-client-servers-netty-client</module>
    </modules>
</project>
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,71 @@
<!--
  ~ MIT License
  ~
  ~ Copyright (c) 2023 OrdinaryRoad
  ~
  ~ Permission is hereby granted, free of charge, to any person obtaining a copy
  ~ of this software and associated documentation files (the "Software"), to deal
  ~ in the Software without restriction, including without limitation the rights
  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  ~ copies of the Software, and to permit persons to whom the Software is
  ~ furnished to do so, subject to the following conditions:
  ~
  ~ The above copyright notice and this permission notice shall be included in all
  ~ copies or substantial portions of the Software.
  ~
  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  ~ SOFTWARE.
  -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.ruoyi</groupId>
        <artifactId>live-chat-clients</artifactId>
        <version>${revision}</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <packaging>jar</packaging>
    <artifactId>live-chat-client-bilibili</artifactId>
    <name>live-chat-client-bilibili</name>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.ruoyi</groupId>
            <artifactId>live-chat-client-servers-netty-client</artifactId>
        </dependency>
        <dependency>
            <groupId>com.aayushatharva.brotli4j</groupId>
            <artifactId>brotli4j</artifactId>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>${junit-jupiter.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/api/BilibiliApis.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,247 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.api;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import tech.ordinaryroad.live.chat.client.bilibili.api.request.BilibiliLikeReportV3Request;
import tech.ordinaryroad.live.chat.client.bilibili.api.request.BilibiliSendMsgRequest;
import tech.ordinaryroad.live.chat.client.commons.base.exception.BaseException;
import tech.ordinaryroad.live.chat.client.commons.util.OrLiveChatCookieUtil;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static tech.ordinaryroad.live.chat.client.commons.base.msg.BaseMsg.OBJECT_MAPPER;
/**
 * B站API简易版
 *
 * @author mjz
 * @date 2023/5/5
 */
@Slf4j
public class BilibiliApis {
    public static final TimedCache<Long, String> GIFT_IMG_CACHE = new TimedCache<>(TimeUnit.DAYS.toMillis(1));
    public static final String KEY_COOKIE_CSRF = "bili_jct";
    public static final String KEY_UID = "DedeUserID";
    @SneakyThrows
    public static RoomInitResult roomInit(long roomId, String cookie) {
        @Cleanup
        HttpResponse response = createGetRequest("https://api.live.bilibili.com/room/v1/Room/room_init?id=" + roomId, cookie).execute();
        JsonNode dataJsonNode = responseInterceptor(response.body());
        return OBJECT_MAPPER.readValue(dataJsonNode.toString(), RoomInitResult.class);
    }
    public static JsonNode roomGiftConfig(long roomId, String cookie) {
        @Cleanup
        HttpResponse response = createGetRequest("https://api.live.bilibili.com/xlive/web-room/v1/giftPanel/roomGiftConfig?platform=pc&source=live&build=0&global_version=0&room_id=" + roomId, cookie).execute();
        return responseInterceptor(response.body());
    }
    /**
     * @param roomId
     * @param type   ç›´æ’­é—´ç”¨0
     * @return <pre>{@code
     * {
     *    "group": "live",
     *    "business_id": 0,
     *    "refresh_row_factor": 0.125,
     *    "refresh_rate": 100,
     *    "max_delay": 5000,
     *    "token": "-wm5-Qo4BBAztd1qp5ZJpgyTMRBhCc7yikz5d9rAd63PV46G9BMwl0R10kMM8Ilb-UieZGjLtipPrz4Cvi0DdhGFwOi8PJpFN9K-LoXh6Z_4yjEIwgRerDiMIstHzJ80J3B7wnRisAYkWA==",
     *    "host_list": [{
     *       "host": "ali-bj-live-comet-09.chat.bilibili.com",
     *       "port": 2243,
     *       "wss_port": 443,
     *       "ws_port": 2244
     *        }, {
     *       "host": "ali-gz-live-comet-02.chat.bilibili.com",
     *       "port": 2243,
     *       "wss_port": 443,
     *       "ws_port": 2244
     *    }, {
     *       "host": "broadcastlv.chat.bilibili.com",
     *       "port": 2243,
     *       "wss_port": 443,
     *       "ws_port": 2244
     *    }]
     * }
     * }</pre>
     */
    public static JsonNode getDanmuInfo(long roomId, int type, String cookie) {
        @Cleanup
        HttpResponse response = createGetRequest("https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo?id=" + roomId + "&type=" + type, cookie).execute();
        return responseInterceptor(response.body());
    }
    public static String getGiftImgById(long giftId, long roomId) {
        if (!GIFT_IMG_CACHE.containsKey(giftId)) {
            ThreadUtil.execAsync(() -> {
                updateGiftImgCache(roomId, null);
            });
        }
        return GIFT_IMG_CACHE.get(giftId);
    }
    /**
     * æ›´æ–°ç¤¼ç‰©å›¾ç‰‡ç¼“å­˜
     */
    public static void updateGiftImgCache(long roomId, String cookie) {
        JsonNode jsonNode = roomGiftConfig(roomId, cookie);
        for (JsonNode node : jsonNode.get("global_gift").get("list")) {
            long giftId = node.get("id").asLong();
            String giftImgUrl = node.get("webp").asText();
            GIFT_IMG_CACHE.put(giftId, giftImgUrl);
        }
    }
    /**
     * å‘送弹幕
     *
     * @param request {@link BilibiliSendMsgRequest}
     * @param cookie  Cookie
     */
    public static void sendMsg(BilibiliSendMsgRequest request, String cookie) {
        if (StrUtil.isBlank(cookie)) {
            throw new BaseException("发送弹幕接口cookie不能为空");
        }
        Map<String, Object> stringObjectMap = BeanUtil.beanToMap(request);
        @Cleanup HttpResponse execute = HttpUtil.createPost("https://api.live.bilibili.com/msg/send")
                .cookie(cookie)
                .form(stringObjectMap)
                .execute();
        responseInterceptor(execute.body());
    }
    /**
     * å‘送弹幕
     *
     * @param msg        å†…容
     * @param realRoomId çœŸå®žæˆ¿é—´id
     * @param cookie     Cookie
     */
    public static void sendMsg(String msg, long realRoomId, String cookie) {
        String biliJct = OrLiveChatCookieUtil.getCookieByName(cookie, KEY_COOKIE_CSRF, () -> {
            throw new BaseException("cookie中缺少参数" + KEY_COOKIE_CSRF);
        });
        BilibiliSendMsgRequest request = new BilibiliSendMsgRequest(msg, StrUtil.toString(ZonedDateTime.now(ZoneId.of("Asia/Shanghai")).toEpochSecond()), realRoomId, biliJct, biliJct);
        sendMsg(request, cookie);
    }
    /**
     * ä¸ºä¸»æ’­ç‚¹èµž
     *
     * @param request {@link BilibiliLikeReportV3Request}
     * @param cookie  Cookie
     */
    public static void likeReportV3(BilibiliLikeReportV3Request request, String cookie) {
        if (StrUtil.isBlank(cookie)) {
            throw new BaseException("为主播点赞接口cookie不能为空");
        }
        Map<String, Object> stringObjectMap = BeanUtil.beanToMap(request);
        @Cleanup HttpResponse execute = HttpUtil.createPost("https://api.live.bilibili.com/xlive/app-ucenter/v1/like_info_v3/like/likeReportV3")
                .cookie(cookie)
                .form(stringObjectMap)
                .execute();
        responseInterceptor(execute.body());
    }
    /**
     * ä¸ºä¸»æ’­ç‚¹èµž
     *
     * @param anchor_id  ä¸»æ’­Uid {@link RoomInitResult#uid}
     * @param realRoomId çœŸå®žæˆ¿é—´Id {@link RoomInitResult#room_id}
     * @param cookie     Cookie
     */
    public static void likeReportV3(long anchor_id, long realRoomId, String cookie) {
        String uid = OrLiveChatCookieUtil.getCookieByName(cookie, KEY_UID, () -> {
            throw new BaseException("cookie中缺少参数" + KEY_UID);
        });
        String biliJct = OrLiveChatCookieUtil.getCookieByName(cookie, KEY_COOKIE_CSRF, () -> {
            throw new BaseException("cookie中缺少参数" + KEY_COOKIE_CSRF);
        });
        BilibiliLikeReportV3Request request = new BilibiliLikeReportV3Request(realRoomId, uid, anchor_id, biliJct, biliJct);
        likeReportV3(request, cookie);
    }
    public static HttpRequest createGetRequest(String url, String cookies) {
        return HttpUtil.createGet(url)
                .cookie(cookies);
    }
    private static JsonNode responseInterceptor(String responseString) {
        try {
            JsonNode jsonNode = OBJECT_MAPPER.readTree(responseString);
            int code = jsonNode.get("code").asInt();
            if (code == 0) {
                // æˆåŠŸ
                return jsonNode.get("data");
            } else {
                throw new BaseException(jsonNode.get("message").asText());
            }
        } catch (JsonProcessingException e) {
            throw new BaseException(e);
        }
    }
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    public static class RoomInitResult {
        private long room_id;
        private int short_id;
        private long uid;
        private int need_p2p;
        private boolean is_hidden;
        private boolean is_locked;
        private boolean is_portrait;
        private int live_status;
        private int hidden_till;
        private int lock_till;
        private boolean encrypted;
        private boolean pwd_verified;
        private long live_time;
        private int room_shield;
        private int is_sp;
        private int special_type;
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/api/request/BilibiliLikeReportV3Request.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.api.request;
import cn.hutool.core.util.StrUtil;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * @author mjz
 * @date 2024/1/31
 */
@Data
@NoArgsConstructor
public class BilibiliLikeReportV3Request {
    /**
     * æœ¬æ¬¡ç‚¹èµžæ¬¡æ•°
     */
    private int click_time = 1;
    /**
     * æˆ¿é—´çœŸå®žID
     */
    private long room_id;
    /**
     * Cookie中的DedeUserID
     */
    private String uid;
    /**
     * RoomInitResult中的uid
     */
    private long anchor_id;
    /**
     * Cookie中的bili_jct
     */
    private String csrf;
    /**
     * Cookie中的bili_jct
     */
    private String csrf_token;
    /**
     * æš‚时留空
     */
    private String visit_id = StrUtil.EMPTY;
    public BilibiliLikeReportV3Request(long room_id, String uid, long anchor_id, String csrf, String csrf_token) {
        this.room_id = room_id;
        this.uid = uid;
        this.anchor_id = anchor_id;
        this.csrf = csrf;
        this.csrf_token = csrf_token;
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/api/request/BilibiliSendMsgRequest.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.api.request;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * @author mjz
 * @date 2023/9/7
 */
@Data
@NoArgsConstructor
public class BilibiliSendMsgRequest {
    private String bubble = "0";
    /**
     * å¼¹å¹•内容
     */
    private String msg;
    /**
     * å¼¹å¹•颜色
     */
    private String color = "16777215";
    private String mode = "1";
    private String room_type = "0";
    private String jumpfrom = "0";
    /**
     * å­—体大小
     */
    private String fontsize = "25";
    /**
     * æ—¶é—´æˆ³ï¼ˆç§’)
     */
    private String rnd;
    /**
     * æˆ¿é—´çœŸå®žID
     */
    private long roomid;
    /**
     * Cookie中的bili_jct
     */
    private String csrf;
    /**
     * Cookie中的bili_jct
     */
    private String csrf_token;
    public BilibiliSendMsgRequest(String msg, String rnd, long roomid, String csrf, String csrf_token) {
        this.msg = msg;
        this.rnd = rnd;
        this.roomid = roomid;
        this.csrf = csrf;
        this.csrf_token = csrf_token;
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/client/BilibiliLiveChatClient.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,184 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.client;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import lombok.extern.slf4j.Slf4j;
import tech.ordinaryroad.live.chat.client.bilibili.api.BilibiliApis;
import tech.ordinaryroad.live.chat.client.bilibili.config.BilibiliLiveChatClientConfig;
import tech.ordinaryroad.live.chat.client.bilibili.constant.BilibiliCmdEnum;
import tech.ordinaryroad.live.chat.client.bilibili.listener.IBilibiliConnectionListener;
import tech.ordinaryroad.live.chat.client.bilibili.listener.IBilibiliMsgListener;
import tech.ordinaryroad.live.chat.client.bilibili.msg.base.IBilibiliMsg;
import tech.ordinaryroad.live.chat.client.bilibili.netty.handler.BilibiliBinaryFrameHandler;
import tech.ordinaryroad.live.chat.client.bilibili.netty.handler.BilibiliConnectionHandler;
import tech.ordinaryroad.live.chat.client.commons.base.exception.BaseException;
import tech.ordinaryroad.live.chat.client.commons.base.listener.IBaseConnectionListener;
import tech.ordinaryroad.live.chat.client.servers.netty.client.base.BaseNettyClient;
import java.util.List;
import java.util.function.Consumer;
/**
 * B站直播间弹幕客户端
 *
 * @author mjz
 * @date 2023/8/20
 */
@Slf4j
public class BilibiliLiveChatClient extends BaseNettyClient<
        BilibiliLiveChatClientConfig,
        BilibiliCmdEnum,
        IBilibiliMsg,
        IBilibiliMsgListener,
        BilibiliConnectionHandler,
        BilibiliBinaryFrameHandler
        > {
    private BilibiliApis.RoomInitResult roomInitResult = new BilibiliApis.RoomInitResult();
    public BilibiliLiveChatClient(BilibiliLiveChatClientConfig config, List<IBilibiliMsgListener> msgListeners, IBilibiliConnectionListener connectionListener, EventLoopGroup workerGroup) {
        super(config, workerGroup, connectionListener);
        addMsgListeners(msgListeners);
        // åˆå§‹åŒ–
        this.init();
    }
    public BilibiliLiveChatClient(BilibiliLiveChatClientConfig config, IBilibiliMsgListener msgListener, IBilibiliConnectionListener connectionListener, EventLoopGroup workerGroup) {
        super(config, workerGroup, connectionListener);
        addMsgListener(msgListener);
        // åˆå§‹åŒ–
        this.init();
    }
    public BilibiliLiveChatClient(BilibiliLiveChatClientConfig config, IBilibiliMsgListener msgListener, IBilibiliConnectionListener connectionListener) {
        this(config, msgListener, connectionListener, new NioEventLoopGroup());
    }
    public BilibiliLiveChatClient(BilibiliLiveChatClientConfig config, IBilibiliMsgListener msgListener) {
        this(config, msgListener, null, new NioEventLoopGroup());
    }
    public BilibiliLiveChatClient(BilibiliLiveChatClientConfig config) {
        this(config, null);
    }
    @Override
    public void init() {
        roomInitResult = BilibiliApis.roomInit(getConfig().getRoomId(), getConfig().getCookie());
        super.init();
    }
    @Override
    public BilibiliConnectionHandler initConnectionHandler(IBaseConnectionListener<BilibiliConnectionHandler> clientConnectionListener) {
        return new BilibiliConnectionHandler(
                WebSocketClientHandshakerFactory.newHandshaker(getWebsocketUri(), WebSocketVersion.V13, null, true, new DefaultHttpHeaders(), getConfig().getMaxFramePayloadLength()),
                BilibiliLiveChatClient.this, clientConnectionListener
        );
    }
    @Override
    public BilibiliBinaryFrameHandler initBinaryFrameHandler() {
        return new BilibiliBinaryFrameHandler(super.msgListeners, BilibiliLiveChatClient.this);
    }
    @Override
    public void sendDanmu(Object danmu, Runnable success, Consumer<Throwable> failed) {
        if (!checkCanSendDanmu(false)) {
            return;
        }
        if (danmu instanceof String) {
            String msg = (String) danmu;
            try {
                if (log.isDebugEnabled()) {
                    log.debug("{} bilibili发送弹幕 {}", getConfig().getRoomId(), danmu);
                }
                boolean sendSuccess = false;
                try {
                    BilibiliApis.sendMsg(msg, roomInitResult.getRoom_id(), getConfig().getCookie());
                    sendSuccess = true;
                } catch (Exception e) {
                    log.error("bilibili弹幕发送失败", e);
                    if (failed != null) {
                        failed.accept(e);
                    }
                }
                if (!sendSuccess) {
                    return;
                }
                if (log.isDebugEnabled()) {
                    log.debug("bilibili弹幕发送成功 {}", danmu);
                }
                if (success != null) {
                    success.run();
                }
                finishSendDanmu();
            } catch (Exception e) {
                log.error("bilibili弹幕发送失败", e);
                if (failed != null) {
                    failed.accept(e);
                }
            }
        } else {
            super.sendDanmu(danmu, success, failed);
        }
    }
    @Override
    public void clickLike(int count, Runnable success, Consumer<Throwable> failed) {
        if (count <= 0) {
            throw new BaseException("点赞次数必须大于0");
        }
        boolean successfullyClicked = false;
        try {
            BilibiliApis.likeReportV3(roomInitResult.getUid(), roomInitResult.getRoom_id(), getConfig().getCookie());
            successfullyClicked = true;
        } catch (Exception e) {
            log.error("Bilibili为直播间点赞失败", e);
            if (failed != null) {
                failed.accept(e);
            }
        }
        if (!successfullyClicked) {
            return;
        }
        if (log.isDebugEnabled()) {
            log.debug("Bilibili为直播间点赞成功");
        }
        if (success != null) {
            success.run();
        }
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/config/BilibiliLiveChatClientConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.config;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import tech.ordinaryroad.live.chat.client.bilibili.constant.ProtoverEnum;
import tech.ordinaryroad.live.chat.client.commons.util.OrLiveChatNumberUtil;
import tech.ordinaryroad.live.chat.client.servers.netty.client.config.BaseNettyClientConfig;
/**
 * B站直播间弹幕客户端配置
 *
 * @author mjz
 * @date 2023/8/21
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder(toBuilder = true)
public class BilibiliLiveChatClientConfig extends BaseNettyClientConfig {
    /**
     * @see ProtoverEnum
     */
    @Builder.Default
    private ProtoverEnum protover = ProtoverEnum.NORMAL_ZLIB;
    @Builder.Default
    private String websocketUri = "wss://broadcastlv.chat.bilibili.com:443/sub";
    @Override
    public Long getRoomId() {
        return OrLiveChatNumberUtil.parseLong(super.getRoomId());
    }
    public void setProtover(ProtoverEnum protover) {
        ProtoverEnum oldValue = this.protover;
        this.protover = protover;
        super.propertyChangeSupport.firePropertyChange("protover", oldValue, protover);
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/constant/BilibiliCmdEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,143 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.constant;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
 * @author mjz
 * @date 2023/1/6
 */
@Getter
@RequiredArgsConstructor
public enum BilibiliCmdEnum {
    /**
     * æ¸¸å®¢çŠ¶æ€ä¸‹ï¼Œ5分钟后会出现登录提示,弹幕中的用户名、用户id等信息将不再可见
     */
    LOG_IN_NOTICE,
    /**
     * æ”¶åˆ°å¼¹å¹•
     */
    DANMU_MSG,
    /**
     * æ”¶åˆ°ç¤¼ç‰©
     */
    SEND_GIFT,
    /**
     * æœ‰äººä¸Šèˆ°
     */
    GUARD_BUY,
    /**
     * æ¬¢è¿Žèˆ°é•¿
     */
    WELCOME_GUARD,
    WELCOME,
    /**
     * ç¤¼ç‰©è¿žå‡»
     */
    COMBO_SEND,
    /**
     * æ¬¢è¿Žé«˜èƒ½ç”¨æˆ·ã€(舰长?待验证)特殊消息
     */
    ENTRY_EFFECT,
    HOT_RANK_CHANGED,
    HOT_RANK_CHANGED_V2,
    INTERACT_WORD,
    /**
     * å¼€å§‹ç›´æ’­
     */
    LIVE,
    LIVE_INTERACTIVE_GAME,
    NOTICE_MSG,
    /**
     * é«˜èƒ½æ¦œæ•°é‡æ›´æ–°
     */
    ONLINE_RANK_COUNT,
    ONLINE_RANK_TOP3,
    ONLINE_RANK_V2,
    PK_BATTLE_END,
    PK_BATTLE_FINAL_PROCESS,
    PK_BATTLE_PROCESS,
    PK_BATTLE_PROCESS_NEW,
    PK_BATTLE_SETTLE,
    PK_BATTLE_SETTLE_USER,
    PK_BATTLE_SETTLE_V2,
    /**
     * ä¸»æ’­å‡†å¤‡ä¸­
     */
    PREPARING,
    ROOM_REAL_TIME_MESSAGE_UPDATE,
    /**
     * åœæ­¢ç›´æ’­çš„æˆ¿é—´ID列表
     */
    STOP_LIVE_ROOM_LIST,
    /**
     * é†’目留言
     */
    SUPER_CHAT_MESSAGE,
    SUPER_CHAT_MESSAGE_JPN,
    /**
     * åˆ é™¤é†’目留言
     */
    SUPER_CHAT_MESSAGE_DELETE,
    WIDGET_BANNER,
    /**
     * ç‚¹èµžæ•°æ›´æ–°
     */
    LIKE_INFO_V3_UPDATE,
    /**
     * ä¸ºä¸»æ’­ç‚¹èµž
     */
    LIKE_INFO_V3_CLICK,
    HOT_ROOM_NOTIFY,
    /**
     * è§‚看人数变化
     */
    WATCHED_CHANGE,
    POPULAR_RANK_CHANGED,
    COMMON_NOTICE_DANMAKU,
    LIVE_MULTI_VIEW_CHANGE,
    RECOMMEND_CARD,
    PK_BATTLE_START_NEW,
    PK_BATTLE_ENTRANCE,
    AREA_RANK_CHANGED,
    ROOM_BLOCK_MSG,
    USER_TOAST_MSG,
    PK_BATTLE_PRE_NEW,
    PK_BATTLE_RANK_CHANGE,
    PK_BATTLE_START,
    PK_BATTLE_PRE,
    PLAY_TAG,
    ;
    public static BilibiliCmdEnum getByString(String cmd) {
        try {
            return BilibiliCmdEnum.valueOf(cmd);
        } catch (Exception e) {
            return null;
        }
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/constant/OperationEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,86 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.constant;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
 * @author mjz
 * @date 2023/1/5
 */
@Getter
@RequiredArgsConstructor
public enum OperationEnum {
    HANDSHAKE(0),
    HANDSHAKE_REPLY(1),
    /**
     * å¿ƒè·³åŒ…
     */
    HEARTBEAT(2),
    /**
     * å¿ƒè·³åŒ…回复(人气值)
     */
    HEARTBEAT_REPLY(3),
    SEND_MSG(4),
    /**
     * æ™®é€šåŒ…(命令)
     */
    SEND_SMS_REPLY(5),
    DISCONNECT_REPLY(6),
    /**
     * è®¤è¯åŒ…
     */
    AUTH(7),
    /**
     * è®¤è¯åŒ…回复
     */
    AUTH_REPLY(8),
    RAW(9),
    PROTO_READY(10),
    PROTO_FINISH(11),
    CHANGE_ROOM(12),
    CHANGE_ROOM_REPLY(13),
    REGISTER(14),
    REGISTER_REPLY(15),
    UNREGISTER(16),
    UNREGISTER_REPLY(17),
    ;
    private final int code;
    public static OperationEnum getByCode(int code) {
        for (OperationEnum value : OperationEnum.values()) {
            if (value.code == code) {
                return value;
            }
        }
        return null;
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/constant/ProtoverEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.constant;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
 * @author mjz
 * @date 2023/1/5
 */
@Getter
@RequiredArgsConstructor
public enum ProtoverEnum {
    /**
     * æ™®é€šåŒ…正文不使用压缩
     */
    NORMAL_NO_COMPRESSION(0),
    /**
     * å¿ƒè·³åŠè®¤è¯åŒ…正文不使用压缩
     */
    HEARTBEAT_AUTH_NO_COMPRESSION(1),
    /**
     * æ™®é€šåŒ…正文使用zlib压缩
     */
    NORMAL_ZLIB(2),
    /**
     * æ™®é€šåŒ…正文使用brotli压缩,解压为一个带头部的协议0普通包
     */
    NORMAL_BROTLI(3),
    ;
    private final int code;
    public static ProtoverEnum getByCode(int code) {
        for (ProtoverEnum value : ProtoverEnum.values()) {
            if (value.code == code) {
                return value;
            }
        }
        return null;
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/listener/IBilibiliConnectionListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.listener;
import tech.ordinaryroad.live.chat.client.bilibili.netty.handler.BilibiliConnectionHandler;
import tech.ordinaryroad.live.chat.client.commons.base.listener.IBaseConnectionListener;
/**
 * è¿žæŽ¥å›žè°ƒ
 *
 * @author mjz
 * @date 2023/8/21
 */
public interface IBilibiliConnectionListener extends IBaseConnectionListener<BilibiliConnectionHandler> {
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/listener/IBilibiliMsgListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,138 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.listener;
import tech.ordinaryroad.live.chat.client.bilibili.constant.BilibiliCmdEnum;
import tech.ordinaryroad.live.chat.client.bilibili.msg.*;
import tech.ordinaryroad.live.chat.client.bilibili.netty.handler.BilibiliBinaryFrameHandler;
import tech.ordinaryroad.live.chat.client.commons.base.listener.*;
/**
 * @author mjz
 * @date 2023/1/7
 */
public interface IBilibiliMsgListener extends IBaseMsgListener<BilibiliBinaryFrameHandler, BilibiliCmdEnum>,
        IDanmuMsgListener<BilibiliBinaryFrameHandler, DanmuMsgMsg>,
        IGiftMsgListener<BilibiliBinaryFrameHandler, SendGiftMsg>,
        ISuperChatMsgListener<BilibiliBinaryFrameHandler, SuperChatMessageMsg>,
        IEnterRoomMsgListener<BilibiliBinaryFrameHandler, InteractWordMsg>,
        ILikeMsgListener<BilibiliBinaryFrameHandler, LikeInfoV3ClickMsg> {
    /**
     * æ”¶åˆ°ç¤¼ç‰©
     *
     * @param binaryFrameHandler BilibiliBinaryFrameHandler
     * @param msg                SendSmsReplyMsg
     * @deprecated use {@link IGiftMsgListener#onGiftMsg(Object, Object)}
     */
    default void onSendGift(BilibiliBinaryFrameHandler binaryFrameHandler, SendSmsReplyMsg msg) {
        this.onSendGift(msg);
    }
    /**
     * @deprecated use {@link IGiftMsgListener#onGiftMsg(Object)}
     */
    default void onSendGift(SendSmsReplyMsg msg) {
        // ignore
    }
    /**
     * æ™®é€šç”¨æˆ·è¿›å…¥ç›´æ’­é—´
     *
     * @param binaryFrameHandler BilibiliBinaryFrameHandler
     * @param msg                SendSmsReplyMsg
     * @deprecated use {@link IEnterRoomMsgListener#onEnterRoomMsg}
     */
    default void onEnterRoom(BilibiliBinaryFrameHandler binaryFrameHandler, SendSmsReplyMsg msg) {
        this.onEnterRoom(msg);
    }
    /**
     * @deprecated use {@link IEnterRoomMsgListener#onEnterRoomMsg}
     */
    default void onEnterRoom(SendSmsReplyMsg msg) {
        // ignore
    }
    /**
     * å…¥åœºæ•ˆæžœï¼ˆé«˜èƒ½ç”¨æˆ·ï¼‰
     *
     * @param binaryFrameHandler BilibiliBinaryFrameHandler
     * @param sendSmsReplyMsg    SendSmsReplyMsg
     */
    default void onEntryEffect(BilibiliBinaryFrameHandler binaryFrameHandler, SendSmsReplyMsg sendSmsReplyMsg) {
        this.onEntryEffect(sendSmsReplyMsg);
    }
    default void onEntryEffect(SendSmsReplyMsg sendSmsReplyMsg) {
        // ignore
    }
    /**
     * è§‚看人数变化
     *
     * @param binaryFrameHandler BilibiliBinaryFrameHandler
     * @param msg                SendSmsReplyMsg
     */
    default void onWatchedChange(BilibiliBinaryFrameHandler binaryFrameHandler, SendSmsReplyMsg msg) {
        this.onWatchedChange(msg);
    }
    default void onWatchedChange(SendSmsReplyMsg msg) {
        // ignore
    }
    /**
     * ä¸ºä¸»æ’­ç‚¹èµž
     *
     * @param binaryFrameHandler BilibiliBinaryFrameHandler
     * @param msg                SendSmsReplyMsg
     * @deprecated use {@link ILikeMsgListener#onLikeMsg}
     */
    default void onClickLike(BilibiliBinaryFrameHandler binaryFrameHandler, SendSmsReplyMsg msg) {
        this.onClickLike(msg);
    }
    /**
     * @deprecated use {@link ILikeMsgListener#onLikeMsg}
     */
    default void onClickLike(SendSmsReplyMsg msg) {
        // ignore
    }
    /**
     * ç‚¹èµžæ•°æ›´æ–°
     *
     * @param binaryFrameHandler BilibiliBinaryFrameHandler
     * @param msg                SendSmsReplyMsg
     */
    default void onClickUpdate(BilibiliBinaryFrameHandler binaryFrameHandler, SendSmsReplyMsg msg) {
        this.onClickUpdate(msg);
    }
    default void onClickUpdate(SendSmsReplyMsg msg) {
        // ignore
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/AuthMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,92 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import tech.ordinaryroad.live.chat.client.bilibili.constant.OperationEnum;
import tech.ordinaryroad.live.chat.client.bilibili.constant.ProtoverEnum;
import tech.ordinaryroad.live.chat.client.bilibili.msg.base.BaseBilibiliMsg;
/**
 * @author mjz
 * @date 2023/1/6
 */
@Getter
@Setter
@RequiredArgsConstructor
public class AuthMsg extends BaseBilibiliMsg {
    /**
     * ç”¨æˆ·uid,0代表游客
     */
    private long uid;
    /**
     * æˆ¿é—´id room_id,不是短id short_id
     * å¯ä»¥é€šè¿‡å°†url参数id改为直播地址中的数字来查询房间真实id
     * example: <a href="https://api.live.bilibili.com/room/v1/Room/room_init?id=6">https://api.live.bilibili.com/room/v1/Room/room_init?id=6</a>
     */
    private final long roomid;
    /**
     * åè®®ç‰ˆæœ¬
     *
     * @see ProtoverEnum#getCode()
     */
    private final int protover;
    /**
     * å¹³å°æ ‡è¯†
     */
    private String platform = "web";
    private int type = 2;
    /**
     * å¿…须字段
     *
     * @since 2023-08-19
     */
    private final String buvid;
    /**
     * è®¤è¯ç§˜é’¥ï¼ˆå¿…须字段)
     *
     * @since @since 2023-08-19
     */
    private final String key;
    @Override
    public ProtoverEnum getProtoverEnum() {
        return ProtoverEnum.getByCode(this.protover);
    }
    @Override
    public OperationEnum getOperationEnum() {
        return OperationEnum.AUTH;
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/AuthReplyMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import tech.ordinaryroad.live.chat.client.bilibili.constant.OperationEnum;
import tech.ordinaryroad.live.chat.client.bilibili.constant.ProtoverEnum;
import tech.ordinaryroad.live.chat.client.bilibili.msg.base.BaseBilibiliMsg;
/**
 * @author mjz
 * @date 2023/1/6
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class AuthReplyMsg extends BaseBilibiliMsg {
    /**
     * 0: OK,-101: TOKEN_ERROR
     */
    private int code;
    @JsonIgnore
    private int protover;
    @Override
    public ProtoverEnum getProtoverEnum() {
        return ProtoverEnum.getByCode(protover);
    }
    @Override
    public OperationEnum getOperationEnum() {
        return OperationEnum.AUTH_REPLY;
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/DanmuMsgMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,102 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg;
import cn.hutool.core.codec.Base64;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import tech.ordinaryroad.live.chat.client.bilibili.constant.OperationEnum;
import tech.ordinaryroad.live.chat.client.bilibili.msg.base.BaseBilibiliMsg;
import tech.ordinaryroad.live.chat.client.commons.base.msg.IDanmuMsg;
/**
 * @author mjz
 * @date 2023/9/8
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class DanmuMsgMsg extends BaseBilibiliMsg implements IDanmuMsg {
    private JsonNode info;
    private String dm_v2;
    @Override
    public OperationEnum getOperationEnum() {
        return OperationEnum.SEND_SMS_REPLY;
    }
    @Override
    public String getBadgeName() {
        JsonNode jsonNode3 = info.get(3);
        if (jsonNode3.isEmpty()) {
            return "";
        }
        return jsonNode3.get(1).asText();
    }
    @Override
    public byte getBadgeLevel() {
        JsonNode jsonNode3 = info.get(3);
        if (jsonNode3.isEmpty()) {
            return 0;
        }
        return (byte) jsonNode3.get(0).asInt();
    }
    @Override
    public String getUid() {
        JsonNode jsonNode2 = info.get(2);
        return jsonNode2.get(0).asText();
    }
    @Override
    public String getUsername() {
        JsonNode jsonNode2 = info.get(2);
        return jsonNode2.get(1).asText();
    }
    @Override
    public String getUserAvatar() {
        String avatar = null;
        try {
            tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2 dmV2 = tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2.parseFrom(Base64.decode(dm_v2));
            avatar = dmV2.getDmV220().getAvatar();
        } catch (Exception e) {
            // ignore
        }
        return avatar;
    }
    @Override
    public String getContent() {
        JsonNode jsonNode1 = info.get(1);
        return jsonNode1.asText();
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/HeartbeatMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import tech.ordinaryroad.live.chat.client.bilibili.constant.OperationEnum;
import tech.ordinaryroad.live.chat.client.bilibili.constant.ProtoverEnum;
import tech.ordinaryroad.live.chat.client.bilibili.msg.base.BaseBilibiliMsg;
/**
 * @author mjz
 * @date 2023/1/6
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class HeartbeatMsg extends BaseBilibiliMsg {
    @JsonIgnore
    private int protover;
    @Override
    public ProtoverEnum getProtoverEnum() {
        return ProtoverEnum.getByCode(protover);
    }
    @Override
    public OperationEnum getOperationEnum() {
        return OperationEnum.HEARTBEAT;
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/HeartbeatReplyMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import tech.ordinaryroad.live.chat.client.bilibili.constant.OperationEnum;
import tech.ordinaryroad.live.chat.client.bilibili.constant.ProtoverEnum;
import tech.ordinaryroad.live.chat.client.bilibili.msg.base.BaseBilibiliMsg;
/**
 * @author mjz
 * @date 2023/1/6
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class HeartbeatReplyMsg extends BaseBilibiliMsg {
    private int popularity;
    @JsonIgnore
    private int protover;
    @Override
    public ProtoverEnum getProtoverEnum() {
        return ProtoverEnum.getByCode(protover);
    }
    @Override
    public OperationEnum getOperationEnum() {
        return OperationEnum.HEARTBEAT_REPLY;
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/InteractWordMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,396 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import tech.ordinaryroad.live.chat.client.bilibili.constant.OperationEnum;
import tech.ordinaryroad.live.chat.client.bilibili.msg.base.BaseBilibiliMsg;
import tech.ordinaryroad.live.chat.client.commons.base.msg.IEnterRoomMsg;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author mjz
 * @date 2023/12/26
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class InteractWordMsg extends BaseBilibiliMsg implements IEnterRoomMsg {
    private Data data;
    @Override
    public OperationEnum getOperationEnum() {
        return OperationEnum.SEND_SMS_REPLY;
    }
    @Override
    public String getBadgeName() {
        if (data == null || data.fans_medal == null) {
            return null;
        }
        return data.fans_medal.medal_name;
    }
    @Override
    public byte getBadgeLevel() {
        if (data == null || data.fans_medal == null) {
            return 0;
        }
        return data.fans_medal.medal_level;
    }
    @Override
    public String getUid() {
        if (data == null) {
            return null;
        }
        return Long.toString(data.uid);
    }
    @Override
    public String getUsername() {
        if (data == null) {
            return null;
        }
        return data.uname;
    }
    @Override
    public String getUserAvatar() {
        if (data == null || data.uinfo == null || data.uinfo.base == null) {
            return null;
        }
        return data.uinfo.base.face;
    }
    @lombok.Data
    public static class Data {
        private Contribution contribution;
        private Contribution_v2 contribution_v2;
        private int core_user_type;
        private int dmscore;
        private Fans_medal fans_medal;
        private String group_medal;
        private List<Integer> identities;
        private boolean is_mystery;
        private int is_spread;
        private int msg_type;
        private int privilege_type;
        private long roomid;
        private long score;
        private String spread_desc;
        private String spread_info;
        private int tail_icon;
        private String tail_text;
        private long timestamp;
        private long trigger_time;
        private long uid;
        private Uinfo uinfo;
        private String uname;
        private String uname_color;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Contribution {
        private int grade;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Contribution_v2 {
        private int grade;
        private String rank_type;
        private String text;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Fans_medal {
        private long anchor_roomid;
        private int guard_level;
        private int icon_id;
        private int is_lighted;
        private long medal_color;
        private long medal_color_border;
        private long medal_color_end;
        private long medal_color_start;
        private byte medal_level;
        private String medal_name;
        private long score;
        private String special;
        private long target_id;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Origin_info {
        private String face;
        private String name;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Risk_ctrl_info {
        private String face;
        private String name;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Official_info {
        private int role;
        private String title;
        private String desc;
        private int type;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Base {
        private String face;
        private boolean is_mystery;
        private String name;
        private int name_color;
        private Origin_info origin_info;
        private Risk_ctrl_info risk_ctrl_info;
        private Official_info official_info;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Medal {
        private String name;
        private int level;
        private long color_start;
        private long color_end;
        private long color_border;
        private long color;
        private int id;
        private int typ;
        private int is_light;
        private long ruid;
        private int guard_level;
        private int score;
        private String guard_icon;
        private String honor_icon;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Guard {
        private int level;
        private String expired_str;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Uinfo {
        private long uid;
        private Base base;
        private Medal medal;
        private String wealth;
        private String title;
        private Guard guard;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/LikeInfoV3ClickMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,158 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import tech.ordinaryroad.live.chat.client.bilibili.constant.OperationEnum;
import tech.ordinaryroad.live.chat.client.bilibili.msg.base.BaseBilibiliMsg;
import tech.ordinaryroad.live.chat.client.commons.base.msg.ILikeMsg;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author mjz
 * @date 2024/1/31
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class LikeInfoV3ClickMsg extends BaseBilibiliMsg implements ILikeMsg {
    private Data data;
    @Override
    public OperationEnum getOperationEnum() {
        return OperationEnum.SEND_SMS_REPLY;
    }
    @Override
    public String getBadgeName() {
        if (this.data == null || this.data.getFans_medal() == null) {
            return null;
        }
        return this.data.getFans_medal().getMedal_name();
    }
    @Override
    public byte getBadgeLevel() {
        if (this.data == null || this.data.getFans_medal() == null) {
            return 0;
        }
        return this.data.getFans_medal().getMedal_level();
    }
    @Override
    public String getUid() {
        if (this.data == null) {
            return null;
        }
        return Long.toString(this.data.getUid());
    }
    @Override
    public String getUsername() {
        if (this.data == null) {
            return "";
        }
        return this.data.getUname();
    }
    @Override
    public String getUserAvatar() {
        if (this.data == null || this.data.getUinfo() == null || this.data.getUinfo().getBase() == null) {
            return "";
        }
        return this.data.getUinfo().getBase().getFace();
    }
    @lombok.Data
    public static class Data {
        private int show_area;
        private int msg_type;
        private String like_icon;
        private long uid;
        private String like_text;
        private String uname;
        private String uname_color;
        private List<Integer> identities;
        private InteractWordMsg.Fans_medal fans_medal;
        private Contribution_info contribution_info;
        private int dmscore;
        private String group_medal;
        private boolean is_mystery;
        private InteractWordMsg.Uinfo uinfo;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Contribution_info {
        private int grade;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/SendGiftMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,351 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import tech.ordinaryroad.live.chat.client.bilibili.api.BilibiliApis;
import tech.ordinaryroad.live.chat.client.bilibili.constant.OperationEnum;
import tech.ordinaryroad.live.chat.client.bilibili.msg.base.BaseBilibiliMsg;
import tech.ordinaryroad.live.chat.client.bilibili.msg.dto.MedalInfo;
import tech.ordinaryroad.live.chat.client.commons.base.msg.IGiftMsg;
import java.util.HashMap;
import java.util.Map;
/**
 * @author mjz
 * @date 2023/9/8
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class SendGiftMsg extends BaseBilibiliMsg implements IGiftMsg {
    private Data data;
    /**
     * é¢å¤–属性,获取礼物图片时可能会用到
     */
    private long roomId;
    @Override
    public String getBadgeName() {
        if (data == null || data.medal_info == null) {
            return IGiftMsg.super.getBadgeName();
        }
        return data.medal_info.getMedal_name();
    }
    @Override
    public byte getBadgeLevel() {
        if (data == null || data.medal_info == null) {
            return IGiftMsg.super.getBadgeLevel();
        }
        return data.medal_info.getMedal_level();
    }
    @Override
    public String getUid() {
        if (this.data == null) {
            return null;
        }
        return Long.toString(this.data.getUid());
    }
    @Override
    public String getUsername() {
        if (this.data == null) {
            return "";
        }
        return this.data.getUname();
    }
    @Override
    public String getUserAvatar() {
        if (this.data == null) {
            return "";
        }
        return this.data.getFace();
    }
    @Override
    public String getGiftName() {
        if (this.data == null) {
            return "未知礼物";
        }
        return this.data.getGiftName();
    }
    @Override
    public String getGiftImg() {
        return BilibiliApis.getGiftImgById(this.data.giftId, this.roomId);
    }
    @Override
    public String getGiftId() {
        if (this.data == null) {
            return null;
        }
        return Long.toString(data.getGiftId());
    }
    @Override
    public int getGiftCount() {
        if (this.data == null) {
            return 0;
        }
        return data.getNum();
    }
    @Override
    public int getGiftPrice() {
        if (this.data == null) {
            return -1;
        }
        return data.getPrice();
    }
    @Override
    public String getReceiveUid() {
        if (this.data == null || this.data.getReceive_user_info() == null) {
            return null;
        }
        return Long.toString(data.getReceive_user_info().getUid());
    }
    @Override
    public String getReceiveUsername() {
        if (this.data == null || this.data.getReceive_user_info() == null) {
            return "";
        }
        return data.getReceive_user_info().getUname();
    }
    @Override
    public OperationEnum getOperationEnum() {
        return OperationEnum.SEND_SMS_REPLY;
    }
    @lombok.Data
    public static class Data {
        private int draw;
        private int gold;
        private int silver;
        private int num;
        private int total_coin;
        private int effect;
        private int broadcast_id;
        private int crit_prob;
        private int guard_level;
        private long rcost;
        private long uid;
        private long timestamp;
        private int giftId;
        private int giftType;
        @JsonProperty("super")
        private int _super;
        private int super_gift_num;
        private int super_batch_gift_num;
        private int remain;
        private int discount_price;
        private int price;
        private String beatId;
        private String biz_source;
        private String action;
        private String coin_type;
        private String uname;
        private String face;
        private String batch_combo_id;
        private String rnd;
        private String giftName;
        private String original_gift_name;
        private Combo_send combo_send;
        private Batch_combo_send batch_combo_send;
        private String tag_image;
        private String top_list;
        private String send_master;
        private boolean is_first;
        private int demarcation;
        private int combo_stay_time;
        private int combo_total_coin;
        private String tid;
        private int effect_block;
        private int is_special_batch;
        private int combo_resources_id;
        private int magnification;
        private String name_color;
        private MedalInfo medal_info;
        private int svga_block;
        private JsonNode blind_gift;
        private int float_sc_resource_id;
        @JsonProperty("switch")
        private boolean _switch;
        private int face_effect_type;
        private int face_effect_id;
        private boolean is_naming;
        private Receive_user_info receive_user_info;
        private boolean is_join_receiver;
        private Bag_gift bag_gift;
        private int wealth_level;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Combo_send {
        private long uid;
        private int gift_num;
        private int combo_num;
        private int gift_id;
        private String combo_id;
        private String gift_name;
        private String action;
        private String uname;
        private String send_master;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Receive_user_info {
        private String uname;
        private long uid;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Batch_combo_send {
        private long uid;
        private int gift_num;
        private int batch_combo_num;
        private int gift_id;
        private String batch_combo_id;
        private String gift_name;
        private String action;
        private String uname;
        private String send_master;
        private JsonNode blind_gift;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Bag_gift {
        private int show_price;
        private int price_for_show;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/SendSmsReplyMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import tech.ordinaryroad.live.chat.client.bilibili.constant.OperationEnum;
import tech.ordinaryroad.live.chat.client.bilibili.msg.base.BaseBilibiliCmdMsg;
/**
 * @author mjz
 * @date 2023/1/6
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class SendSmsReplyMsg extends BaseBilibiliCmdMsg {
    private Long id;
    private String name;
    private JsonNode full;
    private JsonNode half;
    private JsonNode side;
    private JsonNode data;
    private JsonNode info;
    private JsonNode msg_common;
    private JsonNode msg_self;
    private JsonNode link_url;
    private JsonNode msg_type;
    private JsonNode shield_uid;
    private JsonNode business_id;
    private JsonNode scatter;
    private long roomid;
    private long real_roomid;
    @Override
    public OperationEnum getOperationEnum() {
        return OperationEnum.SEND_SMS_REPLY;
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/SuperChatMessageMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,202 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import tech.ordinaryroad.live.chat.client.bilibili.constant.OperationEnum;
import tech.ordinaryroad.live.chat.client.bilibili.msg.base.BaseBilibiliMsg;
import tech.ordinaryroad.live.chat.client.bilibili.msg.dto.MedalInfo;
import tech.ordinaryroad.live.chat.client.commons.base.msg.ISuperChatMsg;
import java.util.HashMap;
import java.util.Map;
/**
 * @author mjz
 * @date 2023/9/24
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class SuperChatMessageMsg extends BaseBilibiliMsg implements ISuperChatMsg {
    private long roomid;
    private Data data;
    @Override
    public OperationEnum getOperationEnum() {
        return OperationEnum.SEND_SMS_REPLY;
    }
    @Override
    public String getUid() {
        if (this.data == null) {
            return null;
        }
        return Long.toString(this.data.uid);
    }
    @Override
    public String getUsername() {
        if (this.data == null || this.data.getUser_info() == null) {
            return "";
        }
        return this.data.user_info.uname;
    }
    @Override
    public String getUserAvatar() {
        if (this.data == null || this.data.getUser_info() == null) {
            return "";
        }
        return this.data.user_info.face;
    }
    @Override
    public String getContent() {
        if (this.data == null) {
            return "";
        }
        return this.data.message;
    }
    @Override
    public int getDuration() {
        if (this.data == null) {
            return 0;
        }
        return this.data.time;
    }
    @lombok.Data
    public static class Data {
        private String background_bottom_color;
        private String background_color;
        private String background_color_end;
        private String background_color_start;
        private String background_icon;
        private String background_image;
        private String background_price_color;
        private double color_point;
        private int dmscore;
        private long end_time;
        private Gift gift;
        private long id;
        private int is_ranked;
        private int is_send_audit;
        private MedalInfo medal_info;
        private String message;
        private String message_font_color;
        private String message_trans;
        private int price;
        private int rate;
        private long start_time;
        private int time;
        private String token;
        private int trans_mark;
        private long ts;
        private long uid;
        private User_info user_info;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class Gift {
        private int gift_id;
        private String gift_name;
        private int num;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
    @lombok.Data
    public static class User_info {
        private String face;
        private String face_frame;
        private int guard_level;
        private int is_main_vip;
        private int is_svip;
        private int is_vip;
        private String level_color;
        private int manager;
        private String name_color;
        private String title;
        private String uname;
        private int user_level;
        /**
         * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
         */
        private final Map<String, JsonNode> unknownProperties = new HashMap<>();
        @JsonAnyGetter
        public Map<String, JsonNode> getUnknownProperties() {
            return unknownProperties;
        }
        @JsonAnySetter
        public void setOther(String key, JsonNode value) {
            this.unknownProperties.put(key, value);
        }
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/base/BaseBilibiliCmdMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg.base;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import tech.ordinaryroad.live.chat.client.bilibili.constant.BilibiliCmdEnum;
import tech.ordinaryroad.live.chat.client.bilibili.constant.ProtoverEnum;
import tech.ordinaryroad.live.chat.client.commons.base.msg.BaseCmdMsg;
/**
 * @author mjz
 * @date 2023/1/6
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public abstract class BaseBilibiliCmdMsg extends BaseCmdMsg<BilibiliCmdEnum> implements IBilibiliMsg {
    private int protover;
    private String cmd;
    @Override
    public String getCmd() {
        return this.cmd;
    }
    @Override
    public void setCmd(String cmd) {
        this.cmd = cmd;
    }
    @Override
    public BilibiliCmdEnum getCmdEnum() {
        return BilibiliCmdEnum.getByString(getCmd());
    }
    @Override
    public ProtoverEnum getProtoverEnum() {
        return ProtoverEnum.getByCode(this.protover);
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/base/BaseBilibiliMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg.base;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import tech.ordinaryroad.live.chat.client.bilibili.constant.ProtoverEnum;
import tech.ordinaryroad.live.chat.client.commons.base.msg.BaseMsg;
/**
 * @author mjz
 * @date 2023/1/6
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public abstract class BaseBilibiliMsg extends BaseMsg implements IBilibiliMsg {
    private int protover;
    @Override
    public ProtoverEnum getProtoverEnum() {
        return ProtoverEnum.getByCode(protover);
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/base/IBilibiliMsg.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg.base;
import com.fasterxml.jackson.annotation.JsonIgnore;
import tech.ordinaryroad.live.chat.client.bilibili.constant.OperationEnum;
import tech.ordinaryroad.live.chat.client.bilibili.constant.ProtoverEnum;
import tech.ordinaryroad.live.chat.client.commons.base.msg.IMsg;
/**
 * @author mjz
 * @date 2023/8/26
 */
public interface IBilibiliMsg extends IMsg {
    @JsonIgnore
    ProtoverEnum getProtoverEnum();
    @JsonIgnore
    OperationEnum getOperationEnum();
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/msg/dto/MedalInfo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.msg.dto;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class MedalInfo {
    private long target_id;
    private String special;
    private int icon_id;
    private String anchor_uname;
    private int anchor_roomid;
    private byte medal_level;
    private String medal_name;
    private String medal_color;
    private long medal_color_start;
    private long medal_color_end;
    private long medal_color_border;
    private int is_lighted;
    private int guard_level;
    /**
     * æœªçŸ¥å±žæ€§éƒ½æ”¾åœ¨è¿™
     */
    private final Map<String, JsonNode> unknownProperties = new HashMap<>();
    @JsonAnyGetter
    public Map<String, JsonNode> getUnknownProperties() {
        return unknownProperties;
    }
    @JsonAnySetter
    public void setOther(String key, JsonNode value) {
        this.unknownProperties.put(key, value);
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/netty/frame/AuthWebSocketFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.netty.frame;
import io.netty.buffer.ByteBuf;
import tech.ordinaryroad.live.chat.client.bilibili.netty.frame.base.BaseBilibiliWebSocketFrame;
/**
 * @author mjz
 * @date 2023/1/5
 */
public class AuthWebSocketFrame extends BaseBilibiliWebSocketFrame {
    public AuthWebSocketFrame(ByteBuf byteBuf) {
        super(byteBuf);
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/netty/frame/HeartbeatWebSocketFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.netty.frame;
import io.netty.buffer.ByteBuf;
import tech.ordinaryroad.live.chat.client.bilibili.netty.frame.base.BaseBilibiliWebSocketFrame;
/**
 * @author mjz
 * @date 2023/1/5
 */
public class HeartbeatWebSocketFrame extends BaseBilibiliWebSocketFrame {
    public HeartbeatWebSocketFrame(ByteBuf byteBuf) {
        super(byteBuf);
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/netty/frame/base/BaseBilibiliWebSocketFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.netty.frame.base;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import tech.ordinaryroad.live.chat.client.bilibili.constant.OperationEnum;
import tech.ordinaryroad.live.chat.client.bilibili.constant.ProtoverEnum;
/**
 * å®žçްBilibili协议的BinaryWebSocketFrame
 * <a href="https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/live/message_stream.md#数据包格式">数据包格式</a>
 *
 * @author mjz
 * @date 2023/1/5
 */
public abstract class BaseBilibiliWebSocketFrame extends BinaryWebSocketFrame {
    public static int sequence = 0;
    public ProtoverEnum getProtoverEnum() {
        return ProtoverEnum.getByCode(super.content().getShort(6));
    }
    public OperationEnum getOperationEnum() {
        return OperationEnum.getByCode(super.content().getInt(8));
    }
    public BaseBilibiliWebSocketFrame(ByteBuf byteBuf) {
        super(byteBuf);
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/netty/frame/factory/BilibiliWebSocketFrameFactory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,113 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.netty.frame.factory;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.NumberUtil;
import com.fasterxml.jackson.databind.JsonNode;
import tech.ordinaryroad.live.chat.client.bilibili.api.BilibiliApis;
import tech.ordinaryroad.live.chat.client.bilibili.constant.ProtoverEnum;
import tech.ordinaryroad.live.chat.client.bilibili.msg.AuthMsg;
import tech.ordinaryroad.live.chat.client.bilibili.msg.HeartbeatMsg;
import tech.ordinaryroad.live.chat.client.bilibili.netty.frame.AuthWebSocketFrame;
import tech.ordinaryroad.live.chat.client.bilibili.netty.frame.HeartbeatWebSocketFrame;
import tech.ordinaryroad.live.chat.client.bilibili.util.BilibiliCodecUtil;
import tech.ordinaryroad.live.chat.client.commons.base.exception.BaseException;
import tech.ordinaryroad.live.chat.client.commons.util.OrLiveChatCookieUtil;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * @author mjz
 * @date 2023/1/5
 */
public class BilibiliWebSocketFrameFactory {
    private static final ConcurrentHashMap<Long, BilibiliWebSocketFrameFactory> CACHE = new ConcurrentHashMap<>();
    /**
     * æµè§ˆå™¨åœ°å€ä¸­çš„æˆ¿é—´id,支持短id
     */
    private final long roomId;
    private volatile static HeartbeatMsg heartbeatMsg;
    public BilibiliWebSocketFrameFactory(long roomId) {
        this.roomId = roomId;
    }
    public synchronized static BilibiliWebSocketFrameFactory getInstance(long roomId) {
        return CACHE.computeIfAbsent(roomId, aLong -> new BilibiliWebSocketFrameFactory(roomId));
    }
    /**
     * åˆ›å»ºè®¤è¯åŒ…
     *
     * @param protover {@link ProtoverEnum}
     * @param cookie   æµè§ˆå™¨cookie,仅用来维持登录状态
     * @return AuthWebSocketFrame
     */
    public AuthWebSocketFrame createAuth(ProtoverEnum protover, String cookie) {
        try {
            Map<String, String> cookieMap = OrLiveChatCookieUtil.parseCookieString(cookie);
            String buvid3 = OrLiveChatCookieUtil.getCookieByName(cookieMap, "buvid3", () -> UUID.randomUUID().toString());
            String uid = OrLiveChatCookieUtil.getCookieByName(cookieMap, "DedeUserID", () -> "0");
            BilibiliApis.RoomInitResult data = BilibiliApis.roomInit(roomId, cookie);
            JsonNode danmuInfo = BilibiliApis.getDanmuInfo(roomId, 0, cookie);
            long realRoomId = data.getRoom_id();
            AuthMsg authMsg = new AuthMsg(realRoomId, protover.getCode(), buvid3, danmuInfo.get("token").asText());
            authMsg.setUid(NumberUtil.parseLong(uid));
            return new AuthWebSocketFrame(BilibiliCodecUtil.encode(authMsg));
        } catch (Exception e) {
            throw new BaseException(String.format("认证包创建失败,请检查房间号是否正确。roomId: %d, msg: %s", roomId, e.getMessage()));
        }
    }
    public AuthWebSocketFrame createAuth(ProtoverEnum protover) {
        return this.createAuth(protover, null);
    }
    public HeartbeatWebSocketFrame createHeartbeat(ProtoverEnum protover) {
        return new HeartbeatWebSocketFrame(BilibiliCodecUtil.encode(this.getHeartbeatMsg(protover)));
    }
    /**
     * å¿ƒè·³åŒ…单例模式
     *
     * @param protover {@link ProtoverEnum}
     * @return HeartbeatWebSocketFrame
     */
    public HeartbeatMsg getHeartbeatMsg(ProtoverEnum protover) {
        if (heartbeatMsg == null) {
            synchronized (BilibiliWebSocketFrameFactory.this) {
                if (heartbeatMsg == null) {
                    heartbeatMsg = new HeartbeatMsg(protover.getCode());
                }
            }
        }
        return heartbeatMsg;
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/netty/handler/BilibiliBinaryFrameHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,153 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.netty.handler;
import cn.hutool.core.util.StrUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import tech.ordinaryroad.live.chat.client.bilibili.client.BilibiliLiveChatClient;
import tech.ordinaryroad.live.chat.client.bilibili.constant.BilibiliCmdEnum;
import tech.ordinaryroad.live.chat.client.bilibili.listener.IBilibiliMsgListener;
import tech.ordinaryroad.live.chat.client.bilibili.msg.*;
import tech.ordinaryroad.live.chat.client.bilibili.msg.base.BaseBilibiliMsg;
import tech.ordinaryroad.live.chat.client.bilibili.msg.base.IBilibiliMsg;
import tech.ordinaryroad.live.chat.client.bilibili.util.BilibiliCodecUtil;
import tech.ordinaryroad.live.chat.client.commons.base.msg.ICmdMsg;
import tech.ordinaryroad.live.chat.client.servers.netty.client.handler.BaseNettyClientBinaryFrameHandler;
import java.util.List;
/**
 * æ¶ˆæ¯å¤„理器
 *
 * @author mjz
 * @date 2023/1/4
 */
@Slf4j
@ChannelHandler.Sharable
public class BilibiliBinaryFrameHandler extends BaseNettyClientBinaryFrameHandler<BilibiliLiveChatClient, BilibiliBinaryFrameHandler, BilibiliCmdEnum, IBilibiliMsg, IBilibiliMsgListener> {
    public BilibiliBinaryFrameHandler(List<IBilibiliMsgListener> msgListeners, BilibiliLiveChatClient client) {
        super(msgListeners, client);
    }
    public BilibiliBinaryFrameHandler(List<IBilibiliMsgListener> msgListeners, long roomId) {
        super(msgListeners, roomId);
    }
    @SneakyThrows
    @Override
    public void onCmdMsg(BilibiliCmdEnum cmd, ICmdMsg<BilibiliCmdEnum> cmdMsg) {
        if (super.msgListeners.isEmpty()) {
            return;
        }
        SendSmsReplyMsg sendSmsReplyMsg = (SendSmsReplyMsg) cmdMsg;
        switch (cmd) {
            case DANMU_MSG: {
                DanmuMsgMsg danmuMsgMsg = new DanmuMsgMsg();
                danmuMsgMsg.setProtover(sendSmsReplyMsg.getProtover());
                danmuMsgMsg.setInfo(sendSmsReplyMsg.getInfo());
                danmuMsgMsg.setDm_v2(StrUtil.toStringOrNull(sendSmsReplyMsg.getUnknownProperties().get("dm_v2")));
                iteratorMsgListeners(msgListener -> msgListener.onDanmuMsg(BilibiliBinaryFrameHandler.this, danmuMsgMsg));
                break;
            }
            case SEND_GIFT: {
                SendGiftMsg sendGiftMsg = new SendGiftMsg();
                sendGiftMsg.setRoomId(getRoomIdAsLong());
                sendGiftMsg.setProtover(sendSmsReplyMsg.getProtover());
                SendGiftMsg.Data data = BaseBilibiliMsg.OBJECT_MAPPER.treeToValue(sendSmsReplyMsg.getData(), SendGiftMsg.Data.class);
                sendGiftMsg.setData(data);
                iteratorMsgListeners(msgListener -> {
                    msgListener.onGiftMsg(BilibiliBinaryFrameHandler.this, sendGiftMsg);
                    msgListener.onSendGift(BilibiliBinaryFrameHandler.this, sendSmsReplyMsg);
                });
                break;
            }
            case SUPER_CHAT_MESSAGE: {
                SuperChatMessageMsg superChatMessageMsg = new SuperChatMessageMsg();
                superChatMessageMsg.setProtover(sendSmsReplyMsg.getProtover());
                superChatMessageMsg.setRoomid(sendSmsReplyMsg.getRoomid());
                SuperChatMessageMsg.Data data = BaseBilibiliMsg.OBJECT_MAPPER.treeToValue(sendSmsReplyMsg.getData(), SuperChatMessageMsg.Data.class);
                superChatMessageMsg.setData(data);
                iteratorMsgListeners(msgListener -> msgListener.onSuperChatMsg(BilibiliBinaryFrameHandler.this, superChatMessageMsg));
                break;
            }
            case INTERACT_WORD: {
                InteractWordMsg interactWordMsg = new InteractWordMsg();
                interactWordMsg.setProtover(sendSmsReplyMsg.getProtover());
                InteractWordMsg.Data data = BaseBilibiliMsg.OBJECT_MAPPER.treeToValue(sendSmsReplyMsg.getData(), InteractWordMsg.Data.class);
                interactWordMsg.setData(data);
                iteratorMsgListeners(msgListener -> {
                    msgListener.onEnterRoomMsg(BilibiliBinaryFrameHandler.this, interactWordMsg);
                    msgListener.onEnterRoom(BilibiliBinaryFrameHandler.this, sendSmsReplyMsg);
                });
                break;
            }
            case ENTRY_EFFECT: {
                iteratorMsgListeners(msgListener -> msgListener.onEntryEffect(BilibiliBinaryFrameHandler.this, sendSmsReplyMsg));
                break;
            }
            case WATCHED_CHANGE: {
                iteratorMsgListeners(msgListener -> msgListener.onWatchedChange(BilibiliBinaryFrameHandler.this, sendSmsReplyMsg));
                break;
            }
            case LIKE_INFO_V3_CLICK: {
                LikeInfoV3ClickMsg likeInfoV3ClickMsg = new LikeInfoV3ClickMsg();
                likeInfoV3ClickMsg.setProtover(sendSmsReplyMsg.getProtover());
                LikeInfoV3ClickMsg.Data data = BaseBilibiliMsg.OBJECT_MAPPER.treeToValue(sendSmsReplyMsg.getData(), LikeInfoV3ClickMsg.Data.class);
                likeInfoV3ClickMsg.setData(data);
                iteratorMsgListeners(msgListener -> {
                    msgListener.onLikeMsg(BilibiliBinaryFrameHandler.this, likeInfoV3ClickMsg);
                    msgListener.onClickLike(BilibiliBinaryFrameHandler.this, sendSmsReplyMsg);
                });
                break;
            }
            case LIKE_INFO_V3_UPDATE: {
                iteratorMsgListeners(msgListener -> msgListener.onClickUpdate(BilibiliBinaryFrameHandler.this, sendSmsReplyMsg));
                break;
            }
            default: {
                iteratorMsgListeners(msgListener -> msgListener.onOtherCmdMsg(BilibiliBinaryFrameHandler.this, cmd, cmdMsg));
            }
        }
    }
    @Override
    protected List<IBilibiliMsg> decode(ByteBuf byteBuf) {
        return BilibiliCodecUtil.decode(byteBuf);
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/netty/handler/BilibiliConnectionHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,154 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package tech.ordinaryroad.live.chat.client.bilibili.netty.handler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import lombok.extern.slf4j.Slf4j;
import tech.ordinaryroad.live.chat.client.bilibili.client.BilibiliLiveChatClient;
import tech.ordinaryroad.live.chat.client.bilibili.config.BilibiliLiveChatClientConfig;
import tech.ordinaryroad.live.chat.client.bilibili.constant.ProtoverEnum;
import tech.ordinaryroad.live.chat.client.bilibili.netty.frame.factory.BilibiliWebSocketFrameFactory;
import tech.ordinaryroad.live.chat.client.commons.base.listener.IBaseConnectionListener;
import tech.ordinaryroad.live.chat.client.servers.netty.client.handler.BaseNettyClientConnectionHandler;
/**
 * è¿žæŽ¥å¤„理器
 *
 * @author mjz
 * @date 2023/8/21
 */
@Slf4j
@ChannelHandler.Sharable
public class BilibiliConnectionHandler extends BaseNettyClientConnectionHandler<BilibiliLiveChatClient, BilibiliConnectionHandler> {
    /**
     * ä»¥ClientConfig为主
     */
    private final long roomId;
    /**
     * ä»¥ClientConfig为主
     */
    private final ProtoverEnum protover;
    /**
     * ä»¥ClientConfig为主
     */
    private String cookie;
    public BilibiliConnectionHandler(WebSocketClientHandshaker handshaker, BilibiliLiveChatClient client, IBaseConnectionListener<BilibiliConnectionHandler> listener) {
        super(handshaker, client, listener);
        this.roomId = client.getConfig().getRoomId();
        this.protover = client.getConfig().getProtover();
        this.cookie = client.getConfig().getCookie();
    }
    public BilibiliConnectionHandler(WebSocketClientHandshaker handshaker, BilibiliLiveChatClient client) {
        this(handshaker, client, null);
    }
    public BilibiliConnectionHandler(WebSocketClientHandshaker handshaker, long roomId, ProtoverEnum protover, IBaseConnectionListener<BilibiliConnectionHandler> listener, String cookie) {
        super(handshaker, listener);
        this.roomId = roomId;
        this.protover = protover;
        this.cookie = cookie;
    }
    public BilibiliConnectionHandler(WebSocketClientHandshaker handshaker, long roomId, ProtoverEnum protover, IBaseConnectionListener<BilibiliConnectionHandler> listener) {
        this(handshaker, roomId, protover, listener, null);
    }
    public BilibiliConnectionHandler(WebSocketClientHandshaker handshaker, long roomId, ProtoverEnum protover, String cookie) {
        this(handshaker, roomId, protover, null, cookie);
    }
    public BilibiliConnectionHandler(WebSocketClientHandshaker handshaker, long roomId, ProtoverEnum protover) {
        this(handshaker, roomId, protover, null, null);
    }
    @Override
    protected void sendHeartbeat(ChannelHandlerContext ctx) {
        if (log.isDebugEnabled()) {
            log.debug("发送心跳包");
        }
        ctx.writeAndFlush(
                getWebSocketFrameFactory(getRoomId()).createHeartbeat(getProtover())
        ).addListener((ChannelFutureListener) future -> {
            if (future.isSuccess()) {
                if (log.isDebugEnabled()) {
                    log.debug("心跳包发送完成");
                }
            } else {
                log.error("心跳包发送失败", future.cause());
            }
        });
    }
    private static BilibiliWebSocketFrameFactory getWebSocketFrameFactory(long roomId) {
        return BilibiliWebSocketFrameFactory.getInstance(roomId);
    }
    @Override
    public void sendAuthRequest(Channel channel) {
        // 5s内认证
        if (log.isDebugEnabled()) {
            log.debug("发送认证包");
        }
        channel.writeAndFlush(getWebSocketFrameFactory(getRoomId()).createAuth(getProtover(), getCookie()));
    }
    public long getRoomId() {
        return client != null ? client.getConfig().getRoomId() : roomId;
    }
    private ProtoverEnum getProtover() {
        return client != null ? client.getConfig().getProtover() : protover;
    }
    private String getCookie() {
        return client != null ? client.getConfig().getCookie() : cookie;
    }
    @Override
    protected long getHeartbeatPeriod() {
        if (client == null) {
            return BilibiliLiveChatClientConfig.DEFAULT_HEARTBEAT_PERIOD;
        } else {
            return client.getConfig().getHeartbeatPeriod();
        }
    }
    @Override
    protected long getHeartbeatInitialDelay() {
        if (client == null) {
            return BilibiliLiveChatClientConfig.DEFAULT_HEARTBEAT_INITIAL_DELAY;
        } else {
            return client.getConfig().getHeartbeatInitialDelay();
        }
    }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/protobuf/Dm_v2Proto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,78 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
// Generated by the protocol buffer compiler.  DO NOT EDIT!
// source: dm_v2.proto
package tech.ordinaryroad.live.chat.client.bilibili.protobuf;
public final class Dm_v2Proto {
  private Dm_v2Proto() {}
  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistryLite registry) {
  }
  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistry registry) {
    registerAllExtensions(
        (com.google.protobuf.ExtensionRegistryLite) registry);
  }
  static final com.google.protobuf.Descriptors.Descriptor
    internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_descriptor;
  static final
    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
      internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_fieldAccessorTable;
  public static com.google.protobuf.Descriptors.FileDescriptor
      getDescriptor() {
    return descriptor;
  }
  private static  com.google.protobuf.Descriptors.FileDescriptor
      descriptor;
  static {
    String[] descriptorData = {
      "\n\013dm_v2.proto\0224tech.ordinaryroad.live.ch" +
      "at.client.bilibili.protobuf\032\016dm_v2_20.pr" +
      "oto\"Y\n\005dm_v2\022P\n\010dm_v2_20\030\024 \001(\0132>.tech.or" +
      "dinaryroad.live.chat.client.bilibili.pro" +
      "tobuf.dm_v2_20BJ\n4tech.ordinaryroad.live" +
      ".chat.client.bilibili.protobufB\nDm_v2Pro" +
      "toP\001\242\002\003GPBb\006proto3"
    };
    descriptor = com.google.protobuf.Descriptors.FileDescriptor
      .internalBuildGeneratedFileFrom(descriptorData,
        new com.google.protobuf.Descriptors.FileDescriptor[] {
          Dm_v2_20Proto.getDescriptor(),
        });
    internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_descriptor =
      getDescriptor().getMessageTypes().get(0);
    internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_fieldAccessorTable = new
      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
        internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_descriptor,
        new String[] { "DmV220", });
    Dm_v2_20Proto.getDescriptor();
  }
  // @@protoc_insertion_point(outer_class_scope)
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/protobuf/Dm_v2_20Proto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
// Generated by the protocol buffer compiler.  DO NOT EDIT!
// source: dm_v2_20.proto
package tech.ordinaryroad.live.chat.client.bilibili.protobuf;
public final class Dm_v2_20Proto {
  private Dm_v2_20Proto() {}
  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistryLite registry) {
  }
  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistry registry) {
    registerAllExtensions(
        (com.google.protobuf.ExtensionRegistryLite) registry);
  }
  static final com.google.protobuf.Descriptors.Descriptor
    internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_20_descriptor;
  static final
    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
      internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_20_fieldAccessorTable;
  public static com.google.protobuf.Descriptors.FileDescriptor
      getDescriptor() {
    return descriptor;
  }
  private static  com.google.protobuf.Descriptors.FileDescriptor
      descriptor;
  static {
    String[] descriptorData = {
      "\n\016dm_v2_20.proto\0224tech.ordinaryroad.live" +
      ".chat.client.bilibili.protobuf\"\032\n\010dm_v2_" +
      "20\022\016\n\006avatar\030\004 \001(\tBM\n4tech.ordinaryroad." +
      "live.chat.client.bilibili.protobufB\rDm_v" +
      "2_20ProtoP\001\242\002\003GPBb\006proto3"
    };
    descriptor = com.google.protobuf.Descriptors.FileDescriptor
      .internalBuildGeneratedFileFrom(descriptorData,
        new com.google.protobuf.Descriptors.FileDescriptor[] {
        });
    internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_20_descriptor =
      getDescriptor().getMessageTypes().get(0);
    internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_20_fieldAccessorTable = new
      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
        internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_20_descriptor,
        new String[] { "Avatar", });
  }
  // @@protoc_insertion_point(outer_class_scope)
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/protobuf/dm_v2.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,610 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
// Generated by the protocol buffer compiler.  DO NOT EDIT!
// source: dm_v2.proto
package tech.ordinaryroad.live.chat.client.bilibili.protobuf;
/**
 * Protobuf type {@code tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2}
 */
public final class dm_v2 extends
    com.google.protobuf.GeneratedMessageV3 implements
    // @@protoc_insertion_point(message_implements:tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2)
    dm_v2OrBuilder {
private static final long serialVersionUID = 0L;
  // Use dm_v2.newBuilder() to construct.
  private dm_v2(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
    super(builder);
  }
  private dm_v2() {
  }
  @Override
  @SuppressWarnings({"unused"})
  protected Object newInstance(
      UnusedPrivateParameter unused) {
    return new dm_v2();
  }
  public static final com.google.protobuf.Descriptors.Descriptor
      getDescriptor() {
    return Dm_v2Proto.internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_descriptor;
  }
  @Override
  protected FieldAccessorTable
      internalGetFieldAccessorTable() {
    return Dm_v2Proto.internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_fieldAccessorTable
        .ensureFieldAccessorsInitialized(
            dm_v2.class, Builder.class);
  }
  public static final int DM_V2_20_FIELD_NUMBER = 20;
  private dm_v2_20 dmV220_;
  /**
   * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
   * @return Whether the dmV220 field is set.
   */
  @Override
  public boolean hasDmV220() {
    return dmV220_ != null;
  }
  /**
   * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
   * @return The dmV220.
   */
  @Override
  public dm_v2_20 getDmV220() {
    return dmV220_ == null ? dm_v2_20.getDefaultInstance() : dmV220_;
  }
  /**
   * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
   */
  @Override
  public dm_v2_20OrBuilder getDmV220OrBuilder() {
    return dmV220_ == null ? dm_v2_20.getDefaultInstance() : dmV220_;
  }
  private byte memoizedIsInitialized = -1;
  @Override
  public final boolean isInitialized() {
    byte isInitialized = memoizedIsInitialized;
    if (isInitialized == 1) return true;
    if (isInitialized == 0) return false;
    memoizedIsInitialized = 1;
    return true;
  }
  @Override
  public void writeTo(com.google.protobuf.CodedOutputStream output)
                      throws java.io.IOException {
    if (dmV220_ != null) {
      output.writeMessage(20, getDmV220());
    }
    getUnknownFields().writeTo(output);
  }
  @Override
  public int getSerializedSize() {
    int size = memoizedSize;
    if (size != -1) return size;
    size = 0;
    if (dmV220_ != null) {
      size += com.google.protobuf.CodedOutputStream
        .computeMessageSize(20, getDmV220());
    }
    size += getUnknownFields().getSerializedSize();
    memoizedSize = size;
    return size;
  }
  @Override
  public boolean equals(final Object obj) {
    if (obj == this) {
     return true;
    }
    if (!(obj instanceof dm_v2)) {
      return super.equals(obj);
    }
    dm_v2 other = (dm_v2) obj;
    if (hasDmV220() != other.hasDmV220()) return false;
    if (hasDmV220()) {
      if (!getDmV220()
          .equals(other.getDmV220())) return false;
    }
    if (!getUnknownFields().equals(other.getUnknownFields())) return false;
    return true;
  }
  @Override
  public int hashCode() {
    if (memoizedHashCode != 0) {
      return memoizedHashCode;
    }
    int hash = 41;
    hash = (19 * hash) + getDescriptor().hashCode();
    if (hasDmV220()) {
      hash = (37 * hash) + DM_V2_20_FIELD_NUMBER;
      hash = (53 * hash) + getDmV220().hashCode();
    }
    hash = (29 * hash) + getUnknownFields().hashCode();
    memoizedHashCode = hash;
    return hash;
  }
  public static dm_v2 parseFrom(
      java.nio.ByteBuffer data)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data);
  }
  public static dm_v2 parseFrom(
      java.nio.ByteBuffer data,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data, extensionRegistry);
  }
  public static dm_v2 parseFrom(
      com.google.protobuf.ByteString data)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data);
  }
  public static dm_v2 parseFrom(
      com.google.protobuf.ByteString data,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data, extensionRegistry);
  }
  public static dm_v2 parseFrom(byte[] data)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data);
  }
  public static dm_v2 parseFrom(
      byte[] data,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data, extensionRegistry);
  }
  public static dm_v2 parseFrom(java.io.InputStream input)
      throws java.io.IOException {
    return com.google.protobuf.GeneratedMessageV3
        .parseWithIOException(PARSER, input);
  }
  public static dm_v2 parseFrom(
      java.io.InputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
    return com.google.protobuf.GeneratedMessageV3
        .parseWithIOException(PARSER, input, extensionRegistry);
  }
  public static dm_v2 parseDelimitedFrom(java.io.InputStream input)
      throws java.io.IOException {
    return com.google.protobuf.GeneratedMessageV3
        .parseDelimitedWithIOException(PARSER, input);
  }
  public static dm_v2 parseDelimitedFrom(
      java.io.InputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
    return com.google.protobuf.GeneratedMessageV3
        .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
  }
  public static dm_v2 parseFrom(
      com.google.protobuf.CodedInputStream input)
      throws java.io.IOException {
    return com.google.protobuf.GeneratedMessageV3
        .parseWithIOException(PARSER, input);
  }
  public static dm_v2 parseFrom(
      com.google.protobuf.CodedInputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
    return com.google.protobuf.GeneratedMessageV3
        .parseWithIOException(PARSER, input, extensionRegistry);
  }
  @Override
  public Builder newBuilderForType() { return newBuilder(); }
  public static Builder newBuilder() {
    return DEFAULT_INSTANCE.toBuilder();
  }
  public static Builder newBuilder(dm_v2 prototype) {
    return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
  }
  @Override
  public Builder toBuilder() {
    return this == DEFAULT_INSTANCE
        ? new Builder() : new Builder().mergeFrom(this);
  }
  @Override
  protected Builder newBuilderForType(
      BuilderParent parent) {
    Builder builder = new Builder(parent);
    return builder;
  }
  /**
   * Protobuf type {@code tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2}
   */
  public static final class Builder extends
      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
      // @@protoc_insertion_point(builder_implements:tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2)
      dm_v2OrBuilder {
    public static final com.google.protobuf.Descriptors.Descriptor
        getDescriptor() {
      return Dm_v2Proto.internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_descriptor;
    }
    @Override
    protected FieldAccessorTable
        internalGetFieldAccessorTable() {
      return Dm_v2Proto.internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_fieldAccessorTable
          .ensureFieldAccessorsInitialized(
              dm_v2.class, Builder.class);
    }
    // Construct using tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2.newBuilder()
    private Builder() {
    }
    private Builder(
        BuilderParent parent) {
      super(parent);
    }
    @Override
    public Builder clear() {
      super.clear();
      bitField0_ = 0;
      dmV220_ = null;
      if (dmV220Builder_ != null) {
        dmV220Builder_.dispose();
        dmV220Builder_ = null;
      }
      return this;
    }
    @Override
    public com.google.protobuf.Descriptors.Descriptor
        getDescriptorForType() {
      return Dm_v2Proto.internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_descriptor;
    }
    @Override
    public dm_v2 getDefaultInstanceForType() {
      return dm_v2.getDefaultInstance();
    }
    @Override
    public dm_v2 build() {
      dm_v2 result = buildPartial();
      if (!result.isInitialized()) {
        throw newUninitializedMessageException(result);
      }
      return result;
    }
    @Override
    public dm_v2 buildPartial() {
      dm_v2 result = new dm_v2(this);
      if (bitField0_ != 0) { buildPartial0(result); }
      onBuilt();
      return result;
    }
    private void buildPartial0(dm_v2 result) {
      int from_bitField0_ = bitField0_;
      if (((from_bitField0_ & 0x00000001) != 0)) {
        result.dmV220_ = dmV220Builder_ == null
            ? dmV220_
            : dmV220Builder_.build();
      }
    }
    @Override
    public Builder clone() {
      return super.clone();
    }
    @Override
    public Builder setField(
        com.google.protobuf.Descriptors.FieldDescriptor field,
        Object value) {
      return super.setField(field, value);
    }
    @Override
    public Builder clearField(
        com.google.protobuf.Descriptors.FieldDescriptor field) {
      return super.clearField(field);
    }
    @Override
    public Builder clearOneof(
        com.google.protobuf.Descriptors.OneofDescriptor oneof) {
      return super.clearOneof(oneof);
    }
    @Override
    public Builder setRepeatedField(
        com.google.protobuf.Descriptors.FieldDescriptor field,
        int index, Object value) {
      return super.setRepeatedField(field, index, value);
    }
    @Override
    public Builder addRepeatedField(
        com.google.protobuf.Descriptors.FieldDescriptor field,
        Object value) {
      return super.addRepeatedField(field, value);
    }
    @Override
    public Builder mergeFrom(com.google.protobuf.Message other) {
      if (other instanceof dm_v2) {
        return mergeFrom((dm_v2)other);
      } else {
        super.mergeFrom(other);
        return this;
      }
    }
    public Builder mergeFrom(dm_v2 other) {
      if (other == dm_v2.getDefaultInstance()) return this;
      if (other.hasDmV220()) {
        mergeDmV220(other.getDmV220());
      }
      this.mergeUnknownFields(other.getUnknownFields());
      onChanged();
      return this;
    }
    @Override
    public final boolean isInitialized() {
      return true;
    }
    @Override
    public Builder mergeFrom(
        com.google.protobuf.CodedInputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws java.io.IOException {
      if (extensionRegistry == null) {
        throw new NullPointerException();
      }
      try {
        boolean done = false;
        while (!done) {
          int tag = input.readTag();
          switch (tag) {
            case 0:
              done = true;
              break;
            case 162: {
              input.readMessage(
                  getDmV220FieldBuilder().getBuilder(),
                  extensionRegistry);
              bitField0_ |= 0x00000001;
              break;
            } // case 162
            default: {
              if (!super.parseUnknownField(input, extensionRegistry, tag)) {
                done = true; // was an endgroup tag
              }
              break;
            } // default:
          } // switch (tag)
        } // while (!done)
      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
        throw e.unwrapIOException();
      } finally {
        onChanged();
      } // finally
      return this;
    }
    private int bitField0_;
    private dm_v2_20 dmV220_;
    private com.google.protobuf.SingleFieldBuilderV3<
        dm_v2_20, dm_v2_20.Builder, dm_v2_20OrBuilder> dmV220Builder_;
    /**
     * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
     * @return Whether the dmV220 field is set.
     */
    public boolean hasDmV220() {
      return ((bitField0_ & 0x00000001) != 0);
    }
    /**
     * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
     * @return The dmV220.
     */
    public dm_v2_20 getDmV220() {
      if (dmV220Builder_ == null) {
        return dmV220_ == null ? dm_v2_20.getDefaultInstance() : dmV220_;
      } else {
        return dmV220Builder_.getMessage();
      }
    }
    /**
     * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
     */
    public Builder setDmV220(dm_v2_20 value) {
      if (dmV220Builder_ == null) {
        if (value == null) {
          throw new NullPointerException();
        }
        dmV220_ = value;
      } else {
        dmV220Builder_.setMessage(value);
      }
      bitField0_ |= 0x00000001;
      onChanged();
      return this;
    }
    /**
     * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
     */
    public Builder setDmV220(
        dm_v2_20.Builder builderForValue) {
      if (dmV220Builder_ == null) {
        dmV220_ = builderForValue.build();
      } else {
        dmV220Builder_.setMessage(builderForValue.build());
      }
      bitField0_ |= 0x00000001;
      onChanged();
      return this;
    }
    /**
     * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
     */
    public Builder mergeDmV220(dm_v2_20 value) {
      if (dmV220Builder_ == null) {
        if (((bitField0_ & 0x00000001) != 0) &&
          dmV220_ != null &&
          dmV220_ != dm_v2_20.getDefaultInstance()) {
          getDmV220Builder().mergeFrom(value);
        } else {
          dmV220_ = value;
        }
      } else {
        dmV220Builder_.mergeFrom(value);
      }
      bitField0_ |= 0x00000001;
      onChanged();
      return this;
    }
    /**
     * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
     */
    public Builder clearDmV220() {
      bitField0_ = (bitField0_ & ~0x00000001);
      dmV220_ = null;
      if (dmV220Builder_ != null) {
        dmV220Builder_.dispose();
        dmV220Builder_ = null;
      }
      onChanged();
      return this;
    }
    /**
     * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
     */
    public dm_v2_20.Builder getDmV220Builder() {
      bitField0_ |= 0x00000001;
      onChanged();
      return getDmV220FieldBuilder().getBuilder();
    }
    /**
     * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
     */
    public dm_v2_20OrBuilder getDmV220OrBuilder() {
      if (dmV220Builder_ != null) {
        return dmV220Builder_.getMessageOrBuilder();
      } else {
        return dmV220_ == null ?
            dm_v2_20.getDefaultInstance() : dmV220_;
      }
    }
    /**
     * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
     */
    private com.google.protobuf.SingleFieldBuilderV3<
        dm_v2_20, dm_v2_20.Builder, dm_v2_20OrBuilder>
        getDmV220FieldBuilder() {
      if (dmV220Builder_ == null) {
        dmV220Builder_ = new com.google.protobuf.SingleFieldBuilderV3<
            dm_v2_20, dm_v2_20.Builder, dm_v2_20OrBuilder>(
                getDmV220(),
                getParentForChildren(),
                isClean());
        dmV220_ = null;
      }
      return dmV220Builder_;
    }
    @Override
    public final Builder setUnknownFields(
        final com.google.protobuf.UnknownFieldSet unknownFields) {
      return super.setUnknownFields(unknownFields);
    }
    @Override
    public final Builder mergeUnknownFields(
        final com.google.protobuf.UnknownFieldSet unknownFields) {
      return super.mergeUnknownFields(unknownFields);
    }
    // @@protoc_insertion_point(builder_scope:tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2)
  }
  // @@protoc_insertion_point(class_scope:tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2)
  private static final dm_v2 DEFAULT_INSTANCE;
  static {
    DEFAULT_INSTANCE = new dm_v2();
  }
  public static dm_v2 getDefaultInstance() {
    return DEFAULT_INSTANCE;
  }
  private static final com.google.protobuf.Parser<dm_v2>
      PARSER = new com.google.protobuf.AbstractParser<dm_v2>() {
    @Override
    public dm_v2 parsePartialFrom(
        com.google.protobuf.CodedInputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      Builder builder = newBuilder();
      try {
        builder.mergeFrom(input, extensionRegistry);
      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
        throw e.setUnfinishedMessage(builder.buildPartial());
      } catch (com.google.protobuf.UninitializedMessageException e) {
        throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());
      } catch (java.io.IOException e) {
        throw new com.google.protobuf.InvalidProtocolBufferException(e)
            .setUnfinishedMessage(builder.buildPartial());
      }
      return builder.buildPartial();
    }
  };
  public static com.google.protobuf.Parser<dm_v2> parser() {
    return PARSER;
  }
  @Override
  public com.google.protobuf.Parser<dm_v2> getParserForType() {
    return PARSER;
  }
  @Override
  public dm_v2 getDefaultInstanceForType() {
    return DEFAULT_INSTANCE;
  }
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/protobuf/dm_v2OrBuilder.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
// Generated by the protocol buffer compiler.  DO NOT EDIT!
// source: dm_v2.proto
package tech.ordinaryroad.live.chat.client.bilibili.protobuf;
public interface dm_v2OrBuilder extends
    // @@protoc_insertion_point(interface_extends:tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2)
    com.google.protobuf.MessageOrBuilder {
  /**
   * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
   * @return Whether the dmV220 field is set.
   */
  boolean hasDmV220();
  /**
   * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
   * @return The dmV220.
   */
  dm_v2_20 getDmV220();
  /**
   * <code>.tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20 dm_v2_20 = 20;</code>
   */
  dm_v2_20OrBuilder getDmV220OrBuilder();
}
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/protobuf/dm_v2_20.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,565 @@
/*
 * MIT License
 *
 * Copyright (c) 2023 OrdinaryRoad
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
// Generated by the protocol buffer compiler.  DO NOT EDIT!
// source: dm_v2_20.proto
package tech.ordinaryroad.live.chat.client.bilibili.protobuf;
/**
 * Protobuf type {@code tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20}
 */
public final class dm_v2_20 extends
    com.google.protobuf.GeneratedMessageV3 implements
    // @@protoc_insertion_point(message_implements:tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20)
    dm_v2_20OrBuilder {
private static final long serialVersionUID = 0L;
  // Use dm_v2_20.newBuilder() to construct.
  private dm_v2_20(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
    super(builder);
  }
  private dm_v2_20() {
    avatar_ = "";
  }
  @Override
  @SuppressWarnings({"unused"})
  protected Object newInstance(
      UnusedPrivateParameter unused) {
    return new dm_v2_20();
  }
  public static final com.google.protobuf.Descriptors.Descriptor
      getDescriptor() {
    return Dm_v2_20Proto.internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_20_descriptor;
  }
  @Override
  protected FieldAccessorTable
      internalGetFieldAccessorTable() {
    return Dm_v2_20Proto.internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_20_fieldAccessorTable
        .ensureFieldAccessorsInitialized(
            dm_v2_20.class, Builder.class);
  }
  public static final int AVATAR_FIELD_NUMBER = 4;
  @SuppressWarnings("serial")
  private volatile Object avatar_ = "";
  /**
   * <code>string avatar = 4;</code>
   * @return The avatar.
   */
  @Override
  public String getAvatar() {
    Object ref = avatar_;
    if (ref instanceof String) {
      return (String) ref;
    } else {
      com.google.protobuf.ByteString bs =
          (com.google.protobuf.ByteString) ref;
      String s = bs.toStringUtf8();
      avatar_ = s;
      return s;
    }
  }
  /**
   * <code>string avatar = 4;</code>
   * @return The bytes for avatar.
   */
  @Override
  public com.google.protobuf.ByteString
      getAvatarBytes() {
    Object ref = avatar_;
    if (ref instanceof String) {
      com.google.protobuf.ByteString b =
          com.google.protobuf.ByteString.copyFromUtf8(
              (String) ref);
      avatar_ = b;
      return b;
    } else {
      return (com.google.protobuf.ByteString) ref;
    }
  }
  private byte memoizedIsInitialized = -1;
  @Override
  public final boolean isInitialized() {
    byte isInitialized = memoizedIsInitialized;
    if (isInitialized == 1) return true;
    if (isInitialized == 0) return false;
    memoizedIsInitialized = 1;
    return true;
  }
  @Override
  public void writeTo(com.google.protobuf.CodedOutputStream output)
                      throws java.io.IOException {
    if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(avatar_)) {
      com.google.protobuf.GeneratedMessageV3.writeString(output, 4, avatar_);
    }
    getUnknownFields().writeTo(output);
  }
  @Override
  public int getSerializedSize() {
    int size = memoizedSize;
    if (size != -1) return size;
    size = 0;
    if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(avatar_)) {
      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, avatar_);
    }
    size += getUnknownFields().getSerializedSize();
    memoizedSize = size;
    return size;
  }
  @Override
  public boolean equals(final Object obj) {
    if (obj == this) {
     return true;
    }
    if (!(obj instanceof dm_v2_20)) {
      return super.equals(obj);
    }
    dm_v2_20 other = (dm_v2_20) obj;
    if (!getAvatar()
        .equals(other.getAvatar())) return false;
    if (!getUnknownFields().equals(other.getUnknownFields())) return false;
    return true;
  }
  @Override
  public int hashCode() {
    if (memoizedHashCode != 0) {
      return memoizedHashCode;
    }
    int hash = 41;
    hash = (19 * hash) + getDescriptor().hashCode();
    hash = (37 * hash) + AVATAR_FIELD_NUMBER;
    hash = (53 * hash) + getAvatar().hashCode();
    hash = (29 * hash) + getUnknownFields().hashCode();
    memoizedHashCode = hash;
    return hash;
  }
  public static dm_v2_20 parseFrom(
      java.nio.ByteBuffer data)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data);
  }
  public static dm_v2_20 parseFrom(
      java.nio.ByteBuffer data,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data, extensionRegistry);
  }
  public static dm_v2_20 parseFrom(
      com.google.protobuf.ByteString data)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data);
  }
  public static dm_v2_20 parseFrom(
      com.google.protobuf.ByteString data,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data, extensionRegistry);
  }
  public static dm_v2_20 parseFrom(byte[] data)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data);
  }
  public static dm_v2_20 parseFrom(
      byte[] data,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws com.google.protobuf.InvalidProtocolBufferException {
    return PARSER.parseFrom(data, extensionRegistry);
  }
  public static dm_v2_20 parseFrom(java.io.InputStream input)
      throws java.io.IOException {
    return com.google.protobuf.GeneratedMessageV3
        .parseWithIOException(PARSER, input);
  }
  public static dm_v2_20 parseFrom(
      java.io.InputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
    return com.google.protobuf.GeneratedMessageV3
        .parseWithIOException(PARSER, input, extensionRegistry);
  }
  public static dm_v2_20 parseDelimitedFrom(java.io.InputStream input)
      throws java.io.IOException {
    return com.google.protobuf.GeneratedMessageV3
        .parseDelimitedWithIOException(PARSER, input);
  }
  public static dm_v2_20 parseDelimitedFrom(
      java.io.InputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
    return com.google.protobuf.GeneratedMessageV3
        .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
  }
  public static dm_v2_20 parseFrom(
      com.google.protobuf.CodedInputStream input)
      throws java.io.IOException {
    return com.google.protobuf.GeneratedMessageV3
        .parseWithIOException(PARSER, input);
  }
  public static dm_v2_20 parseFrom(
      com.google.protobuf.CodedInputStream input,
      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
      throws java.io.IOException {
    return com.google.protobuf.GeneratedMessageV3
        .parseWithIOException(PARSER, input, extensionRegistry);
  }
  @Override
  public Builder newBuilderForType() { return newBuilder(); }
  public static Builder newBuilder() {
    return DEFAULT_INSTANCE.toBuilder();
  }
  public static Builder newBuilder(dm_v2_20 prototype) {
    return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
  }
  @Override
  public Builder toBuilder() {
    return this == DEFAULT_INSTANCE
        ? new Builder() : new Builder().mergeFrom(this);
  }
  @Override
  protected Builder newBuilderForType(
      BuilderParent parent) {
    Builder builder = new Builder(parent);
    return builder;
  }
  /**
   * Protobuf type {@code tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20}
   */
  public static final class Builder extends
      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
      // @@protoc_insertion_point(builder_implements:tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20)
      dm_v2_20OrBuilder {
    public static final com.google.protobuf.Descriptors.Descriptor
        getDescriptor() {
      return Dm_v2_20Proto.internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_20_descriptor;
    }
    @Override
    protected FieldAccessorTable
        internalGetFieldAccessorTable() {
      return Dm_v2_20Proto.internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_20_fieldAccessorTable
          .ensureFieldAccessorsInitialized(
              dm_v2_20.class, Builder.class);
    }
    // Construct using tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20.newBuilder()
    private Builder() {
    }
    private Builder(
        BuilderParent parent) {
      super(parent);
    }
    @Override
    public Builder clear() {
      super.clear();
      bitField0_ = 0;
      avatar_ = "";
      return this;
    }
    @Override
    public com.google.protobuf.Descriptors.Descriptor
        getDescriptorForType() {
      return Dm_v2_20Proto.internal_static_tech_ordinaryroad_live_chat_client_bilibili_protobuf_dm_v2_20_descriptor;
    }
    @Override
    public dm_v2_20 getDefaultInstanceForType() {
      return dm_v2_20.getDefaultInstance();
    }
    @Override
    public dm_v2_20 build() {
      dm_v2_20 result = buildPartial();
      if (!result.isInitialized()) {
        throw newUninitializedMessageException(result);
      }
      return result;
    }
    @Override
    public dm_v2_20 buildPartial() {
      dm_v2_20 result = new dm_v2_20(this);
      if (bitField0_ != 0) { buildPartial0(result); }
      onBuilt();
      return result;
    }
    private void buildPartial0(dm_v2_20 result) {
      int from_bitField0_ = bitField0_;
      if (((from_bitField0_ & 0x00000001) != 0)) {
        result.avatar_ = avatar_;
      }
    }
    @Override
    public Builder clone() {
      return super.clone();
    }
    @Override
    public Builder setField(
        com.google.protobuf.Descriptors.FieldDescriptor field,
        Object value) {
      return super.setField(field, value);
    }
    @Override
    public Builder clearField(
        com.google.protobuf.Descriptors.FieldDescriptor field) {
      return super.clearField(field);
    }
    @Override
    public Builder clearOneof(
        com.google.protobuf.Descriptors.OneofDescriptor oneof) {
      return super.clearOneof(oneof);
    }
    @Override
    public Builder setRepeatedField(
        com.google.protobuf.Descriptors.FieldDescriptor field,
        int index, Object value) {
      return super.setRepeatedField(field, index, value);
    }
    @Override
    public Builder addRepeatedField(
        com.google.protobuf.Descriptors.FieldDescriptor field,
        Object value) {
      return super.addRepeatedField(field, value);
    }
    @Override
    public Builder mergeFrom(com.google.protobuf.Message other) {
      if (other instanceof dm_v2_20) {
        return mergeFrom((dm_v2_20)other);
      } else {
        super.mergeFrom(other);
        return this;
      }
    }
    public Builder mergeFrom(dm_v2_20 other) {
      if (other == dm_v2_20.getDefaultInstance()) return this;
      if (!other.getAvatar().isEmpty()) {
        avatar_ = other.avatar_;
        bitField0_ |= 0x00000001;
        onChanged();
      }
      this.mergeUnknownFields(other.getUnknownFields());
      onChanged();
      return this;
    }
    @Override
    public final boolean isInitialized() {
      return true;
    }
    @Override
    public Builder mergeFrom(
        com.google.protobuf.CodedInputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws java.io.IOException {
      if (extensionRegistry == null) {
        throw new NullPointerException();
      }
      try {
        boolean done = false;
        while (!done) {
          int tag = input.readTag();
          switch (tag) {
            case 0:
              done = true;
              break;
            case 34: {
              avatar_ = input.readStringRequireUtf8();
              bitField0_ |= 0x00000001;
              break;
            } // case 34
            default: {
              if (!super.parseUnknownField(input, extensionRegistry, tag)) {
                done = true; // was an endgroup tag
              }
              break;
            } // default:
          } // switch (tag)
        } // while (!done)
      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
        throw e.unwrapIOException();
      } finally {
        onChanged();
      } // finally
      return this;
    }
    private int bitField0_;
    private Object avatar_ = "";
    /**
     * <code>string avatar = 4;</code>
     * @return The avatar.
     */
    public String getAvatar() {
      Object ref = avatar_;
      if (!(ref instanceof String)) {
        com.google.protobuf.ByteString bs =
            (com.google.protobuf.ByteString) ref;
        String s = bs.toStringUtf8();
        avatar_ = s;
        return s;
      } else {
        return (String) ref;
      }
    }
    /**
     * <code>string avatar = 4;</code>
     * @return The bytes for avatar.
     */
    public com.google.protobuf.ByteString
        getAvatarBytes() {
      Object ref = avatar_;
      if (ref instanceof String) {
        com.google.protobuf.ByteString b =
            com.google.protobuf.ByteString.copyFromUtf8(
                (String) ref);
        avatar_ = b;
        return b;
      } else {
        return (com.google.protobuf.ByteString) ref;
      }
    }
    /**
     * <code>string avatar = 4;</code>
     * @param value The avatar to set.
     * @return This builder for chaining.
     */
    public Builder setAvatar(
        String value) {
      if (value == null) { throw new NullPointerException(); }
      avatar_ = value;
      bitField0_ |= 0x00000001;
      onChanged();
      return this;
    }
    /**
     * <code>string avatar = 4;</code>
     * @return This builder for chaining.
     */
    public Builder clearAvatar() {
      avatar_ = getDefaultInstance().getAvatar();
      bitField0_ = (bitField0_ & ~0x00000001);
      onChanged();
      return this;
    }
    /**
     * <code>string avatar = 4;</code>
     * @param value The bytes for avatar to set.
     * @return This builder for chaining.
     */
    public Builder setAvatarBytes(
        com.google.protobuf.ByteString value) {
      if (value == null) { throw new NullPointerException(); }
      checkByteStringIsUtf8(value);
      avatar_ = value;
      bitField0_ |= 0x00000001;
      onChanged();
      return this;
    }
    @Override
    public final Builder setUnknownFields(
        final com.google.protobuf.UnknownFieldSet unknownFields) {
      return super.setUnknownFields(unknownFields);
    }
    @Override
    public final Builder mergeUnknownFields(
        final com.google.protobuf.UnknownFieldSet unknownFields) {
      return super.mergeUnknownFields(unknownFields);
    }
    // @@protoc_insertion_point(builder_scope:tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20)
  }
  // @@protoc_insertion_point(class_scope:tech.ordinaryroad.live.chat.client.bilibili.protobuf.dm_v2_20)
  private static final dm_v2_20 DEFAULT_INSTANCE;
  static {
    DEFAULT_INSTANCE = new dm_v2_20();
  }
  public static dm_v2_20 getDefaultInstance() {
    return DEFAULT_INSTANCE;
  }
  private static final com.google.protobuf.Parser<dm_v2_20>
      PARSER = new com.google.protobuf.AbstractParser<dm_v2_20>() {
    @Override
    public dm_v2_20 parsePartialFrom(
        com.google.protobuf.CodedInputStream input,
        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
        throws com.google.protobuf.InvalidProtocolBufferException {
      Builder builder = newBuilder();
      try {
        builder.mergeFrom(input, extensionRegistry);
      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
        throw e.setUnfinishedMessage(builder.buildPartial());
      } catch (com.google.protobuf.UninitializedMessageException e) {
        throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());
      } catch (java.io.IOException e) {
        throw new com.google.protobuf.InvalidProtocolBufferException(e)
            .setUnfinishedMessage(builder.buildPartial());
      }
      return builder.buildPartial();
    }
  };
  public static com.google.protobuf.Parser<dm_v2_20> parser() {
    return PARSER;
  }
  @Override
  public com.google.protobuf.Parser<dm_v2_20> getParserForType() {
    return PARSER;
  }
  @Override
  public dm_v2_20 getDefaultInstanceForType() {
    return DEFAULT_INSTANCE;
  }
}
在上述文件截断后对比
ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/protobuf/dm_v2_20OrBuilder.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/java/tech/ordinaryroad/live/chat/client/bilibili/util/BilibiliCodecUtil.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/resources/proto/dm_v2.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/main/resources/proto/dm_v2_20.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/test/java/tech/ordinaryroad/live/chat/client/bilibili/api/BilibiliApisTest.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-bilibili/src/test/java/tech/ordinaryroad/live/chat/client/bilibili/client/BilibiliLiveChatClientTest.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/pom.xml ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/ClientModeExample.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/api/DouyinApis.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/client/DouyinLiveChatClient.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/config/DouyinLiveChatClientConfig.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/constant/DouyinCmdEnum.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/listener/IDouyinConnectionListener.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/listener/IDouyinMsgListener.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/msg/DouyinDanmuMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/msg/DouyinEnterRoomMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/msg/DouyinGiftMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/msg/DouyinLikeMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/msg/base/IDouyinCmdMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/msg/base/IDouyinMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/netty/handler/DouyinBinaryFrameHandler.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/netty/handler/DouyinConnectionHandler.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/Douyin_cmd_msgProto.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/Douyin_webcast_chat_message_msgProto.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/Douyin_webcast_gift_message_msgProto.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/Douyin_webcast_member_message_msgProto.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/Douyin_websocket_frameProto.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_cmd_msg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_cmd_msgOrBuilder.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_webcast_chat_message_msg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_webcast_chat_message_msgOrBuilder.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_webcast_gift_message_msg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_webcast_gift_message_msgOrBuilder.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_webcast_like_message_msg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_webcast_like_message_msgOrBuilder.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_webcast_like_message_msgProto.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_webcast_member_message_msg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_webcast_member_message_msgOrBuilder.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_websocket_frame.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_websocket_frameOrBuilder.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_websocket_frame_msg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_websocket_frame_msgOrBuilder.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/douyin_websocket_frame_msgProto.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/CommonOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/DoubleLikeDetailOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/GiftIMPriorityOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/GiftStructOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/ImageOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/PatternRefOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/PublicAreaCommonOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/TextEffectDetailOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/TextEffectOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/TextFormatOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/TextOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/TextPieceGiftOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/TextPieceHeartOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/TextPieceImageOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/TextPieceOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/TextPiecePatternRefOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/TextPieceUserOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/java/tech/ordinaryroad/live/chat/client/douyin/protobuf/dto/UserOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/Common.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/DoubleLikeDetail.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/GiftIMPriority.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/GiftStruct.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/Image.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/PatternRef.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/PublicAreaCommon.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/Text.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/TextEffect.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/TextEffectDetail.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/TextFormat.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/TextPiece.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/TextPieceGift.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/TextPieceHeart.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/TextPieceImage.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/TextPiecePatternRef.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/TextPieceUser.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/User.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/douyin_cmd_msg.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/douyin_webcast_chat_message_msg.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/douyin_webcast_gift_message_msg.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/douyin_webcast_like_message_msg.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/douyin_webcast_member_message_msg.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/douyin_websocket_frame.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/main/resources/proto/douyin_websocket_frame_msg.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/test/java/tech/ordinaryroad/live/chat/client/douyin/api/DouyinApisTest.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyin/src/test/java/tech/ordinaryroad/live/chat/client/douyin/client/DouyinLiveChatClientTest.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/README.md ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/pom.xml ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/api/DouyuApis.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/client/DouyuDanmuLiveChatClient.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/client/DouyuLiveChatClient.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/client/DouyuWsLiveChatClient.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/client/base/BaseDouyuLiveChatClient.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/config/DouyuLiveChatClientConfig.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/constant/DouyuClientModeEnum.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/constant/DouyuCmdEnum.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/listener/IDouyuConnectionListener.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/listener/IDouyuMsgListener.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/ChatmessageMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/ChatmsgMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/DgbMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/DouyuCmdMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/H5ckreqMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/H5csMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/H5gkcreqMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/HeartbeatMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/HeartbeatReplyMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/JoingroupMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/KeepliveMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/LoginreqMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/LoginresMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/MapkbMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/MsgrepeaterproxylistMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/SubMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/UenterMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/base/BaseDouyuCmdMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/base/IDouyuMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/dto/GiftListInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/dto/GiftPropInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/msg/dto/GiftPropSingle.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/netty/frame/AuthWebSocketFrame.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/netty/frame/HeartbeatWebSocketFrame.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/netty/frame/KeepliveWebSocketFrame.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/netty/frame/base/BaseDouyuWebSocketFrame.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/netty/frame/factory/DouyuWebSocketFrameFactory.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/netty/handler/DouyuBinaryFrameHandler.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/netty/handler/DouyuConnectionHandler.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/main/java/tech/ordinaryroad/live/chat/client/douyu/util/DouyuCodecUtil.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/test/java/tech/ordinaryroad/live/chat/client/douyu/api/DouyuApisTest.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/test/java/tech/ordinaryroad/live/chat/client/douyu/client/ChatChoice.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/test/java/tech/ordinaryroad/live/chat/client/douyu/client/ChatCompletionResponse.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/test/java/tech/ordinaryroad/live/chat/client/douyu/client/DouyuLiveChatClientTest.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/test/java/tech/ordinaryroad/live/chat/client/douyu/client/Message.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/test/java/tech/ordinaryroad/live/chat/client/douyu/client/Usage.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-douyu/src/test/java/tech/ordinaryroad/live/chat/client/douyu/util/DouyuCodecUtilTest.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/pom.xml ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/api/HuyaApis.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/client/HuyaLiveChatClient.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/config/HuyaLiveChatClientConfig.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/constant/HuyaClientTemplateTypeEnum.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/constant/HuyaCmdEnum.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/constant/HuyaDecorationAppTypeEnum.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/constant/HuyaDecorationViewTypeEnum.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/constant/HuyaGenderEnum.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/constant/HuyaLiveSource.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/constant/HuyaOperationEnum.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/constant/HuyaStreamLineTypeEnum.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/constant/HuyaWupFunctionEnum.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/listener/IHuyaConnectionListener.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/listener/IHuyaMsgListener.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/BaseWup.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/ConnectParaInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/LiveLaunchRsp.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/MessageNoticeMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/PushMessage.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/PushMessage_V2.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/RegisterGroupRsp.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/RegisterRsp.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/SendItemSubBroadcastPacketMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/UserInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/VerifyCookieRsp.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/VipEnterBannerMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/WebSocketCommand.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/WupRsp.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/base/BaseHuyaCmdMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/base/BaseHuyaMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/base/IHuyaCmdMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/base/IHuyaMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/ACEnterBanner.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/BadgeInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/BulletBorderGroundFormat.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/BulletFormat.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/ChannelPair.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/CommEnterBanner.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/ContentFormat.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/CustomBadgeDynamicExternal.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/DIYBigGiftEffect.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/DecorationInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/DecorationInfoRsp.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/DeviceInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/DisplayInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/FaithInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/FaithPresenter.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/GuardInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/ItemEffectInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/LiveAppUAEx.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/LiveProxyValue.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/LiveUserbase.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/MessageContentExpand.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/MessageTagInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/MsgItem.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/MsgStatInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/NobleInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/NobleLevelAttr.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/NobleLevelInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/NoblePetAttr.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/PresenterChannelInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/PropView.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/PropsIdentity.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/PropsItem.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/SendMessageFormat.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/SenderInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/SpecialInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/SuperFansInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/UidNickName.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/UserId.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/UserIdentityInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/UserRidePetInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/dto/WeekRankInfo.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/req/GetLivingInfoReq.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/req/GetPropsListReq.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/req/GetPropsListRsp.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/req/LaunchReq.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/req/LiveLaunchReq.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/req/RegisterGroupReq.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/req/SendMessageReq.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/req/UpdateUserInfoReq.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/req/UserHeartBeatReq.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/req/VerifyCookieReq.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/msg/req/WupReq.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/netty/frame/factory/HuyaWebSocketFrameFactory.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/netty/handler/HuyaBinaryFrameHandler.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/netty/handler/HuyaConnectionHandler.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/main/java/tech/ordinaryroad/live/chat/client/huya/util/HuyaCodecUtil.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/test/java/tech/ordinaryroad/live/chat/client/huya/api/HuyaApisTest.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/test/java/tech/ordinaryroad/live/chat/client/huya/client/HuyaLiveChatClientTest.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-huya/src/test/java/tech/ordinaryroad/live/chat/client/huya/util/HuyaCodecUtilTest.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/pom.xml ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/ClientModeExample.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/api/KuaishouApis.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/client/KuaishouLiveChatClient.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/config/KuaishouLiveChatClientConfig.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/listener/IKuaishouConnectionListener.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/listener/IKuaishouMsgListener.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/msg/KuaishouDanmuMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/msg/KuaishouGiftMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/msg/KuaishouLikeMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/msg/base/IKuaishouCmdMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/msg/base/IKuaishouMsg.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/netty/handler/KuaishouBinaryFrameHandler.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/netty/handler/KuaishouConnectionHandler.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/AuditAudienceMaskOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/CSErrorOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/CSHeartbeatOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/CSPingOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/CSWebEnterRoomOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/CSWebErrorOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/CSWebHeartbeatOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/CSWebUserExitOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/CSWebUserPauseOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/ClientIdOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/ConfigSwitchItemOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/ConfigSwitchTypeOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/GzoneNameplateOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/LiveAudienceStateOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/LiveCdnNodeViewOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/LiveFansGroupStateOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/PSHostInfoOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/PayloadTypeOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/PicUrlOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCEchoOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCErrorOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCHeartbeatAckOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCInfoOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCLiveWarningMaskStatusChangedAudienceOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCPingAckOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebAuthorPauseOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebAuthorResumeOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebBetChangedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebBetClosedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebCurrentRedPackFeedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebEnterRoomAckOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebErrorOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebFeedPushOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebGuessClosedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebGuessOpenedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebHeartbeatAckOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebLiveSpecialAccountConfigStateOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebLiveWatchingUsersOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebPipEndedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebPipStartedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebRefreshWalletOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebRideChangedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SCWebSuspectedViolationOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SimpleUserInfoOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/SocketMessageOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/UserInfoOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/WebComboCommentFeedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/WebCommentFeedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/WebCommentFeedShowTypeOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/WebGiftFeedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/WebLikeFeedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/WebLiveAssistantTypeOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/WebPauseTypeOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/WebRedPackCoverTypeOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/WebRedPackInfoOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/WebShareFeedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/WebSystemNoticeFeedOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/WebUserPauseTypeOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/java/tech/ordinaryroad/live/chat/client/kuaishou/protobuf/WebWatchingUserInfoOuterClass.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/AuditAudienceMask.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/CSError.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/CSHeartbeat.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/CSPing.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/CSWebEnterRoom.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/CSWebError.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/CSWebHeartbeat.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/CSWebUserExit.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/CSWebUserPause.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/ClientId.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/ConfigSwitchItem.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/ConfigSwitchType.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/GzoneNameplate.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/LiveAudienceState.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/LiveCdnNodeView.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/LiveFansGroupState.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/PSHostInfo.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/PayloadType.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/PicUrl.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCEcho.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCError.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCHeartbeatAck.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCInfo.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCLiveWarningMaskStatusChangedAudience.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCPingAck.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebAuthorPause.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebAuthorResume.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebBetChanged.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebBetClosed.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebCurrentRedPackFeed.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebEnterRoomAck.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebError.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebFeedPush.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebGuessClosed.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebGuessOpened.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebHeartbeatAck.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebLiveSpecialAccountConfigState.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebLiveWatchingUsers.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebPipEnded.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebPipStarted.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebRefreshWallet.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebRideChanged.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SCWebSuspectedViolation.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SimpleUserInfo.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/SocketMessage.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/UserInfo.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/WebComboCommentFeed.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/WebCommentFeed.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/WebCommentFeedShowType.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/WebGiftFeed.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/WebLikeFeed.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/WebLiveAssistantType.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/WebPauseType.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/WebRedPackCoverType.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/WebRedPackInfo.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/WebShareFeed.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/WebSystemNoticeFeed.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/WebUserPauseType.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/main/resources/proto/WebWatchingUserInfo.proto ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/test/java/tech/ordinaryroad/live/chat/client/kuaishou/api/KuaishouApisTest.java ruoyi-modules/ruoyi-live/live-chat-clients/live-chat-client-kuaishou/src/test/java/tech/ordinaryroad/live/chat/client/kuaishou/client/KuaishouLiveChatClientTest.java ruoyi-modules/ruoyi-live/live-chat-clients/pom.xml ruoyi-modules/ruoyi-live/pom.xml ruoyi-modules/ruoyi-midjourney/pom.xml (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/Constants.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/ProxyApplication.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/ProxyProperties.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/ReturnCode.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/controller/AccountController.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/controller/FaceController.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/controller/SubmitController.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/controller/TaskController.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/domain/DiscordAccount.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/domain/DomainObject.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/domain/InsightFace.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/domain/MjPriceConfig.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/dto/BaseSubmitDTO.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/dto/SubmitActionDTO.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/dto/SubmitBlendDTO.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/dto/SubmitChangeDTO.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/dto/SubmitDescribeDTO.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/dto/SubmitImagineDTO.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/dto/SubmitModalDTO.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/dto/SubmitShortenDTO.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/dto/SubmitSimpleChangeDTO.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/dto/TaskConditionDTO.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/enums/ActionType.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/enums/BlendDimensions.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/enums/MessageType.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/enums/TaskAction.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/enums/TaskStatus.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/enums/TranslateWay.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/exception/BannedPromptException.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/exception/SnowFlakeException.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/loadbalancer/DiscordInstance.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/loadbalancer/DiscordInstanceImpl.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/loadbalancer/DiscordLoadBalancer.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/loadbalancer/rule/BestWaitIdleRule.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/loadbalancer/rule/IRule.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/loadbalancer/rule/RoundRobinRule.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/result/Message.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/result/SubmitResultVO.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/service/DiscordService.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/service/DiscordServiceImpl.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/service/NotifyService.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/service/NotifyServiceImpl.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/service/TaskService.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/service/TaskServiceImpl.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/service/TaskStoreService.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/service/TranslateService.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/service/store/InMemoryTaskStoreServiceImpl.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/service/store/RedisTaskStoreServiceImpl.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/service/translate/BaiduTranslateServiceImpl.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/service/translate/GPTTranslateServiceImpl.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/service/translate/NoTranslateServiceImpl.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/support/ApiAuthorizeInterceptor.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/support/DiscordAccountHelper.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/support/DiscordAccountInitializer.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/support/DiscordHelper.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/support/SpringContextHolder.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/support/Task.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/support/TaskCondition.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/support/TaskTimeoutSchedule.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/util/AsyncLockUtils.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/util/BannedPromptUtils.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/util/ContentParseData.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/util/ConvertUtils.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/util/MimeTypeUtils.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/util/MjOkHttpUtil.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/util/SnowFlake.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/util/TaskChangeParams.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/util/UVContentParseData.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/wss/WebSocketStarter.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/wss/handle/BlendSuccessHandler.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/wss/handle/DescribeSuccessHandler.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/wss/handle/ErrorMessageHandler.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/wss/handle/ImagineSuccessHandler.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/wss/handle/MessageHandler.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/wss/handle/RerollSuccessHandler.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/wss/handle/StartAndProgressHandler.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/wss/handle/UpscaleSuccessHandler.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/wss/handle/VariationSuccessHandler.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/wss/user/UserMessageListener.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/com/xmzs/midjourney/wss/user/UserWebSocketStarter.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/spring/config/BeanConfig.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/java/spring/config/WebMvcConfig.java (已删除) ruoyi-modules/ruoyi-midjourney/src/main/resources/api-params/blend.json (已删除) ruoyi-modules/ruoyi-midjourney/src/main/resources/api-params/describe.json (已删除) ruoyi-modules/ruoyi-midjourney/src/main/resources/api-params/imagine.json (已删除) ruoyi-modules/ruoyi-midjourney/src/main/resources/api-params/message.json (已删除) ruoyi-modules/ruoyi-midjourney/src/main/resources/api-params/reroll.json (已删除) ruoyi-modules/ruoyi-midjourney/src/main/resources/api-params/upscale.json (已删除) ruoyi-modules/ruoyi-midjourney/src/main/resources/api-params/variation.json (已删除) ruoyi-modules/ruoyi-midjourney/src/main/resources/banned-words.txt (已删除) ruoyi-modules/ruoyi-midjourney/src/main/resources/mime.types (已删除) ruoyi-modules/ruoyi-system/pom.xml ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/cofing/GptConfig.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/cofing/KeywordConfig.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/cofing/QqConfig.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/cofing/WechatConfig.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/cofing/WxMaConfiguration.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/cofing/WxMaProperties.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/monitor/CacheController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/monitor/SysLogininforController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/monitor/SysOperlogController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/monitor/SysUserOnlineController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysConfigController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysDeptController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysDictDataController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysDictTypeController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysMenuController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysModelController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysNoticeController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysOssConfigController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysOssController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysPostController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysProfileController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysRoleController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysTenantController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysTenantPackageController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/controller/system/SysUserController.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/ChatMessage.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/ChatToken.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/PaymentOrders.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysCache.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysConfig.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysDept.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysDictData.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysDictType.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysLogininfor.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysMenu.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysModel.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysNotice.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysOperLog.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysOss.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysOssConfig.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysPost.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysRole.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysRoleDept.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysRoleMenu.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysTenant.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysTenantPackage.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysUser.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysUserOnline.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysUserPost.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/SysUserRole.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/VoiceRole.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/ChatMessageBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/PaymentOrdersBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysConfigBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysDeptBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysDictDataBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysDictTypeBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysLogininforBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysMenuBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysModelBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysNoticeBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysOperLogBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysOssBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysOssConfigBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysPostBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysRoleBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysTenantBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysTenantPackageBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysUserBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/SysUserProfileBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/bo/VoiceRoleBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/request/EmailRequest.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/request/OrderRequest.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/request/UserRequest.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/AvatarVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/CacheListInfoVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/CaptchaVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/ChatMessageVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/ChatTokenVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/DeptTreeSelectVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/LoginTenantVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/LoginVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/MenuTreeSelectVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/MetaVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/PaymentOrdersVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/ProfileVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/RouterVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysConfigVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysDeptVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysDictDataVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysDictTypeVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysLogininforVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysMenuVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysModelVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysNoticeVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysOperLogVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysOssConfigVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysOssUploadVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysOssVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysPostVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysRoleVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysTenantPackageVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysTenantVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysUserExportVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysUserImportVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysUserInfoVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/SysUserVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/TenantListVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/UserInfoVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/domain/vo/VoiceRoleVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/handler/CustomerBigDecimalSerialize.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/handler/WechatMessageHandler.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/listener/SSEEventSourceListener.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/listener/SysUserImportListener.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/ChatMessageMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/ChatTokenMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/PaymentOrdersMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysConfigMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysDeptMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysDictDataMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysDictTypeMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysLogininforMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysMenuMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysModelMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysNoticeMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysOperLogMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysOssConfigMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysOssMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysPostMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysRoleDeptMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysRoleMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysRoleMenuMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysTenantMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysTenantPackageMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysUserMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysUserPostMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/SysUserRoleMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/mapper/VoiceRoleMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/runner/SystemApplicationRunner.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ChatService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/IChatCostService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/IChatMessageService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/IChatService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/IChatTokenService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/IPaymentOrdersService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISseService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysConfigService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysDataScopeService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysDeptService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysDictDataService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysDictTypeService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysLogininforService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysMenuService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysModelService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysNoticeService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysOperLogService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysOssConfigService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysOssService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysPermissionService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysPostService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysRoleService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysTenantPackageService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysTenantService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ISysUserService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/SseService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/SysLoginService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/SysRegisterService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/TextReviewService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/ChatCostServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/ChatMessageServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/ChatServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/ChatTokenServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/PaymentOrdersServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SseServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysConfigServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysDataScopeServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysDeptServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysDictDataServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysDictTypeServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysLogininforServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysMenuServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysModelServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysNoticeServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysOperLogServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysOssConfigServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysOssServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysPermissionServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysPostServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysRoleServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysSensitiveServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysTenantPackageServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysTenantServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SysUserServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/util/BotUtil.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/util/OrderNumberGenerator.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/builder/AbstractBuilder.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/builder/ImageBuilder.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/builder/TextBuilder.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/cofing/OkHttpConfig.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/cofing/WxCpConfiguration.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/cofing/WxCpProperties.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/ChatConfigController.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/ChatStoreController.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/ChatVoucherController.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/WeChatController.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/WxRobConfigController.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/wxsingle/WxJsController.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/wxsingle/WxPortalController.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/ChatAppStore.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/ChatConfig.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/Cover.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/CoverPromptAudio.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/VoiceRole.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/bo/ChatAppStoreBo.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/bo/VoiceRoleBo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/request/translation/TranslationRequest.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/ChatAppStoreVo.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/VoiceRoleVo.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/cover/CoverCallbackVo.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/cover/CoverParamVo.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/cover/CoverPromptAudioVo.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/cover/CoverVo.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/cover/MusicVo.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/ppt/PptAllQueryDto.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/ppt/PptGenerateContentDto.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/ppt/PptGenerateOutlineDto.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/ppt/PptGeneratePptxDto.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/ppt/PptTemplateFilterDto.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/domain/vo/ppt/PptTemplateQueryDto.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/MyMsgHandler.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/AbstractHandler.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/ContactChangeHandler.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/EnterAgentHandler.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/LocationHandler.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/LogHandler.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/MenuHandler.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/MsgHandler.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/NullHandler.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/ScanHandler.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/SubscribeHandler.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/handler/wxcp/UnsubscribeHandler.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/listener/SSEEventSourceListener.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/ChatAppStoreMapper.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/CoverMapper.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/CoverPromptAudioMapper.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/mapper/VoiceRoleMapper.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/response/rolelist/ChatAppStoreVO.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/response/rolelist/RoleListVO.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/IChatAppStoreService.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/ICoverPromptAudioService.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/ICoverService.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/IPptService.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/ISseService.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/IVoiceRoleService.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/SysLoginService.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/ChatAppStoreImpl.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/CoverPromptAudioServiceImpl.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/CoverServiceImpl.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/PptServiceImpl.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/SseServiceImpl.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/VoiceRoleServiceImpl.java (已删除) ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/util/HttpUtils.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/util/WddPptApi.java ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/util/WeChatScanHttpUtil.java ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md (已删除) ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/CoverMapper.xml ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/CoverPromptAudioMapper.xml script/bin/ry.bat (已删除) script/bin/ry.sh (已删除) script/docker/.env (已删除) script/docker/milvus/docker-compose.yml script/docker/ruoyi-ai.sql script/docker/ry-vue.sql (已删除) script/docker/weaviate/docker-compose.yml script/sql/oracle/oracle_ry_vue_5.X.sql (已删除) script/sql/oracle/oracle_test.sql (已删除) script/sql/postgres/postgres_ry_vue_5.X.sql (已删除) script/sql/postgres/postgres_test.sql (已删除) script/sql/ruoyi-ai.sql script/sql/ry-vue.sql (已删除) script/sql/sqlserver/sqlserver_ry_vue_5.X.sql (已删除) script/sql/sqlserver/sqlserver_test.sql (已删除) script/sql/update/update20241227.sql (已删除) script/sql/update/update_20250111.sql