Skip to content

BOT应用后端开发

1.1 Bot应用与Bot应用服务端交互流程图

Bot应用与Bot应用服务端交互流程图

1.2 MosApp的Bot会话发送消息到Bot应用服务端

用户给Bot应用发消息后,MosApp会将消息通过Bot应用服务端配置的webhook透传给Bot应用服务端。

1.2.1 报文示例

java
{
    "reqId": "4E3FC140-73E6-4E18-BD98-99E19A4496B9",
    "botAppId": "696290824258245",
    "eventType": "MESSAGE",
    "conversation": {
        "conversationId": "696638485037509"
    },
    "message": {
        "messageId": "1950519940851331072",
        "text": "/start",
        "timestamp": 1753875167470,
        "type": -1
    },
    "miniApp": {
        "openid": "47179fef0cff7ab186e2bcc3ac46790c"
    },
    "sender": {
        "nickname": "mosUser"
    },
    "timestamp": 1753875167470
}

1.2.2 webhook参数说明

属性类型必填说明
reqIdString请求id,每个请求唯一
eventTypeString事件类型: message/callbackQuery
timestampLong事件发生时间戳
botAppIdStringbot应用id
sender发送者信息对象
--nicknameString用户昵称
conversation会话信息对象
--conversationIdString会话id
message用户发送的消息内容(Message 对象),仅在 eventType 为 message 时存在
--messageIdString用户发送的消息的消息id
--textString发送文本
--timestampLong消息发送时间
callbackQuery内联按钮点击事件的详细信息(CallbackQuery 对象),仅在 eventType 为 callback_query 时存在
--dataString回调数据(通常由开发者定义)
--inlineMessageIdString内联消息id
miniApp微应用信息对象 BotApp绑定了微应用,该实体有值
--openidString用户在对应微应用中的openid

1.2.3 Java使用范例

请求入参

java
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;

/**
 * 点击内联按钮入参
 * @author admin001
 * @date 2025/7/8 19:55
 */
@Data
@Accessors(chain = true)
public class WebhookParam implements Serializable {

    private static final long serialVersionUID = 6142195922243220516L;

    /**
     * 请求id,每个请求唯一
     */
    private String reqId;

    /**
     * 事件类型: message/callbackQuery
     */
    private String eventType;

    /**
     * 事件发生时间戳
     */
    private Long timestamp;

    /**
     * botApp id
     */
    private String botAppId;

    /**
     * 发送者信息,表示发起事件的用户。
     */
    private UserInfo sender;

    /**
     * 会话信息
     */
    private Conversation conversation;

    /**
     * 用户发送的消息内容(Message 对象),仅在 eventType 为 message 时存在
     */
    private Message message;

    /**
     * 内联按钮点击事件的详细信息(CallbackQuery 对象),仅在 eventType 为 callback_query 时存在。
     */
    private CallbackQuery callbackQuery;

    /**
     * 微应用信息 BotApp绑定了微应用,该实体有值
     */
    private MiniApp miniApp;


    // 嵌套类: 用户信息
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @Data
    public static class UserInfo implements Serializable {
        private static final long serialVersionUID = 1L;

        /**
         * 用户昵称
         */
        private String nickname;
    }

    // 嵌套类: 会话信息
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @Data
    public static class Conversation implements Serializable {
        private static final long serialVersionUID = 1L;

        /**
         * 会话id
         */
        private String conversationId;
    }

    // 嵌套类: 消息信息
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @Data
    public static class Message implements Serializable {
        private static final long serialVersionUID = 1L;

        /**
         * 用户发送的消息的消息id
         */
        private String messageId;
        /**
         * 发送文本
         */
        private String text;
        /**
         * 消息发送时间
         */
        private Long timestamp;

    }

    // 嵌套类: 回调查询(内联按钮点击)
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @Data
    public static class CallbackQuery implements Serializable {
        private static final long serialVersionUID = 1L;

        /**
         * 回调数据(通常由开发者定义)
         */
        private String data;
        /**
         * 内联消息id
         */
        private String inlineMessageId;

    }

    // 嵌套类: 微应用信息
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @Data
    public static class MiniApp implements Serializable {
        private static final long serialVersionUID = 1L;

        /**
         * 用户在对应微应用中的openid
         */
        private String openid;

    }

}

控制器类

java
@RestController
@RequestMapping("/botApp")
@Slf4j
public class BotAppController {

