Commit 7b318c8d by 周海峰

no message

parent a7e1914e
......@@ -104,7 +104,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
"/api/ps/account_sel/**", "/znzl/file/**", "/auth/v1/**", "/auth/user/**",
"/error/**", "/weixin/wxuserinfo/**", "/weixin/information/**", "/auth/dt/**",
"/avatar/**", "/user/updateWxPlatformPersonnelByAccount", "/wechatApi/**",
"/PlatformUserFavoriteAppsController/**", "/roleuser/addUserNoticeRole"
"/PlatformUserFavoriteAppsController/**", "/roleuser/addUserNoticeRole",
"/messagepush/**"
).permitAll()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证
......
package com.metro.auth.platform.messagepush.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 企业微信内网应用配置属性
*/
@Data
@Component
@ConfigurationProperties(prefix = "weixin-params")
public class WeChatConfig {
private String wxCorpId;
private String wxAgentId;
private String wxSecret;
private String wxTxSecret;
private String wxTokenUrl;
private String wxSendMessageUrl;
private String wxGetUserInfo;
private String wxGetUserByCode;
private String wxTxGetList;
private String wxUserDeptDetail;
}
package com.metro.auth.platform.messagepush.controller;
import com.alibaba.fastjson.JSONObject;
import com.metro.auth.platform.domain.ResultCode;
import com.metro.auth.platform.domain.ResultJson;
import com.metro.auth.platform.messagepush.model.request.MessageSubmitRequest;
import com.metro.auth.platform.messagepush.service.MessagePushService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 企业微信内网应用消息推送控制器
*/
@Slf4j
@RestController
@RequestMapping("/messagepush")
public class MessagePushController {
@Resource
private MessagePushService messagePushService;
/**
* 获取 AccessToken
* GET /messagepush/accesstoken
*/
@GetMapping("/accesstoken")
public ResultJson getAccessToken() {
String token = messagePushService.getAccessToken();
if (StringUtils.hasLength(token)) {
return ResultJson.ok(token);
}
return ResultJson.failure(ResultCode.SERVER_ERROR, "获取access_token失败");
}
/**
* 强制刷新 AccessToken
* GET /messagepush/accesstoken/refresh
*/
@GetMapping("/accesstoken/refresh")
public ResultJson refreshAccessToken() {
String token = messagePushService.refreshAccessToken();
if (StringUtils.hasLength(token)) {
return ResultJson.ok(token);
}
return ResultJson.failure(ResultCode.SERVER_ERROR, "刷新access_token失败");
}
/**
* 获取部门列表
* GET /messagepush/department/list?id=xxx
*/
@GetMapping("/department/list")
public ResultJson getDepartmentList(@RequestParam(required = false) Integer id) {
JSONObject result = messagePushService.getDepartmentList(id);
if (result == null) {
return ResultJson.failure(ResultCode.SERVER_ERROR, "调用企业微信API失败");
}
if (result.getInteger("errcode") != null && result.getInteger("errcode") != 0) {
log.error("获取部门列表失败: {}", result.toJSONString());
return ResultJson.failure(ResultCode.SERVER_ERROR, result.getString("errmsg"));
}
return ResultJson.ok(result.getJSONArray("department"));
}
/**
* 获取部门用户详情列表
* GET /messagepush/user/list?departmentId=1&fetchChild=1
*/
@GetMapping("/user/list")
public ResultJson getUserList(
@RequestParam(required = true) Integer departmentId,
@RequestParam(required = false, defaultValue = "1") Integer fetchChild) {
if (departmentId == null) {
return ResultJson.failure(ResultCode.BAD_REQUEST, "departmentId不能为空");
}
JSONObject result = messagePushService.getUserListByDepartment(departmentId, fetchChild);
if (result == null) {
return ResultJson.failure(ResultCode.SERVER_ERROR, "调用企业微信API失败");
}
if (result.getInteger("errcode") != null && result.getInteger("errcode") != 0) {
log.error("获取用户列表失败: {}", result.toJSONString());
return ResultJson.failure(ResultCode.SERVER_ERROR, result.getString("errmsg"));
}
return ResultJson.ok(result.getJSONArray("userlist"));
}
/**
* 获取应用后台免登用户信息
* GET /messagepush/auth/getuserinfo?code=xxx
*/
@GetMapping("/auth/getuserinfo")
public ResultJson getUserInfo(@RequestParam(required = true) String code) {
if (!StringUtils.hasLength(code)) {
return ResultJson.failure(ResultCode.BAD_REQUEST, "code不能为空");
}
JSONObject result = messagePushService.getUserInfoByCode(code);
if (result == null) {
return ResultJson.failure(ResultCode.SERVER_ERROR, "调用企业微信API失败");
}
if (result.getInteger("errcode") != null && result.getInteger("errcode") != 0) {
log.error("获取用户信息失败: {}", result.toJSONString());
return ResultJson.failure(ResultCode.SERVER_ERROR, result.getString("errmsg"));
}
return ResultJson.ok(result);
}
/**
* 根据 code 获取完整用户信息
* GET /messagepush/user/getuserinfo?code=xxx
*/
@GetMapping("/user/getuserinfo")
public ResultJson getUserDetailByCode(@RequestParam(required = true) String code) {
if (!StringUtils.hasLength(code)) {
return ResultJson.failure(ResultCode.BAD_REQUEST, "code不能为空");
}
JSONObject result = messagePushService.getUserDetailByCode(code);
if (result == null) {
return ResultJson.failure(ResultCode.SERVER_ERROR, "调用企业微信API失败");
}
if (result.getInteger("errcode") != null && result.getInteger("errcode") != 0) {
log.error("获取用户详情失败: {}", result.toJSONString());
return ResultJson.failure(ResultCode.SERVER_ERROR, result.getString("errmsg"));
}
return ResultJson.ok(result);
}
/**
* 发送应用消息(JSON格式,透传)
* POST /messagepush/message/send
*/
@PostMapping("/message/send")
public ResultJson sendMessage(@RequestBody JSONObject messageBody) {
if (messageBody == null || messageBody.isEmpty()) {
return ResultJson.failure(ResultCode.BAD_REQUEST, "消息内容不能为空");
}
log.info("发送应用消息请求: {}", messageBody.toJSONString());
JSONObject result = messagePushService.sendMessage(messageBody.toJSONString());
if (result == null) {
return ResultJson.failure(ResultCode.SERVER_ERROR, "调用企业微信API失败");
}
if (result.getInteger("errcode") != null && result.getInteger("errcode") != 0) {
log.error("发送消息失败: {}", result.toJSONString());
return ResultJson.failure(ResultCode.SERVER_ERROR, result.getString("errmsg"));
}
return ResultJson.ok(result);
}
/**
* 提交应用消息(实体类参数)
* POST /messagepush/message/submit
*/
@PostMapping("/message/submit")
public ResultJson submitMessage(@RequestBody MessageSubmitRequest request) {
if (request == null) {
return ResultJson.failure(ResultCode.BAD_REQUEST, "消息内容不能为空");
}
if (!StringUtils.hasLength(request.getUserId())) {
return ResultJson.failure(ResultCode.BAD_REQUEST, "userId不能为空");
}
if (!StringUtils.hasLength(request.getMessageType())) {
return ResultJson.failure(ResultCode.BAD_REQUEST, "messageType不能为空");
}
log.info("提交应用消息请求: {}", JSONObject.toJSONString(request));
JSONObject result = messagePushService.submitMessage(request);
if (result == null) {
return ResultJson.failure(ResultCode.SERVER_ERROR, "调用企业微信API失败");
}
if (result.getInteger("errcode") != null && result.getInteger("errcode") != 0) {
log.error("提交消息失败: {}", result.toJSONString());
return ResultJson.failure(ResultCode.SERVER_ERROR, result.getString("errmsg"));
}
return ResultJson.ok(result);
}
}
package com.metro.auth.platform.messagepush.model.request;
import lombok.Data;
/**
* 消息提交请求参数
*/
@Data
public class MessageSubmitRequest {
/**
* 应用标识
*/
private String appId;
/**
* 目标用户ID
*/
private String userId;
/**
* 消息标题
*/
private String title;
/**
* 消息内容
*/
private String content;
/**
* 跳转链接
*/
private String targetUrl;
/**
* 消息类型:text、textcard、markdown、image、file、news、mpnews、miniprogram_notice
*/
private String messageType;
/**
* 时间戳,格式:YYYY-MM-DD HH:MM:SS
*/
private String timestamp;
/**
* 特定消息类型的扩展数据
*/
private Object msgData;
}
\ No newline at end of file
package com.metro.auth.platform.messagepush.model.request;
import lombok.Data;
import java.util.List;
/**
* 发送应用消息请求参数
*/
@Data
public class SendMessageRequest {
/**
* 接收人类型:user|party|tag
*/
private String touser;
private String toparty;
private String totag;
/**
* 消息类型:text/textcard/markdown/image/file/news/mpnews/miniprogram_notice
*/
private String msgtype;
/**
* 应用agentid
*/
private Integer agentid;
/**
* 文本消息内容
*/
private TextContent text;
/**
* 文本卡片消息内容
*/
private TextCardContent textcard;
@Data
public static class TextContent {
private String content;
}
@Data
public static class TextCardContent {
private String title;
private String description;
private String url;
private String btntxt;
}
}
package com.metro.auth.platform.messagepush.model.request;
import lombok.Data;
/**
* 获取部门用户列表请求参数
*/
@Data
public class UserListRequest {
/**
* 获取的部门id
*/
private Integer departmentId;
/**
* 1/0:是否递归获取子部门下的用户
*/
private Integer fetchChild = 1;
}
package com.metro.auth.platform.messagepush.model.response;
import lombok.Data;
/**
* 企业微信部门信息
*/
@Data
public class WxDepartment {
/**
* 部门id
*/
private Integer id;
/**
* 部门名称
*/
private String name;
/**
* 父部门id
*/
private Integer parentid;
/**
* 排序字段,值越小排序越靠前
*/
private Integer order;
/**
* 部门层级
*/
private Integer level;
/**
* 子部门数量
*/
private Integer childCount;
}
package com.metro.auth.platform.messagepush.model.response;
import lombok.Data;
/**
* 企业微信消息发送结果
*/
@Data
public class WxMessageResult {
/**
* 返回码,0表示成功
*/
private Integer errcode;
/**
* 对返回码的文本描述
*/
private String errmsg;
/**
* 消息id
*/
private Long msgid;
/**
* 响应结果,0=成功
*/
private Integer responseType;
/**
* 消息是否全部发送成功
*/
private Boolean invalidUser;
/**
* 无效的partyid
*/
private Boolean invalidParty;
/**
* 无效的tagid
*/
private Boolean invalidTag;
}
package com.metro.auth.platform.messagepush.model.response;
import lombok.Data;
/**
* 企业微信用户信息
*/
@Data
public class WxUser {
/**
* 成员UserID
*/
private String userid;
/**
* 成员名称
*/
private String name;
/**
* 部门id列表
*/
private Integer[] department;
/**
* 职位信息
*/
private String position;
/**
* 手机号
*/
private String mobile;
/**
* 邮箱
*/
private String email;
/**
* 头像url
*/
private String avatar;
/**
* 性别。0表示未定义,1表示男性,2表示女性
*/
private Integer gender;
/**
* 员工个人二维码,样式是一个小程序的二维码
*/
private String qrCode;
/**
* 关注状态 1=已关注 2=禁用 4=未关注
*/
private Integer status;
/**
* 是否是系统管理员
*/
private Boolean isleader;
/**
* 成员备注
*/
private String remark;
/**
* 激活状态 1=已激活 5=已退出
*/
private Integer enable;
}
package com.metro.auth.platform.messagepush.model.response;
import lombok.Data;
/**
* 企业微信用户免登信息
*/
@Data
public class WxUserInfo {
/**
* 成员UserID
*/
private String UserId;
/**
* 成员DeviceId
*/
private String DeviceId;
/**
* 只有手机和邮箱没有匹配时返回,扫码登录时会有此字段
*/
private String userTicket;
/**
* userTicket的有效期(userTicket的有效期通过user_ticket获取用户信息时才会返回)
*/
private Integer expiresIn;
}
package com.metro.auth.platform.messagepush.service;
import com.alibaba.fastjson.JSONObject;
import com.metro.auth.platform.messagepush.model.request.MessageSubmitRequest;
/**
* 企业微信内网应用消息推送服务接口
*/
public interface MessagePushService {
/**
* 获取 AccessToken
*/
String getAccessToken();
/**
* 强制刷新 AccessToken
*/
String refreshAccessToken();
/**
* 获取部门列表
*
* @param id 部门id,不传则获取全部
*/
JSONObject getDepartmentList(Integer id);
/**
* 获取部门用户详情列表
*
* @param departmentId 部门id
* @param fetchChild 是否递归获取子部门(1=递归,0=不递归)
*/
JSONObject getUserListByDepartment(Integer departmentId, Integer fetchChild);
/**
* 获取应用后台免登用户信息(OAuth2)
*
* @param code 授权码
*/
JSONObject getUserInfoByCode(String code);
/**
* 根据授权码获取完整用户信息
*
* @param code 授权码
*/
JSONObject getUserDetailByCode(String code);
/**
* 发送应用消息
*
* @param messageJson 消息 JSON
*/
JSONObject sendMessage(String messageJson);
/**
* 发送应用消息
*
* @param request 消息提交请求
*/
JSONObject submitMessage(MessageSubmitRequest request);
}
package com.metro.auth.platform.messagepush.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.metro.auth.platform.messagepush.model.request.MessageSubmitRequest;
import com.metro.auth.platform.messagepush.service.MessagePushService;
import com.metro.auth.platform.messagepush.util.WeChatApiUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 企业微信内网应用消息推送服务实现
*/
@Slf4j
@Service
public class MessagePushServiceImpl implements MessagePushService {
@Resource
private WeChatApiUtil weChatApiUtil;
@Override
public String getAccessToken() {
return weChatApiUtil.getAccessToken();
}
@Override
public String refreshAccessToken() {
return weChatApiUtil.refreshAccessToken();
}
@Override
public JSONObject getDepartmentList(Integer id) {
return weChatApiUtil.getDepartmentList(id);
}
@Override
public JSONObject getUserListByDepartment(Integer departmentId, Integer fetchChild) {
return weChatApiUtil.getUserListByDepartment(departmentId, fetchChild);
}
@Override
public JSONObject getUserInfoByCode(String code) {
return weChatApiUtil.getUserInfoByCode(code);
}
@Override
public JSONObject getUserDetailByCode(String code) {
return weChatApiUtil.getUserDetailByCode(code);
}
@Override
public JSONObject sendMessage(String messageJson) {
return weChatApiUtil.sendMessage(messageJson);
}
@Override
public JSONObject submitMessage(MessageSubmitRequest request) {
if (request == null) {
return null;
}
// 构建企业微信消息格式
JSONObject message = new JSONObject();
message.put("touser", request.getUserId());
message.put("msgtype", request.getMessageType());
message.put("agentid", Integer.parseInt(weChatApiUtil.getWeChatConfig().getWxAgentId()));
// 根据消息类型构建对应的消息体
switch (request.getMessageType()) {
case "text":
JSONObject text = new JSONObject();
text.put("content", request.getContent());
message.put("text", text);
break;
case "textcard":
JSONObject textcard = new JSONObject();
textcard.put("title", request.getTitle());
textcard.put("description", request.getContent());
textcard.put("url", request.getTargetUrl());
// msg_data 可能包含 btntxt
if (request.getMsgData() != null) {
if (request.getMsgData() instanceof JSONObject) {
JSONObject msgData = (JSONObject) request.getMsgData();
if (msgData.containsKey("btntxt")) {
textcard.put("btntxt", msgData.getString("btntxt"));
}
}
} else {
textcard.put("btntxt", "查看详情");
}
message.put("textcard", textcard);
break;
case "markdown":
JSONObject markdown = new JSONObject();
if (request.getMsgData() != null && request.getMsgData() instanceof JSONObject) {
markdown.putAll((JSONObject) request.getMsgData());
}
message.put("markdown", markdown);
break;
case "image":
JSONObject image = new JSONObject();
if (request.getMsgData() != null && request.getMsgData() instanceof JSONObject) {
image.putAll((JSONObject) request.getMsgData());
}
message.put("image", image);
break;
case "file":
JSONObject file = new JSONObject();
if (request.getMsgData() != null && request.getMsgData() instanceof JSONObject) {
file.putAll((JSONObject) request.getMsgData());
}
message.put("file", file);
break;
case "news":
case "mpnews":
JSONObject news = new JSONObject();
if (request.getMsgData() != null && request.getMsgData() instanceof JSONObject) {
news.putAll((JSONObject) request.getMsgData());
}
message.put(request.getMessageType(), news);
break;
default:
// 其他消息类型按通用格式处理
if (request.getMsgData() != null && request.getMsgData() instanceof JSONObject) {
message.put(request.getMessageType(), request.getMsgData());
}
break;
}
return weChatApiUtil.sendMessage(message.toJSONString());
}
}
package com.metro.auth.platform.messagepush.util;
import com.alibaba.fastjson.JSONObject;
import com.metro.auth.platform.http.HttpAPIService;
import com.metro.auth.platform.messagepush.config.WeChatConfig;
import com.metro.auth.platform.redis.RedisUtils;
import com.metro.auth.platform.wxmessage.ApiConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
* 企业微信内网应用 API 调用工具类
*/
@Slf4j
@Component
public class WeChatApiUtil {
private static final String ACCESS_TOKEN_KEY = "wechat:access_token";
private static final long ACCESS_TOKEN_EXPIRE = 7100L;
@Resource
private WeChatConfig weChatConfig;
@Resource
private HttpAPIService httpAPIService;
@Resource
private RedisUtils redisUtils;
/**
* 获取 AccessToken(优先从 Redis 缓存获取)
*/
public String getAccessToken() {
Object cached = redisUtils.get(ACCESS_TOKEN_KEY);
if (cached != null && StringUtils.hasLength(cached.toString())) {
log.debug("从Redis缓存获取access_token");
return cached.toString();
}
log.debug("Redis缓存未命中,从API获取access_token");
return refreshAccessToken();
}
/**
* 强制刷新 AccessToken
*/
public String refreshAccessToken() {
String url = weChatConfig.getWxTokenUrl()
+ "?corpid=" + weChatConfig.getWxCorpId()
+ "&corpsecret=" + weChatConfig.getWxSecret();
try {
String result = httpAPIService.doGet(url);
if (result != null) {
JSONObject json = JSONObject.parseObject(result);
String token = json.getString("access_token");
Integer expiresIn = json.getInteger("expires_in");
if (StringUtils.hasLength(token)) {
redisUtils.set(ACCESS_TOKEN_KEY, token, expiresIn != null ? expiresIn : ACCESS_TOKEN_EXPIRE, TimeUnit.SECONDS);
log.info("access_token刷新成功: {}", token);
return token;
}
}
} catch (Exception e) {
log.error("刷新access_token失败", e);
}
return null;
}
/**
* 获取部门列表
*
* @param id 部门id,不传则获取全部
*/
public JSONObject getDepartmentList(Integer id) {
String token = getAccessToken();
String url = weChatConfig.getWxTxGetList() + token;
if (id != null) {
url += "&id=" + id;
}
String result = httpAPIService.doGet(url);
return result != null ? JSONObject.parseObject(result) : null;
}
/**
* 获取部门用户详情列表
*
* @param departmentId 部门id
* @param fetchChild 是否递归获取子部门
*/
public JSONObject getUserListByDepartment(Integer departmentId, Integer fetchChild) {
if (departmentId == null) {
return null;
}
String token = getAccessToken();
String url = weChatConfig.getWxUserDeptDetail() + token
+ "&department_id=" + departmentId
+ "&fetch_child=" + (fetchChild != null ? fetchChild : 1);
String result = httpAPIService.doGet(url);
return result != null ? JSONObject.parseObject(result) : null;
}
/**
* 获取应用后台免登用户信息(OAuth2 授权码)
*
* @param code OAuth2 授权码
*/
public JSONObject getUserInfoByCode(String code) {
if (!StringUtils.hasLength(code)) {
return null;
}
String token = getAccessToken();
String url = weChatConfig.getWxGetUserInfo() + token + "&code=" + code;
String result = httpAPIService.doGet(url);
return result != null ? JSONObject.parseObject(result) : null;
}
/**
* 根据 code 获取完整用户信息
*
* @param code OAuth2 授权码
*/
public JSONObject getUserDetailByCode(String code) {
if (!StringUtils.hasLength(code)) {
return null;
}
String token = getAccessToken();
String url = weChatConfig.getWxGetUserByCode() + token + "&code=" + code;
String result = httpAPIService.doGet(url);
return result != null ? JSONObject.parseObject(result) : null;
}
/**
* 发送应用消息
*
* @param messageJson 消息 JSON
*/
public JSONObject sendMessage(String messageJson) {
String token = getAccessToken();
String url = weChatConfig.getWxSendMessageUrl() + token;
return httpAPIService.doPost(url, messageJson);
}
public WeChatConfig getWeChatConfig() {
return weChatConfig;
}
}
......@@ -182,6 +182,7 @@ weixin-params:
wx_token_url : https://qyapi.weixin.qq.com/cgi-bin/gettoken
wx_jstiket : https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=
wx_getuserinfo : https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=
wx_getuser_bycode : https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo_bycode?access_token=
wx_all_userinfo : https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=
#微信通讯录管理
#获取通讯录管理secret
......
......@@ -185,6 +185,7 @@ weixin-params:
wx_token_url : https://qyapi.weixin.qq.com/cgi-bin/gettoken
wx_jstiket : https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=
wx_getuserinfo : https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=
wx_getuser_bycode : https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo_bycode?access_token=
wx_all_userinfo : https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=
#微信通讯录管理
#获取通讯录管理secret
......
......@@ -159,6 +159,7 @@ weixin-params:
wx_token_url : https://qyapi.weixin.qq.com/cgi-bin/gettoken
wx_jstiket : https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=
wx_getuserinfo : https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=
wx_getuser_bycode : https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo_bycode?access_token=
wx_all_userinfo : https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=
#微信通讯录管理
#获取通讯录管理secret
......
......@@ -183,6 +183,7 @@ weixin-params:
wx_token_url : https://qyapi.weixin.qq.com/cgi-bin/gettoken
wx_jstiket : https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=
wx_getuserinfo : https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=
wx_getuser_bycode : https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo_bycode?access_token=
wx_all_userinfo : https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=
#微信通讯录管理
#获取通讯录管理secret
......
......@@ -185,6 +185,7 @@ weixin-params:
wx_token_url : https://qyapi.weixin.qq.com/cgi-bin/gettoken
wx_jstiket : https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=
wx_getuserinfo : https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=
wx_getuser_bycode : https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo_bycode?access_token=
wx_all_userinfo : https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=
#微信通讯录管理
#获取通讯录管理secret
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论