|
| 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