业务逻辑介绍
步骤一
实现文件作为临时素材上传到腾讯企业微信
步骤二
通过企业微信接口的手机号获取到指定用户信息
步骤三
将临时素材上传到腾讯企业微信生成的media_id通过推送消息接口推送给目标用户
上传临时素材
最后更新:2024/07/22
素材上传得到media_id,该media_id仅三天内有效
media_id在同一企业内应用之间可以共享
请求方式: POST(HTTPS )
**请求地址:**https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN\&type=TYPE
使用multipart/form-data POST上传文件, 文件标识名为"media"
参数说明:
参数 | 必须 | 说明 |
---|---|---|
access_token | 是 | 调用接口凭证 |
type | 是 | 媒体文件类型,分别有图片(image)、语音(voice)、视频(video),普通文件(file) |
POST的请求包中,form-data中媒体文件标识,应包含有 filename、filelength、content-type等信息
filename标识文件展示的名称。比如,使用该media_id发消息时,展示的文件名由该字段控制
请求示例:
POST https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=accesstoken001&type=file HTTP/1.1
Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
Content-Length: 220
---------------------------acebdf13572468
Content-Disposition: form-data; name="media";filename="wework.txt"; filelength=6
Content-Type: application/octet-stream
mytext
---------------------------acebdf13572468--
返回数据:
{
"errcode": 0,
"errmsg": "",
"type": "image",
"media_id": "1G6nrLmr5EC3MMb_-zK1dDdzmd0p7cNliYu9V5w7o8K0",
"created_at": "1380000000"
}
参数说明:
参数 | 说明 |
---|---|
type | 媒体文件类型,分别有图片(image)、语音(voice)、视频(video),普通文件(file) |
media_id | 媒体文件上传后获取的唯一标识,3天内有效 |
created_at | 媒体文件上传时间戳 |
上传的媒体文件限制
所有文件size必须大于5个字节
- 图片(image):10MB,支持JPG,PNG格式
- 语音(voice) :2MB,播放长度不超过60s,仅支持AMR格式
- 视频(video) :10MB,支持MP4格式
- 普通文件(file):20MB
代码示例
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class WeChatMediaUploader {
/**
* 上传临时素材到企业微信
*
* @param accessToken 调用接口凭证
* @param filePath 要上传的文件路径
* @param mediaType 媒体文件类型,可选值: image, voice, video, file
* @return 上传结果JSON对象,包含media_id等信息
*/
public static JSONObject uploadMedia(String accessToken, String filePath, String mediaType) {
// 检查文件是否存在
File file = new File(filePath);
if (!file.exists() || !file.isFile()) {
return createErrorResult(-1, "文件不存在");
}
// 检查文件大小
long fileSize = file.length();
if (fileSize <= 5) {
return createErrorResult(-1, "文件大小必须大于5字节");
}
// 检查文件类型和大小限制
if ("image".equals(mediaType) && fileSize > 10 * 1024 * 1024) {
return createErrorResult(-1, "图片大小不能超过10MB");
} else if ("voice".equals(mediaType) && fileSize > 2 * 1024 * 1024) {
return createErrorResult(-1, "语音大小不能超过2MB");
} else if ("video".equals(mediaType) && fileSize > 10 * 1024 * 1024) {
return createErrorResult(-1, "视频大小不能超过10MB");
} else if ("file".equals(mediaType) && fileSize > 20 * 1024 * 1024) {
return createErrorResult(-1, "文件大小不能超过20MB");
}
// 构建请求URL
String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=" + accessToken + "&type=" + mediaType;
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(url);
// 构建multipart/form-data请求体
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addBinaryBody(
"media",
file,
ContentType.APPLICATION_OCTET_STREAM,
file.getName()
);
HttpEntity multipart = builder.build();
httpPost.setEntity(multipart);
// 发送请求并处理响应
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
String responseString = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
return new JSONObject(responseString);
}
}
} catch (IOException e) {
return createErrorResult(-1, "请求失败: " + e.getMessage());
}
return createErrorResult(-1, "未知错误");
}
/**
* 创建错误结果JSON对象
*/
private static JSONObject createErrorResult(int errcode, String errmsg) {
JSONObject result = new JSONObject();
result.put("errcode", errcode);
result.put("errmsg", errmsg);
return result;
}
/**
* 使用示例
*/
public static void main(String[] args) {
// 替换为你的access_token
String accessToken = "YOUR_ACCESS_TOKEN";
// 替换为你要上传的文件路径
String filePath = "./test.txt";
// 指定文件类型
String mediaType = "file"; // 可选: image, voice, video, file
// 上传文件
JSONObject result = uploadMedia(accessToken, filePath, mediaType);
// 输出结果
if (result.has("errcode") && result.getInt("errcode") == 0) {
System.out.println("上传成功!");
System.out.println("media_id: " + result.getString("media_id"));
System.out.println("类型: " + result.getString("type"));
System.out.println("创建时间: " + result.getLong("created_at"));
} else {
System.out.println("上传失败: " + result.getString("errmsg"));
}
}
}
读取成员
最后更新:2025/03/06
应用只能获取可见范围内的成员信息,且每种应用获取的字段有所不同,在返回结果说明中会逐个说明。企业通讯录安全特别重要,企业微信将持续升级加固通讯录接口的安全机制,以下是关键的变更点:
- 从2022年6月20号20点开始,除通讯录同步以外的基础应用(如客户联系、微信客服、会话存档、日程等),以及新创建的自建应用与代开发应用,调用该接口时,不再返回以下字段:头像、性别、手机、邮箱、企业邮箱、员工个人二维码、地址,应用需要通过oauth2手工授权的方式获取管理员与员工本人授权的字段。
- 【重要】 从2022年8月15日10点开始,"企业管理后台 - 管理工具 - 通讯录同步"的新增IP将不能再调用此接口,企业可通过「获取成员ID列表」和「获取部门ID列表」接口获取userid和部门ID列表。查看调整详情。
请求方式: GET(HTTPS )
**请求地址:**https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN\&userid=USERID
参数说明:
参数 | 必须 | 说明 |
---|---|---|
access_token | 是 | 调用接口凭证 |
userid | 是 | 成员UserID。对应管理端的账号,企业内必须唯一。不区分大小写,长度为1~64个字节 |
权限说明:
应用须拥有指定成员的查看权限。
返回结果:
{
"errcode": 0,
"errmsg": "ok",
"userid": "zhangsan",
"name": "张三",
"department": [1, 2],
"order": [1, 2],
"position": "后台工程师",
"mobile": "13800000000",
"gender": "1",
"email": "zhangsan@qq.com",
"biz_mail":"zhangsan@tencent.com",
"is_leader_in_dept": [1, 0],
"direct_leader":["lisi"],
"avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0",
"thumb_avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/100",
"telephone": "020-123456",
"alias": "jackzhang",
"address": "广州市海珠区新港中路",
"open_userid": "xxxxxx",
"main_department": 1,
"extattr": {
"attrs": [
{
"type": 0,
"name": "文本名称",
"text": {
"value": "文本"
}
},
{
"type": 1,
"name": "网页名称",
"web": {
"url": "http://www.test.com",
"title": "标题"
}
}
]
},
"status": 1,
"qr_code": "https://open.work.weixin.qq.com/wwopen/userQRCode?vcode=xxx",
"external_position": "产品经理",
"external_profile": {
"external_corp_name": "企业简称",
"wechat_channels": {
"nickname": "视频号名称",
"status": 1
},
"external_attr": [{
"type": 0,
"name": "文本名称",
"text": {
"value": "文本"
}
},
{
"type": 1,
"name": "网页名称",
"web": {
"url": "http://www.test.com",
"title": "标题"
}
},
{
"type": 2,
"name": "测试app",
"miniprogram": {
"appid": "wx8bd80126147dFAKE",
"pagepath": "/index",
"title": "my miniprogram"
}
}
]
}
}
参数说明:
参数 | 说明 |
---|---|
errcode | 返回码 |
errmsg | 对返回码的文本描述内容 |
userid | 成员UserID。对应管理端的账号,企业内必须唯一。不区分大小写,长度为1~64个字节;第三方应用返回的值为open_userid |
name | 成员名称;第三方不可获取,调用时返回userid以代替name;代开发自建应用需要管理员授权才返回;对于非第三方创建的成员,第三方通讯录应用也不可获取;未返回name的情况需要通过通讯录展示组件来展示名字 |
mobile | 手机号码,代开发自建应用需要管理员授权且成员oauth2授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 |
department | 成员所属部门id列表,仅返回该应用有查看权限的部门id;成员授权模式下,固定返回根部门id,即固定为1。对授权了"组织架构信息"权限的第三方应用或授权了"组织架构信息"-"部门及父部门ID、部门负责人"权限的代开发应用,返回成员所属的全部部门id |
order | 部门内的排序值,默认为0。数量必须和department一致,数值越大排序越前面。值范围是[0, 2^32)。成员授权模式下不返回该字段 |
position | 职务信息;代开发自建应用需要管理员授权才返回;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 |
gender | 性别。0表示未定义,1表示男性,2表示女性。代开发自建应用需要管理员授权且成员oauth2授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段。注:不可获取指返回值0 |
邮箱,代开发自建应用需要管理员授权且成员oauth2授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 | |
biz_mail | 企业邮箱,代开发自建应用需要管理员授权且成员oauth2授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 |
is_leader_in_dept | 表示在所在的部门内是否为部门负责人,数量与department一致;第三方通讯录应用或者授权了"组织架构信息-应用可获取企业的部门组织架构信息-部门负责人"权限的第三方应用和代开发应用可获取;对于非第三方创建的成员,第三方通讯录应用不可获取;上游企业不可获取下游企业成员该字段 |
direct_leader | 直属上级UserID,返回在应用可见范围内的直属上级列表,最多有1个直属上级;第三方通讯录应用或者授权了"组织架构信息-应用可获取可见范围内成员组织架构信息-直属上级"权限的第三方应用和代开发应用可获取;对于非第三方创建的成员,第三方通讯录应用不可获取;上游企业不可获取下游企业成员该字段 |
avatar | 头像url。 代开发自建应用需要管理员授权且成员oauth2授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 |
thumb_avatar | 头像缩略图url。第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 |
telephone | 座机。代开发自建应用需要管理员授权才返回;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 |
alias | 别名;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 |
extattr | 扩展属性,字段详见成员扩展属性。代开发自建应用需要管理员授权才返回;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 |
status | 激活状态: 1=已激活,2=已禁用,4=未激活,5=退出企业。 已激活代表已激活企业微信或已关注微信插件(原企业号)。未激活代表既未激活企业微信又未关注微信插件(原企业号)。 |
qr_code | 员工个人二维码,扫描可添加为外部联系人(注意返回的是一个url,可在浏览器上打开该url以展示二维码);代开发自建应用需要管理员授权且成员oauth2授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 |
external_profile | 成员对外属性,字段详情见对外属性;代开发自建应用需要管理员授权才返回;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 |
external_position | 对外职务,如果设置了该值,则以此作为对外展示的职务,否则以position来展示。代开发自建应用需要管理员授权才返回;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 |
address | 地址。代开发自建应用需要管理员授权且成员oauth2授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段 |
open_userid | 全局唯一。对于同一个服务商,不同应用获取到企业内同一个成员的open_userid是相同的,最多64个字节。仅第三方应用可获取。 |
main_department | 主部门,仅当应用对主部门有查看权限时返回。 |
应用获取敏感字段的说明
为保护企业数据与用户隐私,从2022年6月20号20点开始,新创建的自建应用与代开发应用,调用该接口时,不再返回以下字段:头像、性别、手机、邮箱、企业邮箱、员工个人二维码、地址,应用需要通过oauth2手工授权的方式获取管理员与员工本人授权的字段。
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import java.nio.charset.StandardCharsets;
public class WeChatUserInfoFetcher {
/**
* 获取企业微信成员信息
*
* @param accessToken 调用接口凭证
* @param userId 成员UserID
* @return 成员信息JSON对象
*/
public static JSONObject getUserInfo(String accessToken, String userId) {
// 构建请求URL
String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=" + accessToken + "&userid=" + userId;
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpGet httpGet = new HttpGet(url);
// 发送请求并处理响应
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
String responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
return new JSONObject(responseString);
}
} catch (Exception e) {
JSONObject errorResult = new JSONObject();
errorResult.put("errcode", -1);
errorResult.put("errmsg", "请求失败: " + e.getMessage());
return errorResult;
}
}
/**
* 使用示例
*/
public static void main(String[] args) {
// 替换为你的access_token
String accessToken = "YOUR_ACCESS_TOKEN";
// 替换为你要查询的用户ID
String userId = "zhangsan";
// 获取用户信息
JSONObject result = getUserInfo(accessToken, userId);
// 输出结果
if (result.has("errcode") && result.getInt("errcode") == 0) {
System.out.println("获取用户信息成功!");
System.out.println("用户ID: " + result.getString("userid"));
System.out.println("姓名: " + result.optString("name", "未返回"));
System.out.println("部门: " + result.optJSONArray("department"));
System.out.println("职位: " + result.optString("position", "未返回"));
// 注意:根据API变更,以下字段可能不会返回,需要通过OAuth2授权获取
System.out.println("手机: " + result.optString("mobile", "需OAuth2授权获取"));
System.out.println("邮箱: " + result.optString("email", "需OAuth2授权获取"));
System.out.println("头像: " + result.optString("avatar", "需OAuth2授权获取"));
// 其他字段...
} else {
System.out.println("获取用户信息失败: " + result.getString("errmsg"));
System.out.println("错误码: " + result.getInt("errcode"));
}
}
}
发送应用消息
最后更新:2025/09/24
接口定义
应用支持推送文本、图片、视频、文件、图文等类型。
请求方式: POST(HTTPS )
请求地址: https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN
参数说明:
参数 | 是否必须 | 说明 |
---|---|---|
access_token | 是 | 调用接口凭证 |
- 各个消息类型的具体POST格式请阅后续"消息类型"部分。
- 如果有在管理端对应用设置"在微工作台中始终进入主页",应用在微信端只能接收到文本消息,并且文本消息的长度限制为20字节,超过20字节会被截断。同时其他消息类型也会转换为文本消息,提示用户到企业微信查看。
- 支持id转译,将userid/部门id转成对应的用户名/部门名,在企业授权了会话内容存档接口权限时,也可以将消息id和群id转成对应的消息内容/群名称,目前仅文本/文本卡片/图文/图文(mpnews)/任务卡片/小程序通知/模版消息/模板卡片消息 这八种消息类型的部分字段 支持。具体支持的范围和语法,请查看附录id转译说明。
- 支持重复消息检查,当指定
"enable_duplicate_check": 1
开启: 表示在一定时间间隔内,同样内容(请求json)的消息,不会重复收到;时间间隔可通过duplicate_check_interval
指定,默认1800秒
。- 从2021年2月4日开始,企业关联添加的「小程序」应用,也可以发送文本、图片、视频、文件、图文等各种类型的消息了。
调用建议:大部分企业应用在每小时的0分或30分触发推送消息,容易造成资源挤占,从而投递不够及时,建议尽量避开这两个时间点进行调用。
频率限制:每应用不可超过账号上限数*200人次/天(注:若调用api一次发给1000人,算1000人次;若企业账号上限是500人,则每个应用每天可发送100000人次的消息)。每应用对同一个成员不可超过30次/分钟,1000次/小时,超过部分会被丢弃不下发
返回示例:
language-javascript
<span style="color:var(--ww_base_gray_080)"><span style="background-color:#ffffff"><span style="color:#000000"><code class="language-javascript"><span style="color:#5f6364">{</span>
<span style="color:#2f9c0a">"errcode"</span> <span style="background-color:rgba(255, 255, 255, 0.5)"><span style="color:#a67f59">:</span></span> <span style="color:#c92c2c">0</span><span style="color:#5f6364">,</span>
<span style="color:#2f9c0a">"errmsg"</span> <span style="background-color:rgba(255, 255, 255, 0.5)"><span style="color:#a67f59">:</span></span> <span style="color:#2f9c0a">"ok"</span><span style="color:#5f6364">,</span>
<span style="color:#2f9c0a">"invaliduser"</span> <span style="background-color:rgba(255, 255, 255, 0.5)"><span style="color:#a67f59">:</span></span> <span style="color:#2f9c0a">"userid1|userid2"</span><span style="color:#5f6364">,</span>
<span style="color:#2f9c0a">"invalidparty"</span> <span style="background-color:rgba(255, 255, 255, 0.5)"><span style="color:#a67f59">:</span></span> <span style="color:#2f9c0a">"partyid1|partyid2"</span><span style="color:#5f6364">,</span>
<span style="color:#2f9c0a">"invalidtag"</span><span style="background-color:rgba(255, 255, 255, 0.5)"><span style="color:#a67f59">:</span></span> <span style="color:#2f9c0a">"tagid1|tagid2"</span><span style="color:#5f6364">,</span>
<span style="color:#2f9c0a">"unlicenseduser"</span> <span style="background-color:rgba(255, 255, 255, 0.5)"><span style="color:#a67f59">:</span></span> <span style="color:#2f9c0a">"userid3|userid4"</span><span style="color:#5f6364">,</span>
<span style="color:#2f9c0a">"msgid"</span><span style="background-color:rgba(255, 255, 255, 0.5)"><span style="color:#a67f59">:</span></span> <span style="color:#2f9c0a">"xxxx"</span><span style="color:#5f6364">,</span>
<span style="color:#2f9c0a">"response_code"</span><span style="background-color:rgba(255, 255, 255, 0.5)"><span style="color:#a67f59">:</span></span> <span style="color:#2f9c0a">"xyzxyz"</span>
<span style="color:#5f6364">}</span></code></span></span></span>
如果部分接收人无权限或不存在,发送仍然执行,但会返回无效的部分(即invaliduser或invalidparty或invalidtag或unlicenseduser),常见的原因是接收人不在应用的可见范围内 。
权限包含应用可见范围 和基础接口权限 (基础账号、互通账号均可),unlicenseduser中的用户在应用可见范围内但没有基础接口权限。
如果全部 接收人无权限或不存在,则本次调用返回失败,errcode为81013。
返回包中的userid,不区分大小写,统一转为小写
消息类型有很多,这里我选择文件类型
文件消息
请求示例:
{
"touser" : "UserID1|UserID2|UserID3",
"toparty" : "PartyID1|PartyID2",
"totag" : "TagID1 | TagID2",
"msgtype" : "file",
"agentid" : 1,
"file" : {
"media_id" : "1Yv-zXfHjSjU-7LH-GwtYqDGS-zz6w22KmWAT5COgP7o"
},
"safe":0,
"enable_duplicate_check": 0,
"duplicate_check_interval": 1800
}
参数说明:
参数 | 是否必须 | 说明 |
---|---|---|
touser | 否 | 成员ID列表(消息接收者,多个接收者用'|'分隔,最多支持1000个)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送 |
toparty | 否 | 部门ID列表,多个接收者用'|'分隔,最多支持100个。当touser为@all时忽略本参数 |
totag | 否 | 标签ID列表,多个接收者用'|'分隔,最多支持100个。当touser为@all时忽略本参数 |
msgtype | 是 | 消息类型,此时固定为:file |
agentid | 是 | 企业应用的id,整型。企业内部开发,可在应用的设置页面查看;第三方服务商,可通过接口 获取企业授权信息 获取该参数值 |
media_id | 是 | 文件id,可以调用上传临时素材接口获取 |
safe | 否 | 表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0,保密消息支持以下格式文件: txt、pdf、doc、docx、ppt、pptx、xls、xlsx、xml、jpg、jpeg、png、bmp、gif |
enable_duplicate_check | 否 | 表示是否开启重复消息检查,0表示否,1表示是,默认0 |
duplicate_check_interval | 否 | 表示是否重复消息检查的时间间隔,默认1800s,最大不超过4小时 |
文件消息展现:

