文章目录
前言
企业微信开放了消息发送接口,企业可以使用这些接口让自定义应用与企业微信后台或用户间进行双向通信。
消息接口总体上分为主动发送单聊消息、接收单聊消息以及发送消息到群三部分:
- 主动发送应用消息:企业后台调用接口通过应用向指定成员发送单聊消息
- 接收消息:企业后台接收来自成员的消息或事件 要使用接收消息,需要在应用中设置开发者的回调服务器配置。 接收消息分为两种:1. 成员在应用客户端里发送的消息;2. 某种条件下触发的事件消息。
- 开发者后台在接收消息后,可以在响应的返回包里带上回复消息,企业微信会将这条消息推送给成员。这就是“被动回复消息”。
- 发送消息到群聊会话:企业后台调用接口创建群聊后,可通过应用推送消息到群内。(暂不支持接收群聊消息)
本章实现企业微信向企业用户主动发送应用文本消息。
一、应用消息接口定义
应用支持推送文本、图片、视频、文件、图文等类型。
请求方式:POST(HTTPS) 请求地址:
https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN
参数说明:access_token 必传,是调用接口的凭证
二、推送文本消息
1. 文本消息类型概述
前面写到,应用支持推送多种类型的消息,其实大同小异,这里我们实现推送文本消息。
首先,在 微信开发者中心服务端API 中有详细的开发指导,其中有他们提供的请求示例:
{
"touser" : "UserID1|UserID2|UserID3",
"toparty" : "PartyID1|PartyID2",
"totag" : "TagID1 | TagID2",
"msgtype" : "text",
"agentid" : 1,
"text" : {
"content" : "你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看<a href=\"http://work.weixin.qq.com\">邮件中心视频实况</a>,聪明避开排队。"
},
"safe":0,
"enable_id_trans": 0,
"enable_duplicate_check": 0,
"duplicate_check_interval": 1800
}
参数说明:
了解了文本消息基本的内容就可以尝试开发了
2. 代码实现
2.1 实体类
2.1.1 消息基类 — BaseMessage
/**
* FileName: BaseMessage
* Author: XH
* Date: 2022/2/28 14:59
* Description: 消息基类
* History:
*/
package com.xh.wx.sendMessage.entity;
import lombok.Data;
/**
* 〈一句话功能简述〉
* 〈消息基类〉
*
* @author XH
* @create 2022/2/28
* @since 1.0.0
*/
@Data
public class BaseMessage {
/**
* 成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。
* 非必传
* 特殊情况:指定为@all,则向该企业应用的全部成员发送
* touser、toparty、totag不能同时为空。
*/
private String touser;
/**
* 部门ID列表,多个接收者用‘|’分隔,最多支持100个。
* 非必传
* 当touser为@all时忽略本参数
*/
private String toparty;
/**
* 标签ID列表,多个接收者用‘|’分隔,最多支持100个。
* 非必传
* 当touser为@all时忽略本参数
*/
private String totag;
/**
* 消息类型
* 必传
*/
private String msgtype;
/**
* 企业应用的id。可在应用的设置页面查看
* 必传
*/
private int agentid;
}
2.1.2 文本消息 — Text、TextMessage
上面我们贴出了企业微信官方文档提供的关于文本消息请求的说明 我们可把整个 json 对象看做一个 java 对象,而在这个 json 对象中又包含一个 text 对象。(json中的对象用 { } 包裹起来,json 中的数组用 [ ] 包裹起来)
需注意 agentid、safe 为 int 型。于是可以把 text 看做一个 java 对象,这样 TextMessage 类组合了 Text 类,转 json 字符串的时候,就可以直接使用
String jsonTextMessage = gson.toJson(textMessage)
于是,我们开始对文本消息进行封装。
Text.java
/**
* FileName: Text
* Author: XH
* Date: 2022/2/28 15:10
* Description: 消息
* History:
*/
package com.xh.wx.sendMessage.entity;
import lombok.Data;
/**
* 〈一句话功能简述〉
* 〈文本〉
*
* @author XH
* @create 2022/2/28
* @since 1.0.0
*/
@Data
public class Text {
/**
* 消息内容,最长不超过2048个字节
* 必传
*/
private String content;
}
TextMessage.java
/**
* FileName: TextMessage
* Author: XH
* Date: 2022/2/28 15:11
* Description: 文本消息
* History:
*/
package com.xh.wx.sendMessage.entity;
import lombok.Data;
/**
* 〈一句话功能简述〉
* 〈文本消息〉
*
* @author XH
* @create 2022/2/28
* @since 1.0.0
*/
@Data
public class TextMessage extends BaseMessage{
/**
* 文本
*/
private Text text;
/**
* 表示是否是保密消息,0表示否,1表示是,默认0
*/
private int safe;
}
2.2 发送消息业务类 — SendMessageService
/**
* FileName: SendMessageService
* Author: XH
* Date: 2022/2/28 15:14
* Description: 发送消息
* History:
*/
package com.xh.wx.sendMessage.service;
import com.xh.wx.sendMessage.utils.WeiXinUtil;
import com.xh.wx.sendMessage.entity.BaseMessage;
import com.xh.wx.sendMessage.entity.Text;
import com.xh.wx.sendMessage.entity.TextMessage;
import com.google.gson.Gson;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* 〈一句话功能简述〉
* 〈发送消息〉
*
* @author XH
* @create 2022/2/28
* @since 1.0.0
*/
@Component
public class SendMessageService {
@Value("${qywx.agentid}")
private String qyWxAgentId;
@Value("${qywx.corpsecret}")
private String qyWxCorpsecret;
/**
* 应用消息接口的请求地址
*/
@Value("${qywx.sendMessage_url}")
private String sendMessageUrl;
/**
* 文本消息
* @param content 消息
* @param touser 成员ID列表
*/
public void testSendTextMessage(String touser, String content){
//创建文本消息对象
TextMessage message = new TextMessage();
message.setTouser(touser);
message.setMsgtype("text");
Text text = new Text();
text.setContent(content);
message.setText(text);
//发送消息
sendMessage(message);
}
/**
* 公共方法:发送消息
* @param message
*/
public void sendMessage(BaseMessage message){
message.setAgentid(qyWxAgentId);
// 获取 accessToken
// 此处仅做示例,因为每日获取 accessToken 有次数限制,不建议每次调用消息接口就重新请求获取
// 实际应用建议把查询到的 accessToken 存入缓存或者存入数据库中以便查询
// 等待 accessToken 过期后再重新查询
String accessToken = WeiXinUtil.getAccessToken(qyWxAgentId, qyWxCorpsecret).getToken();
// 1.获取 json 字符串:将 message 对象转换为 json 字符串
Gson gson = new Gson();
// 使用 gson.toJson(message) 即可将 message 对象顺序转成 json
String jsonMessage = gson.toJson(message);
System.out.println("jsonTextMessage:"+jsonMessage);
// 2.请求的 url
sendMessageUrl = sendMessageUrl.replace("ACCESS_TOKEN", accessToken);
// 3.调用接口,发送消息
JSONObject jsonObject = WeiXinUtil.httpRequest(sendMessageUrl, "POST", jsonMessage);
System.out.println("jsonObject:"+jsonObject.toString());
// 4.错误消息处理
if (null != jsonObject) {
if (0 != jsonObject.getInt("errcode")) {
System.err.println("发送消息失败 errcode:"+jsonObject.getInt("errcode")+", errmsg:"+jsonObject.getString("errmsg"));
}
}
}
}
这里我使用读取配置文件的内容,加入后期改动的话会比较方便,这里看大家选择哪种咯~
配置文件:
2.3 工具类
MyX509TrustManager.java
/**
* FileName: MyX509TrustManager
* Author: XH
* Date: 2022/2/28 15:27
* Description:
* History:
*/
package com.xh.wx.sendMessage.util;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* 〈一句话功能简述〉
* 〈证书信任管理器(用于https请求) 〉
*
* @author XH
* @create 2022/2/28
* @since 1.0.0
*/
public class MyX509TrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
AccessToken.java
/**
* FileName: TextMessage
* Author: XH
* Date: 2022/2/28 15:11
* Description: 文本消息
* History:
*/
package com.xh.wx.sendMessage.util;
import lombok.Data;
/**
* 〈一句话功能简述〉
* 〈AccessToken〉
*
* @author XH
* @create 2022/2/28
* @since 1.0.0
*/
@Data
public class TextMessage extends BaseMessage{
/**
* 获取到的凭证
*/
private String token;
/**
* 凭证有效时间,单位:秒
*/
private int expiresIn;
}
WXUtil.java
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
public class WeiXinUtil {
//微信的请求url
//获取access_token的接口地址(GET) 限200(次/天)
public final static String access_token_url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpId}&corpsecret={corpsecret}";
//获取jsapi_ticket的接口地址(GET) 限200(次/天)
public final static String jsapi_ticket_url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=ACCESSTOKEN";
/**
* 1.发起https请求并获取结果
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
StringBuffer buffer = new StringBuffer();
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
// 设置请求方式(GET/POST)
httpUrlConn.setRequestMethod(requestMethod);
if ("GET".equalsIgnoreCase(requestMethod))
httpUrlConn.connect();
// 当有数据需要提交时
if (null != outputStr) {
OutputStream outputStream = httpUrlConn.getOutputStream();
// 注意编码格式,防止中文乱码
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException ce) {
ce.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return jsonObject;
}
/**
* 获取access_token
*
* @param appid 凭证
* @param appsecret 密钥
* @return
*/
public static AccessToken getAccessToken(String appid, String appsecret) {
AccessToken accessToken = null;
String requestUrl = access_token_url.replace("{corpId}", appid).replace("{corpsecret}", appsecret);
JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
// 如果请求成功
if (null != jsonObject) {
try {
accessToken = new AccessToken();
accessToken.setToken(jsonObject.getString("access_token"));
accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
} catch (JSONException e) {
accessToken = null;
// 获取token失败
System.out.println("获取token失败 errcode:{} errmsg:{}"+jsonObject.getInt("errcode")+":"+ jsonObject.getString("errmsg"));
}
}
return accessToken;
}
}
2.4 发送消息
public class SendMessageTest {
@Autowired
SendMessageService sendMessageService;
public void testSendTextMessage(){
//0.设置消息内容
String content="你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看" +
"<a href=\"http://work.weixin.qq.com\">邮件中心视频实况" +
"</a>,聪明避开排队。";
// 企业微信消息推送
// touser 可发送全部:"@all",也可填写人员的id
sendMessageService.testSendTextMessage(touser, content);
}
运行一下就可以收到消息了~~~
总结
以上就是全部的企业微信推送文本消息的内容了,其他的消息推送基本都差不多,由于后期改动了一些代码,如有异常麻烦大家提示我更正哈哈哈。
下面是参考引用的资料:
企业微信接口文档