Java調(diào)用企業(yè)微信群機(jī)器人發(fā)送消息
2022/4/22更新:新增可發(fā)送文件消息。
發(fā)送文件消息需要先將文件上傳到企業(yè)微信的臨時(shí)素材,url為https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?type=file&key=**********,這個(gè)key就是群機(jī)器人Webhook地址的key參數(shù),在代碼里我已經(jīng)處理好了,只要有Webhook地址就行。獲取到media_id,再拿media_id和文件一起就可以調(diào)用群機(jī)器人的發(fā)送接口了。
2021/12/3 周五
主要參考 企業(yè)微信接口文檔(但這里用的不是文檔里的API) 和 企業(yè)微信機(jī)器人自動(dòng)發(fā)送群消息 提供的方法,
將企業(yè)微信群機(jī)器人發(fā)送 文字、圖片、MarkDown、文件消息 封裝成了一個(gè)工具類。
- 用于自建的群,即不是使用企業(yè)微信api創(chuàng)建的群,不需要群id;
- 主要使用 okhttp3 調(diào)用機(jī)器人api和上傳文件到臨時(shí)素材api;
- 有含代理的構(gòu)造方法和不含代理的構(gòu)造方法,可根據(jù)需要選擇調(diào)用;
- 參數(shù)使用的是JSONObject,防止在用字符串拼接參數(shù)時(shí)出現(xiàn)各種特殊字符轉(zhuǎn)義問(wèn)題;
- 發(fā)送圖片大小不超過(guò)2M(企業(yè)微信的規(guī)定)。
使用步驟:
1. 創(chuàng)建群機(jī)器人
在企業(yè)微信已經(jīng)建好的群中,添加群機(jī)器人(怎么添加可以參考:企業(yè)微信機(jī)器人發(fā)送消息),獲取群機(jī)器人的Webhook地址。
需注意:
(1)因?yàn)椴皇怯闷髽I(yè)微信api創(chuàng)建的群,沒(méi)有群id,無(wú)法指定群機(jī)器人只發(fā)送到某一個(gè)群,所以建議該機(jī)器人不要發(fā)布到公司或者添加到其他群。
(2)還需注意群機(jī)器人Webhook地址的保密性,因?yàn)槿魏稳四玫侥愕牡刂?,就可以朝你的群里發(fā)消息了。
關(guān)于Webhook:
Webhook是一個(gè) API 概念,簡(jiǎn)單來(lái)說(shuō), 就是一個(gè)接收 HTTP POST(或GET,PUT,DELETE)的URL。
比如說(shuō)我可以直接在postman測(cè)試工具里,帶上需要的參數(shù),向群機(jī)器人的Webhook地址發(fā)送請(qǐng)求,企業(yè)微信對(duì)應(yīng)的群里就能收到這個(gè)機(jī)器人發(fā)送的消息。
2. 將工具類放到項(xiàng)目中,需要添加依賴
將工具類放到項(xiàng)目中,代碼在最后。
需要在項(xiàng)目pom.xml文件中添加okhttp3和圖片操作的依賴:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.9</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
(PS:如果圖片過(guò)大,可能導(dǎo)致base64編碼結(jié)果過(guò)長(zhǎng)超過(guò)String的最大長(zhǎng)度,導(dǎo)致圖片發(fā)送失敗。另外,企業(yè)微信也有規(guī)定圖片不能超過(guò)2M.)
3. 調(diào)用
(1)直接 new 一個(gè)WeChatBotUtils,帶上群機(jī)器人Webhook地址和代理服務(wù)器相關(guān)配置:
WeChatBotUtils robot = new WeChatBotUtils(url, hostname, port);
或者從配置中獲取代理信息,就可以用第二個(gè)構(gòu)造方法:
WeChatBotUtils robot = new WeChatBotUtils(url, true);
(如果不需要使用代理,改為false就可以了)
IDEA將代理信息配置在啟動(dòng)參數(shù)的方法如下圖:
(2)帶上對(duì)應(yīng)消息內(nèi)容參數(shù),調(diào)用sendTextMsg(String msg)、sendImgMsg(String path)、sendMarKDownMsg(String msg)、sendFileMsg(String path)方法,即可發(fā)送請(qǐng)求:
robot.sendTextMsg(msg);
4. 返回參數(shù)
除了調(diào)用群機(jī)器人正常發(fā)送消息,還可能會(huì)有一些請(qǐng)求報(bào)錯(cuò),比如圖片大小無(wú)效、md5值不匹配等等,具體原因可以查看 企業(yè)微信全局錯(cuò)誤碼。
5. 代碼
0積分下載資源:Java企業(yè)微信群機(jī)器人發(fā)送消息,可以直接放到項(xiàng)目里使用。
以下是代碼:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-401633.html
package com.ruoyi.project.tool.robot;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.Base64;
import java.util.concurrent.TimeUnit;
/**
* 微信群機(jī)器人
*/
public class WeChatBotUtils {
private Logger log = LoggerFactory.getLogger(this.getClass());
// 配置的群機(jī)器人Webhook地址
private String botUrl;
// 配置代理服務(wù)器
private String hostname;
private int port;
// 需要使用代理時(shí)調(diào)用的構(gòu)造函數(shù)
public WeChatBotUtils(String botUrl, String hostname, int port) {
this.botUrl = botUrl;
this.hostname = hostname;
this.port = port;
}
// 直接從配置中獲取代理信息
public WeChatBotUtils(String botUrl, boolean byProxy) {
this.botUrl = botUrl;
if (byProxy) {
hostname = System.getProperty("proxyHost");
port = Integer.valueOf(System.getProperty("proxyPort"));
}
}
/**
* 發(fā)送文字消息
*
* @param msg 需要發(fā)送的消息
* @return
* @throws Exception
*/
public String sendTextMsg(String msg) throws Exception {
JSONObject text = new JSONObject();
text.put("content", msg);
JSONObject reqBody = new JSONObject();
reqBody.put("msgtype", "text");
reqBody.put("text", text);
reqBody.put("safe", 0);
return callWeChatBot(reqBody.toString());
}
/**
* 發(fā)送圖片消息,需要對(duì)圖片進(jìn)行base64編碼并計(jì)算圖片的md5值
*
* @param path 需要發(fā)送的圖片路徑
* @return
* @throws Exception
*/
public String sendImgMsg(String path) throws Exception {
String base64 = "";
String md5 = "";
// 獲取Base64編碼
try {
FileInputStream inputStream = new FileInputStream(path);
byte[] bs = new byte[inputStream.available()];
inputStream.read(bs);
base64 = Base64.getEncoder().encodeToString(bs);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 獲取md5值
try {
FileInputStream inputStream = new FileInputStream(path);
byte[] buf = new byte[inputStream.available()];
inputStream.read(buf);
md5 = DigestUtils.md5Hex(buf);
} catch (IOException e) {
e.printStackTrace();
}
JSONObject image = new JSONObject();
image.put("base64", base64);
image.put("md5", md5);
JSONObject reqBody = new JSONObject();
reqBody.put("msgtype", "image");
reqBody.put("image", image);
reqBody.put("safe", 0);
return callWeChatBot(reqBody.toString());
}
/**
* 發(fā)送MarKDown消息
*
* @param msg 需要發(fā)送的消息
* @return
* @throws Exception
*/
public String sendMarKDownMsg(String msg) throws Exception {
JSONObject markdown = new JSONObject();
markdown.put("content", msg);
JSONObject reqBody = new JSONObject();
reqBody.put("msgtype", "markdown");
reqBody.put("markdown", markdown);
reqBody.put("safe", 0);
return callWeChatBot(reqBody.toString());
}
/**
* 發(fā)送文件消息,需要先將文件上傳到企業(yè)微信臨時(shí)素材,再根據(jù)獲取的media_id調(diào)用群機(jī)器人
*
* @param path 需要發(fā)送的文件路徑
* @return
* @throws Exception
*/
public String sendFileMsg(String path) throws Exception {
File file = new File(path);
// 構(gòu)造RequestBody對(duì)象,用來(lái)攜帶要提交的數(shù)據(jù);需要指定MediaType,用于描述請(qǐng)求/響應(yīng) body 的內(nèi)容類型
MediaType contentType = MediaType.parse("application/form-data; boundary");
RequestBody body = RequestBody.create(contentType, file);
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(), body)
.build();
// 上傳到臨時(shí)素材
String key = botUrl.substring(botUrl.indexOf("key="));
System.out.println(key);
String mediaUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?type=file&"+key;
log.info("將文件" + path+ "上傳到臨時(shí)素材:" + mediaUrl);
String respMsg = okHttp(requestBody, mediaUrl);
// 獲取臨時(shí)素材id
JSONObject result = JSONObject.parseObject(respMsg);
String media_id = result.getString("media_id");
JSONObject fileJson = new JSONObject();
fileJson.put("media_id", media_id);
JSONObject reqBody = new JSONObject();
reqBody.put("msgtype", "file");
reqBody.put("file", fileJson);
reqBody.put("safe", 0);
// 調(diào)用群機(jī)器人發(fā)送消息
return callWeChatBot(reqBody.toString());
}
/**
* 調(diào)用群機(jī)器人
*
* @param reqBody 接口請(qǐng)求參數(shù)
* @throws Exception 可能有IO異常
*/
public String callWeChatBot(String reqBody) throws Exception {
log.info("請(qǐng)求參數(shù):" + reqBody);
// 構(gòu)造RequestBody對(duì)象,用來(lái)攜帶要提交的數(shù)據(jù);需要指定MediaType,用于描述請(qǐng)求/響應(yīng) body 的內(nèi)容類型
MediaType contentType = MediaType.parse("application/json; charset=utf-8");
RequestBody body = RequestBody.create(contentType, reqBody);
// 調(diào)用群機(jī)器人
String respMsg = okHttp(body, botUrl);
if ("0".equals(respMsg.substring(11, 12))) {
log.info("向群發(fā)送消息成功!");
} else {
log.info("請(qǐng)求失??!");
// 發(fā)送錯(cuò)誤信息到群
sendTextMsg("群機(jī)器人推送消息失敗,錯(cuò)誤信息:\n" + respMsg);
}
return respMsg;
}
/**
*
* @param body 攜帶需要提交的數(shù)據(jù)
* @param url 請(qǐng)求地址
* @return
* @throws Exception
*/
public String okHttp(RequestBody body, String url) throws Exception {
// 構(gòu)造和配置OkHttpClient
OkHttpClient client;
if(hostname != null && port != 0){
client = new OkHttpClient.Builder()
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(hostname, port))) // 內(nèi)網(wǎng)使用代理,不需要可注釋
.connectTimeout(10, TimeUnit.SECONDS) // 設(shè)置連接超時(shí)時(shí)間
.readTimeout(20, TimeUnit.SECONDS) // 設(shè)置讀取超時(shí)時(shí)間
.build();
} else{
client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS) // 設(shè)置連接超時(shí)時(shí)間
.readTimeout(20, TimeUnit.SECONDS) // 設(shè)置讀取超時(shí)時(shí)間
.build();
}
// 構(gòu)造Request對(duì)象
Request request = new Request.Builder()
.url(url)
.post(body)
.addHeader("cache-control", "no-cache") // 響應(yīng)消息不緩存
.build();
// 構(gòu)建Call對(duì)象,通過(guò)Call對(duì)象的execute()方法提交異步請(qǐng)求
Response response = null;
try {
response = client.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}
// 請(qǐng)求結(jié)果處理
byte[] datas = response.body().bytes();
String respMsg = new String(datas);
log.info("返回結(jié)果:" + respMsg);
return respMsg;
}
}
6. 調(diào)用
public static void main(String[] args) throws Exception {
String botUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=**********";
WeChatBotUtils weChatBot = new WeChatBotUtils(botUrl, true);
// 發(fā)送文本消息
weChatBot.sendTextMsg("測(cè)試消息\n" + "hello world!");
// 發(fā)送圖片消息
weChatBot.sendImgMsg("C:/User/Desktop/test.jpg");
// 發(fā)送MarkDown消息
String markdownMsg =
"測(cè)試:您的會(huì)議室已經(jīng)預(yù)定,稍后會(huì)同步到`郵箱` \n" +
" >**事項(xiàng)詳情** \n" +
" >事 項(xiàng):<font color=\"info\">開(kāi)會(huì)</font> \n" +
" >組織者:@admin \n" +
" >參與者:@admin \n" +
" >\n" +
" >會(huì)議室:<font color=\"info\">廣州TIT 1樓 301</font>\n" +
" >日 期:<font color=\"warning\">2022年4月22日</font>\n" +
" >時(shí) 間:<font color=\"comment\">上午9:00-11:00</font>\n" +
" >\n" +
" >請(qǐng)準(zhǔn)時(shí)參加會(huì)議。\n";
weChatBot.sendMarKDownMsg(markdownMsg);
// 發(fā)送文件消息
weChatBot.sendFileMsg("C:/User/Desktop/test.xlsx");
}
就介么簡(jiǎn)單~ ^_^文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-401633.html
到了這里,關(guān)于【Java】企業(yè)微信群機(jī)器人發(fā)送消息(文字、圖片、MarkDown、文件消息)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!