    @PostMapping("/webhook")
    public Void miniAppLogin(@RequestBody WebhookParam webhookParam) {
        log.info("webhookParam: {}", webhookParam);
        // other code
    }
}

1.3 Bot应用服务端发送消息到MosApp的Bot会话

1.3.1 MosApp 开放 API 地址

https://mos-test.mos.me/open-apis/botApp/v1/sendMessage/{token}

地址中的 {token} 为应用创建后唯一生成的字符串,可在 Bot 应用详情页查看并复制;请妥善保管,切勿泄露。

MosApp 开放 API 地址

1.3.2 报文示例

java
{
    "reqId": "2530D143-2C3E-4970-B4AE-8216CEA5653A",
    "conversationId": "696638485037509",
    "inlineMessageId": "",
    "editCurrent": false,
    "text": "Hello Bot app",
    "inlineButtons": [
        [
            {
                "data": "callbackData",
                "text": "callback Button",
                "type": "callback"
            }
        ],
        [
            {
                "data": "https://www.google.com/",
                "text": "Google",
                "type": "url"
            }
        ],
        [
            {
                "data": "",
                "text": "Mini app",
                "type": "miniApp"
            }
        ]
    ]
}

1.3.3 入参说明

属性类型必填说明
reqIdString请求id,每个请求唯一
conversationIdString会话id
editCurrentBoolean是否编辑单条消息
inlineMessageIdString内联消息id
textString消息内容
inlineButtons List<List<InlineButton>>
inline button list object
--textString按钮文案
--typeString按钮类型(callback/url/miniApp)详细说明见下"内联按钮类型说明"
--dataString按钮键值 详细说明见下"内联按钮键值详细说明"

内联按钮类型说明:

  1. callback (回调类型) :用户点击后,会触发一条 eventType=callbackQuery 的消息,通过 webhook 发送至 Bot 应用服务端;该消息不会在会话中显示,仅将按钮的 data 值传递给Bot应用服务端。
  2. url (跳转链接类型):点击后将打开浏览器显示指定链接;若为内部链接(如用户、群组、频道等链接),则会在 MosApp 内打开。)
  3. miniApp(微应用跳转类型): 若 Bot 应用已绑定微应用,用户点击后将直接进入该绑定的微应用。

内联按钮键值说明:

  1. 当类型为 callback 时,data 为 Bot 应用服务端配置的字符串;用户点击按钮时,MosApp 会将该 data 内容直接透传给Bot应用服务端,便于Bot应用服务端区分用户点击的具体按钮。
  2. 当类型为 url 时,data 为 Bot 应用服务端配置的外部 URL 链接或 MosApp 内部链接
  3. 当类型为 miniApp 时,data 可配置页面路径等信息;打开微应用时,该路径会以参数形式携带在 URL 后。

1.3.4 Java使用范例

请求入参

java
package com.wecloud.modules.openapi.bot.ao;

import lombok.Data;

import java.util.List;

@Data
public class BotAppMessageAo {

    /**
     * 请求id
     */
    private String reqId;

    /**
     * 会话id
     */
    private String conversationId;

    /**
     * 消息内容
     */
    private String text;

    /**
     * 内联按钮 二维数组
     */
    private List<List<InlineButton>> inlineButtons;

    /**
     * 是否编辑单条消息
     */
    private Boolean editCurrent;

    /**
     * 内联消息id
     */
    private String inlineMessageId;

    @Data
    public static class InlineButton {
        /**
         * 按钮文案
         */
        private String text;
    
        /**
         * 按钮类型
         */
        private String type;
    
        /**
         * 按钮键值 开发者用来区分是哪个按钮
         */
        private String data;
    }
}

处理用户消息并响应

java
@RestController
@RequestMapping("/botApp")
@Slf4j
public class BotAppController {

    // bot app token
    private static final String token = "bot app token";
    // open api base Request
    private static final String openApiBaseUrl = "https://mos.mos.me/open-apis/botApp/v1/sendMessage/";

    // envet type
    private static final String EVENT_TYPE_CALLBACK_QUERY = "CALLBACK_QUERY";
    private static final String EVENT_TYPE_MESSAGE = "MESSAGE";

    @Autowired
    private RestTemplate restTemplate;

