因项目需要,需要配置spring的全局异常消息捕获,并进行钉钉消息推送,使用钉钉的机器人进行消息群推送,以下是钉钉机器人的配置使用
在进行钉钉消息推送的时候,本地测试消息推送无异常,但项目已启动进行异常消息推送的时候,总是报错:
com.dingtalk.api.DingTalkClient
查询了很多资料,排查了很多地方,并没有找到具体原因,本身使用的是钉钉的sdk,已经加载到项目中了,使用的方式按照以下文章进行的配置:
因为项目本身加载了众多淘宝系的sdk,经推测可能是众多com.top包下的类及方法重复,使程序并不明白具体的指向,但仅仅是推测并未找到具体原因,因项目进度问题,无法继续深入研究,所以在查看了钉钉sdk的底层代码后,具体使用自定义的方法进行钉钉的消息推送
钉钉的消息推送是post请求,前面是关于钉钉的请求源码分析,后面是我仿照其源码编写的请求工具类,可直接使用

上面这行代码在
package com.dingtalk.api;包下的 DefaultDingTalkClient类中
红色框中圈起来的是重点代码,
fullUrl:这个参数是请求的url地址,这个是你配置钉钉机器人给的,url需要是全的后面带token jsonParams:这个是里面是请求的参数和具体内容,具体可以debug走一遍,注意是要转为json的格式
connectTimeout readTimeout 这两个参数具体值类中有配置,固定参数

上面这个方法的作用其实是拼接了请求的格式,即
ctype== "application/json;charset=UTF-8" ;
然后把请求的参数和具体内容转换为字节数组,然后调用dopost方法

