简介:本教程深入讲解企业微信API的应用,涵盖通讯录管理、消息接口操作、自定义菜单构建、多媒体处理和用户认证等核心功能。通过实践任务,学生将掌握这些知识点的实现,包括部门管理、消息发送、菜单动态构建、文件上传下载和OAuth2.0授权流程。掌握这些技能将使学生能够开发出满足企业内部沟通和协作需求的系统。
1. Java企业微信开发概述
企业微信是腾讯旗下的企业级即时通讯工具,提供丰富的API接口,方便企业进行二次开发,实现个性化业务需求。Java作为一种广泛使用的编程语言,提供了丰富的库和框架,非常适合企业微信开发。
本教程将从基础开始,逐步介绍Java企业微信开发的各个方面,包括API基础、通讯录管理、消息接口封装、自定义菜单构建、多媒体上传下载、授权与二次验证等内容。通过学习本教程,开发者可以快速上手Java企业微信开发,构建出符合企业需求的应用。
2.1 企业微信API架构
架构组成
企业微信API架构主要由以下组件组成:
- 基础API: 提供基础的企业微信功能,如认证、授权、通讯录管理等。
- 消息API: 处理企业微信消息的收发,包括文本、图片、语音、视频和文件消息。
- 应用API: 管理企业微信应用,包括创建、查询、修改和删除应用。
- 多媒体API: 上传和下载企业微信的多媒体文件,如图片、语音、视频和文件。
- 授权API: 处理企业微信的授权和二次验证,包括OAuth2.0授权和签名生成。
架构特点
企业微信API架构具有以下特点:
- 模块化: API被划分为不同的模块,每个模块负责特定的功能,便于开发和维护。
- 开放性: API对外开放,允许开发者通过HTTP请求访问企业微信的功能。
- 安全性: API采用HTTPS协议和签名机制,确保数据的安全性和完整性。
- 可扩展性: API架构可扩展,可以根据需要添加新的模块或功能。
API接口
企业微信API提供了丰富的接口,涵盖企业微信的各个功能。开发者可以通过调用这些接口,实现企业微信应用的各种功能。
基础API接口:
- 获取企业微信access_token
- 获取企业微信jsapi_ticket
- 获取企业微信成员信息
- 获取企业微信部门信息
- 创建企业微信标签
消息API接口:
- 发送文本消息
- 发送图片消息
- 发送语音消息
- 发送视频消息
- 发送文件消息
应用API接口:
- 创建企业微信应用
- 查询企业微信应用
- 修改企业微信应用
- 删除企业微信应用
多媒体API接口:
- 上传企业微信文件
- 下载企业微信文件
授权API接口:
- 获取企业微信OAuth2.0授权码
- 使用授权码换取企业微信access_token
- 生成企业微信签名
3. 通讯录管理
通讯录管理是企业微信开发中重要的基础模块,它提供了对企业组织架构、成员信息、标签管理等功能的管理能力。本章节将详细介绍通讯录管理相关的API接口和使用方法。
3.1 部门管理
部门管理主要包括部门的增删改查等操作。
创建部门
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.tencent.wework.api.WxApiClient;
import com.tencent.wework.api.WxApiResponse;
import com.tencent.wework.api.domain.corp.Department;
import com.tencent.wework.api.domain.corp.DepartmentCreateResponse;
public class DepartmentCreate {
public static void main(String[] args) throws Exception {
// 获取企业微信API客户端
WxApiClient apiClient = WxApiClient.create(corpId, corpSecret);
// 创建部门
Department department = new Department();
department.setName("技术部");
department.setParentId(1);
department.setOrder(1);
// 发送请求
WxApiResponse response = apiClient.department().create(department);
// 解析响应结果
if (response.hasError()) {
System.out.println("创建部门失败:" + response.getError());
return;
}
// 获取部门ID
Gson gson = new Gson();
JsonObject jsonObject = JsonParser.parseString(response.getBody()).getAsJsonObject();
int departmentId = jsonObject.get("id").getAsInt();
System.out.println("创建部门成功,部门ID:" + departmentId);
}
}
参数说明:
-
corpId
: 企业ID -
corpSecret
: 企业密钥 -
department
: 部门信息
返回结果:
-
DepartmentCreateResponse
: 创建部门的响应结果,包括部门ID
逻辑分析:
- 创建部门对象,设置部门名称、父部门ID和排序值。
- 调用企业微信API的
department().create()
方法创建部门。 - 解析响应结果,判断是否创建成功。
- 获取创建成功的部门ID。
3.2 标签管理
标签管理主要包括标签的增删改查等操作。
创建标签
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.tencent.wework.api.WxApiClient;
import com.tencent.wework.api.WxApiResponse;
import com.tencent.wework.api.domain.corp.Tag;
import com.tencent.wework.api.domain.corp.TagCreateResponse;
public class TagCreate {
public static void main(String[] args) throws Exception {
// 获取企业微信API客户端
WxApiClient apiClient = WxApiClient.create(corpId, corpSecret);
// 创建标签
Tag tag = new Tag();
tag.setName("技术");
tag.setOrder(1);
// 发送请求
WxApiResponse response = apiClient.tag().create(tag);
// 解析响应结果
if (response.hasError()) {
System.out.println("创建标签失败:" + response.getError());
return;
}
// 获取标签ID
Gson gson = new Gson();
JsonObject jsonObject = JsonParser.parseString(response.getBody()).getAsJsonObject();
int tagId = jsonObject.get("tagid").getAsInt();
System.out.println("创建标签成功,标签ID:" + tagId);
}
}
参数说明:
-
corpId
: 企业ID -
corpSecret
: 企业密钥 -
tag
: 标签信息
返回结果:
-
TagCreateResponse
: 创建标签的响应结果,包括标签ID
逻辑分析:
- 创建标签对象,设置标签名称和排序值。
- 调用企业微信API的
tag().create()
方法创建标签。 - 解析响应结果,判断是否创建成功。
- 获取创建成功的标签ID。
3.3 成员管理
成员管理主要包括成员的增删改查等操作。
创建成员
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.tencent.wework.api.WxApiClient;
import com.tencent.wework.api.WxApiResponse;
import com.tencent.wework.api.domain.corp.User;
import com.tencent.wework.api.domain.corp.UserCreateResponse;
public class UserCreate {
public static void main(String[] args) throws Exception {
// 获取企业微信API客户端
WxApiClient apiClient = WxApiClient.create(corpId, corpSecret);
// 创建成员
User user = new User();
user.setName("张三");
user.setMobile("13800000000");
user.setDepartment(new int[]{1});
user.setPosition("工程师");
// 发送请求
WxApiResponse response = apiClient.user().create(user);
// 解析响应结果
if (response.hasError()) {
System.out.println("创建成员失败:" + response.getError());
return;
}
// 获取成员ID
Gson gson = new Gson();
JsonObject jsonObject = JsonParser.parseString(response.getBody()).getAsJsonObject();
String userId = jsonObject.get("userid").getAsString();
System.out.println("创建成员成功,成员ID:" + userId);
}
}
参数说明:
-
corpId
: 企业ID -
corpSecret
: 企业密钥 -
user
: 成员信息
返回结果:
-
UserCreateResponse
: 创建成员的响应结果,包括成员ID
逻辑分析:
- 创建成员对象,设置成员姓名、手机号、部门和职位。
- 调用企业微信API的
user().create()
方法创建成员。 - 解析响应结果,判断是否创建成功。
- 获取创建成功的成员ID。
3.4 异步调用
通讯录管理接口支持异步调用,可以通过指定回调URL来接收异步处理结果。
异步创建部门
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.tencent.wework.api.WxApiClient;
import com.tencent.wework.api.WxApiResponse;
import com.tencent.wework.api.domain.corp.Department;
import com.tencent.wework.api.domain.corp.DepartmentCreateAsyncResponse;
public class DepartmentCreateAsync {
public static void main(String[] args) throws Exception {
// 获取企业微信API客户端
WxApiClient apiClient = WxApiClient.create(corpId, corpSecret);
// 创建部门
Department department = new Department();
department.setName("技术部");
department.setParentId(1);
department.setOrder(1);
// 设置回调URL
String callbackUrl = "https://your-callback-url.com";
// 发送请求
WxApiResponse response = apiClient.department().createAsync(department, callbackUrl);
// 解析响应结果
if (response.hasError()) {
System.out.println("异步创建部门失败:" + response.getError());
return;
}
// 获取异步任务ID
Gson gson = new Gson();
JsonObject jsonObject = JsonParser.parseString(response.getBody()).getAsJsonObject();
String taskId = jsonObject.get("taskid").getAsString();
System.out.println("异步创建部门成功,任务ID:" + taskId);
}
}
参数说明:
-
corpId
: 企业ID -
corpSecret
: 企业密钥 -
department
: 部门信息 -
callbackUrl
: 回调URL
返回结果:
-
DepartmentCreateAsyncResponse
: 异步创建部门的响应结果,包括异步任务ID
逻辑分析:
- 创建部门对象,设置部门名称、父部门ID和排序值。
- 设置回调URL。
- 调用企业微信API的
department().createAsync()
方法异步创建部门。 - 解析响应结果,判断是否创建成功。
- 获取异步任务ID。
4. 消息接口封装
4.1 文本消息
文本消息是最常用的消息类型,主要用于发送文字信息。
请求参数:
{
"touser": "USERID",
"msgtype": "text",
"agentid": 1000002,
"text": {
"content": "你的快递已到,请携带工卡前往邮件中心领取。"
},
"safe": 0
}
参数说明:
- touser:接收消息的成员ID
- msgtype:消息类型,固定为"text"
- agentid:企业应用的id
- text:文本消息内容
- safe:表示是否是保密消息,0表示否,1表示是
逻辑分析:
-
touser
参数指定消息接收者,可以是单个成员ID或部门ID。 -
msgtype
参数固定为"text",表示发送文本消息。 -
agentid
参数指定发送消息的企业应用ID。 -
text
参数指定消息内容,可以包含表情符号。 -
safe
参数表示消息是否保密,保密消息只能通过微信企业号客户端查看。
4.2 图片消息
图片消息用于发送图片信息。
请求参数:
{
"touser": "USERID",
"msgtype": "image",
"agentid": 1000002,
"image": {
"media_id": "MEDIA_ID"
},
"safe": 0
}
参数说明:
- touser:接收消息的成员ID
- msgtype:消息类型,固定为"image"
- agentid:企业应用的id
- image:图片消息内容
- safe:表示是否是保密消息,0表示否,1表示是
逻辑分析:
-
touser
参数指定消息接收者,可以是单个成员ID或部门ID。 -
msgtype
参数固定为"image",表示发送图片消息。 -
agentid
参数指定发送消息的企业应用ID。 -
image
参数指定图片消息内容,需要先通过上传临时素材
接口获取media_id。 -
safe
参数表示消息是否保密,保密消息只能通过微信企业号客户端查看。
4.3 语音消息
语音消息用于发送语音信息。
请求参数:
{
"touser": "USERID",
"msgtype": "voice",
"agentid": 1000002,
"voice": {
"media_id": "MEDIA_ID"
},
"safe": 0
}
参数说明:
- touser:接收消息的成员ID
- msgtype:消息类型,固定为"voice"
- agentid:企业应用的id
- voice:语音消息内容
- safe:表示是否是保密消息,0表示否,1表示是
逻辑分析:
-
touser
参数指定消息接收者,可以是单个成员ID或部门ID。 -
msgtype
参数固定为"voice",表示发送语音消息。 -
agentid
参数指定发送消息的企业应用ID。 -
voice
参数指定语音消息内容,需要先通过上传临时素材
接口获取media_id。 -
safe
参数表示消息是否保密,保密消息只能通过微信企业号客户端查看。
4.4 视频消息
视频消息用于发送视频信息。
请求参数:
{
"touser": "USERID",
"msgtype": "video",
"agentid": 1000002,
"video": {
"media_id": "MEDIA_ID",
"title": "视频标题",
"description": "视频描述"
},
"safe": 0
}
参数说明:
- touser:接收消息的成员ID
- msgtype:消息类型,固定为"video"
- agentid:企业应用的id
- video:视频消息内容
- safe:表示是否是保密消息,0表示否,1表示是
逻辑分析:
-
touser
参数指定消息接收者,可以是单个成员ID或部门ID。 -
msgtype
参数固定为"video",表示发送视频消息。 -
agentid
参数指定发送消息的企业应用ID。 -
video
参数指定视频消息内容,需要先通过上传临时素材
接口获取media_id。 -
safe
参数表示消息是否保密,保密消息只能通过微信企业号客户端查看。
4.5 文件消息
文件消息用于发送文件信息。
请求参数:
{
"touser": "USERID",
"msgtype": "file",
"agentid": 1000002,
"file": {
"media_id": "MEDIA_ID"
},
"safe": 0
}
参数说明:
- touser:接收消息的成员ID
- msgtype:消息类型,固定为"file"
- agentid:企业应用的id
- file:文件消息内容
- safe:表示是否是保密消息,0表示否,1表示是
逻辑分析:
-
touser
参数指定消息接收者,可以是单个成员ID或部门ID。 -
msgtype
参数固定为"file",表示发送文件消息。 -
agentid
参数指定发送消息的企业应用ID。 -
file
参数指定文件消息内容,需要先通过上传临时素材
接口获取media_id。 -
safe
参数表示消息是否保密,保密消息只能通过微信企业号客户端查看。
5. 自定义菜单构建
自定义菜单是企业微信中重要的功能之一,它允许企业为员工提供个性化的菜单选项,方便员工访问企业提供的服务和信息。本节将介绍自定义菜单的创建、查询、修改和删除操作。
5.1 创建菜单
创建菜单需要使用 menu/create
接口。该接口接收一个 JSON 格式的菜单定义,并返回一个菜单 ID。
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
public class CreateMenu {
public static void main(String[] args) throws IOException, InterruptedException {
// 企业微信CorpID
String corpId = "your_corp_id";
// 企业微信应用Secret
String secret = "your_secret";
// 获取access_token
String accessToken = getAccessToken(corpId, secret);
// 创建菜单
JsonObject menu = new JsonObject();
JsonArray buttons = new JsonArray();
JsonObject button1 = new JsonObject();
button1.addProperty("type", "click");
button1.addProperty("name", "菜单1");
button1.addProperty("key", "key1");
buttons.add(button1);
JsonObject button2 = new JsonObject();
button2.addProperty("type", "view");
button2.addProperty("name", "菜单2");
button2.addProperty("url", "https://www.example.com");
buttons.add(button2);
menu.add("button", buttons);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://qyapi.weixin.qq.com/cgi-bin/menu/create?access_token=" + accessToken))
.POST(HttpRequest.BodyPublishers.ofString(menu.toString()))
.header("Content-Type", "application/json")
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// 解析响应
JsonObject result = new Gson().fromJson(response.body(), JsonObject.class);
if (result.has("errcode") && result.get("errcode").getAsInt() == 0) {
System.out.println("创建菜单成功");
} else {
System.out.println("创建菜单失败:" + result.get("errmsg").getAsString());
}
}
private static String getAccessToken(String corpId, String secret) throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + corpId + "&corpsecret=" + secret))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// 解析响应
JsonObject result = new Gson().fromJson(response.body(), JsonObject.class);
if (result.has("access_token")) {
return result.get("access_token").getAsString();
} else {
throw new RuntimeException("获取access_token失败:" + result.get("errmsg").getAsString());
}
}
}
参数说明:
-
access_token
:企业微信应用的access_token -
menu
:菜单定义,JSON 格式
返回结果:
-
errcode
:错误码,0 表示成功 -
errmsg
:错误消息 -
menuid
:菜单 ID
5.2 查询菜单
查询菜单需要使用 menu/get
接口。该接口接收一个菜单 ID,并返回菜单定义。
import com.google.gson.Gson;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class GetMenu {
public static void main(String[] args) throws IOException, InterruptedException {
// 企业微信CorpID
String corpId = "your_corp_id";
// 企业微信应用Secret
String secret = "your_secret";
// 获取access_token
String accessToken = getAccessToken(corpId, secret);
// 查询菜单
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://qyapi.weixin.qq.com/cgi-bin/menu/get?access_token=" + accessToken))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// 解析响应
Gson gson = new Gson();
JsonObject result = gson.fromJson(response.body(), JsonObject.class);
if (result.has("errcode") && result.get("errcode").getAsInt() == 0) {
System.out.println("查询菜单成功");
System.out.println(gson.toJson(result.get("menu")));
} else {
System.out.println("查询菜单失败:" + result.get("errmsg").getAsString());
}
}
private static String getAccessToken(String corpId, String secret) throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + corpId + "&corpsecret=" + secret))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// 解析响应
Gson gson = new Gson();
JsonObject result = gson.fromJson(response.body(), JsonObject.class);
if (result.has("access_token")) {
return result.get("access_token").getAsString();
} else {
throw new RuntimeException("获取access_token失败:" + result.get("errmsg").getAsString());
}
}
}
参数说明:
-
access_token
:企业微信应用的access_token
返回结果:
-
errcode
:错误码,0 表示成功 -
errmsg
:错误消息 -
menu
:菜单定义
5.3 修改菜单
修改菜单需要使用 menu/update
接口。该接口接收一个菜单 ID 和一个新的菜单定义,并更新菜单。
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class UpdateMenu {
public static void main(String[] args) throws IOException, InterruptedException {
// 企业微信CorpID
String corpId = "your_corp_id";
// 企业微信应用Secret
String secret = "your_secret";
// 获取access_token
String accessToken = getAccessToken(corpId, secret);
// 修改菜单
JsonObject menu = new JsonObject();
JsonArray buttons = new JsonArray();
JsonObject button1 = new JsonObject();
button1.addProperty("type", "click");
button1.addProperty("name", "菜单1");
button1.addProperty("key", "key1");
buttons.add(button1);
JsonObject button2 = new JsonObject();
button2.addProperty("type", "view");
button2.addProperty("name", "菜单2");
button2.addProperty("url", "https://www.example.com");
buttons.add(button2);
menu.add("button", buttons);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://qyapi.weixin.qq.com/cgi-bin/menu/update?access_token=" + accessToken))
.POST(HttpRequest.BodyPublishers.ofString(menu.toString()))
.header("Content-Type", "application/json")
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// 解析响应
JsonObject result = new Gson().fromJson(response.body(), JsonObject.class);
if (result.has("errcode") && result.get("errcode").getAsInt() == 0) {
System.out.println("修改菜单成功");
} else {
System.
# 6. 多媒体上传下载
## 6.1 文件流上传
### 6.1.1 上传文件
文件流上传是指直接将文件内容作为请求体发送给企业微信服务器,适用于上传较小文件。
**请求参数:**
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| media | file | 是 | 文件内容 |
| type | string | 是 | 文件类型,如image/jpeg |
| filename | string | 是 | 文件名 |
**请求示例:**
```java
String mediaId = corpMessageService.uploadMedia(new FileInputStream(file), "image/jpeg", "test.jpg");
6.1.2 上传临时素材
临时素材上传是指将文件上传到企业微信服务器,并获取一个临时的media_id,该media_id可在一定时间内用于发送消息。
请求参数:
| 参数名 | 类型 | 必填 | 说明 | |---|---|---|---| | media | file | 是 | 文件内容 | | type | string | 是 | 文件类型,如image/jpeg |
请求示例:
String mediaId = corpMessageService.uploadTemporaryMedia(new FileInputStream(file), "image/jpeg");
6.2 网络传输上传
网络传输上传是指通过HTTP POST请求将文件上传到企业微信服务器,适用于上传较大文件。
6.2.1 上传永久素材
永久素材上传是指将文件上传到企业微信服务器,并保存为永久素材,可长期使用。
请求参数:
| 参数名 | 类型 | 必填 | 说明 | |---|---|---|---| | media | file | 是 | 文件内容 | | type | string | 是 | 文件类型,如image/jpeg | | filename | string | 是 | 文件名 |
请求示例:
String mediaId = corpMessageService.uploadPermanentMedia(new FileInputStream(file), "image/jpeg", "test.jpg");
6.2.2 上传临时素材
临时素材上传与文件流上传类似,但使用HTTP POST请求方式。
请求参数:
| 参数名 | 类型 | 必填 | 说明 | |---|---|---|---| | media | file | 是 | 文件内容 | | type | string | 是 | 文件类型,如image/jpeg |
请求示例:
String mediaId = corpMessageService.uploadTemporaryMedia(new FileInputStream(file), "image/jpeg");
6.3 文件流下载
文件流下载是指直接将企业微信服务器上的文件内容作为响应体返回给客户端,适用于下载较小文件。
6.3.1 下载文件
请求参数:
| 参数名 | 类型 | 必填 | 说明 | |---|---|---|---| | media_id | string | 是 | 文件media_id |
请求示例:
corpMessageService.downloadMedia(mediaId, new FileOutputStream(file));
6.3.2 下载临时素材
请求参数:
| 参数名 | 类型 | 必填 | 说明 | |---|---|---|---| | media_id | string | 是 | 文件media_id |
请求示例:
corpMessageService.downloadTemporaryMedia(mediaId, new FileOutputStream(file));
6.4 网络传输下载
网络传输下载是指通过HTTP GET请求将企业微信服务器上的文件下载到客户端,适用于下载较大文件。
6.4.1 下载永久素材
请求参数:
| 参数名 | 类型 | 必填 | 说明 | |---|---|---|---| | media_id | string | 是 | 文件media_id |
请求示例:
corpMessageService.downloadPermanentMedia(mediaId, new FileOutputStream(file));
6.4.2 下载临时素材
请求参数:
| 参数名 | 类型 | 必填 | 说明 | |---|---|---|---| | media_id | string | 是 | 文件media_id |
请求示例:
corpMessageService.downloadTemporaryMedia(mediaId, new FileOutputStream(file));
7. 授权与二次验证
7.1 OAuth2.0授权流程
OAuth2.0是一种授权协议,允许用户授权第三方应用程序访问其数据,而无需共享密码。企业微信的OAuth2.0授权流程如下:
- 用户访问第三方应用程序,触发授权流程。
- 第三方应用程序重定向用户到企业微信授权页面,页面上包含
appid
、redirect_uri
和response_type
参数。 - 用户在授权页面上确认授权,企业微信返回
code
参数给第三方应用程序。 - 第三方应用程序使用
code
参数向企业微信换取access_token
。 - 第三方应用程序使用
access_token
访问企业微信API。
7.2 code换取access_token
code
参数是授权流程中的临时凭证,需要及时兑换为 access_token
。 access_token
是访问企业微信API的令牌,有效期为2小时。兑换 access_token
的请求如下:
import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
public class GetAccessToken {
public static void main(String[] args) throws IOException {
String appId = "YOUR_APP_ID";
String secret = "YOUR_APP_SECRET";
String code = "YOUR_CODE";
String redirectUri = "YOUR_REDIRECT_URI";
HttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("https://qyapi.weixin.qq.com/cgi-bin/gettoken");
Map<String, String> params = new HashMap<>();
params.put("corpid", appId);
params.put("corpsecret", secret);
params.put("code", code);
params.put("grant_type", "authorization_code");
StringEntity entity = new StringEntity(URLEncoder.encode(params.toString(), "UTF-8"));
httpPost.setEntity(entity);
// 发送请求并获取响应
// ...
// 解析响应并获取access_token
// ...
}
}
7.3 签名生成
企业微信的API调用需要签名,签名算法如下:
signature = sha1(nonce + timestamp + url + body)
其中:
-
nonce
:随机字符串,长度为32个字符以内。 -
timestamp
:时间戳,从1970年1月1日0点0分0秒开始到现在的秒数。 -
url
:请求的URL地址,不包括查询字符串。 -
body
:请求体,如果是GET请求则为null
。
签名算法的实现代码如下:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Signature {
public static String generate(String nonce, String timestamp, String url, String body) throws NoSuchAlgorithmException {
String stringToSign = nonce + timestamp + url + body;
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
byte[] signatureBytes = sha1.digest(stringToSign.getBytes());
return bytesToHex(signatureBytes);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}
7.4 时间戳防重放
为了防止重放攻击,企业微信要求每个请求的 timestamp
必须与服务器时间戳相差不大于5分钟。服务器时间戳可以通过以下接口获取:
import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
public class GetServerTimestamp {
public static void main(String[] args) throws IOException {
HttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket");
Map<String, String> params = new HashMap<>();
params.put("type", "jsapi");
StringEntity entity = new StringEntity(URLEncoder.encode(params.toString(), "UTF-8"));
httpPost.setEntity(entity);
// 发送请求并获取响应
// ...
// 解析响应并获取server_timestamp
// ...
}
}
简介:本教程深入讲解企业微信API的应用,涵盖通讯录管理、消息接口操作、自定义菜单构建、多媒体处理和用户认证等核心功能。通过实践任务,学生将掌握这些知识点的实现,包括部门管理、消息发送、菜单动态构建、文件上传下载和OAuth2.0授权流程。掌握这些技能将使学生能够开发出满足企业内部沟通和协作需求的系统。