    @PostMapping("/webhook")
    public Void miniAppLogin(@RequestBody WebhookParam webhookParam) {
        log.info("webhookParam: {}", webhookParam);
        BotAppMessageAo botAppMessageAo = new BotAppMessageAo();
        WebhookParam.Conversation conversation = webhookParam.getConversation();
        botAppMessageAo.setReqId(webhookParam.getReqId());
        botAppMessageAo.setConversationId(conversation.getConversationId());
        // 内联按钮请求
        if (EVENT_TYPE_CALLBACK_QUERY.equals(webhookParam.getEventType())) {
            WebhookParam.CallbackQuery callbackQuery = webhookParam.getCallbackQuery();
            String data = callbackQuery.getData();
            botAppMessageAo.setText(data);
            // 内联按钮
            List<List<InlineButton>> inlineButtons = new ArrayList<>();
            // 第一行
            List<InlineButton> inlineButtonRow1 = new ArrayList<>();
            InlineButton row1Column1 = new InlineButton();
            row1Column1.setText("row1Column1");
            row1Column1.setType("callback");
            row1Column1.setData("row1Column1");
            inlineButtonRow1.add(row1Column1);
            InlineButton row2Column2 = new InlineButton();
            row2Column2.setText("row2Column2");
            row2Column2.setType("callback");
            row2Column2.setData("row2Column2");
            inlineButtonRow1.add(row2Column2);
            inlineButtons.add(inlineButtonRow1);
            // 第二行
            List<InlineButton> inlineButtonRow2 = new ArrayList<>();
            InlineButton row2Column1 = new InlineButton();
            row2Column1.setText("row2Column1");
            row2Column1.setType("url");
            row2Column1.setData("https://www.google.com/");
            inlineButtonRow2.add(row2Column1);
            inlineButtons.add(inlineButtonRow2);
            // 第三行
            List<InlineButton> inlineButtonRow3 = new ArrayList<>();
            InlineButton row3Column1 = new InlineButton();
            row3Column1.setText("row3Column1");
            row3Column1.setType("miniApp");
            row3Column1.setData("https://www.google.com/");
            inlineButtonRow3.add(row3Column1);
            inlineButtons.add(inlineButtonRow3);
            botAppMessageAo.setInlineButtons(inlineButtons);
            botAppMessageAo.setEditCurrent(true);
            botAppMessageAo.setInlineMessageId(callbackQuery.getInlineMessageId());
        }
        // 消息请求
        else if (EVENT_TYPE_MESSAGE.equals(webhookParam.getEventType())) {
            WebhookParam.Message message = webhookParam.getMessage();
            String data = message.getText();
            if ("/start".equals(data)) {
                botAppMessageAo.setText(data);
                // 内联按钮
                List<List<InlineButton>> inlineButtons = new ArrayList<>();
                // 第一行
                List<InlineButton> inlineButtonRow1 = new ArrayList<>();
                InlineButton row1Column1 = new InlineButton();
                row1Column1.setText("row1Column1");
                row1Column1.setType("callback");
                row1Column1.setData("row1Column1");
                inlineButtonRow1.add(row1Column1);
                InlineButton row2Column2 = new InlineButton();
                row2Column2.setText("row2Column2");
                row2Column2.setType("callback");
                row2Column2.setData("row2Column2");
                inlineButtonRow1.add(row2Column2);
                inlineButtons.add(inlineButtonRow1);
                // 第二行
                List<InlineButton> inlineButtonRow2 = new ArrayList<>();
                InlineButton row2Column1 = new InlineButton();
                row2Column1.setText("row2Column1");
                row2Column1.setType("url");
                row2Column1.setData("https://www.google.com/");
                inlineButtonRow2.add(row2Column1);
                inlineButtons.add(inlineButtonRow2);
                // 第三行
                List<InlineButton> inlineButtonRow3 = new ArrayList<>();
                InlineButton row3Column1 = new InlineButton();
                row3Column1.setText("row3Column1");
                row3Column1.setType("miniApp");
                row3Column1.setData("https://www.google.com/");
                inlineButtonRow3.add(row3Column1);
                inlineButtons.add(inlineButtonRow3);
        
                botAppMessageAo.setInlineButtons(inlineButtons);
                botAppMessageAo.setEditCurrent(false);
                botAppMessageAo.setInlineMessageId("");
            } else {
                botAppMessageAo.setText(data);
                botAppMessageAo.setEditCurrent(false);
                botAppMessageAo.setInlineMessageId("");
            }
        }
        try {
            String url = openApiBaseUrl + token;
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<BotAppMessageAo> requestEntity = new HttpEntity<>(botAppMessageAo, headers);
            ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);
        } catch (Exception e) {
            log.error("error ", e);
        }
    }
}