从这段代码中可以看出来,进行了钉钉的消息推送并获取返回值,以上方法就是钉钉消息推送的具体代码内容,仿照其内容进行编写即可实现
从上面的代码看出,使用的httpclient进行的请求和响应,所以首先要加载其jar包
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
使用pom进行配置
spring或者springboot的全局异常捕获,可以使用注解的方式进行捕获,但spring需要记得配置包扫描
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class ExceptionHandle {
@ExceptionHandler(value=Exception.class)
public Boolean exceptionHandler(Exception e){
//全局捕获异常,并进行钉钉异常消息推送
DingTalkUtils.dingTalkSendException(e);
return false;
}
}
DingTalkUtils是我自定义的工具类:自定义关键词可更换,具体在钉钉机器人上设置.钉钉的消息可以分为多种,支持text,支持markdown,支持url,这里我使用的是最简单text,方便,只是为了推送个异常消息,如果有需要可以自行更改
import org.apache.commons.lang.StringUtils;
import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
/**
* @description: 钉钉机器人
* @author:
* @date: 2021-09-09 10:03
* @version: 1.0
*/
public class DingTalkUtils {
private static boolean ignoreSSLCheck = true;
private static boolean ignoreHostCheck = true;
private static String URL="替换自己的url";
private static String Ctype = "application/json;charset=UTF-8";
/**
* @description:钉钉机器人异常信息推送
* @attention:监控报警是我自定义的关键词,使用此关键词钉钉才会推送,这个是钉钉机器人的自定义配置
* @date: 2021/7/15 12:19
* @param: e
* @return: void
*/
public static void dingTalkSendException(Exception e){
//得到异常棧的首个元素
StackTraceElement stackTrace = e.getStackTrace()[0];
StringBuilder sb=new StringBuilder();
sb.append("监控报警报错信息:"+e.getMessage()+"\n")
.append("报错文件:"+stackTrace.getFileName()+"\n")
.append("报错行号:"+stackTrace.getLineNumber()+"\n")
.append("报错方法:"+stackTrace.getMethodName()+"\n")
.append("报错Class:"+stackTrace.getClass()+"\n")
.append("报错ClassName:"+stackTrace.getClassName());
Map<String, Object> jsonParams = new HashMap();
Map<String,Boolean> atMap=new HashMap<>();
atMap.put("isAtAll",true);
jsonParams.put("at",atMap);
Map<String,String> contextMap=new HashMap<>();
contextMap.put("content",sb.toString());
jsonParams.put("text",contextMap);
jsonParams.put("msgtype","text");
String body = JsonUtils.objectToJson(jsonParams);
byte[] content = body.getBytes(StandardCharsets.UTF_8);
try {
HttpResponseData httpResponseData = _doPost(URL, Ctype, content, 15000, 30000, (Map) null, (Proxy) null);
System.out.println("钉钉机器人异常通知返回信息:"+JsonUtils.objectToJson(httpResponseData.getBody()));
}catch (Exception exception){
exception.printStackTrace();
}
// System.out.println("钉钉机器人异常通知返回信息:"+response.getBody());
}
public static HttpResponseData _doPost(String url, String ctype, byte[] content, int connectTimeout, int readTimeout, Map<String, String> headerMap, Proxy proxy) throws Exception {
HttpURLConnection conn = null;
OutputStream out = null;
String rsp = null;
HttpResponseData data = new HttpResponseData();
try {
conn = getConnection(new URL(url), "POST", ctype, headerMap, proxy);
conn.setConnectTimeout(connectTimeout);
conn.setReadTimeout(readTimeout);
out = conn.getOutputStream();
out.write(content);
rsp = getResponseAsString(conn);
data.setBody(rsp);
Map<String, List<String>> headers = conn.getHeaderFields();
data.setHeaders(headers);
} finally {
if (out != null) {
out.close();
}
if (conn != null) {
conn.disconnect();
}
}
return data;
}
private static HttpURLConnection getConnection(URL url, String method, String ctype, Map<String, String> headerMap, Proxy proxy) throws IOException {
HttpURLConnection conn = null;
if (proxy == null) {
conn = (HttpURLConnection)url.openConnection();
} else {
conn = (HttpURLConnection)url.openConnection(proxy);
}
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection connHttps = (HttpsURLConnection)conn;
if (ignoreSSLCheck) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init((KeyManager[])null, new TrustManager[]{new WebV2Utils.TrustAllTrustManager()}, new SecureRandom());
connHttps.setSSLSocketFactory(ctx.getSocketFactory());
connHttps.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
} catch (Exception var8) {
throw new IOException(var8.toString());
}
} else if (ignoreHostCheck) {
connHttps.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
}
conn = connHttps;
}
((HttpURLConnection)conn).setRequestMethod(method);
((HttpURLConnection)conn).setDoInput(true);
((HttpURLConnection)conn).setDoOutput(true);
if (headerMap != null && headerMap.get("TOP_HTTP_DNS_HOST") != null) {
((HttpURLConnection)conn).setRequestProperty("Host", (String)headerMap.get("TOP_HTTP_DNS_HOST"));
} else {
((HttpURLConnection)conn).setRequestProperty("Host", url.getHost());
}
((HttpURLConnection)conn).setRequestProperty("Accept", "text/xml,text/javascript");
((HttpURLConnection)conn).setRequestProperty("User-Agent", "top-sdk-java");
((HttpURLConnection)conn).setRequestProperty("Content-Type", ctype);
if (headerMap != null) {
Iterator var9 = headerMap.entrySet().iterator();
while(var9.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry)var9.next();
if (!"TOP_HTTP_DNS_HOST".equals(entry.getKey())) {
((HttpURLConnection)conn).setRequestProperty((String)entry.getKey(), (String)entry.getValue());
}
}
}
return (HttpURLConnection)conn;
}
protected static String getResponseAsString(HttpURLConnection conn) throws IOException {
String charset = getResponseCharset(conn.getContentType());
if (conn.getResponseCode() < 400) {
String contentEncoding = conn.getContentEncoding();
return "gzip".equalsIgnoreCase(contentEncoding) ? getStreamAsString(new GZIPInputStream(conn.getInputStream()), charset) : getStreamAsString(conn.getInputStream(), charset);
} else {
if (conn.getResponseCode() == 400) {
InputStream error = conn.getErrorStream();
if (error != null) {
return getStreamAsString(error, charset);
}
}
throw new IOException(conn.getResponseCode() + " " + conn.getResponseMessage());
}
}
public static String getStreamAsString(InputStream stream, String charset) throws IOException {
try {
Reader reader = new InputStreamReader(stream, charset);
StringBuilder response = new StringBuilder();
char[] buff = new char[1024];
boolean var5 = false;
int read;
while((read = reader.read(buff)) > 0) {
response.append(buff, 0, read);
}
String var6 = response.toString();
return var6;
} finally {
if (stream != null) {
stream.close();
}
}
}
public static String getResponseCharset(String ctype) {
String charset = "UTF-8";
if (!StringUtils.isEmpty(ctype)) {
String[] params = ctype.split(";");
String[] var3 = params;
int var4 = params.length;
for(int var5 = 0; var5 < var4; ++var5) {
String param = var3[var5];
param = param.trim();
if (param.startsWith("charset")) {
String[] pair = param.split("=", 2);
if (pair.length == 2 && !StringUtils.isEmpty(pair[1])) {
charset = pair[1].trim();
}
break;
}
}
}
return charset;
}
}
这个是相应的实体,如果不需要返回请求是否成功,具体看情况是否配置
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
* @description:
* @author:
* @date: 2021-09-08 10:37
* @version: 1.0
*/
public class HttpResponseData implements Serializable {
private static final long serialVersionUID = -6975537945058755923L;
private String body;
private Map<String, List<String>> headers;
public HttpResponseData() {
}
public String getBody() {
return this.body;
}
public void setBody(String body) {
this.body = body;
}
public Map<String, List<String>> getHeaders() {
return this.headers;
}
public void setHeaders(Map<String, List<String>> headers) {
this.headers = headers;
}
}
这个是上面请求会使用到工具类i,其实可以和上面的请求工具类合并到一起,但是我懒,就没改。。。。。。
package com.irs.util;
import javax.net.ssl.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* @description:
* @author:
* @date: 2021-09-09 14:52
* @version: 1.0
*/
public class WebV2Utils {
private WebV2Utils() {
}
public static class TrustAllTrustManager implements X509TrustManager {
public TrustAllTrustManager() {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
}
}
以上就可以实现,项目的全局异常捕获,比较适合项目上线了,有错误可以及时通知到相关人员
SpringBoot全局异常处理与钉钉消息推送实践
本文介绍了如何在SpringBoot项目中配置全局异常捕获,并结合钉钉机器人进行异常消息推送。详细讲解了创建钉钉机器人、设置IP白名单、处理HTTP请求以发送钉钉消息的过程,以及在项目中遇到的问题和解决方案。此外,还分享了相关配置代码和自定义工具类的使用。
https://blog.youkuaiyun.com/bigbig_bug/article/details/118958687?spm=1001.2014.3001.5501
1194

被折叠的 条评论
为什么被折叠?



