TelegramBot 框架设计

1.添加依赖

添加的依赖主要是减少一些重复代码,也可以忽略此步骤.

  1. 使用WebClient作为与Telegram API交互的HTTP客户端

    使用其它客户端也可以

1
2
3
4
5
6
7
8
9
10
11
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-webflux
implementation 'org.springframework.boot:spring-boot-starter-webflux:3.4.1'

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-webflux -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>3.4.1</version>
</dependency>

// 版本号视自身情况设置
  1. 使用开源项目已设计好的工具库

    自行设计也可以

1
2
3
4
5
6
7
8
9
10
11
// https://mvnrepository.com/artifact/org.telegram/telegrambots-meta
implementation 'org.telegram:telegrambots-meta:8.2.0'

<!-- https://mvnrepository.com/artifact/org.telegram/telegrambots-meta -->
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-meta</artifactId>
<version>8.2.0</version>
</dependency>

// 版本号视自身情况设置

项目地址: https://github.com/rubenlagus/TelegramBots 特别鸣谢

2.自定义WebClient

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
@Configuration
public class WebClientConfig {
private static final String BOT_URL = "https://api.telegram.org"; // Telegram API 默认 URL
@Autowired
private ApplicationContext applicationContext;

/**
* 连接池管理
* @return
*/
private ConnectionProvider connectionProvider() {
ConnectionProvider connectionProvider = ConnectionProvider.builder("tgBotWebClient")
.maxConnections(100)
.pendingAcquireMaxCount(1000)
.pendingAcquireTimeout(Duration.ofMillis(1000))
.maxIdleTime(Duration.ofSeconds(60))
.maxLifeTime(Duration.ofSeconds(120))
.build();
System.out.println("ConnectionProvider bean created: " + connectionProvider);
return connectionProvider;
}

/**
* HttpClient配置
* @return
*/
@Bean
public HttpClient httpClient() {
// 检查是否已存在 ConnectionProvider
Map<String, ConnectionProvider> existingProviders =
applicationContext.getBeansOfType(ConnectionProvider.class);
ConnectionProvider provider;
if (!existingProviders.isEmpty()) {
provider = existingProviders.values().iterator().next();
} else {
provider = connectionProvider(); // 创建新的连接池
}
return HttpClient.create(provider)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
.responseTimeout(Duration.ofSeconds(5L))
.doOnConnected(connection -> {
connection.addHandlerLast(new ReadTimeoutHandler(5))
.addHandlerLast(new WriteTimeoutHandler(5));
})
.wiretap(true)
.compress(true)
.followRedirect(true)
.keepAlive(true);
}

/**
* 初始化WebClient
* @param httpClient
* @return
*/
@Bean("tgBotWebClient")
public WebClient tgBotWebClient(HttpClient httpClient) {
return WebClient.builder()
.baseUrl(BOT_URL)
.clientConnector(new ReactorClientHttpConnector(httpClient))
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}
}

3.根据开源库设计基础文件

  • 实现TelegramClient中的方法(主要是实现AbstractTelegramClient中的方法)

    其实不实现也可以,添加关联依赖也可以

1
2
3
4
5
6
7
8
9
// https://mvnrepository.com/artifact/org.telegram/telegrambots-client
implementation 'org.telegram:telegrambots-client:8.2.0'

<!-- https://mvnrepository.com/artifact/org.telegram/telegrambots-client -->
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-client</artifactId>
<version>8.2.0</version>
</dependency>
  • 设计TelegramBot工具类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Setter;
import lombok.SneakyThrows;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.telegram.telegrambots.meta.api.methods.botapimethods.BotApiMethod;
import org.telegram.telegrambots.meta.api.methods.botapimethods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.methods.groupadministration.SetChatPhoto;
import org.telegram.telegrambots.meta.api.methods.send.*;
import org.telegram.telegrambots.meta.api.methods.stickers.*;
import org.telegram.telegrambots.meta.api.methods.updates.SetWebhook;
import org.telegram.telegrambots.meta.api.methods.updatingmessages.EditMessageMedia;
import org.telegram.telegrambots.meta.api.objects.File;
import org.telegram.telegrambots.meta.api.objects.media.*;
import org.telegram.telegrambots.meta.api.objects.media.paid.InputPaidMedia;
import org.telegram.telegrambots.meta.api.objects.media.paid.InputPaidMediaVideo;
import org.telegram.telegrambots.meta.api.objects.message.Message;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
* Telegram Bot
*/
@Component
public class TGBots extends AbstractTelegramClient {
@Setter
private String Token;
private String BaseUrl = null;
@Qualifier("tgBotWebClient")
private final WebClient webClient;
private final ObjectMapper objectMapper;

public TGBots(WebClient webClient) {
this.webClient = webClient; // 自定义的WebClient
this.objectMapper = new CustomObjectMapper(); // 自定义ObjectMapper(主要用于去除开源项目实体对象类不需要的字段)
}

/**
* 自定义BaseUrl(本地服务器API)
* @param url url
* @return TGBots
*/
public TGBots setBaseUrl(String url) {
this.BaseUrl = url;
return this;
}

/**
* 加载BotWebClient(主要用于自定义BaseUrl时重新配置WebClient)
* @return WebClient
*/
private WebClient loadWebClient() {
return this.BaseUrl == null ? webClient : webClient.mutate().baseUrl(this.BaseUrl).build();
}

/**
* 根据自身情况实现此方法
* @param method
* @return
* @param <T>
* @param <Method>
* @throws TelegramApiException
*/
@SneakyThrows
@Override
public <T extends Serializable, Method extends BotApiMethod<T>> CompletableFuture<T> executeAsync(Method method) throws TelegramApiException {
if (method == null) {
throw new TelegramApiException("Parameter method can not be null");
} else {
method.validate();

String body = this.objectMapper.writeValueAsString(method);
return this.sendRequest(method, body);
}
}

/**
* 发送请求
* @param method
* @param body
* @return
* @param <T>
* @param <Method>
*/
private <T extends Serializable, Method extends PartialBotApiMethod<T>> CompletableFuture<T> sendRequest(Method method, String body) {
CompletableFuture<T> future = new CompletableFuture<>();
this.loadWebClient()
.post()
.uri("/bot{token}/{method}", Token, method.getMethod())
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(body)
.retrieve()
.bodyToMono(String.class)
.doOnSuccess(response -> {
try {
LogUtils.debug(null, 0, "TG-API", method.getMethod(), response);
T result = method.deserializeResponse(response);
future.complete(result);
} catch (Exception e) {
future.completeExceptionally(e);
}
})
.doOnError(error -> {
LogUtils.error(null, 0, "TG-API", method.getMethod(), error.getMessage());
future.completeExceptionally(error);
})
.subscribe();
return future;
}
}

4.使用示例

  • 接收Telegram更新消息

    具体视自身框架设计,后续业务处理可以获取到即可

  • 使用TGBots

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Service
public class BotService {
private final TGBots tgBots;
public BotService(TGBots tgBots) {
this.tgBots = tgBots;
}
public void init(Update update, ResponseObject resp) throws Exception {
this.tgBots.setToken(""); // 视自身情况设置Token
// 处理文本消息
if (update.hasMessage() && update.getMessage().hasText()) {
this.tgBots.execute(); // 调用工具类中的execute执行回复
} else {
// 处理其它消息
this.tgBots.execute(); // 调用工具类中的execute执行回复
}
}
}

TGBots工具类中没有execute()方法是因为父类中存在此方法