| 订阅方式 | 介绍 |
|---|---|
| 使用长连接接收事件 | 该方式是飞书 SDK 内提供的能力,你可以通过集成飞书 SDK 与开放平台建立一条 WebSocket 全双工通道(你的服务器需要能够访问公网)。后续当应用订阅的事件发生时,开放平台会通过该通道向你的服务器发送消息。相较 于传统的 Webhook 模式,长连接模式大大降低了接入成本,将原先 1 周左右的开发周期降低到 5 分钟。具体优势如下:测试阶段无需使用内网穿透工具,通过长连接模式在本地开发环境中即可接收事件回调。SDK 内封装了鉴权逻辑,只在建连时进行鉴权,后续事件推送均为明文数据,无需再处理解密和验签逻辑。只需保证运行环境具备访问公网能力即可,无需提供公网 IP 或域名。无需部署防火墙和配置白名单。 |
| 将事件发送至开发者服务器 | 传统的 Webhook 模式,该方式需要你提供用于接收事件消息的服务器公网地址。后续当应用订阅的事件发生时,开放平台会向服务器的公网地址发送 HTTP POST 请求,请求内包含事件数据。 |

package com.lark.oapi.sample.ws;
import com.lark.oapi.core.request.EventReq;
import com.lark.oapi.core.utils.Jsons;
import com.lark.oapi.event.CustomEventHandler;
import com.lark.oapi.event.EventDispatcher;
import com.lark.oapi.service.im.ImService;
import com.lark.oapi.service.im.v1.model.P2MessageReceiveV1;
import com.lark.oapi.ws.Client;
import java.nio.charset.StandardCharsets;
public class Sample {
// onP2MessageReceiveV1 为接收消息 v2.0;onCustomizedEvent 内的 message 为接收消息 v1.0。
private static final EventDispatcher EVENT_HANDLER = EventDispatcher.newBuilder("", "")
.onP2MessageReceiveV1(new ImService.P2MessageReceiveV1Handler() {
@Override
public void handle(P2MessageReceiveV1 event) throws Exception {
System.out.printf("[ onP2MessageReceiveV1 access ], data: %s\n", Jsons.DEFAULT.toJson(event.getEvent()));
}
})
.onCustomizedEvent("这里填入你要自定义订阅的 event 的 key,例如 out_approval", new CustomEventHandler() {
@Override
public void handle(EventReq event) throws Exception {
System.out.printf("[ onCustomizedEvent access ], type: message, data: %s\n", new String(event.getBody(), StandardCharsets.UTF_8));
}
})
.build();
public static void main(String[] args) {
Client cli = new Client.Builder("YOUR_APP_ID", "YOUR_APP_SECRET")
.eventHandler(EVENT_HANDLER)
.build();
cli.start();
}
}
onP2MessageReceiveV1 注册接收消息事件回调时,P2便对应的是 v2.0 版本事件结构。



<dependency>
<artifactId>oapi-sdk-servlet-ext</artifactId>
<groupId>com.larksuite.oapi</groupId>
<version>1.0.0-rc3</version>
<exclusions>
<exclusion>
<artifactId>oapi-sdk</artifactId>
<groupId>com.larksuite.oapi</groupId>
</exclusion>
</exclusions>
</dependency>import com.lark.oapi.sdk.servlet.ext.ServletAdapter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class AppStartup {
public static void main(String[] args) {
SpringApplication.run(AppStartup.class, args);
}
// 注入扩展实例到 IOC 容器
@Bean
public ServletAdapter getServletAdapter() {
return new ServletAdapter();
}
}import com.lark.oapi.core.utils.Jsons;
import com.lark.oapi.event.EventDispatcher;
import com.lark.oapi.service.contact.v3.ContactService;
import com.lark.oapi.service.contact.v3.model.P2UserCreatedV3;
import com.lark.oapi.service.im.v1.ImService;
import com.lark.oapi.service.im.v1.model.P1MessageReadV1;
import com.lark.oapi.service.im.v1.model.P2MessageReadV1;
import com.lark.oapi.service.im.v1.model.P2MessageReceiveV1;
import com.lark.oapi.sdk.servlet.ext.ServletAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class EventController {
//1. 注册消息处理器
private final EventDispatcher EVENT_DISPATCHER = EventDispatcher.newBuilder("verificationToken",
"encryptKey")
.onP2MessageReceiveV1(new ImService.P2MessageReceiveV1Handler() {
@Override
public void handle(P2MessageReceiveV1 event) {
System.out.println(Jsons.DEFAULT.toJson(event));
System.out.println(event.getRequestId());
}
}).onCustomizedEvent("这里填入你要自定义订阅的 event 的 key,例如 out_approval", new CustomEventHandler() {
@Override
public void handle(EventReq event) {
System.out.println("body:" + new String(event.getBody()));
System.out.println("plain:" + event.getPlain());
}
})
.build();
//2. 注入 ServletAdapter 实例
@Autowired
private ServletAdapter servletAdapter;
//3. 创建路由处理器
@RequestMapping("/webhook/event")
public void event(HttpServletRequest request, HttpServletResponse response)
throws Throwable {
//3.1 回调扩展包提供的事件回调处理器
servletAdapter.handleEvent(request, response, EVENT_DISPATCHER);
}
}
package com.lark.oapi.sample.event;
import com.lark.oapi.core.request.RequestOptions;
import com.lark.oapi.core.utils.Jsons;
import com.lark.oapi.event.EventDispatcher;
import com.lark.oapi.service.im.v1.ImService.P2MessageReceiveV1Handler;
import com.lark.oapi.service.im.v1.enums.ReceiveIdTypeEnum;
import com.lark.oapi.service.im.v1.model.CreateMessageReq;
import com.lark.oapi.service.im.v1.model.CreateMessageReqBody;
import com.lark.oapi.service.im.v1.model.P2MessageReceiveV1;
import com.lark.oapi.sdk.servlet.ext.ServletAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class EventController {
//1. 注册消息处理器
private final EventDispatcher EVENT_DISPATCHER = EventDispatcher.newBuilder("", "")
.onP2MessageReceiveV1(new P2MessageReceiveV1Handler() {
@Override
public void handle(P2MessageReceiveV1 event) throws Exception {
// 处理消息
System.out.println(Jsons.DEFAULT.toJson(event));
System.out.println(event.getRequestId());
// 获取企业或组织 key
String tenantKey = event.getTenantKey();
// 发送请求
client.im().message().create(CreateMessageReq.newBuilder()
.receiveIdType(ReceiveIdTypeEnum.OPEN_ID)
.createMessageReqBody(CreateMessageReqBody.newBuilder()
.content("text")
.build())
.build()
, RequestOptions.newBuilder()
.tenantKey(tenantKey)
.build());
}
}).build();
//2. 注入 ServletAdapter 实例
@Autowired
private ServletAdapter servletAdapter;
//3. 创建路由处理器
@RequestMapping("/webhook/event")
public void event(HttpServletRequest request, HttpServletResponse response)
throws Throwable {
//3.1 回调扩展包提供的事件回调处理器
servletAdapter.handleEvent(request, response, EVENT_DISPATCHER);
}
}