根据自己需要修改即可
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import java.nio.charset.StandardCharsets;
public class WeChatFileMessageSender {
/**
* 发送文件消息到企业微信
*
* @param accessToken 调用接口凭证
* @param messageData 消息数据JSON对象
* @return 发送结果JSON对象
*/
public static JSONObject sendFileMessage(String accessToken, JSONObject messageData) {
// 构建请求URL
String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken;
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(url);
// 设置请求头
httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
// 设置请求体
StringEntity entity = new StringEntity(messageData.toString(), StandardCharsets.UTF_8);
httpPost.setEntity(entity);
// 发送请求并处理响应
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
String responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
return new JSONObject(responseString);
}
} catch (Exception e) {
JSONObject errorResult = new JSONObject();
errorResult.put("errcode", -1);
errorResult.put("errmsg", "请求失败: " + e.getMessage());
return errorResult;
}
}
/**
* 构建文件消息JSON对象
*
* @param toUser 成员ID列表,多个用|分隔,@all表示全部成员
* @param toParty 部门ID列表,多个用|分隔
* @param toTag 标签ID列表,多个用|分隔
* @param agentId 企业应用ID
* @param mediaId 文件media_id
* @param safe 是否保密消息,0-否,1-是
* @param enableDuplicateCheck 是否开启重复消息检查,0-否,1-是
* @param duplicateCheckInterval 重复消息检查时间间隔(秒)
* @return 消息JSON对象
*/
public static JSONObject buildFileMessage(String toUser, String toParty, String toTag,
int agentId, String mediaId, int safe,
int enableDuplicateCheck, int duplicateCheckInterval) {
JSONObject message = new JSONObject();
// 接收人设置
if (toUser != null && !toUser.isEmpty()) {
message.put("touser", toUser);
}
if (toParty != null && !toParty.isEmpty()) {
message.put("toparty", toParty);
}
if (toTag != null && !toTag.isEmpty()) {
message.put("totag", toTag);
}
// 消息类型和内容
message.put("msgtype", "file");
message.put("agentid", agentId);
JSONObject fileContent = new JSONObject();
fileContent.put("media_id", mediaId);
message.put("file", fileContent);
// 可选参数
message.put("safe", safe);
message.put("enable_duplicate_check", enableDuplicateCheck);
message.put("duplicate_check_interval", duplicateCheckInterval);
return message;
}
/**
* 使用示例
*/
public static void main(String[] args) {
// 替换为你的access_token
String accessToken = "YOUR_ACCESS_TOKEN";
// 消息接收方设置(根据实际情况选择使用哪些参数)
String toUser = "UserID1|UserID2|UserID3"; // 成员ID列表,多个用|分隔
// String toUser = "@all"; // 发送给所有成员
String toParty = "PartyID1|PartyID2"; // 部门ID列表,多个用|分隔
String toTag = "TagID1|TagID2"; // 标签ID列表,多个用|分隔
// 应用和文件信息
int agentId = 1000001; // 企业应用ID
String mediaId = "1Yv-zXfHjSjU-7LH-GwtYqDGS-zz6w22KmWAT5COgP7o"; // 文件media_id
// 可选参数
int safe = 0; // 0-非保密消息,1-保密消息
int enableDuplicateCheck = 0; // 0-不开启重复消息检查,1-开启
int duplicateCheckInterval = 1800; // 重复消息检查时间间隔(秒)
// 构建消息
JSONObject message = buildFileMessage(toUser, toParty, toTag, agentId, mediaId,
safe, enableDuplicateCheck, duplicateCheckInterval);
System.out.println("发送的消息内容: " + message.toString());
// 发送消息
JSONObject result = sendFileMessage(accessToken, message);
// 处理结果
if (result.has("errcode") && result.getInt("errcode") == 0) {
System.out.println("消息发送成功!");
System.out.println("消息ID: " + result.optString("msgid", "未知"));
} else {
System.out.println("消息发送失败: " + result.getString("errmsg"));
System.out.println("错误码: " + result.getInt("errcode"));
}
}
}