Skip to content

Commit ed636f1

Browse files
author
litongjava
committed
add tio-boot example for exception and push to wechat
1 parent d1381c2 commit ed636f1

File tree

3 files changed

+298
-10
lines changed

3 files changed

+298
-10
lines changed

docs/.vuepress/config/sidebar-zh.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,6 @@
171171
{
172172
"title": "99_案例",
173173
"collapsable": false,
174-
"children": ["99_案例/01.md"]
174+
"children": ["99_案例/01.md", "99_案例/02.md"]
175175
}
176176
]

docs/zh/05_web开发/15.md

+28-9
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,35 @@ Tio-Boot 提供了全局异常处理器的功能,允许你在应用程序中
1111
首先,你需要创建一个自定义的异常处理器类。这个类需要实现 `TioBootExceptionHandler` 接口,并覆盖 `handler` 方法。在 `handler` 方法中,你可以定义当异常发生时,如何处理这些异常。
1212

1313
```java
14+
import java.io.PrintWriter;
15+
import java.io.StringWriter;
16+
import java.util.Map;
17+
1418
import com.litongjava.tio.boot.exception.TioBootExceptionHandler;
1519
import com.litongjava.tio.http.common.HttpRequest;
20+
1621
import lombok.extern.slf4j.Slf4j;
1722

1823
@Slf4j
19-
public class MyExceptionHandler implements TioBootExceptionHandler {
24+
public class GlobalExceptionHadler implements TioBootExceptionHandler {
25+
2026
@Override
2127
public void handler(HttpRequest request, Throwable e) {
22-
String requestURI = request.getRequestURI();
23-
log.error("{},{}", requestURI, e);
28+
StringBuffer requestURL = request.getRequestURL();
29+
Map<String, String> headers = request.getHeaders();
30+
String bodyString = request.getBodyString();
31+
32+
// 获取完整的堆栈跟踪
33+
StringWriter sw = new StringWriter();
34+
PrintWriter pw = new PrintWriter(sw);
35+
e.printStackTrace(pw);
36+
String stackTrace = sw.toString();
37+
38+
log.info("{},{},{},{}", requestURL.toString(), headers, bodyString, stackTrace);
39+
2440
}
2541
}
42+
2643
```
2744

2845
在这个例子中,`MyExceptionHandler` 记录了请求的 URI 和异常信息。
@@ -34,17 +51,17 @@ public class MyExceptionHandler implements TioBootExceptionHandler {
3451
```java
3552
import com.litongjava.jfinal.aop.annotation.AConfiguration;
3653
import com.litongjava.jfinal.aop.annotation.AInitialization;
37-
import com.litongjava.tio.boot.exception.TioBootExceptionHandler;
3854
import com.litongjava.tio.boot.server.TioBootServer;
55+
import com.litongjava.tio.web.hello.handler.GlobalExceptionHadler;
3956

4057
@AConfiguration
4158
public class TioBootServerConfiguration {
4259
@AInitialization
4360
public void config() {
44-
TioBootExceptionHandler exceptionHandler = new MyExceptionHandler();
45-
TioBootServer.me().setExceptionHandler(exceptionHandler);
61+
TioBootServer.me().setExceptionHandler(new GlobalExceptionHadler());
4662
}
4763
}
64+
4865
```
4966

5067
在这个配置类中,`@AConfiguration` 表明这是一个配置类,`@AInitialization` 标记的方法 `config` 会在服务器启动时执行,设置了我们自定义的异常处理器。
@@ -97,9 +114,8 @@ public class ExceptionApp {
97114
通过查看应用程序的日志输出,你应该能看到由 `MyExceptionHandler` 记录的异常信息,这表明全局异常处理器正常工作。
98115

99116
```
100-
09:57:09.965 [tio-group-8] ERROR com.litongjava.tio.web.hello.config.MyExceptionHandler - /exception,{}
101-
java.lang.ArithmeticException: / by zero
102-
at com.litongjava.tio.web.hello.controller.ExceptionController.index(ExceptionController.java:10)
117+
2024-02-04 10:12:36.683 [tio-group-3] INFO c.l.t.w.h.h.GlobalExceptionHadler.handler:27 - /exception,{sec-fetch-mode=navigate, sec-fetch-site=none, accept-language=en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7, cookie=PHPSESSID=45ab823cf4424734b764d8888b77130e, sec-fetch-user=?1, accept=text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7, sec-ch-ua="Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121", sec-ch-ua-mobile=?0, sec-ch-ua-platform="Windows", host=localhost, upgrade-insecure-requests=1, connection=keep-alive, cache-control=max-age=0, accept-encoding=gzip, deflate, br, user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36, sec-fetch-dest=document},null,java.lang.ArithmeticException: / by zero
118+
at com.litongjava.tio.web.hello.controller.ExceptionController.index(ExceptionController.java:9)
103119
at com.litongjava.tio.web.hello.controller.ExceptionControllerMethodAccess.invoke(Unknown Source)
104120
at com.esotericsoftware.reflectasm.MethodAccess.invoke(MethodAccess.java:39)
105121
at com.litongjava.tio.boot.http.handler.HandlerDispatcher.executeAction(HandlerDispatcher.java:73)
@@ -124,4 +140,7 @@ java.lang.ArithmeticException: / by zero
124140

125141
### 其他
126142

143+
测试源码
144+
https://github.com/litongjava/java-ee-tio-boot-study/tree/main/tio-boot-latest-study/tio-boot-web-exception-handler-demo01
145+
127146
你可以通过自定义全局异常处理器将异常存入数据库或者发送的微信群

docs/zh/99_案例/02.md

+269
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
# tio-boot 案例 异常捕获与企业微信群通知案例
2+
3+
## 概述
4+
5+
本案例旨在介绍如何在 `tio-boot` 框架中实现全局异常捕获,并将异常信息实时推送到企业微信群,从而实现及时的异常告警和问题跟踪。实现这一功能,涉及到以下关键知识点:
6+
7+
- `tio-boot` 的全局异常处理机制。
8+
- `tio-boot` 的 notification(通知)组件的使用。
9+
10+
## 开发步骤
11+
12+
### 1. 配置 Maven 依赖(pom.xml)
13+
14+
在项目的 `pom.xml` 文件中,首先配置项目属性和依赖,确保项目编译和运行所需的环境和库都能正确加载。
15+
16+
#### 代码片段:pom.xml
17+
18+
```
19+
<properties>
20+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
21+
<java.version>1.8</java.version>
22+
<maven.compiler.source>${java.version}</maven.compiler.source>
23+
<maven.compiler.target>${java.version}</maven.compiler.target>
24+
<tio-boot.version>1.3.9</tio-boot.version>
25+
</properties>
26+
<dependencies>
27+
<dependency>
28+
<groupId>com.litongjava</groupId>
29+
<artifactId>tio-boot</artifactId>
30+
<version>${tio-boot.version}</version>
31+
</dependency>
32+
<dependency>
33+
<groupId>org.projectlombok</groupId>
34+
<artifactId>lombok</artifactId>
35+
<version>1.18.30</version>
36+
<scope>provided</scope>
37+
</dependency>
38+
<dependency>
39+
<groupId>com.squareup.okhttp3</groupId>
40+
<artifactId>okhttp</artifactId>
41+
<version>3.14.9</version>
42+
</dependency>
43+
</dependencies>
44+
45+
<profiles>
46+
<!-- 开发环境 -->
47+
<profile>
48+
<id>development</id>
49+
<activation>
50+
<activeByDefault>true</activeByDefault>
51+
</activation>
52+
<dependencies>
53+
<dependency>
54+
<groupId>ch.qos.logback</groupId>
55+
<artifactId>logback-classic</artifactId>
56+
<version>1.2.3</version>
57+
</dependency>
58+
</dependencies>
59+
</profile>
60+
61+
<!-- 生产环境 -->
62+
<profile>
63+
<id>production</id>
64+
<dependencies>
65+
<dependency>
66+
<groupId>ch.qos.logback</groupId>
67+
<artifactId>logback-classic</artifactId>
68+
<version>1.2.3</version>
69+
</dependency>
70+
</dependencies>
71+
<build>
72+
<plugins>
73+
<plugin>
74+
<groupId>org.springframework.boot</groupId>
75+
<artifactId>spring-boot-maven-plugin</artifactId>
76+
<version>2.7.4</version>
77+
<configuration>
78+
<mainClass>${main.class}</mainClass>
79+
<excludeGroupIds>org.projectlombok</excludeGroupIds>
80+
</configuration>
81+
<!-- 设置执行目标 -->
82+
<executions>
83+
<execution>
84+
<goals>
85+
<goal>repackage</goal>
86+
</goals>
87+
</execution>
88+
</executions>
89+
</plugin>
90+
</plugins>
91+
</build>
92+
</profile>
93+
</profiles>
94+
```
95+
96+
### 2. 配置应用属性(app.properties)
97+
98+
设置企业微信的 Webhook URL,以便通知服务能够将异常信息发送到指定的微信群。
99+
100+
#### 文件内容:app.properties
101+
102+
```
103+
app.name=tio-boot-example-push-exception-to-wecome-demo
104+
notification.webhook.url=https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxx
105+
```
106+
107+
### 3. 创建应用启动类
108+
109+
初始化并启动 `tio-boot` 应用,设置组件扫描的包路径。
110+
111+
#### 代码片段:ExceptionPushToWecomeApp.java
112+
113+
```
114+
package com.litongjava.tio.web.hello;
115+
116+
import com.litongjava.jfinal.aop.annotation.AComponentScan;
117+
import com.litongjava.tio.boot.TioApplication;
118+
119+
@AComponentScan
120+
public class ExceptionPushToWecomeApp {
121+
public static void main(String[] args) {
122+
long start = System.currentTimeMillis();
123+
TioApplication.run(ExceptionPushToWecomeApp.class, args);
124+
long end = System.currentTimeMillis();
125+
System.out.println((end - start) + "ms");
126+
}
127+
}
128+
129+
```
130+
131+
### 4. 实现全局异常处理器
132+
133+
创建自定义的异常处理器 `GlobalExceptionHadler`,在处理器中捕获异常并构建告警信息,最后通过企业微信 Webhook 接口发送到微信群。
134+
135+
```
136+
import java.io.PrintWriter;
137+
import java.io.StringWriter;
138+
import java.util.Date;
139+
import java.util.Map;
140+
141+
import com.litongjava.tio.boot.constatns.ConfigKeys;
142+
import com.litongjava.tio.boot.exception.TioBootExceptionHandler;
143+
import com.litongjava.tio.http.common.HttpRequest;
144+
import com.litongjava.tio.utils.environment.EnvironmentUtils;
145+
import com.litongjava.tio.utils.network.IpUtils;
146+
import com.litongjava.tio.utils.notification.NotifactionWarmModel;
147+
import com.litongjava.tio.utils.notification.NotificationUtils;
148+
149+
import lombok.extern.slf4j.Slf4j;
150+
151+
@Slf4j
152+
public class GlobalExceptionHadler implements TioBootExceptionHandler {
153+
154+
@Override
155+
public void handler(HttpRequest request, Throwable e) {
156+
StringBuffer requestURL = request.getRequestURL();
157+
Map<String, String> headers = request.getHeaders();
158+
String bodyString = request.getBodyString();
159+
160+
// 获取完整的堆栈跟踪
161+
StringWriter sw = new StringWriter();
162+
PrintWriter pw = new PrintWriter(sw);
163+
e.printStackTrace(pw);
164+
String stackTrace = sw.toString();
165+
166+
log.info("{},{},{},{}", requestURL.toString(), headers, bodyString, stackTrace);
167+
NotifactionWarmModel model = new NotifactionWarmModel();
168+
169+
String localIp = IpUtils.getLocalIp();
170+
model.setAppGroupName("tio-boot");
171+
model.setAppName(EnvironmentUtils.get(ConfigKeys.APP_NAME));
172+
model.setWarningName("运行异常");
173+
model.setLevel("普通级别");
174+
175+
model.setDeviceName(localIp);
176+
model.setTime(new Date());
177+
model.setContent(requestURL + "\n" + stackTrace);
178+
179+
NotificationUtils.sendWarm(model);
180+
181+
}
182+
}
183+
```
184+
185+
### 5. 配置异常处理器
186+
187+
在 TioBootServer 的配置类中注册自定义的异常处理器。
188+
189+
#### 代码片段:TioBootServerConfiguration.java
190+
191+
```
192+
import com.litongjava.jfinal.aop.annotation.AConfiguration;
193+
import com.litongjava.jfinal.aop.annotation.AInitialization;
194+
import com.litongjava.tio.boot.server.TioBootServer;
195+
196+
@AConfiguration
197+
public class TioBootServerConfiguration {
198+
199+
@AInitialization
200+
public void config() {
201+
TioBootServer.me().setExceptionHandler(new GlobalExceptionHadler());
202+
}
203+
}
204+
205+
```
206+
207+
### 6. 创建触发异常的控制器
208+
209+
开发一个简单的控制器,用于模拟触发异常的场景。
210+
211+
```
212+
package com.litongjava.tio.web.hello.controller;
213+
214+
import com.litongjava.tio.http.server.annotation.RequestPath;
215+
216+
@RequestPath("/exception")
217+
public class ExceptionController {
218+
219+
@RequestPath()
220+
public Integer index() {
221+
return (0 / 0);
222+
}
223+
224+
}
225+
226+
```
227+
228+
### 7. 测试与验证
229+
230+
启动应用并访问 `/exception` 路径,触发异常。如果配置正确,你应该能在指定的企业微信群收到异常告警信息。
231+
232+
#### 企业微信群收到的告警信息示例:
233+
234+
```
235+
Alarm Time : 2024-02-04 10:43:08
236+
App Group Name : tio-boot
237+
App Name : tio-boot-example-push-exception-to-wecome-demo
238+
Alarm name : 运行异常
239+
Alarm Level : 普通级别
240+
Alarm Device : 70-66-55-B9-28-B9
241+
Alarm Content : http://null/exception
242+
java.lang.ArithmeticException: / by zero
243+
at com.litongjava.tio.web.hello.controller.ExceptionController.index(ExceptionController.java:10)
244+
at com.litongjava.tio.web.hello.controller.ExceptionControllerMethodAccess.invoke(Unknown Source)
245+
at com.esotericsoftware.reflectasm.MethodAccess.invoke(MethodAccess.java:39)
246+
at com.litongjava.tio.boot.http.handler.HandlerDispatcher.executeAction(HandlerDispatcher.java:73)
247+
at com.litongjava.tio.boot.http.handler.DefaultHttpRequestHandlerDispather.processDynamic(DefaultHttpRequestHandlerDispather.java:374)
248+
at com.litongjava.tio.boot.http.handler.DefaultHttpRequestHandlerDispather.handler(DefaultHttpRequestHandlerDispather.java:305)
249+
at com.litongjava.tio.http.server.HttpServerAioHandler.handler(HttpServerAioHandler.java:94)
250+
at com.litongjava.tio.boot.server.TioBootServerHandler.handler(TioBootServerHandler.java:140)
251+
at com.litongjava.tio.core.task.HandlerRunnable.handler(HandlerRunnable.java:67)
252+
at com.litongjava.tio.core.task.DecodeRunnable.handler(DecodeRunnable.java:55)
253+
at com.litongjava.tio.core.task.DecodeRunnable.decode(DecodeRunnable.java:205)
254+
at com.litongjava.tio.core.ReadCompletionHandler.completed(ReadCompletionHandler.java:83)
255+
at com.litongjava.tio.core.ReadCompletionHandler.completed(ReadCompletionHandler.java:21)
256+
at sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:126)
257+
at sun.nio.ch.Invoker$2.run(Invoker.java:218)
258+
at sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112)
259+
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
260+
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
261+
at java.lang.Thread.run(Thread.java:745)
262+
263+
```
264+
265+
### 结语
266+
267+
通过上述步骤,我们演示了如何在 `tio-boot` 框架中实现异常捕获,并将异常信息实时推送到企业微信群。这种实时监控和通知机制对于及时发现并处理生产环境中的问题至关重要。
268+
269+
### 测试代码地址

0 commit comments

Comments
 (0)