mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2026-03-10 00:13:40 +08:00
合并开发分支,发布正式版
This commit is contained in:
@@ -7,11 +7,11 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>weixin-java-cp</artifactId>
|
||||
<name>WxJava - CP</name>
|
||||
<name>WxJava - CP Java SDK</name>
|
||||
<description>微信企业号/企业微信 Java SDK</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -84,6 +84,11 @@ public class WxCpConsts {
|
||||
*/
|
||||
public static final String LOCATION_SELECT = "location_select";
|
||||
|
||||
/**
|
||||
* 任务卡片事件推送.
|
||||
*/
|
||||
public static final String TASKCARD_CLICK = "taskcard_click";
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,4 +131,46 @@ public class WxCpConsts {
|
||||
public static final String UPDATE_TAG = "update_tag";
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用推送消息的消息类型.
|
||||
*/
|
||||
public static class AppChatMsgType {
|
||||
/**
|
||||
* 文本消息.
|
||||
*/
|
||||
public static final String TEXT = "text";
|
||||
/**
|
||||
* 图片消息.
|
||||
*/
|
||||
public static final String IMAGE = "image";
|
||||
/**
|
||||
* 语音消息.
|
||||
*/
|
||||
public static final String VOICE = "voice";
|
||||
/**
|
||||
* 视频消息.
|
||||
*/
|
||||
public static final String VIDEO = "video";
|
||||
/**
|
||||
* 发送文件(CP专用).
|
||||
*/
|
||||
public static final String FILE = "file";
|
||||
/**
|
||||
* 文本卡片消息(CP专用).
|
||||
*/
|
||||
public static final String TEXTCARD = "textcard";
|
||||
/**
|
||||
* 图文消息(点击跳转到外链).
|
||||
*/
|
||||
public static final String NEWS = "news";
|
||||
/**
|
||||
* 图文消息(点击跳转到图文消息页面).
|
||||
*/
|
||||
public static final String MPNEWS = "mpnews";
|
||||
/**
|
||||
* markdown消息.
|
||||
*/
|
||||
public static final String MARKDOWN = "markdown";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,46 +3,75 @@ package me.chanjar.weixin.cp.api;
|
||||
import java.util.List;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.bean.WxCpAppChatMessage;
|
||||
import me.chanjar.weixin.cp.bean.WxCpChat;
|
||||
|
||||
/**
|
||||
* 群聊服务
|
||||
* 群聊服务.
|
||||
*
|
||||
* @author gaigeshen
|
||||
*/
|
||||
public interface WxCpChatService {
|
||||
String APPCHAT_CREATE = "https://qyapi.weixin.qq.com/cgi-bin/appchat/create";
|
||||
String APPCHAT_UPDATE = "https://qyapi.weixin.qq.com/cgi-bin/appchat/update";
|
||||
String APPCHAT_GET_CHATID = "https://qyapi.weixin.qq.com/cgi-bin/appchat/get?chatid=";
|
||||
|
||||
/**
|
||||
* 创建群聊会话,注意:刚创建的群,如果没有下发消息,在企业微信不会出现该群。
|
||||
* 创建群聊会话,注意:刚创建的群,如果没有下发消息,在企业微信不会出现该群.
|
||||
*
|
||||
* @param name 群聊名,最多50个utf8字符,超过将截断
|
||||
* @param owner 指定群主的id。如果不指定,系统会随机从userlist中选一人作为群主
|
||||
* @param users 群成员id列表。至少2人,至多500人
|
||||
* @param name 群聊名,最多50个utf8字符,超过将截断
|
||||
* @param owner 指定群主的id。如果不指定,系统会随机从userlist中选一人作为群主
|
||||
* @param users 群成员id列表。至少2人,至多500人
|
||||
* @param chatId 群聊的唯一标志,不能与已有的群重复;字符串类型,最长32个字符。只允许字符0-9及字母a-zA-Z。如果不填,系统会随机生成群id
|
||||
* @return 创建群聊会话的结果,群聊的唯一标志
|
||||
* @return 创建的群聊会话chatId
|
||||
* @throws WxErrorException 发生异常
|
||||
*/
|
||||
String chatCreate(String name, String owner, List<String> users, String chatId) throws WxErrorException;
|
||||
|
||||
|
||||
/**
|
||||
* 修改群聊会话
|
||||
*
|
||||
* @param chatId 群聊id
|
||||
* @param name 新的群聊名。若不需更新,请忽略此参数(null or empty)。最多50个utf8字符,超过将截断
|
||||
* @param owner 新群主的id。若不需更新,请忽略此参数(null or empty)
|
||||
* @param usersToAdd 添加成员的id列表,若不需要更新,则传递空对象或者空集合
|
||||
* chatCreate 同名方法
|
||||
*/
|
||||
String create(String name, String owner, List<String> users, String chatId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 修改群聊会话.
|
||||
*
|
||||
* @param chatId 群聊id
|
||||
* @param name 新的群聊名。若不需更新,请忽略此参数(null or empty)。最多50个utf8字符,超过将截断
|
||||
* @param owner 新群主的id。若不需更新,请忽略此参数(null or empty)
|
||||
* @param usersToAdd 添加成员的id列表,若不需要更新,则传递空对象或者空集合
|
||||
* @param usersToDelete 踢出成员的id列表,若不需要更新,则传递空对象或者空集合
|
||||
* @throws WxErrorException 发生异常
|
||||
*/
|
||||
void chatUpdate(String chatId, String name, String owner, List<String> usersToAdd, List<String> usersToDelete) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获取群聊会话
|
||||
*
|
||||
* chatUpdate 同名方法
|
||||
*/
|
||||
void update(String chatId, String name, String owner, List<String> usersToAdd, List<String> usersToDelete) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获取群聊会话.
|
||||
*
|
||||
* @param chatId 群聊编号
|
||||
* @return 群聊会话
|
||||
* @throws WxErrorException 发生异常
|
||||
*/
|
||||
WxCpChat chatGet(String chatId) throws WxErrorException;
|
||||
|
||||
|
||||
/**
|
||||
* chatGet 同名方法
|
||||
*/
|
||||
WxCpChat get(String chatId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 应用支持推送文本、图片、视频、文件、图文等类型.
|
||||
* 请求方式: POST(HTTPS)
|
||||
* 请求地址: https://qyapi.weixin.qq.com/cgi-bin/appchat/send?access_token=ACCESS_TOKEN
|
||||
* 文档地址:https://work.weixin.qq.com/api/doc#90000/90135/90248
|
||||
*
|
||||
* @param message 要发送的消息内容对象
|
||||
*/
|
||||
void sendMsg(WxCpAppChatMessage message) throws WxErrorException;
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public interface WxCpDepartmentService {
|
||||
* @return 部门id
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
Integer create(WxCpDepart depart) throws WxErrorException;
|
||||
Long create(WxCpDepart depart) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package me.chanjar.weixin.cp.api;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.bean.WxCpApprovalDataResult;
|
||||
import me.chanjar.weixin.cp.bean.WxCpCheckinData;
|
||||
import me.chanjar.weixin.cp.bean.WxCpCheckinOption;
|
||||
import me.chanjar.weixin.cp.bean.WxCpDialRecord;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Element
|
||||
* @Package me.chanjar.weixin.cp.api
|
||||
* @date 2019-04-06 10:52
|
||||
* @Description: <pre>
|
||||
* 企业微信OA相关接口
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public interface WxCpOAService {
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 获取打卡数据
|
||||
* API doc : https://work.weixin.qq.com/api/doc#90000/90135/90262
|
||||
* </pre>
|
||||
*
|
||||
* @param openCheckinDataType 打卡类型。1:上下班打卡;2:外出打卡;3:全部打卡
|
||||
* @param starttime 获取打卡记录的开始时间
|
||||
* @param endtime 获取打卡记录的结束时间
|
||||
* @param userIdList 需要获取打卡记录的用户列表
|
||||
*/
|
||||
List<WxCpCheckinData> getCheckinData(Integer openCheckinDataType, Date starttime, Date endtime, List<String> userIdList) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 获取打卡规则
|
||||
* API doc : https://work.weixin.qq.com/api/doc#90000/90135/90263
|
||||
* </pre>
|
||||
*
|
||||
* @param datetime 需要获取规则的当天日期
|
||||
* @param userIdList 需要获取打卡规则的用户列表
|
||||
* @return
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
List<WxCpCheckinOption> getCheckinOption(Date datetime, List<String> userIdList) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 获取审批数据
|
||||
* 通过本接口来获取公司一段时间内的审批记录。一次拉取调用最多拉取10000个审批记录,可以通过多次拉取的方式来满足需求,但调用频率不可超过600次/分。
|
||||
* API doc : https://work.weixin.qq.com/api/doc#90000/90135/91530
|
||||
* </pre>
|
||||
*
|
||||
* @param starttime 获取审批记录的开始时间
|
||||
* @param endtime 获取审批记录的结束时间
|
||||
* @param nextSpnum 第一个拉取的审批单号,不填从该时间段的第一个审批单拉取
|
||||
* @return
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
WxCpApprovalDataResult getApprovalData(Date starttime, Date endtime, Long nextSpnum) throws WxErrorException;
|
||||
|
||||
List<WxCpDialRecord> getDialRecord(Date starttime, Date endtime, Integer offset, Integer limit) throws WxErrorException;
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.RequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.RequestHttp;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessage;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessageSendResult;
|
||||
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
||||
@@ -16,6 +17,15 @@ import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
||||
* @author chanjaster
|
||||
*/
|
||||
public interface WxCpService {
|
||||
String GET_JSAPI_TICKET = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket";
|
||||
String GET_AGENT_CONFIG_TICKET = "https://qyapi.weixin.qq.com/cgi-bin/ticket/get?&type=agent_config";
|
||||
String MESSAGE_SEND = "https://qyapi.weixin.qq.com/cgi-bin/message/send";
|
||||
String GET_CALLBACK_IP = "https://qyapi.weixin.qq.com/cgi-bin/getcallbackip";
|
||||
String BATCH_REPLACE_PARTY = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceparty";
|
||||
String BATCH_REPLACE_USER = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser";
|
||||
String BATCH_GET_RESULT = "https://qyapi.weixin.qq.com/cgi-bin/batch/getresult?jobid=";
|
||||
String JSCODE_TO_SESSION_URL = "https://qyapi.weixin.qq.com/cgi-bin/miniprogram/jscode2session";
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 验证推送过来的消息的正确性
|
||||
@@ -68,6 +78,33 @@ public interface WxCpService {
|
||||
*/
|
||||
String getJsapiTicket(boolean forceRefresh) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获得jsapi_ticket,不强制刷新jsapi_ticket
|
||||
* 应用的jsapi_ticket用于计算agentConfig(参见“通过agentConfig注入应用的权限”)的签名,签名计算方法与上述介绍的config的签名算法完全相同,但需要注意以下区别:
|
||||
*
|
||||
* 签名的jsapi_ticket必须使用以下接口获取。且必须用wx.agentConfig中的agentid对应的应用secret去获取access_token。
|
||||
* 签名用的noncestr和timestamp必须与wx.agentConfig中的nonceStr和timestamp相同。
|
||||
* @see #getJsapiTicket(boolean)
|
||||
*/
|
||||
String getAgentJsapiTicket() throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 获取应用的jsapi_ticket
|
||||
* 应用的jsapi_ticket用于计算agentConfig(参见“通过agentConfig注入应用的权限”)的签名,签名计算方法与上述介绍的config的签名算法完全相同,但需要注意以下区别:
|
||||
*
|
||||
* 签名的jsapi_ticket必须使用以下接口获取。且必须用wx.agentConfig中的agentid对应的应用secret去获取access_token。
|
||||
* 签名用的noncestr和timestamp必须与wx.agentConfig中的nonceStr和timestamp相同。
|
||||
*
|
||||
* 获得时会检查jsapiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
|
||||
*
|
||||
* 详情请见:https://work.weixin.qq.com/api/doc#10029/%E8%8E%B7%E5%8F%96%E5%BA%94%E7%94%A8%E7%9A%84jsapi_ticket
|
||||
* </pre>
|
||||
*
|
||||
* @param forceRefresh 强制刷新
|
||||
*/
|
||||
String getAgentJsapiTicket(boolean forceRefresh) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 创建调用jsapi时所需要的签名
|
||||
@@ -89,6 +126,13 @@ public interface WxCpService {
|
||||
*/
|
||||
WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 小程序登录凭证校验
|
||||
*
|
||||
* @param jsCode 登录时获取的 code
|
||||
*/
|
||||
WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 获取微信服务器的ip段
|
||||
@@ -165,6 +209,13 @@ public interface WxCpService {
|
||||
*/
|
||||
WxSession getSession(String id, boolean create);
|
||||
|
||||
/**
|
||||
* 获取WxSessionManager 对象
|
||||
*
|
||||
* @return WxSessionManager
|
||||
*/
|
||||
WxSessionManager getSessionManager();
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 设置WxSessionManager,只有当需要使用个性化的WxSessionManager的时候才需要调用此方法,
|
||||
@@ -250,8 +301,17 @@ public interface WxCpService {
|
||||
*/
|
||||
WxCpChatService getChatService();
|
||||
|
||||
/**
|
||||
* 获取任务卡片服务
|
||||
*
|
||||
* @return 任务卡片服务
|
||||
*/
|
||||
WxCpTaskCardService getTaskCardService();
|
||||
|
||||
WxCpAgentService getAgentService();
|
||||
|
||||
WxCpOAService getOAService();
|
||||
|
||||
/**
|
||||
* http请求对象
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package me.chanjar.weixin.cp.api;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 任务卡片管理接口.
|
||||
* Created by Jeff on 2019-05-16.
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="https://github.com/domainname">Jeff</a>
|
||||
* @date 2019-05-16
|
||||
*/
|
||||
public interface WxCpTaskCardService {
|
||||
/**
|
||||
* <pre>
|
||||
* 更新任务卡片消息状态
|
||||
* 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/91579
|
||||
*
|
||||
* 注意: 这个方法使用WxCpConfigStorage里的agentId
|
||||
* </pre>
|
||||
*
|
||||
* @param userIds 企业的成员ID列表
|
||||
* @param taskId 任务卡片ID
|
||||
* @param clickedKey 已点击按钮的Key
|
||||
*/
|
||||
void update(List<String> userIds, String taskId, String clickedKey) throws WxErrorException;
|
||||
}
|
||||
@@ -1,16 +1,10 @@
|
||||
package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import me.chanjar.weixin.common.bean.WxJsapiSignature;
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
@@ -24,20 +18,23 @@ import me.chanjar.weixin.common.util.http.RequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.RequestHttp;
|
||||
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
|
||||
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
|
||||
import me.chanjar.weixin.cp.api.WxCpAgentService;
|
||||
import me.chanjar.weixin.cp.api.WxCpChatService;
|
||||
import me.chanjar.weixin.cp.api.WxCpDepartmentService;
|
||||
import me.chanjar.weixin.cp.api.WxCpMediaService;
|
||||
import me.chanjar.weixin.cp.api.WxCpMenuService;
|
||||
import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.api.WxCpTagService;
|
||||
import me.chanjar.weixin.cp.api.WxCpUserService;
|
||||
import me.chanjar.weixin.cp.api.*;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessage;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessageSendResult;
|
||||
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, RequestHttp<H, P> {
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author chanjarster
|
||||
*/
|
||||
public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestHttp<H, P> {
|
||||
protected final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private WxCpUserService userService = new WxCpUserServiceImpl(this);
|
||||
@@ -48,6 +45,8 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ
|
||||
private WxCpOAuth2Service oauth2Service = new WxCpOAuth2ServiceImpl(this);
|
||||
private WxCpTagService tagService = new WxCpTagServiceImpl(this);
|
||||
private WxCpAgentService agentService = new WxCpAgentServiceImpl(this);
|
||||
private WxCpOAService oaService = new WxCpOAServiceImpl(this);
|
||||
private WxCpTaskCardService taskCardService = new WxCpTaskCardServiceImpl(this);
|
||||
|
||||
/**
|
||||
* 全局的是否正在刷新access token的锁
|
||||
@@ -59,14 +58,19 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ
|
||||
*/
|
||||
protected final Object globalJsapiTicketRefreshLock = new Object();
|
||||
|
||||
/**
|
||||
* 全局的是否正在刷新agent的jsapi_ticket的锁
|
||||
*/
|
||||
protected final Object globalAgentJsapiTicketRefreshLock = new Object();
|
||||
|
||||
protected WxCpConfigStorage configStorage;
|
||||
|
||||
private WxSessionManager sessionManager = new StandardSessionManager();
|
||||
|
||||
protected WxSessionManager sessionManager = new StandardSessionManager();
|
||||
/**
|
||||
* 临时文件目录
|
||||
*/
|
||||
protected File tmpDirFile;
|
||||
private File tmpDirFile;
|
||||
private int retrySleepMillis = 1000;
|
||||
private int maxRetryTimes = 5;
|
||||
|
||||
@@ -86,6 +90,30 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ
|
||||
return getAccessToken(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAgentJsapiTicket() throws WxErrorException {
|
||||
return this.getAgentJsapiTicket(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAgentJsapiTicket(boolean forceRefresh) throws WxErrorException {
|
||||
if (forceRefresh) {
|
||||
this.configStorage.expireAgentJsapiTicket();
|
||||
}
|
||||
|
||||
if (this.configStorage.isAgentJsapiTicketExpired()) {
|
||||
synchronized (this.globalAgentJsapiTicketRefreshLock) {
|
||||
if (this.configStorage.isAgentJsapiTicketExpired()) {
|
||||
String responseContent = this.get(WxCpService.GET_AGENT_CONFIG_TICKET, null);
|
||||
JsonObject jsonObject = new JsonParser().parse(responseContent).getAsJsonObject();
|
||||
this.configStorage.updateAgentJsapiTicket(jsonObject.get("ticket").getAsString(),
|
||||
jsonObject.get("expires_in").getAsInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.configStorage.getAgentJsapiTicket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJsapiTicket() throws WxErrorException {
|
||||
@@ -97,20 +125,18 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ
|
||||
if (forceRefresh) {
|
||||
this.configStorage.expireJsapiTicket();
|
||||
}
|
||||
|
||||
if (this.configStorage.isJsapiTicketExpired()) {
|
||||
synchronized (this.globalJsapiTicketRefreshLock) {
|
||||
if (this.configStorage.isJsapiTicketExpired()) {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket";
|
||||
String responseContent = execute(SimpleGetRequestExecutor.create(this), url, null);
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
|
||||
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
|
||||
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
|
||||
this.configStorage.updateJsapiTicket(jsapiTicket,
|
||||
expiresInSeconds);
|
||||
String responseContent = this.get(WxCpService.GET_JSAPI_TICKET, null);
|
||||
JsonObject tmpJsonObject = new JsonParser().parse(responseContent).getAsJsonObject();
|
||||
this.configStorage.updateJsapiTicket(tmpJsonObject.get("ticket").getAsString(),
|
||||
tmpJsonObject.get("expires_in").getAsInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.configStorage.getJsapiTicket();
|
||||
}
|
||||
|
||||
@@ -139,18 +165,27 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ
|
||||
|
||||
@Override
|
||||
public WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send";
|
||||
Integer agentId = message.getAgentId();
|
||||
if(null == agentId){
|
||||
if (null == agentId) {
|
||||
message.setAgentId(this.getWxCpConfigStorage().getAgentId());
|
||||
}
|
||||
return WxCpMessageSendResult.fromJson(this.post(url, message.toJson()));
|
||||
|
||||
return WxCpMessageSendResult.fromJson(this.post(WxCpService.MESSAGE_SEND, message.toJson()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorException {
|
||||
Map<String, String> params = new HashMap<>(2);
|
||||
params.put("js_code", jsCode);
|
||||
params.put("grant_type", "authorization_code");
|
||||
|
||||
String result = this.get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params));
|
||||
return WxCpMaJsCode2SessionResult.fromJson(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getCallbackIp() throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/getcallbackip";
|
||||
String responseContent = get(url, null);
|
||||
String responseContent = get(WxCpService.GET_CALLBACK_IP, null);
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
JsonArray jsonArray = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray();
|
||||
String[] ips = new String[jsonArray.size()];
|
||||
@@ -171,7 +206,7 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ
|
||||
}
|
||||
|
||||
/**
|
||||
* 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求
|
||||
* 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求.
|
||||
*/
|
||||
@Override
|
||||
public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
|
||||
@@ -285,25 +320,28 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ
|
||||
this.sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxSessionManager getSessionManager() {
|
||||
return this.sessionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String replaceParty(String mediaId) throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceparty";
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("media_id", mediaId);
|
||||
return post(url, jsonObject.toString());
|
||||
return post(WxCpService.BATCH_REPLACE_PARTY, jsonObject.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String replaceUser(String mediaId) throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser";
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("media_id", mediaId);
|
||||
return post(url, jsonObject.toString());
|
||||
return post(WxCpService.BATCH_REPLACE_USER, jsonObject.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTaskResult(String joinId) throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/getresult?jobid=" + joinId;
|
||||
String url = WxCpService.BATCH_GET_RESULT + joinId;
|
||||
return get(url, null);
|
||||
}
|
||||
|
||||
@@ -350,6 +388,16 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ
|
||||
return chatService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpOAService getOAService() {
|
||||
return oaService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpTaskCardService getTaskCardService() {
|
||||
return taskCardService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestHttp<?, ?> getRequestHttp() {
|
||||
return this;
|
||||
@@ -1,36 +1,35 @@
|
||||
package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import com.google.gson.JsonParser;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
||||
import me.chanjar.weixin.cp.api.WxCpChatService;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.WxCpAppChatMessage;
|
||||
import me.chanjar.weixin.cp.bean.WxCpChat;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
||||
import me.chanjar.weixin.cp.api.WxCpChatService;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.WxCpChat;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
/**
|
||||
* 群聊服务实现
|
||||
* 群聊服务实现.
|
||||
*
|
||||
* @author gaigeshen
|
||||
*/
|
||||
public class WxCpChatServiceImpl implements WxCpChatService {
|
||||
public class WxCpChatServiceImpl implements WxCpChatService {
|
||||
private static final JsonParser JSON_PARSER = new JsonParser();
|
||||
private final WxCpService cpService;
|
||||
|
||||
private final WxCpService internalService;
|
||||
|
||||
/**
|
||||
* 创建群聊服务实现的实例
|
||||
*
|
||||
* @param internalService 企业微信的服务
|
||||
* 创建群聊服务实现的实例.
|
||||
*
|
||||
* @param cpService 企业微信的服务
|
||||
*/
|
||||
public WxCpChatServiceImpl(WxCpService internalService) {
|
||||
this.internalService = internalService;
|
||||
WxCpChatServiceImpl(WxCpService cpService) {
|
||||
this.cpService = cpService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,12 +47,18 @@ public class WxCpChatServiceImpl implements WxCpChatService {
|
||||
if (StringUtils.isNotBlank(chatId)) {
|
||||
data.put("chatid", chatId);
|
||||
}
|
||||
String result = internalService.post("https://qyapi.weixin.qq.com/cgi-bin/appchat/create", WxGsonBuilder.create().toJson(data));
|
||||
String result = this.cpService.post(APPCHAT_CREATE, WxGsonBuilder.create().toJson(data));
|
||||
return new JsonParser().parse(result).getAsJsonObject().get("chatid").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chatUpdate(String chatId, String name, String owner, List<String> usersToAdd, List<String> usersToDelete) throws WxErrorException {
|
||||
public String create(String name, String owner, List<String> users, String chatId) throws WxErrorException {
|
||||
return chatCreate(name, owner, users, chatId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chatUpdate(String chatId, String name, String owner, List<String> usersToAdd, List<String> usersToDelete)
|
||||
throws WxErrorException {
|
||||
Map<String, Object> data = new HashMap<>(5);
|
||||
if (StringUtils.isNotBlank(chatId)) {
|
||||
data.put("chatid", chatId);
|
||||
@@ -70,14 +75,30 @@ public class WxCpChatServiceImpl implements WxCpChatService {
|
||||
if (usersToDelete != null && !usersToDelete.isEmpty()) {
|
||||
data.put("del_user_list", usersToDelete);
|
||||
}
|
||||
internalService.post("https://qyapi.weixin.qq.com/cgi-bin/appchat/update", WxGsonBuilder.create().toJson(data));
|
||||
|
||||
this.cpService.post(APPCHAT_UPDATE, WxGsonBuilder.create().toJson(data));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(String chatId, String name, String owner, List<String> usersToAdd, List<String> usersToDelete) throws WxErrorException {
|
||||
chatUpdate(chatId, name, owner, usersToAdd, usersToDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpChat chatGet(String chatId) throws WxErrorException {
|
||||
String result = internalService.get("https://qyapi.weixin.qq.com/cgi-bin/appchat/get?chatid=" + chatId, null);
|
||||
return WxCpGsonBuilder.create().fromJson(
|
||||
new JsonParser().parse(result).getAsJsonObject().getAsJsonObject("chat_info").toString(), WxCpChat.class);
|
||||
String result = this.cpService.get(APPCHAT_GET_CHATID + chatId, null);
|
||||
return WxCpGsonBuilder.create()
|
||||
.fromJson(JSON_PARSER.parse(result).getAsJsonObject().getAsJsonObject("chat_info").toString(), WxCpChat.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpChat get(String chatId) throws WxErrorException {
|
||||
return chatGet(chatId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMsg(WxCpAppChatMessage message) throws WxErrorException {
|
||||
this.cpService.post("https://qyapi.weixin.qq.com/cgi-bin/appchat/send", message.toJson());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,11 +28,11 @@ public class WxCpDepartmentServiceImpl implements WxCpDepartmentService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer create(WxCpDepart depart) throws WxErrorException {
|
||||
public Long create(WxCpDepart depart) throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create";
|
||||
String responseContent = this.mainService.post(url, depart.toJson());
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id"));
|
||||
return GsonHelper.getAsLong(tmpJsonElement.getAsJsonObject().get("id"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.api.WxCpOAService;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.WxCpApprovalDataResult;
|
||||
import me.chanjar.weixin.cp.bean.WxCpCheckinData;
|
||||
import me.chanjar.weixin.cp.bean.WxCpCheckinOption;
|
||||
import me.chanjar.weixin.cp.bean.WxCpDialRecord;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Element
|
||||
* @Package me.chanjar.weixin.cp.api.impl
|
||||
* @date 2019-04-06 11:20
|
||||
* @Description: TODO
|
||||
*/
|
||||
public class WxCpOAServiceImpl implements WxCpOAService {
|
||||
|
||||
private WxCpService mainService;
|
||||
|
||||
public WxCpOAServiceImpl(WxCpService mainService) {
|
||||
this.mainService = mainService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WxCpCheckinData> getCheckinData(Integer openCheckinDataType, Date starttime, Date endtime, List<String> userIdList) throws WxErrorException {
|
||||
|
||||
if (starttime == null || endtime == null) {
|
||||
throw new RuntimeException("starttime and endtime can't be null");
|
||||
}
|
||||
|
||||
if (userIdList == null || userIdList.size() > 100) {
|
||||
throw new RuntimeException("用户列表不能为空,不超过100个,若用户超过100个,请分批获取");
|
||||
}
|
||||
|
||||
long endtimestamp = endtime.getTime() / 1000L;
|
||||
long starttimestamp = starttime.getTime() / 1000L;
|
||||
|
||||
if (endtimestamp - starttimestamp < 0 || endtimestamp - starttimestamp >= 30 * 24 * 60 * 60) {
|
||||
throw new RuntimeException("获取记录时间跨度不超过一个月");
|
||||
}
|
||||
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckindata";
|
||||
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
|
||||
jsonObject.addProperty("opencheckindatatype", openCheckinDataType);
|
||||
jsonObject.addProperty("starttime", starttimestamp);
|
||||
jsonObject.addProperty("endtime", endtimestamp);
|
||||
|
||||
for (String userid : userIdList) {
|
||||
jsonArray.add(userid);
|
||||
}
|
||||
|
||||
jsonObject.add("useridlist", jsonArray);
|
||||
|
||||
String responseContent = this.mainService.post(url, jsonObject.toString());
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
return WxCpGsonBuilder.create()
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("checkindata"),
|
||||
new TypeToken<List<WxCpCheckinData>>() {
|
||||
}.getType()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WxCpCheckinOption> getCheckinOption(Date datetime, List<String> userIdList) throws WxErrorException {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckinoption";
|
||||
if (datetime == null) {
|
||||
throw new RuntimeException("datetime can't be null");
|
||||
}
|
||||
|
||||
if (userIdList == null || userIdList.size() > 100) {
|
||||
throw new RuntimeException("用户列表不能为空,不超过100个,若用户超过100个,请分批获取");
|
||||
}
|
||||
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
for (String userid : userIdList) {
|
||||
jsonArray.add(userid);
|
||||
}
|
||||
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("datetime", datetime.getTime() / 1000L);
|
||||
jsonObject.add("useridlist", jsonArray);
|
||||
|
||||
String responseContent = this.mainService.post(url, jsonObject.toString());
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
|
||||
return WxCpGsonBuilder.create()
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("info"),
|
||||
new TypeToken<List<WxCpCheckinOption>>() {
|
||||
}.getType()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpApprovalDataResult getApprovalData(Date starttime, Date endtime, Long nextSpnum) throws WxErrorException {
|
||||
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/corp/getapprovaldata";
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("starttime", starttime.getTime() / 1000L);
|
||||
jsonObject.addProperty("endtime", endtime.getTime() / 1000L);
|
||||
if (nextSpnum != null) {
|
||||
jsonObject.addProperty("next_spnum", nextSpnum);
|
||||
}
|
||||
|
||||
String responseContent = this.mainService.post(url, jsonObject.toString());
|
||||
return WxCpGsonBuilder.create().fromJson(responseContent, WxCpApprovalDataResult.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WxCpDialRecord> getDialRecord(Date starttime, Date endtime, Integer offset, Integer limit) throws WxErrorException {
|
||||
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/dial/get_dial_record";
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
|
||||
if (offset == null) {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (limit == null || limit <= 0) {
|
||||
limit = 100;
|
||||
}
|
||||
|
||||
jsonObject.addProperty("offset", offset);
|
||||
jsonObject.addProperty("limit", limit);
|
||||
|
||||
if (starttime != null && endtime != null) {
|
||||
|
||||
long endtimestamp = endtime.getTime() / 1000L;
|
||||
long starttimestamp = starttime.getTime() / 1000L;
|
||||
|
||||
if (endtimestamp - starttimestamp < 0 || endtimestamp - starttimestamp >= 30 * 24 * 60 * 60) {
|
||||
throw new RuntimeException("受限于网络传输,起止时间的最大跨度为30天,如超过30天,则以结束时间为基准向前取30天进行查询");
|
||||
}
|
||||
|
||||
jsonObject.addProperty("start_time", starttimestamp);
|
||||
jsonObject.addProperty("end_time", endtimestamp);
|
||||
|
||||
|
||||
}
|
||||
|
||||
String responseContent = this.mainService.post(url, jsonObject.toString());
|
||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
|
||||
|
||||
return WxCpGsonBuilder.create()
|
||||
.fromJson(
|
||||
tmpJsonElement.getAsJsonObject().get("record"),
|
||||
new TypeToken<List<WxCpDialRecord>>() {
|
||||
}.getType()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.http.HttpType;
|
||||
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
|
||||
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
|
||||
import me.chanjar.weixin.cp.api.WxCpOAService;
|
||||
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
@@ -18,7 +19,7 @@ import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class WxCpServiceApacheHttpClientImpl extends WxCpServiceAbstractImpl<CloseableHttpClient, HttpHost> {
|
||||
public class WxCpServiceApacheHttpClientImpl extends BaseWxCpServiceImpl<CloseableHttpClient, HttpHost> {
|
||||
protected CloseableHttpClient httpClient;
|
||||
protected HttpHost httpProxy;
|
||||
|
||||
@@ -39,37 +40,37 @@ public class WxCpServiceApacheHttpClientImpl extends WxCpServiceAbstractImpl<Clo
|
||||
|
||||
@Override
|
||||
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
|
||||
if (this.configStorage.isAccessTokenExpired() || forceRefresh) {
|
||||
synchronized (this.globalAccessTokenRefreshLock) {
|
||||
if (this.configStorage.isAccessTokenExpired()) {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"
|
||||
+ "&corpid=" + this.configStorage.getCorpId()
|
||||
+ "&corpsecret=" + this.configStorage.getCorpSecret();
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
if (this.httpProxy != null) {
|
||||
RequestConfig config = RequestConfig.custom()
|
||||
.setProxy(this.httpProxy).build();
|
||||
httpGet.setConfig(config);
|
||||
}
|
||||
String resultContent = null;
|
||||
try (CloseableHttpClient httpclient = getRequestHttpClient();
|
||||
CloseableHttpResponse response = httpclient.execute(httpGet)) {
|
||||
resultContent = new BasicResponseHandler().handleResponse(response);
|
||||
} finally {
|
||||
httpGet.releaseConnection();
|
||||
}
|
||||
WxError error = WxError.fromJson(resultContent, WxType.CP);
|
||||
if (error.getErrorCode() != 0) {
|
||||
throw new WxErrorException(error);
|
||||
}
|
||||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
||||
this.configStorage.updateAccessToken(
|
||||
accessToken.getAccessToken(), accessToken.getExpiresIn());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (!this.configStorage.isAccessTokenExpired() && !forceRefresh) {
|
||||
return this.configStorage.getAccessToken();
|
||||
}
|
||||
|
||||
synchronized (this.globalAccessTokenRefreshLock) {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"
|
||||
+ "&corpid=" + this.configStorage.getCorpId()
|
||||
+ "&corpsecret=" + this.configStorage.getCorpSecret();
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
if (this.httpProxy != null) {
|
||||
RequestConfig config = RequestConfig.custom()
|
||||
.setProxy(this.httpProxy).build();
|
||||
httpGet.setConfig(config);
|
||||
}
|
||||
String resultContent;
|
||||
try (CloseableHttpClient httpclient = getRequestHttpClient();
|
||||
CloseableHttpResponse response = httpclient.execute(httpGet)) {
|
||||
resultContent = new BasicResponseHandler().handleResponse(response);
|
||||
} finally {
|
||||
httpGet.releaseConnection();
|
||||
}
|
||||
WxError error = WxError.fromJson(resultContent, WxType.CP);
|
||||
if (error.getErrorCode() != 0) {
|
||||
throw new WxErrorException(error);
|
||||
}
|
||||
|
||||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
||||
this.configStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return this.configStorage.getAccessToken();
|
||||
|
||||
@@ -8,7 +8,7 @@ import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.http.HttpType;
|
||||
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
||||
|
||||
public class WxCpServiceJoddHttpImpl extends WxCpServiceAbstractImpl<HttpConnectionProvider, ProxyInfo> {
|
||||
public class WxCpServiceJoddHttpImpl extends BaseWxCpServiceImpl<HttpConnectionProvider, ProxyInfo> {
|
||||
protected HttpConnectionProvider httpClient;
|
||||
protected ProxyInfo httpProxy;
|
||||
|
||||
@@ -30,30 +30,29 @@ public class WxCpServiceJoddHttpImpl extends WxCpServiceAbstractImpl<HttpConnect
|
||||
|
||||
@Override
|
||||
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
|
||||
if (this.configStorage.isAccessTokenExpired() || forceRefresh) {
|
||||
synchronized (this.globalAccessTokenRefreshLock) {
|
||||
if (this.configStorage.isAccessTokenExpired()) {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"
|
||||
+ "&corpid=" + this.configStorage.getCorpId()
|
||||
+ "&corpsecret=" + this.configStorage.getCorpSecret();
|
||||
if (!this.configStorage.isAccessTokenExpired() && !forceRefresh) {
|
||||
return this.configStorage.getAccessToken();
|
||||
}
|
||||
|
||||
HttpRequest request = HttpRequest.get(url);
|
||||
if (this.httpProxy != null) {
|
||||
httpClient.useProxy(this.httpProxy);
|
||||
}
|
||||
request.withConnectionProvider(httpClient);
|
||||
HttpResponse response = request.send();
|
||||
synchronized (this.globalAccessTokenRefreshLock) {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"
|
||||
+ "&corpid=" + this.configStorage.getCorpId()
|
||||
+ "&corpsecret=" + this.configStorage.getCorpSecret();
|
||||
|
||||
String resultContent = response.bodyText();
|
||||
WxError error = WxError.fromJson(resultContent, WxType.CP);
|
||||
if (error.getErrorCode() != 0) {
|
||||
throw new WxErrorException(error);
|
||||
}
|
||||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
||||
this.configStorage.updateAccessToken(
|
||||
accessToken.getAccessToken(), accessToken.getExpiresIn());
|
||||
}
|
||||
HttpRequest request = HttpRequest.get(url);
|
||||
if (this.httpProxy != null) {
|
||||
httpClient.useProxy(this.httpProxy);
|
||||
}
|
||||
request.withConnectionProvider(httpClient);
|
||||
HttpResponse response = request.send();
|
||||
|
||||
String resultContent = response.bodyText();
|
||||
WxError error = WxError.fromJson(resultContent, WxType.CP);
|
||||
if (error.getErrorCode() != 0) {
|
||||
throw new WxErrorException(error);
|
||||
}
|
||||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
||||
this.configStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
|
||||
}
|
||||
return this.configStorage.getAccessToken();
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import okhttp3.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class WxCpServiceOkHttpImpl extends WxCpServiceAbstractImpl<OkHttpClient, OkHttpProxyInfo> {
|
||||
public class WxCpServiceOkHttpImpl extends BaseWxCpServiceImpl<OkHttpClient, OkHttpProxyInfo> {
|
||||
protected OkHttpClient httpClient;
|
||||
protected OkHttpProxyInfo httpProxy;
|
||||
|
||||
@@ -33,34 +33,33 @@ public class WxCpServiceOkHttpImpl extends WxCpServiceAbstractImpl<OkHttpClient,
|
||||
|
||||
@Override
|
||||
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
|
||||
this.log.debug("WxCpServiceOkHttpImpl is running");
|
||||
if (this.configStorage.isAccessTokenExpired() || forceRefresh) {
|
||||
synchronized (this.globalAccessTokenRefreshLock) {
|
||||
if (this.configStorage.isAccessTokenExpired()) {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"
|
||||
+ "&corpid=" + this.configStorage.getCorpId()
|
||||
+ "&corpsecret=" + this.configStorage.getCorpSecret();
|
||||
//得到httpClient
|
||||
OkHttpClient client = getRequestHttpClient();
|
||||
//请求的request
|
||||
Request request = new Request.Builder().url(url).get().build();
|
||||
String resultContent = null;
|
||||
try {
|
||||
Response response = client.newCall(request).execute();
|
||||
resultContent = response.body().string();
|
||||
} catch (IOException e) {
|
||||
this.log.error(e.getMessage(), e);
|
||||
}
|
||||
if (!this.configStorage.isAccessTokenExpired() && !forceRefresh) {
|
||||
return this.configStorage.getAccessToken();
|
||||
}
|
||||
|
||||
WxError error = WxError.fromJson(resultContent, WxType.CP);
|
||||
if (error.getErrorCode() != 0) {
|
||||
throw new WxErrorException(error);
|
||||
}
|
||||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
||||
this.configStorage.updateAccessToken(accessToken.getAccessToken(),
|
||||
accessToken.getExpiresIn());
|
||||
synchronized (this.globalAccessTokenRefreshLock) {
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"
|
||||
+ "&corpid=" + this.configStorage.getCorpId()
|
||||
+ "&corpsecret=" + this.configStorage.getCorpSecret();
|
||||
//得到httpClient
|
||||
OkHttpClient client = getRequestHttpClient();
|
||||
//请求的request
|
||||
Request request = new Request.Builder().url(url).get().build();
|
||||
String resultContent = null;
|
||||
try {
|
||||
Response response = client.newCall(request).execute();
|
||||
resultContent = response.body().string();
|
||||
} catch (IOException e) {
|
||||
this.log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
WxError error = WxError.fromJson(resultContent, WxType.CP);
|
||||
if (error.getErrorCode() != 0) {
|
||||
throw new WxErrorException(error);
|
||||
}
|
||||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
||||
this.configStorage.updateAccessToken(accessToken.getAccessToken(),
|
||||
accessToken.getExpiresIn());
|
||||
}
|
||||
return this.configStorage.getAccessToken();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.api.WxCpTaskCardService;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 任务卡片管理接口.
|
||||
* Created by Jeff on 2019-05-16.
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="https://github.com/domainname">Jeff</a>
|
||||
* @date 2019-05-16
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class WxCpTaskCardServiceImpl implements WxCpTaskCardService {
|
||||
private final WxCpService mainService;
|
||||
|
||||
@Override
|
||||
public void update(List<String> userIds, String taskId, String clickedKey) throws WxErrorException {
|
||||
Integer agentId = this.mainService.getWxCpConfigStorage().getAgentId();
|
||||
|
||||
Map<String, Object> data = new HashMap<>(4);
|
||||
data.put("userids", userIds);
|
||||
data.put("agentid", agentId);
|
||||
data.put("task_id", taskId);
|
||||
data.put("clicked_key", clickedKey);
|
||||
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/message/update_taskcard";
|
||||
this.mainService.post(url, WxGsonBuilder.create().toJson(data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import me.chanjar.weixin.cp.WxCpConsts.AppChatMsgType;
|
||||
import me.chanjar.weixin.cp.bean.article.MpnewsArticle;
|
||||
import me.chanjar.weixin.cp.bean.article.NewArticle;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 应用推送消息
|
||||
* Created by Binary Wang on 2019/1/26.
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WxCpAppChatMessage implements Serializable {
|
||||
private static final long serialVersionUID = -5469013416372240229L;
|
||||
|
||||
private String msgType;
|
||||
private String content;
|
||||
private String chatId;
|
||||
private String mediaId;
|
||||
private String title;
|
||||
private String description;
|
||||
private Boolean safe;
|
||||
private String url;
|
||||
private String btnTxt;
|
||||
private List<NewArticle> articles;
|
||||
private List<MpnewsArticle> mpnewsArticles;
|
||||
|
||||
/**
|
||||
* 构建文本消息.
|
||||
*/
|
||||
public static WxCpAppChatMessage buildTextMsg(String chatId, String content, boolean safe) {
|
||||
final WxCpAppChatMessage message = new WxCpAppChatMessage();
|
||||
message.setMsgType(AppChatMsgType.TEXT);
|
||||
message.setContent(content);
|
||||
message.setChatId(chatId);
|
||||
message.setSafe(safe);
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成json字符串.
|
||||
*/
|
||||
public String toJson() {
|
||||
JsonObject messageJson = new JsonObject();
|
||||
messageJson.addProperty("msgtype", this.getMsgType());
|
||||
messageJson.addProperty("chatid", this.getChatId());
|
||||
|
||||
if (this.getSafe() != null && this.getSafe()) {
|
||||
messageJson.addProperty("safe", 1);
|
||||
}
|
||||
|
||||
this.handleMsgType(messageJson);
|
||||
|
||||
return messageJson.toString();
|
||||
}
|
||||
|
||||
private void handleMsgType(JsonObject messageJson) {
|
||||
switch (this.getMsgType()) {
|
||||
case AppChatMsgType.TEXT: {
|
||||
JsonObject text = new JsonObject();
|
||||
text.addProperty("content", this.getContent());
|
||||
messageJson.add("text", text);
|
||||
break;
|
||||
}
|
||||
case AppChatMsgType.MARKDOWN: {
|
||||
JsonObject text = new JsonObject();
|
||||
text.addProperty("content", this.getContent());
|
||||
messageJson.add("markdown", text);
|
||||
break;
|
||||
}
|
||||
case AppChatMsgType.TEXTCARD: {
|
||||
JsonObject text = new JsonObject();
|
||||
text.addProperty("title", this.getTitle());
|
||||
text.addProperty("description", this.getDescription());
|
||||
text.addProperty("url", this.getUrl());
|
||||
text.addProperty("btntxt", this.getBtnTxt());
|
||||
messageJson.add("textcard", text);
|
||||
break;
|
||||
}
|
||||
case AppChatMsgType.IMAGE: {
|
||||
JsonObject image = new JsonObject();
|
||||
image.addProperty("media_id", this.getMediaId());
|
||||
messageJson.add("image", image);
|
||||
break;
|
||||
}
|
||||
case AppChatMsgType.FILE: {
|
||||
JsonObject image = new JsonObject();
|
||||
image.addProperty("media_id", this.getMediaId());
|
||||
messageJson.add("file", image);
|
||||
break;
|
||||
}
|
||||
case AppChatMsgType.VOICE: {
|
||||
JsonObject voice = new JsonObject();
|
||||
voice.addProperty("media_id", this.getMediaId());
|
||||
messageJson.add("voice", voice);
|
||||
break;
|
||||
}
|
||||
case AppChatMsgType.VIDEO: {
|
||||
JsonObject video = new JsonObject();
|
||||
video.addProperty("media_id", this.getMediaId());
|
||||
video.addProperty("title", this.getTitle());
|
||||
video.addProperty("description", this.getDescription());
|
||||
messageJson.add("video", video);
|
||||
break;
|
||||
}
|
||||
case AppChatMsgType.NEWS: {
|
||||
JsonObject newsJsonObject = new JsonObject();
|
||||
JsonArray articleJsonArray = new JsonArray();
|
||||
for (NewArticle article : this.getArticles()) {
|
||||
JsonObject articleJson = new JsonObject();
|
||||
articleJson.addProperty("title", article.getTitle());
|
||||
articleJson.addProperty("description", article.getDescription());
|
||||
articleJson.addProperty("url", article.getUrl());
|
||||
articleJson.addProperty("picurl", article.getPicUrl());
|
||||
articleJsonArray.add(articleJson);
|
||||
}
|
||||
newsJsonObject.add("articles", articleJsonArray);
|
||||
messageJson.add("news", newsJsonObject);
|
||||
break;
|
||||
}
|
||||
case AppChatMsgType.MPNEWS: {
|
||||
JsonObject newsJsonObject = new JsonObject();
|
||||
if (this.getMediaId() != null) {
|
||||
newsJsonObject.addProperty("media_id", this.getMediaId());
|
||||
} else {
|
||||
JsonArray articleJsonArray = new JsonArray();
|
||||
for (MpnewsArticle article : this.getMpnewsArticles()) {
|
||||
JsonObject articleJson = new JsonObject();
|
||||
articleJson.addProperty("title", article.getTitle());
|
||||
articleJson.addProperty("thumb_media_id", article.getThumbMediaId());
|
||||
articleJson.addProperty("author", article.getAuthor());
|
||||
articleJson.addProperty("content_source_url", article.getContentSourceUrl());
|
||||
articleJson.addProperty("content", article.getContent());
|
||||
articleJson.addProperty("digest", article.getDigest());
|
||||
articleJsonArray.add(articleJson);
|
||||
}
|
||||
|
||||
newsJsonObject.add("articles", articleJsonArray);
|
||||
}
|
||||
messageJson.add("mpnews", newsJsonObject);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Element
|
||||
* @Package me.chanjar.weixin.cp.bean
|
||||
* @date 2019-04-06 14:36
|
||||
* @Description: 企业微信 OA 审批数据
|
||||
*/
|
||||
@Data
|
||||
public class WxCpApprovalDataResult implements Serializable {
|
||||
private static final long serialVersionUID = -1046940445840716590L;
|
||||
|
||||
@SerializedName("errcode")
|
||||
private Integer errCode;
|
||||
|
||||
@SerializedName("errmsg")
|
||||
private String errMsg;
|
||||
|
||||
private Integer count;
|
||||
|
||||
private Integer total;
|
||||
|
||||
@SerializedName("next_spnum")
|
||||
private Long nextSpnum;
|
||||
|
||||
private WxCpApprovalData[] data;
|
||||
|
||||
|
||||
@Data
|
||||
public static class WxCpApprovalData implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = -3051785319608491640L;
|
||||
|
||||
private String spname;
|
||||
|
||||
@SerializedName("apply_name")
|
||||
private String applyName;
|
||||
|
||||
@SerializedName("apply_org")
|
||||
private String applyOrg;
|
||||
|
||||
@SerializedName("approval_name")
|
||||
private String[] approvalName;
|
||||
|
||||
@SerializedName("notify_name")
|
||||
private String[] notifyName;
|
||||
|
||||
@SerializedName("sp_status")
|
||||
private Integer spStatus;
|
||||
|
||||
@SerializedName("sp_num")
|
||||
private Long spNum;
|
||||
|
||||
@SerializedName("apply_time")
|
||||
private Long applyTime;
|
||||
|
||||
@SerializedName("apply_user_id")
|
||||
private String applyUserId;
|
||||
|
||||
@SerializedName("comm")
|
||||
private Map<String,String> comm;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Element
|
||||
* @Package me.chanjar.weixin.cp.bean
|
||||
* @date 2019-04-06 11:01
|
||||
* @Description: 企业微信打卡数据
|
||||
*/
|
||||
@Data
|
||||
public class WxCpCheckinData implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1915820330847799605L;
|
||||
|
||||
@SerializedName("userid")
|
||||
private String userId;
|
||||
|
||||
@SerializedName("groupname")
|
||||
private String groupName;
|
||||
|
||||
@SerializedName("checkin_type")
|
||||
private String checkinType;
|
||||
|
||||
@SerializedName("exception_type")
|
||||
private String exceptionType;
|
||||
|
||||
@SerializedName("checkin_time")
|
||||
private Long checkinTime;
|
||||
|
||||
@SerializedName("location_title")
|
||||
private String locationTitle;
|
||||
|
||||
@SerializedName("location_detail")
|
||||
private String locationDetail;
|
||||
|
||||
@SerializedName("wifiname")
|
||||
private String wifiName;
|
||||
|
||||
@SerializedName("wifimac")
|
||||
private String wifiMAC;
|
||||
|
||||
private String notes;
|
||||
|
||||
@SerializedName("mediaids")
|
||||
private List<String> mediaIds;
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Element
|
||||
* @Package me.chanjar.weixin.cp.bean
|
||||
* @date 2019-04-06 13:22
|
||||
* @Description: 企业微信打卡规则
|
||||
*/
|
||||
@Data
|
||||
public class WxCpCheckinOption implements Serializable {
|
||||
private static final long serialVersionUID = -1964233697990417482L;
|
||||
|
||||
@SerializedName("userid")
|
||||
private String userId;
|
||||
|
||||
private Group group;
|
||||
|
||||
|
||||
@Data
|
||||
public static class CheckinDate implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5601722383347110974L;
|
||||
|
||||
private List<Integer> workdays;
|
||||
|
||||
@SerializedName("checkintime")
|
||||
private CheckinTime[] checkinTime;
|
||||
|
||||
@SerializedName("flex_time")
|
||||
private Long flexTime;
|
||||
|
||||
@SerializedName("noneed_offwork")
|
||||
private Boolean noneedOffwork;
|
||||
|
||||
@SerializedName("limit_aheadtime")
|
||||
private Long limitAheadtime;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class CheckinTime implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8579954143265336276L;
|
||||
|
||||
@SerializedName("work_sec")
|
||||
private Long workSec;
|
||||
|
||||
@SerializedName("off_work_sec")
|
||||
private Long offWorkSec;
|
||||
|
||||
@SerializedName("remind_work_sec")
|
||||
private Long remindWorkSec;
|
||||
|
||||
@SerializedName("remind_off_work_sec")
|
||||
private Long remindOffWorkSec;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Group implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5888406969613403044L;
|
||||
|
||||
@SerializedName("groupid")
|
||||
private Long id;
|
||||
|
||||
@SerializedName("groupname")
|
||||
private String name;
|
||||
|
||||
@SerializedName("grouptype")
|
||||
private Integer type;
|
||||
|
||||
@SerializedName("checkindate")
|
||||
private List<CheckinDate> checkinDate;
|
||||
|
||||
@SerializedName("spe_workdays")
|
||||
private List<SpeDay> speWorkdays;
|
||||
|
||||
@SerializedName("spe_offdays")
|
||||
private List<SpeDay> speOffdays;
|
||||
|
||||
@SerializedName("sync_holidays")
|
||||
private Boolean syncHolidays;
|
||||
|
||||
@SerializedName("need_photo")
|
||||
private Boolean needPhoto;
|
||||
|
||||
@SerializedName("note_can_use_local_pic")
|
||||
private Boolean note_can_use_local_pic;
|
||||
|
||||
@SerializedName("allow_checkin_offworkday")
|
||||
private Boolean allow_checkin_offworkday;
|
||||
|
||||
@SerializedName("allow_apply_offworkday")
|
||||
private Boolean allow_apply_offworkday;
|
||||
|
||||
@SerializedName("wifimac_infos")
|
||||
private List<WifiMACInfo> wifiMACInfos;
|
||||
|
||||
@SerializedName("loc_infos")
|
||||
private List<LocInfo> locInfos;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class WifiMACInfo implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = -4657809185716627368L;
|
||||
|
||||
@SerializedName("wifiname")
|
||||
private String name;
|
||||
|
||||
@SerializedName("wifimac")
|
||||
private String mac;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class LocInfo implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = -618965280668099608L;
|
||||
|
||||
private Long lat;
|
||||
private Long lng;
|
||||
|
||||
@SerializedName("loc_title")
|
||||
private String title;
|
||||
|
||||
@SerializedName("loc_detail")
|
||||
private String detail;
|
||||
|
||||
private Long distance;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class SpeDay implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = -3538818921359212748L;
|
||||
|
||||
private Long timestamp;
|
||||
private String notes;
|
||||
|
||||
@SerializedName("checkintime")
|
||||
private List<CheckinTime> checkinTime;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Element
|
||||
* @Package me.chanjar.weixin.cp.bean
|
||||
* @date 2019-04-06 15:38
|
||||
* @Description: 公费电话拨打记录
|
||||
*/
|
||||
@Data
|
||||
public class WxCpDialRecord implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 4178886812949929116L;
|
||||
@SerializedName("call_time")
|
||||
private Long callTime;
|
||||
|
||||
/**
|
||||
* 总通话时长,单位为分钟
|
||||
*/
|
||||
@SerializedName("total_duration")
|
||||
private Integer totalDuration;
|
||||
|
||||
/**
|
||||
* 通话类型,1-单人通话 2-多人通话
|
||||
*/
|
||||
@SerializedName("call_type")
|
||||
private Integer callType;
|
||||
|
||||
private Caller caller;
|
||||
|
||||
private List<Callee> callee;
|
||||
|
||||
/**
|
||||
* 主叫信息
|
||||
*/
|
||||
@Data
|
||||
public static class Caller implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = 4792200404338145607L;
|
||||
|
||||
@SerializedName("userid")
|
||||
private String userId;
|
||||
|
||||
private Integer duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* 被叫信息
|
||||
*/
|
||||
@Data
|
||||
public static class Callee implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = 2390963671336179550L;
|
||||
|
||||
/**
|
||||
* 被叫用户的userid,当被叫用户为企业内用户时返回
|
||||
*/
|
||||
@SerializedName("userid")
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 被叫用户的号码,当被叫用户为外部用户时返回
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
private Integer duration;
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ public class WxCpInviteResult implements Serializable {
|
||||
private String errMsg;
|
||||
|
||||
@SerializedName("invaliduser")
|
||||
private String invalidUsers;
|
||||
private String[] invalidUsers;
|
||||
|
||||
@SerializedName("invalidparty")
|
||||
private String[] invalidParties;
|
||||
@@ -45,16 +45,4 @@ public class WxCpInviteResult implements Serializable {
|
||||
@SerializedName("invalidtag")
|
||||
private String[] invalidTags;
|
||||
|
||||
public List<String> getInvalidUserList() {
|
||||
return this.content2List(this.invalidUsers);
|
||||
}
|
||||
|
||||
private List<String> content2List(String content) {
|
||||
if (StringUtils.isBlank(content)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Splitter.on("|").splitToList(content);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 小程序登录凭证校验
|
||||
* 文档地址:https://work.weixin.qq.com/api/doc#90000/90136/90289/wx.qy.login
|
||||
* </pre>
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Data
|
||||
public class WxCpMaJsCode2SessionResult implements Serializable {
|
||||
private static final long serialVersionUID = 6229609023682814765L;
|
||||
|
||||
@SerializedName("session_key")
|
||||
private String sessionKey;
|
||||
|
||||
@SerializedName("userid")
|
||||
private String userId;
|
||||
|
||||
@SerializedName("corpid")
|
||||
private String corpId;
|
||||
|
||||
public static WxCpMaJsCode2SessionResult fromJson(String json) {
|
||||
return WxCpGsonBuilder.create().fromJson(json, WxCpMaJsCode2SessionResult.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +1,19 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.common.api.WxConsts.KefuMsgType;
|
||||
import me.chanjar.weixin.cp.bean.article.MpnewsArticle;
|
||||
import me.chanjar.weixin.cp.bean.article.NewArticle;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.*;
|
||||
import me.chanjar.weixin.cp.bean.taskcard.TaskCardButton;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.cp.bean.article.MpnewsArticle;
|
||||
import me.chanjar.weixin.cp.bean.article.NewArticle;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.FileBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.ImageBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.MpnewsBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.NewsBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.TextBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.TextCardBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.VideoBuilder;
|
||||
import me.chanjar.weixin.cp.bean.messagebuilder.VoiceBuilder;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
/**
|
||||
* 消息.
|
||||
*
|
||||
@@ -45,6 +41,12 @@ public class WxCpMessage implements Serializable {
|
||||
private List<NewArticle> articles = new ArrayList<>();
|
||||
private List<MpnewsArticle> mpnewsArticles = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 任务卡片特有的属性
|
||||
*/
|
||||
private String taskId;
|
||||
private List<TaskCardButton> taskButtons = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 获得文本消息builder.
|
||||
*/
|
||||
@@ -94,6 +96,13 @@ public class WxCpMessage implements Serializable {
|
||||
return new MpnewsBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得markdown消息builder.
|
||||
*/
|
||||
public static MarkdownMsgBuilder MARKDOWN() {
|
||||
return new MarkdownMsgBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得文件消息builder.
|
||||
*/
|
||||
@@ -101,17 +110,26 @@ public class WxCpMessage implements Serializable {
|
||||
return new FileBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得任务卡片消息builder.
|
||||
*/
|
||||
public static TaskCardBuilder TASKCARD() {
|
||||
return new TaskCardBuilder();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 请使用
|
||||
* {@link WxConsts.KefuMsgType#TEXT}
|
||||
* {@link WxConsts.KefuMsgType#IMAGE}
|
||||
* {@link WxConsts.KefuMsgType#VOICE}
|
||||
* {@link WxConsts.KefuMsgType#MUSIC}
|
||||
* {@link WxConsts.KefuMsgType#VIDEO}
|
||||
* {@link WxConsts.KefuMsgType#NEWS}
|
||||
* {@link WxConsts.KefuMsgType#MPNEWS}
|
||||
* {@link KefuMsgType#TEXT}
|
||||
* {@link KefuMsgType#IMAGE}
|
||||
* {@link KefuMsgType#VOICE}
|
||||
* {@link KefuMsgType#MUSIC}
|
||||
* {@link KefuMsgType#VIDEO}
|
||||
* {@link KefuMsgType#NEWS}
|
||||
* {@link KefuMsgType#MPNEWS}
|
||||
* {@link KefuMsgType#MARKDOWN}
|
||||
* {@link KefuMsgType#TASKCARD}
|
||||
* </pre>
|
||||
*
|
||||
* @param msgType 消息类型
|
||||
@@ -121,7 +139,162 @@ public class WxCpMessage implements Serializable {
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
return WxCpGsonBuilder.create().toJson(this);
|
||||
JsonObject messageJson = new JsonObject();
|
||||
if (this.getAgentId() != null) {
|
||||
messageJson.addProperty("agentid", this.getAgentId());
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(this.getToUser())) {
|
||||
messageJson.addProperty("touser", this.getToUser());
|
||||
}
|
||||
|
||||
messageJson.addProperty("msgtype", this.getMsgType());
|
||||
|
||||
if (StringUtils.isNotBlank(this.getToParty())) {
|
||||
messageJson.addProperty("toparty", this.getToParty());
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(this.getToTag())) {
|
||||
messageJson.addProperty("totag", this.getToTag());
|
||||
}
|
||||
|
||||
this.handleMsgType(messageJson);
|
||||
|
||||
if (StringUtils.isNotBlank(this.getSafe())) {
|
||||
messageJson.addProperty("safe", this.getSafe());
|
||||
}
|
||||
|
||||
return messageJson.toString();
|
||||
}
|
||||
|
||||
private void handleMsgType(JsonObject messageJson) {
|
||||
switch (this.getMsgType()) {
|
||||
case KefuMsgType.TEXT: {
|
||||
JsonObject text = new JsonObject();
|
||||
text.addProperty("content", this.getContent());
|
||||
messageJson.add("text", text);
|
||||
break;
|
||||
}
|
||||
case KefuMsgType.MARKDOWN: {
|
||||
JsonObject text = new JsonObject();
|
||||
text.addProperty("content", this.getContent());
|
||||
messageJson.add("markdown", text);
|
||||
break;
|
||||
}
|
||||
case KefuMsgType.TEXTCARD: {
|
||||
JsonObject text = new JsonObject();
|
||||
text.addProperty("title", this.getTitle());
|
||||
text.addProperty("description", this.getDescription());
|
||||
text.addProperty("url", this.getUrl());
|
||||
text.addProperty("btntxt", this.getBtnTxt());
|
||||
messageJson.add("textcard", text);
|
||||
break;
|
||||
}
|
||||
case KefuMsgType.IMAGE: {
|
||||
JsonObject image = new JsonObject();
|
||||
image.addProperty("media_id", this.getMediaId());
|
||||
messageJson.add("image", image);
|
||||
break;
|
||||
}
|
||||
case KefuMsgType.FILE: {
|
||||
JsonObject image = new JsonObject();
|
||||
image.addProperty("media_id", this.getMediaId());
|
||||
messageJson.add("file", image);
|
||||
break;
|
||||
}
|
||||
case KefuMsgType.VOICE: {
|
||||
JsonObject voice = new JsonObject();
|
||||
voice.addProperty("media_id", this.getMediaId());
|
||||
messageJson.add("voice", voice);
|
||||
break;
|
||||
}
|
||||
case KefuMsgType.VIDEO: {
|
||||
JsonObject video = new JsonObject();
|
||||
video.addProperty("media_id", this.getMediaId());
|
||||
video.addProperty("thumb_media_id", this.getThumbMediaId());
|
||||
video.addProperty("title", this.getTitle());
|
||||
video.addProperty("description", this.getDescription());
|
||||
messageJson.add("video", video);
|
||||
break;
|
||||
}
|
||||
case KefuMsgType.NEWS: {
|
||||
JsonObject newsJsonObject = new JsonObject();
|
||||
JsonArray articleJsonArray = new JsonArray();
|
||||
for (NewArticle article : this.getArticles()) {
|
||||
JsonObject articleJson = new JsonObject();
|
||||
articleJson.addProperty("title", article.getTitle());
|
||||
articleJson.addProperty("description", article.getDescription());
|
||||
articleJson.addProperty("url", article.getUrl());
|
||||
articleJson.addProperty("picurl", article.getPicUrl());
|
||||
articleJsonArray.add(articleJson);
|
||||
}
|
||||
newsJsonObject.add("articles", articleJsonArray);
|
||||
messageJson.add("news", newsJsonObject);
|
||||
break;
|
||||
}
|
||||
case KefuMsgType.MPNEWS: {
|
||||
JsonObject newsJsonObject = new JsonObject();
|
||||
if (this.getMediaId() != null) {
|
||||
newsJsonObject.addProperty("media_id", this.getMediaId());
|
||||
} else {
|
||||
JsonArray articleJsonArray = new JsonArray();
|
||||
for (MpnewsArticle article : this.getMpnewsArticles()) {
|
||||
JsonObject articleJson = new JsonObject();
|
||||
articleJson.addProperty("title", article.getTitle());
|
||||
articleJson.addProperty("thumb_media_id", article.getThumbMediaId());
|
||||
articleJson.addProperty("author", article.getAuthor());
|
||||
articleJson.addProperty("content_source_url", article.getContentSourceUrl());
|
||||
articleJson.addProperty("content", article.getContent());
|
||||
articleJson.addProperty("digest", article.getDigest());
|
||||
articleJson.addProperty("show_cover_pic", article.getShowCoverPic());
|
||||
articleJsonArray.add(articleJson);
|
||||
}
|
||||
|
||||
newsJsonObject.add("articles", articleJsonArray);
|
||||
}
|
||||
messageJson.add("mpnews", newsJsonObject);
|
||||
break;
|
||||
}
|
||||
case KefuMsgType.TASKCARD: {
|
||||
JsonObject text = new JsonObject();
|
||||
text.addProperty("title", this.getTitle());
|
||||
text.addProperty("description", this.getDescription());
|
||||
|
||||
if (StringUtils.isNotBlank(this.getUrl())) {
|
||||
text.addProperty("url", this.getUrl());
|
||||
}
|
||||
|
||||
text.addProperty("task_id", this.getTaskId());
|
||||
|
||||
JsonArray buttonJsonArray = new JsonArray();
|
||||
for (TaskCardButton button : this.getTaskButtons()) {
|
||||
JsonObject buttonJson = new JsonObject();
|
||||
buttonJson.addProperty("key", button.getKey());
|
||||
buttonJson.addProperty("name", button.getName());
|
||||
|
||||
if (StringUtils.isNotBlank(button.getReplaceName())) {
|
||||
buttonJson.addProperty("replace_name", button.getReplaceName());
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(button.getColor())) {
|
||||
buttonJson.addProperty("color", button.getColor());
|
||||
}
|
||||
|
||||
if (button.getBold() != null) {
|
||||
buttonJson.addProperty("is_bold", button.getBold());
|
||||
}
|
||||
|
||||
buttonJsonArray.add(buttonJson);
|
||||
}
|
||||
text.add("btn", buttonJsonArray);
|
||||
|
||||
messageJson.add("taskcard", text);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 更新任务卡片消息状态的返回类
|
||||
* 参考文档:https://work.weixin.qq.com/api/doc#90000/90135/91579
|
||||
* Created by Jeff on 2019-05-16.
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="https://github.com/domainname">Jeff</a>
|
||||
* @date 2019-05-16
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class WxCpTaskCardUpdateResult implements Serializable {
|
||||
|
||||
@SerializedName("errcode")
|
||||
private Integer errcode;
|
||||
|
||||
@SerializedName("errmsg")
|
||||
private String errmsg;
|
||||
|
||||
/**
|
||||
* 用户列表
|
||||
*/
|
||||
@SerializedName("invaliduser")
|
||||
private List<String> invalidUsers;
|
||||
|
||||
public static WxCpTaskCardUpdateResult fromJson(String json) {
|
||||
return WxCpGsonBuilder.create().fromJson(json, WxCpTaskCardUpdateResult.class);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,8 @@ public class WxCpUser implements Serializable {
|
||||
private static final long serialVersionUID = -5696099236344075582L;
|
||||
private String userId;
|
||||
private String name;
|
||||
private Integer[] departIds;
|
||||
private Long[] departIds;
|
||||
private Integer[] orders;
|
||||
private String position;
|
||||
private String mobile;
|
||||
private Gender gender;
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import com.thoughtworks.xstream.annotations.XStreamConverter;
|
||||
import com.thoughtworks.xstream.annotations.XStreamImplicit;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.common.util.XmlUtils;
|
||||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
|
||||
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
||||
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
import me.chanjar.weixin.cp.util.xml.XStreamTransformer;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import com.thoughtworks.xstream.annotations.XStreamConverter;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
|
||||
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
||||
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
import me.chanjar.weixin.cp.util.xml.XStreamTransformer;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@@ -36,6 +38,11 @@ import me.chanjar.weixin.cp.util.xml.XStreamTransformer;
|
||||
public class WxCpXmlMessage implements Serializable {
|
||||
private static final long serialVersionUID = -1042994982179476410L;
|
||||
|
||||
/**
|
||||
* 使用dom4j解析的存放所有xml属性和值的map.
|
||||
*/
|
||||
private Map<String, Object> allFieldsMap;
|
||||
|
||||
///////////////////////
|
||||
// 以下都是微信推送过来的消息的xml的element所对应的属性
|
||||
///////////////////////
|
||||
@@ -149,6 +156,10 @@ public class WxCpXmlMessage implements Serializable {
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String recognition;
|
||||
|
||||
@XStreamAlias("TaskId")
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 通讯录变更事件.
|
||||
* 请参考常量 me.chanjar.weixin.cp.WxCpConsts.ContactChangeType
|
||||
@@ -240,6 +251,13 @@ public class WxCpXmlMessage implements Serializable {
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String telephone;
|
||||
|
||||
/**
|
||||
* 地址.
|
||||
*/
|
||||
@XStreamAlias("Address")
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* 扩展属性.
|
||||
*/
|
||||
@@ -320,17 +338,20 @@ public class WxCpXmlMessage implements Serializable {
|
||||
*/
|
||||
@XStreamAlias("TotalCount")
|
||||
private Integer totalCount;
|
||||
|
||||
/**
|
||||
* 过滤.
|
||||
* (过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数,原则上,filterCount = sentCount + errorCount
|
||||
*/
|
||||
@XStreamAlias("FilterCount")
|
||||
private Integer filterCount;
|
||||
|
||||
/**
|
||||
* 发送成功的粉丝数.
|
||||
*/
|
||||
@XStreamAlias("SentCount")
|
||||
private Integer sentCount;
|
||||
|
||||
/**
|
||||
* 发送失败的粉丝数.
|
||||
*/
|
||||
@@ -349,7 +370,9 @@ public class WxCpXmlMessage implements Serializable {
|
||||
protected static WxCpXmlMessage fromXml(String xml) {
|
||||
//修改微信变态的消息内容格式,方便解析
|
||||
xml = xml.replace("</PicList><PicList>", "");
|
||||
return XStreamTransformer.fromXml(WxCpXmlMessage.class, xml);
|
||||
final WxCpXmlMessage xmlMessage = XStreamTransformer.fromXml(WxCpXmlMessage.class, xml);
|
||||
xmlMessage.setAllFieldsMap(XmlUtils.xml2Map(xml));
|
||||
return xmlMessage;
|
||||
}
|
||||
|
||||
protected static WxCpXmlMessage fromXml(InputStream is) {
|
||||
@@ -402,9 +425,11 @@ public class WxCpXmlMessage implements Serializable {
|
||||
|
||||
@Data
|
||||
public static class ExtAttr {
|
||||
@XStreamAlias("Item")
|
||||
|
||||
@XStreamImplicit(itemFieldName = "Item")
|
||||
protected final List<Item> items = new ArrayList<>();
|
||||
|
||||
@XStreamAlias("Item")
|
||||
@Data
|
||||
public static class Item {
|
||||
@XStreamAlias("Name")
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package me.chanjar.weixin.cp.bean.article;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Created by BinaryWang on 2017/3/27.
|
||||
@@ -12,6 +15,9 @@ import java.io.Serializable;
|
||||
* @author Binary Wang
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class NewArticle implements Serializable {
|
||||
private static final long serialVersionUID = 4087852055781140659L;
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package me.chanjar.weixin.cp.bean.messagebuilder;
|
||||
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessage;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* markdown类型的消息builder
|
||||
* Created by Binary Wang on 2019/1/20.
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public class MarkdownMsgBuilder extends BaseBuilder<MarkdownMsgBuilder> {
|
||||
private String content;
|
||||
|
||||
public MarkdownMsgBuilder() {
|
||||
this.msgType = WxConsts.KefuMsgType.MARKDOWN;
|
||||
}
|
||||
|
||||
public MarkdownMsgBuilder content(String content) {
|
||||
this.content = content;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpMessage build() {
|
||||
WxCpMessage m = super.build();
|
||||
m.setContent(this.content);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package me.chanjar.weixin.cp.bean.messagebuilder;
|
||||
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessage;
|
||||
import me.chanjar.weixin.cp.bean.taskcard.TaskCardButton;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 任务卡片消息Builder
|
||||
* 用法: WxCustomMessage m = WxCustomMessage.TASKCARD().title(...)....toUser(...).build();
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="https://github.com/domainname">Jeff</a>
|
||||
* @date 2019-05-16
|
||||
*/
|
||||
public class TaskCardBuilder extends BaseBuilder<TaskCardBuilder> {
|
||||
private String title;
|
||||
private String description;
|
||||
private String url;
|
||||
private String taskId;
|
||||
/**
|
||||
* 按钮个数为1~2个
|
||||
*/
|
||||
private List<TaskCardButton> buttons;
|
||||
|
||||
public TaskCardBuilder() {
|
||||
this.msgType = WxConsts.KefuMsgType.TASKCARD;
|
||||
}
|
||||
|
||||
public TaskCardBuilder title(String title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TaskCardBuilder description(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TaskCardBuilder url(String url) {
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TaskCardBuilder taskId(String taskId) {
|
||||
this.taskId = taskId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TaskCardBuilder buttons(List<TaskCardButton> buttons) {
|
||||
this.buttons = buttons;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpMessage build() {
|
||||
WxCpMessage m = super.build();
|
||||
m.setSafe(null);
|
||||
m.setTitle(this.title);
|
||||
m.setDescription(this.description);
|
||||
m.setUrl(this.url);
|
||||
m.setTaskId(this.taskId);
|
||||
m.setTaskButtons(this.buttons);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package me.chanjar.weixin.cp.bean.taskcard;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 任务卡片按钮
|
||||
* Created by Jeff on 2019-05-16.
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="https://github.com/domainname">Jeff</a>
|
||||
* @date 2019-05-16
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class TaskCardButton {
|
||||
private String key;
|
||||
private String name;
|
||||
private String replaceName;
|
||||
private String color;
|
||||
private Boolean bold;
|
||||
}
|
||||
@@ -36,11 +36,23 @@ public interface WxCpConfigStorage {
|
||||
|
||||
/**
|
||||
* 应该是线程安全的
|
||||
*
|
||||
* @param jsapiTicket
|
||||
*/
|
||||
void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);
|
||||
|
||||
String getAgentJsapiTicket();
|
||||
|
||||
boolean isAgentJsapiTicketExpired();
|
||||
|
||||
/**
|
||||
* 强制将jsapi ticket过期掉
|
||||
*/
|
||||
void expireAgentJsapiTicket();
|
||||
|
||||
/**
|
||||
* 应该是线程安全的
|
||||
*/
|
||||
void updateAgentJsapiTicket(String jsapiTicket, int expiresInSeconds);
|
||||
|
||||
String getCorpId();
|
||||
|
||||
String getCorpSecret();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package me.chanjar.weixin.cp.config;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import me.chanjar.weixin.common.bean.WxAccessToken;
|
||||
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
|
||||
*
|
||||
@@ -32,6 +32,9 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
|
||||
protected volatile String jsapiTicket;
|
||||
protected volatile long jsapiTicketExpiresTime;
|
||||
|
||||
protected volatile String agentJsapiTicket;
|
||||
protected volatile long agentJsapiTicketExpiresTime;
|
||||
|
||||
protected volatile File tmpDirFile;
|
||||
|
||||
private volatile ApacheHttpClientBuilder apacheHttpClientBuilder;
|
||||
@@ -95,6 +98,28 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
|
||||
this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAgentJsapiTicket() {
|
||||
return this.agentJsapiTicket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAgentJsapiTicketExpired() {
|
||||
return System.currentTimeMillis() > this.agentJsapiTicketExpiresTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expireAgentJsapiTicket() {
|
||||
this.agentJsapiTicketExpiresTime = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAgentJsapiTicket(String jsapiTicket, int expiresInSeconds) {
|
||||
this.agentJsapiTicket = jsapiTicket;
|
||||
// 预留200秒的时间
|
||||
this.agentJsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expireJsapiTicket() {
|
||||
this.jsapiTicketExpiresTime = 0;
|
||||
|
||||
@@ -9,26 +9,21 @@ import redis.clients.jedis.JedisPoolConfig;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Jedis client implementor for wechat config storage.
|
||||
* <pre>
|
||||
* 使用说明:本实现仅供参考,并不完整,
|
||||
* 使用说明:本实现仅供参考,并不完整.
|
||||
* 比如为减少项目依赖,未加入redis分布式锁的实现,如有需要请自行实现。
|
||||
* </pre>
|
||||
*
|
||||
* @author gaigeshen
|
||||
*/
|
||||
public class WxCpJedisConfigStorage implements WxCpConfigStorage {
|
||||
|
||||
/**
|
||||
* Redis keys here
|
||||
*/
|
||||
private static final String ACCESS_TOKEN_KEY = "WX_CP_ACCESS_TOKEN";
|
||||
private static final String ACCESS_TOKEN_EXPIRES_TIME_KEY = "WX_CP_ACCESS_TOKEN_EXPIRES_TIME";
|
||||
private static final String JS_API_TICKET_KEY = "WX_CP_JS_API_TICKET";
|
||||
private static final String JS_API_TICKET_EXPIRES_TIME_KEY = "WX_CP_JS_API_TICKET_EXPIRES_TIME";
|
||||
/**
|
||||
* Redis clients pool
|
||||
*/
|
||||
private static final String AGENT_JSAPI_TICKET_KEY = "WX_CP_AGENT_%s_JSAPI_TICKET";
|
||||
private static final String AGENT_JSAPI_TICKET_EXPIRES_TIME_KEY = "WX_CP_AGENT_%s_JSAPI_TICKET_EXPIRES_TIME";
|
||||
|
||||
private final JedisPool jedisPool;
|
||||
private volatile String corpId;
|
||||
private volatile String corpSecret;
|
||||
@@ -46,7 +41,7 @@ public class WxCpJedisConfigStorage implements WxCpConfigStorage {
|
||||
public WxCpJedisConfigStorage(JedisPool jedisPool) {
|
||||
this.jedisPool = jedisPool;
|
||||
}
|
||||
|
||||
|
||||
public WxCpJedisConfigStorage(String host, int port) {
|
||||
jedisPool = new JedisPool(host, port);
|
||||
}
|
||||
@@ -83,8 +78,7 @@ public class WxCpJedisConfigStorage implements WxCpConfigStorage {
|
||||
String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY);
|
||||
|
||||
if (expiresTimeStr != null) {
|
||||
Long expiresTime = Long.parseLong(expiresTimeStr);
|
||||
return System.currentTimeMillis() > expiresTime;
|
||||
return System.currentTimeMillis() > Long.parseLong(expiresTimeStr);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -123,17 +117,15 @@ public class WxCpJedisConfigStorage implements WxCpConfigStorage {
|
||||
|
||||
@Override
|
||||
public boolean isJsapiTicketExpired() {
|
||||
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
String expiresTimeStr = jedis.get(JS_API_TICKET_EXPIRES_TIME_KEY);
|
||||
|
||||
if (expiresTimeStr != null) {
|
||||
Long expiresTime = Long.parseLong(expiresTimeStr);
|
||||
long expiresTime = Long.parseLong(expiresTimeStr);
|
||||
return System.currentTimeMillis() > expiresTime;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,16 +138,51 @@ public class WxCpJedisConfigStorage implements WxCpConfigStorage {
|
||||
|
||||
@Override
|
||||
public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
|
||||
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.set(JS_API_TICKET_KEY, jsapiTicket);
|
||||
|
||||
jedis.set(JS_API_TICKET_EXPIRES_TIME_KEY,
|
||||
(System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L + ""));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAgentJsapiTicket() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
return jedis.get(String.format(AGENT_JSAPI_TICKET_KEY, agentId));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAgentJsapiTicketExpired() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
String expiresTimeStr = jedis.get(String.format(AGENT_JSAPI_TICKET_EXPIRES_TIME_KEY, agentId));
|
||||
|
||||
if (expiresTimeStr != null) {
|
||||
return System.currentTimeMillis() > Long.parseLong(expiresTimeStr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expireAgentJsapiTicket() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.set(String.format(AGENT_JSAPI_TICKET_EXPIRES_TIME_KEY, agentId), "0");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAgentJsapiTicket(String jsapiTicket, int expiresInSeconds) {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.set(String.format(AGENT_JSAPI_TICKET_KEY, agentId), jsapiTicket);
|
||||
jedis.set(String.format(AGENT_JSAPI_TICKET_EXPIRES_TIME_KEY, agentId),
|
||||
(System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L + ""));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCorpId() {
|
||||
return this.corpId;
|
||||
|
||||
@@ -73,7 +73,7 @@ public class WxCpMessageRouter {
|
||||
this.wxCpService = wxCpService;
|
||||
this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE);
|
||||
this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker();
|
||||
this.sessionManager = new StandardSessionManager();
|
||||
this.sessionManager = wxCpService.getSessionManager();
|
||||
this.exceptionHandler = new LogExceptionHandler();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.util.json.WxErrorAdapter;
|
||||
import me.chanjar.weixin.cp.bean.WxCpChat;
|
||||
import me.chanjar.weixin.cp.bean.WxCpDepart;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessage;
|
||||
import me.chanjar.weixin.cp.bean.WxCpTag;
|
||||
import me.chanjar.weixin.cp.bean.WxCpUser;
|
||||
|
||||
@@ -20,7 +19,6 @@ public class WxCpGsonBuilder {
|
||||
|
||||
static {
|
||||
INSTANCE.disableHtmlEscaping();
|
||||
INSTANCE.registerTypeAdapter(WxCpMessage.class, new WxCpMessageGsonAdapter());
|
||||
INSTANCE.registerTypeAdapter(WxCpChat.class, new WxCpChatGsonAdapter());
|
||||
INSTANCE.registerTypeAdapter(WxCpDepart.class, new WxCpDepartGsonAdapter());
|
||||
INSTANCE.registerTypeAdapter(WxCpUser.class, new WxCpUserGsonAdapter());
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved.
|
||||
*
|
||||
* This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended
|
||||
* only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction
|
||||
* arose from modification of the original source, or other redistribution of this source
|
||||
* is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD.
|
||||
*/
|
||||
package me.chanjar.weixin.cp.util.json;
|
||||
|
||||
import com.google.gson.*;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessage;
|
||||
import me.chanjar.weixin.cp.bean.article.MpnewsArticle;
|
||||
import me.chanjar.weixin.cp.bean.article.NewArticle;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* @author Daniel Qian
|
||||
*/
|
||||
public class WxCpMessageGsonAdapter implements JsonSerializer<WxCpMessage> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(WxCpMessage message, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject messageJson = new JsonObject();
|
||||
messageJson.addProperty("agentid", message.getAgentId());
|
||||
if (StringUtils.isNotBlank(message.getToUser())) {
|
||||
messageJson.addProperty("touser", message.getToUser());
|
||||
}
|
||||
messageJson.addProperty("msgtype", message.getMsgType());
|
||||
|
||||
if (StringUtils.isNotBlank(message.getToParty())) {
|
||||
messageJson.addProperty("toparty", message.getToParty());
|
||||
}
|
||||
if (StringUtils.isNotBlank(message.getToTag())) {
|
||||
messageJson.addProperty("totag", message.getToTag());
|
||||
}
|
||||
if (WxConsts.KefuMsgType.TEXT.equals(message.getMsgType())) {
|
||||
JsonObject text = new JsonObject();
|
||||
text.addProperty("content", message.getContent());
|
||||
messageJson.add("text", text);
|
||||
}
|
||||
|
||||
if (WxConsts.KefuMsgType.TEXTCARD.equals(message.getMsgType())) {
|
||||
JsonObject text = new JsonObject();
|
||||
text.addProperty("title", message.getTitle());
|
||||
text.addProperty("description", message.getDescription());
|
||||
text.addProperty("url", message.getUrl());
|
||||
text.addProperty("btntxt", message.getBtnTxt());
|
||||
messageJson.add("textcard", text);
|
||||
}
|
||||
|
||||
if (WxConsts.KefuMsgType.IMAGE.equals(message.getMsgType())) {
|
||||
JsonObject image = new JsonObject();
|
||||
image.addProperty("media_id", message.getMediaId());
|
||||
messageJson.add("image", image);
|
||||
}
|
||||
|
||||
if (WxConsts.KefuMsgType.FILE.equals(message.getMsgType())) {
|
||||
JsonObject image = new JsonObject();
|
||||
image.addProperty("media_id", message.getMediaId());
|
||||
messageJson.add("file", image);
|
||||
}
|
||||
|
||||
if (WxConsts.KefuMsgType.VOICE.equals(message.getMsgType())) {
|
||||
JsonObject voice = new JsonObject();
|
||||
voice.addProperty("media_id", message.getMediaId());
|
||||
messageJson.add("voice", voice);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(message.getSafe())) {
|
||||
messageJson.addProperty("safe", message.getSafe());
|
||||
}
|
||||
|
||||
if (WxConsts.KefuMsgType.VIDEO.equals(message.getMsgType())) {
|
||||
JsonObject video = new JsonObject();
|
||||
video.addProperty("media_id", message.getMediaId());
|
||||
video.addProperty("thumb_media_id", message.getThumbMediaId());
|
||||
video.addProperty("title", message.getTitle());
|
||||
video.addProperty("description", message.getDescription());
|
||||
messageJson.add("video", video);
|
||||
}
|
||||
|
||||
if (WxConsts.KefuMsgType.NEWS.equals(message.getMsgType())) {
|
||||
JsonObject newsJsonObject = new JsonObject();
|
||||
JsonArray articleJsonArray = new JsonArray();
|
||||
for (NewArticle article : message.getArticles()) {
|
||||
JsonObject articleJson = new JsonObject();
|
||||
articleJson.addProperty("title", article.getTitle());
|
||||
articleJson.addProperty("description", article.getDescription());
|
||||
articleJson.addProperty("url", article.getUrl());
|
||||
articleJson.addProperty("picurl", article.getPicUrl());
|
||||
articleJsonArray.add(articleJson);
|
||||
}
|
||||
newsJsonObject.add("articles", articleJsonArray);
|
||||
messageJson.add("news", newsJsonObject);
|
||||
}
|
||||
|
||||
if (WxConsts.KefuMsgType.MPNEWS.equals(message.getMsgType())) {
|
||||
JsonObject newsJsonObject = new JsonObject();
|
||||
if (message.getMediaId() != null) {
|
||||
newsJsonObject.addProperty("media_id", message.getMediaId());
|
||||
} else {
|
||||
JsonArray articleJsonArray = new JsonArray();
|
||||
for (MpnewsArticle article : message.getMpnewsArticles()) {
|
||||
JsonObject articleJson = new JsonObject();
|
||||
articleJson.addProperty("title", article.getTitle());
|
||||
articleJson.addProperty("thumb_media_id", article.getThumbMediaId());
|
||||
articleJson.addProperty("author", article.getAuthor());
|
||||
articleJson.addProperty("content_source_url", article.getContentSourceUrl());
|
||||
articleJson.addProperty("content", article.getContent());
|
||||
articleJson.addProperty("digest", article.getDigest());
|
||||
articleJson.addProperty("show_cover_pic", article.getShowCoverPic());
|
||||
articleJsonArray.add(articleJson);
|
||||
}
|
||||
|
||||
newsJsonObject.add("articles", articleJsonArray);
|
||||
}
|
||||
messageJson.add("mpnews", newsJsonObject);
|
||||
}
|
||||
|
||||
return messageJson;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
* arose from modification of the original source, or other redistribution of this source
|
||||
* is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD.
|
||||
*/
|
||||
|
||||
package me.chanjar.weixin.cp.util.json;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
@@ -24,11 +25,14 @@ import me.chanjar.weixin.cp.bean.Gender;
|
||||
import me.chanjar.weixin.cp.bean.WxCpUser;
|
||||
|
||||
/**
|
||||
* cp user gson adapter.
|
||||
*
|
||||
* @author Daniel Qian
|
||||
*/
|
||||
public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSerializer<WxCpUser> {
|
||||
private static final String EXTERNAL_PROFILE = "external_profile";
|
||||
private static final String EXTERNAL_ATTR = "external_attr";
|
||||
private static final String EXTATTR = "extattr";
|
||||
|
||||
@Override
|
||||
public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
@@ -37,14 +41,24 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri
|
||||
|
||||
if (o.get("department") != null) {
|
||||
JsonArray departJsonArray = o.get("department").getAsJsonArray();
|
||||
Integer[] departIds = new Integer[departJsonArray.size()];
|
||||
Long[] departIds = new Long[departJsonArray.size()];
|
||||
int i = 0;
|
||||
for (JsonElement jsonElement : departJsonArray) {
|
||||
departIds[i++] = jsonElement.getAsInt();
|
||||
departIds[i++] = jsonElement.getAsLong();
|
||||
}
|
||||
user.setDepartIds(departIds);
|
||||
}
|
||||
|
||||
if (o.get("order") != null) {
|
||||
JsonArray departJsonArray = o.get("order").getAsJsonArray();
|
||||
Integer[] orders = new Integer[departJsonArray.size()];
|
||||
int i = 0;
|
||||
for (JsonElement jsonElement : departJsonArray) {
|
||||
orders[i++] = jsonElement.getAsInt();
|
||||
}
|
||||
user.setOrders(orders);
|
||||
}
|
||||
|
||||
user.setUserId(GsonHelper.getString(o, "userid"));
|
||||
user.setName(GsonHelper.getString(o, "name"));
|
||||
user.setPosition(GsonHelper.getString(o, "position"));
|
||||
@@ -62,64 +76,73 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri
|
||||
user.setQrCode(GsonHelper.getString(o, "qr_code"));
|
||||
user.setToInvite(GsonHelper.getBoolean(o, "to_invite"));
|
||||
|
||||
if (GsonHelper.isNotNull(o.get("extattr"))) {
|
||||
JsonArray attrJsonElements = o.get("extattr").getAsJsonObject().get("attrs").getAsJsonArray();
|
||||
for (JsonElement attrJsonElement : attrJsonElements) {
|
||||
WxCpUser.Attr attr = new WxCpUser.Attr(
|
||||
GsonHelper.getString(attrJsonElement.getAsJsonObject(), "name"),
|
||||
GsonHelper.getString(attrJsonElement.getAsJsonObject(), "value")
|
||||
);
|
||||
user.getExtAttrs().add(attr);
|
||||
}
|
||||
if (GsonHelper.isNotNull(o.get(EXTATTR))) {
|
||||
this.buildExtraAttrs(o, user);
|
||||
}
|
||||
|
||||
if (GsonHelper.isNotNull(o.get(EXTERNAL_PROFILE))) {
|
||||
JsonArray attrJsonElements = o.get(EXTERNAL_PROFILE).getAsJsonObject().get(EXTERNAL_ATTR).getAsJsonArray();
|
||||
for (JsonElement element : attrJsonElements) {
|
||||
final Integer type = GsonHelper.getInteger(element.getAsJsonObject(), "type");
|
||||
final String name = GsonHelper.getString(element.getAsJsonObject(), "name");
|
||||
this.buildExternalAttrs(o, user);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 0: {
|
||||
user.getExternalAttrs()
|
||||
.add(WxCpUser.ExternalAttribute.builder()
|
||||
.type(type)
|
||||
.name(name)
|
||||
.value(GsonHelper.getString(element.getAsJsonObject().get("text").getAsJsonObject(), "value"))
|
||||
.build()
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
final JsonObject web = element.getAsJsonObject().get("web").getAsJsonObject();
|
||||
user.getExternalAttrs()
|
||||
.add(WxCpUser.ExternalAttribute.builder()
|
||||
.type(type)
|
||||
.name(name)
|
||||
.url(GsonHelper.getString(web, "url"))
|
||||
.title(GsonHelper.getString(web, "title"))
|
||||
.build()
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
final JsonObject miniprogram = element.getAsJsonObject().get("miniprogram").getAsJsonObject();
|
||||
user.getExternalAttrs()
|
||||
.add(WxCpUser.ExternalAttribute.builder()
|
||||
.type(type)
|
||||
.name(name)
|
||||
.appid(GsonHelper.getString(miniprogram, "appid"))
|
||||
.pagePath(GsonHelper.getString(miniprogram, "pagepath"))
|
||||
.title(GsonHelper.getString(miniprogram, "title"))
|
||||
.build()
|
||||
);
|
||||
break;
|
||||
}
|
||||
default://ignored
|
||||
return user;
|
||||
}
|
||||
|
||||
private void buildExtraAttrs(JsonObject o, WxCpUser user) {
|
||||
JsonArray attrJsonElements = o.get(EXTATTR).getAsJsonObject().get("attrs").getAsJsonArray();
|
||||
for (JsonElement attrJsonElement : attrJsonElements) {
|
||||
WxCpUser.Attr attr = new WxCpUser.Attr(
|
||||
GsonHelper.getString(attrJsonElement.getAsJsonObject(), "name"),
|
||||
GsonHelper.getString(attrJsonElement.getAsJsonObject(), "value")
|
||||
);
|
||||
user.getExtAttrs().add(attr);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildExternalAttrs(JsonObject o, WxCpUser user) {
|
||||
JsonArray attrJsonElements = o.get(EXTERNAL_PROFILE).getAsJsonObject().get(EXTERNAL_ATTR).getAsJsonArray();
|
||||
for (JsonElement element : attrJsonElements) {
|
||||
final Integer type = GsonHelper.getInteger(element.getAsJsonObject(), "type");
|
||||
final String name = GsonHelper.getString(element.getAsJsonObject(), "name");
|
||||
|
||||
switch (type) {
|
||||
case 0: {
|
||||
user.getExternalAttrs()
|
||||
.add(WxCpUser.ExternalAttribute.builder()
|
||||
.type(type)
|
||||
.name(name)
|
||||
.value(GsonHelper.getString(element.getAsJsonObject().get("text").getAsJsonObject(), "value"))
|
||||
.build()
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
final JsonObject web = element.getAsJsonObject().get("web").getAsJsonObject();
|
||||
user.getExternalAttrs()
|
||||
.add(WxCpUser.ExternalAttribute.builder()
|
||||
.type(type)
|
||||
.name(name)
|
||||
.url(GsonHelper.getString(web, "url"))
|
||||
.title(GsonHelper.getString(web, "title"))
|
||||
.build()
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
final JsonObject miniprogram = element.getAsJsonObject().get("miniprogram").getAsJsonObject();
|
||||
user.getExternalAttrs()
|
||||
.add(WxCpUser.ExternalAttribute.builder()
|
||||
.type(type)
|
||||
.name(name)
|
||||
.appid(GsonHelper.getString(miniprogram, "appid"))
|
||||
.pagePath(GsonHelper.getString(miniprogram, "pagepath"))
|
||||
.title(GsonHelper.getString(miniprogram, "title"))
|
||||
.build()
|
||||
);
|
||||
break;
|
||||
}
|
||||
default://ignored
|
||||
}
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -133,11 +156,20 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri
|
||||
}
|
||||
if (user.getDepartIds() != null) {
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
for (Integer departId : user.getDepartIds()) {
|
||||
for (Long departId : user.getDepartIds()) {
|
||||
jsonArray.add(new JsonPrimitive(departId));
|
||||
}
|
||||
o.add("department", jsonArray);
|
||||
}
|
||||
|
||||
if (user.getOrders() != null) {
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
for (Integer order : user.getOrders()) {
|
||||
jsonArray.add(new JsonPrimitive(order));
|
||||
}
|
||||
o.add("order", jsonArray);
|
||||
}
|
||||
|
||||
if (user.getPosition() != null) {
|
||||
o.addProperty("position", user.getPosition());
|
||||
}
|
||||
@@ -191,14 +223,14 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri
|
||||
}
|
||||
JsonObject attrsJson = new JsonObject();
|
||||
attrsJson.add("attrs", attrsJsonArray);
|
||||
o.add("extattr", attrsJson);
|
||||
o.add(EXTATTR, attrsJson);
|
||||
}
|
||||
|
||||
if (user.getExternalAttrs().size() > 0) {
|
||||
JsonArray attrsJsonArray = new JsonArray();
|
||||
for (WxCpUser.ExternalAttribute attr : user.getExternalAttrs()) {
|
||||
JsonObject attrJson = new JsonObject();
|
||||
attrJson.addProperty("type",attr.getType());
|
||||
attrJson.addProperty("type", attr.getType());
|
||||
attrJson.addProperty("name", attr.getName());
|
||||
switch (attr.getType()) {
|
||||
case 0: {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package me.chanjar.weixin.cp.api;
|
||||
|
||||
import org.testng.annotations.*;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessage;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessageSendResult;
|
||||
import org.testng.annotations.*;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
@@ -14,7 +15,7 @@ import static org.testng.Assert.*;
|
||||
* @author Daniel Qian
|
||||
*
|
||||
*/
|
||||
@Test(groups = "customMessageAPI")
|
||||
@Test
|
||||
@Guice(modules = ApiTestModule.class)
|
||||
public class WxCpMessageAPITest {
|
||||
|
||||
@@ -59,4 +60,51 @@ public class WxCpMessageAPITest {
|
||||
System.out.println(messageSendResult.getInvalidUserList());
|
||||
System.out.println(messageSendResult.getInvalidTagList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMessage_markdown() throws WxErrorException {
|
||||
WxCpMessage message = WxCpMessage
|
||||
.MARKDOWN()
|
||||
.toUser(configStorage.getUserId())
|
||||
.content("您的会议室已经预定,稍后会同步到`邮箱` \n" +
|
||||
" >**事项详情** \n" +
|
||||
" >事 项:<font color=\\\"info\\\">开会</font> \n" +
|
||||
" >组织者:@miglioguan \n" +
|
||||
" >参与者:@miglioguan、@kunliu、@jamdeezhou、@kanexiong、@kisonwang \n" +
|
||||
" > \n" +
|
||||
" >会议室:<font color=\\\"info\\\">广州TIT 1楼 301</font> \n" +
|
||||
" >日 期:<font color=\\\"warning\\\">2018年5月18日</font> \n" +
|
||||
" >时 间:<font color=\\\"comment\\\">上午9:00-11:00</font> \n" +
|
||||
" > \n" +
|
||||
" >请准时参加会议。 \n" +
|
||||
" > \n" +
|
||||
" >如需修改会议信息,请点击:[修改会议信息](https://work.weixin.qq.com)")
|
||||
.build();
|
||||
|
||||
WxCpMessageSendResult messageSendResult = this.wxService.messageSend(message);
|
||||
assertNotNull(messageSendResult);
|
||||
System.out.println(messageSendResult);
|
||||
System.out.println(messageSendResult.getInvalidPartyList());
|
||||
System.out.println(messageSendResult.getInvalidUserList());
|
||||
System.out.println(messageSendResult.getInvalidTagList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMessage_textCard() throws WxErrorException {
|
||||
WxCpMessage message = WxCpMessage
|
||||
.TEXTCARD()
|
||||
.toUser(configStorage.getUserId())
|
||||
.btnTxt("更多")
|
||||
.description( "<div class=\"gray\">2016年9月26日</div> <div class=\"normal\">恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\"highlight\">请于2016年10月10日前联系行政同事领取</div>")
|
||||
.url("URL")
|
||||
.title("领奖通知")
|
||||
.build();
|
||||
|
||||
WxCpMessageSendResult messageSendResult = this.wxService.messageSend(message);
|
||||
assertNotNull(messageSendResult);
|
||||
System.out.println(messageSendResult);
|
||||
System.out.println(messageSendResult.getInvalidPartyList());
|
||||
System.out.println(messageSendResult.getInvalidUserList());
|
||||
System.out.println(messageSendResult.getInvalidTagList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.api.ApiTestModule;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import org.testng.annotations.Guice;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Created by BinaryWang on 2019/3/31.
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Test
|
||||
@Guice(modules = ApiTestModule.class)
|
||||
public class BaseWxCpServiceImplTest {
|
||||
@Inject
|
||||
protected WxCpService wxService;
|
||||
|
||||
@Test
|
||||
public void testGetAgentJsapiTicket() throws WxErrorException {
|
||||
assertThat(this.wxService.getAgentJsapiTicket()).isNotEmpty();
|
||||
assertThat(this.wxService.getAgentJsapiTicket(true)).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsCode2Session() throws WxErrorException {
|
||||
assertThat(this.wxService.jsCode2Session("111")).isNotNull();
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,21 @@ package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import me.chanjar.weixin.cp.bean.WxCpChat;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Guice;
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.*;
|
||||
import org.testng.annotations.*;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.WxCpConsts.AppChatMsgType;
|
||||
import me.chanjar.weixin.cp.api.ApiTestModule;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.WxCpAppChatMessage;
|
||||
import me.chanjar.weixin.cp.bean.WxCpChat;
|
||||
import me.chanjar.weixin.cp.bean.article.MpnewsArticle;
|
||||
import me.chanjar.weixin.cp.bean.article.NewArticle;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* 测试群聊服务
|
||||
@@ -19,28 +25,134 @@ import me.chanjar.weixin.cp.api.WxCpService;
|
||||
*/
|
||||
@Guice(modules = ApiTestModule.class)
|
||||
public class WxCpChatServiceImplTest {
|
||||
private String chatId;
|
||||
private String userId;
|
||||
|
||||
@Inject
|
||||
private WxCpService wxCpService;
|
||||
|
||||
@Test
|
||||
public void create() throws Exception {
|
||||
wxCpService.getChatService().chatCreate("测试群聊", "gaige_shen", Arrays.asList("gaige_shen", "ZhangXiaoMing"), "mychatid");
|
||||
private WxCpService cpService;
|
||||
|
||||
@BeforeTest
|
||||
public void init() {
|
||||
this.chatId = "mychatid";
|
||||
this.userId = ((ApiTestModule.WxXmlCpInMemoryConfigStorage) this.cpService.getWxCpConfigStorage()).getUserId();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void get() throws Exception {
|
||||
WxCpChat chat = wxCpService.getChatService().chatGet("mychatid");
|
||||
public void testChatCreate() throws Exception {
|
||||
final String result = cpService.getChatService().chatCreate("测试群聊", userId,
|
||||
Arrays.asList(userId, userId), chatId);
|
||||
assertThat(result).isNotEmpty();
|
||||
assertThat(result).isEqualTo(chatId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChatGet() throws Exception {
|
||||
WxCpChat chat = this.cpService.getChatService().chatGet(chatId);
|
||||
System.out.println(chat);
|
||||
Assert.assertEquals(chat.getName(), "测试群聊");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void update() throws Exception {
|
||||
wxCpService.getChatService().chatUpdate("mychatid", "", "", Arrays.asList("ZhengWuYao"), null);
|
||||
WxCpChat chat = wxCpService.getChatService().chatGet("mychatid");
|
||||
public void testChatUpdate() throws Exception {
|
||||
this.cpService.getChatService().chatUpdate(chatId, "", "", Arrays.asList("ZhengWuYao"), null);
|
||||
WxCpChat chat = this.cpService.getChatService().chatGet(chatId);
|
||||
System.out.println(chat);
|
||||
Assert.assertEquals(chat.getUsers().size(), 3);
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] messages() {
|
||||
return new Object[][]{
|
||||
{WxCpAppChatMessage.builder()
|
||||
.msgType(AppChatMsgType.TEXT)
|
||||
.chatId(chatId)
|
||||
.content("你的快递已到\n请携带工卡前往邮件中心领取")
|
||||
.build()
|
||||
},
|
||||
{WxCpAppChatMessage.builder()
|
||||
.msgType(AppChatMsgType.IMAGE)
|
||||
.chatId(chatId)
|
||||
.mediaId("3_xWGPXZhpOKZrlRISWrjhPrDUZqZ-jIEVzxd56jLuqM")
|
||||
.build()
|
||||
},
|
||||
{WxCpAppChatMessage.builder()
|
||||
.msgType(AppChatMsgType.VOICE)
|
||||
.chatId(chatId)
|
||||
.mediaId("3X5t6HkdN1hUgB7OzrdRnc8v0yI0CqlAxFxnCkS3msTnTLanpYrV4esLv4foZVnlf")
|
||||
.build()
|
||||
},
|
||||
{WxCpAppChatMessage.builder()
|
||||
.msgType(AppChatMsgType.VIDEO)
|
||||
.chatId(chatId)
|
||||
.mediaId("3otWyy_acbID8fyltmCOW5hGVD8oa0_p0za5jhukxKTUDoGT71lqTvtQAWoycXpQf")
|
||||
.title("aaaa")
|
||||
.description("ddddd")
|
||||
.build()
|
||||
},
|
||||
{WxCpAppChatMessage.builder()
|
||||
.msgType(AppChatMsgType.FILE)
|
||||
.chatId(chatId)
|
||||
.mediaId("34AyVyDdndVhB4Z2tT-_FYKZ7Xqrr47LPC11GHH4oy7o")
|
||||
.build()
|
||||
},
|
||||
{WxCpAppChatMessage.builder()
|
||||
.msgType(AppChatMsgType.TEXTCARD)
|
||||
.chatId(chatId)
|
||||
.btnTxt("更多")
|
||||
.title("领奖通知")
|
||||
.url("https://zhidao.baidu.com/question/2073647112026042748.html")
|
||||
.description("<div class=\"gray\">2016年9月26日</div> <div class=\"normal\"> 恭喜你抽中iPhone 7一台,领奖码:520258</div><div class=\"highlight\">请于2016年10月10日前联系行 政同事领取</div>")
|
||||
.build()
|
||||
},
|
||||
{WxCpAppChatMessage.builder()
|
||||
.msgType(AppChatMsgType.NEWS)
|
||||
.chatId(chatId)
|
||||
.articles(Lists.newArrayList(NewArticle.builder()
|
||||
.title("领奖通知")
|
||||
.url("https://zhidao.baidu.com/question/2073647112026042748.html")
|
||||
.description("今年中秋节公司有豪礼相送")
|
||||
.picUrl("http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png")
|
||||
.build()
|
||||
))
|
||||
.build()
|
||||
},
|
||||
{WxCpAppChatMessage.builder()
|
||||
.msgType(AppChatMsgType.MPNEWS)
|
||||
.chatId(chatId)
|
||||
.mpnewsArticles(Lists.newArrayList(MpnewsArticle.newBuilder()
|
||||
.title("地球一小时")
|
||||
.thumbMediaId("3_xWGPXZhpOKZrlRISWrjhPrDUZqZ-jIEVzxd56jLuqM")
|
||||
.author("Author")
|
||||
.contentSourceUrl("https://work.weixin.qq.com")
|
||||
.content("3月24日20:30-21:30 \n办公区将关闭照明一小时,请各部门同事相互转告")
|
||||
.digest("3月24日20:30-21:30 \n办公区将关闭照明一小时")
|
||||
.build()
|
||||
))
|
||||
.build()
|
||||
},
|
||||
{WxCpAppChatMessage.builder()
|
||||
.msgType(AppChatMsgType.MARKDOWN)
|
||||
.chatId(chatId)
|
||||
.content("您的会议室已经预定,稍后会同步到`邮箱` \n" +
|
||||
" >**事项详情** \n" +
|
||||
" >事 项:<font color=\\\"info\\\">开会</font> \n" +
|
||||
" >组织者:@miglioguan \n" +
|
||||
" >参与者:@miglioguan、@kunliu、@jamdeezhou、@kanexiong、@kisonwang \n" +
|
||||
" > \n" +
|
||||
" >会议室:<font color=\\\"info\\\">广州TIT 1楼 301</font> \n" +
|
||||
" >日 期:<font color=\\\"warning\\\">2018年5月18日</font> \n" +
|
||||
" >时 间:<font color=\\\"comment\\\">上午9:00-11:00</font> \n" +
|
||||
" > \n" +
|
||||
" >请准时参加会议。 \n" +
|
||||
" > \n" +
|
||||
" >如需修改会议信息,请点击:[修改会议信息](https://work.weixin.qq.com)")
|
||||
.build()
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "messages")
|
||||
public void testSendMsg(WxCpAppChatMessage message) throws WxErrorException {
|
||||
this.cpService.getChatService().sendMsg(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class WxCpDepartmentServiceImplTest {
|
||||
cpDepart.setName("子部门" + System.currentTimeMillis());
|
||||
cpDepart.setParentId(1L);
|
||||
cpDepart.setOrder(1L);
|
||||
Integer departId = this.wxCpService.getDepartmentService().create(cpDepart);
|
||||
Long departId = this.wxCpService.getDepartmentService().create(cpDepart);
|
||||
System.out.println(departId);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.inject.Inject;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.api.ApiTestModule;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.WxCpCheckinData;
|
||||
import me.chanjar.weixin.cp.bean.WxCpCheckinOption;
|
||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||
import org.testng.annotations.Guice;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Element
|
||||
* @date 2019-04-20 13:46
|
||||
*/
|
||||
@Guice(modules = ApiTestModule.class)
|
||||
public class WxCpOAServiceImplTest {
|
||||
@Inject
|
||||
protected WxCpService wxService;
|
||||
|
||||
@Test
|
||||
public void testGetCheckinData() throws ParseException, WxErrorException {
|
||||
Date startTime = DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.parse("2019-04-11");
|
||||
Date endTime = DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.parse("2019-05-10");
|
||||
|
||||
List<WxCpCheckinData> results = wxService.getOAService()
|
||||
.getCheckinData(1, startTime, endTime, Lists.newArrayList("binary"));
|
||||
|
||||
assertThat(results).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCheckinOption() throws WxErrorException {
|
||||
Date now = new Date();
|
||||
List<WxCpCheckinOption> results = wxService.getOAService()
|
||||
.getCheckinOption(now, Lists.newArrayList("binary"));
|
||||
assertThat(results).isNotNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.api.ApiTestModule;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessage;
|
||||
import me.chanjar.weixin.cp.bean.WxCpMessageSendResult;
|
||||
import me.chanjar.weixin.cp.bean.taskcard.TaskCardButton;
|
||||
import org.testng.annotations.Guice;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* 测试任务卡片服务
|
||||
*
|
||||
* @author <a href="https://github.com/domainname">Jeff</a>
|
||||
* @date 2019-05-16
|
||||
*/
|
||||
@Guice(modules = ApiTestModule.class)
|
||||
public class WxCpTaskCardServiceImplTest {
|
||||
|
||||
@Inject
|
||||
private WxCpService wxCpService;
|
||||
|
||||
@Test
|
||||
public void testSendTaskCard() throws WxErrorException {
|
||||
TaskCardButton btn1 = TaskCardButton.builder()
|
||||
.key("key1")
|
||||
.name("同意")
|
||||
.replaceName("已同意")
|
||||
.bold(true)
|
||||
.build();
|
||||
TaskCardButton btn2 = TaskCardButton.builder()
|
||||
.key("key2")
|
||||
.name("拒绝")
|
||||
.replaceName("已拒绝")
|
||||
.color("red")
|
||||
.build();
|
||||
WxCpMessage message = WxCpMessage.TASKCARD()
|
||||
.toUser("jeff|mr.t")
|
||||
.title("有一个待审批的请求")
|
||||
.description("申请:购买图书\n金额:100 元")
|
||||
.taskId("task_1")
|
||||
.url("http://www.qq.com")
|
||||
.buttons(Arrays.asList(btn1, btn2))
|
||||
.build();
|
||||
|
||||
WxCpMessageSendResult messageSendResult = this.wxCpService.messageSend(message);
|
||||
assertNotNull(messageSendResult);
|
||||
System.out.println(messageSendResult);
|
||||
System.out.println(messageSendResult.getInvalidPartyList());
|
||||
System.out.println(messageSendResult.getInvalidUserList());
|
||||
System.out.println(messageSendResult.getInvalidTagList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate() throws Exception {
|
||||
wxCpService.getTaskCardService().update(Arrays.asList("jeff", "mr.t"), "task_1", "key1");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -42,7 +42,7 @@ public class WxCpUserServiceImplTest {
|
||||
WxCpUser user = new WxCpUser();
|
||||
user.setUserId(userId);
|
||||
user.setName("Some Woman");
|
||||
user.setDepartIds(new Integer[]{2});
|
||||
user.setDepartIds(new Long[]{2L});
|
||||
user.setEmail("none@none.com");
|
||||
user.setGender(Gender.FEMALE);
|
||||
user.setMobile("13560084979");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.*;
|
||||
import org.testng.annotations.*;
|
||||
|
||||
/**
|
||||
* Created by huansinho on 2018/4/13.
|
||||
@@ -10,7 +10,13 @@ import org.testng.annotations.Test;
|
||||
public class WxCpAgentTest {
|
||||
|
||||
public void testDeserialize() {
|
||||
String json = "{\"errcode\": 0,\"errmsg\": \"ok\",\"agentid\": 9,\"name\": \"测试应用\",\"square_logo_url\": \"http://wx.qlogo.cn/mmhead/alksjf;lasdjf;lasjfuodiuj3rj2o34j/0\",\"description\": \"这是一个企业号应用\",\"allow_userinfos\": {\"user\": [{\"userid\": \"0009854\"}, {\"userid\": \"1723\"}, {\"userid\": \"5625\"}]},\"allow_partys\": {\"partyid\": [42762742]},\"allow_tags\": {\"tagid\": [23, 22, 35, 19, 32, 125, 133, 46, 150, 38, 183, 9, 7]},\"close\": 0,\"redirect_domain\": \"weixin.com.cn\",\"report_location_flag\": 0,\"isreportenter\": 0,\"home_url\": \"\"}";
|
||||
String json = "{\"errcode\": 0,\"errmsg\": \"ok\",\"agentid\": 9,\"name\": \"测试应用\"," +
|
||||
"\"square_logo_url\": \"http://wx.qlogo.cn/mmhead/alksjf;lasdjf;lasjfuodiuj3rj2o34j/0\"," +
|
||||
"\"description\": \"这是一个企业号应用\",\"allow_userinfos\": {\"user\": [{\"userid\": \"0009854\"}," +
|
||||
" {\"userid\": \"1723\"}, {\"userid\": \"5625\"}]},\"allow_partys\": {\"partyid\": [42762742]}," +
|
||||
"\"allow_tags\": {\"tagid\": [23, 22, 35, 19, 32, 125, 133, 46, 150, 38, 183, 9, 7]}," +
|
||||
"\"close\": 0,\"redirect_domain\": \"weixin.com.cn\",\"report_location_flag\": 0," +
|
||||
"\"isreportenter\": 0,\"home_url\": \"\"}";
|
||||
|
||||
WxCpAgent wxCpAgent = WxCpAgent.fromJson(json);
|
||||
|
||||
@@ -18,7 +24,8 @@ public class WxCpAgentTest {
|
||||
|
||||
Assert.assertEquals(new Integer[]{42762742}, wxCpAgent.getAllowParties().getPartyIds().toArray());
|
||||
|
||||
Assert.assertEquals(new Integer[]{23, 22, 35, 19, 32, 125, 133, 46, 150, 38, 183, 9, 7}, wxCpAgent.getAllowTags().getTagIds().toArray());
|
||||
Assert.assertEquals(new Integer[]{23, 22, 35, 19, 32, 125, 133, 46, 150, 38, 183, 9, 7},
|
||||
wxCpAgent.getAllowTags().getTagIds().toArray());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,12 @@ package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import me.chanjar.weixin.cp.bean.article.MpnewsArticle;
|
||||
import me.chanjar.weixin.cp.bean.article.NewArticle;
|
||||
import me.chanjar.weixin.cp.bean.taskcard.TaskCardButton;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
@Test
|
||||
public class WxCpMessageTest {
|
||||
@@ -19,12 +21,16 @@ public class WxCpMessageTest {
|
||||
public void testTextCardBuild() {
|
||||
WxCpMessage reply = WxCpMessage.TEXTCARD().toUser("OPENID")
|
||||
.title("领奖通知")
|
||||
.description("<div class=\"gray\">2016年9月26日</div> <div class=\"normal\">恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\"highlight\">请于2016年10月10日前联系行政同事领取</div>")
|
||||
.description("<div class=\"gray\">2016年9月26日</div> <div class=\"normal\">恭喜你抽中iPhone 7一台," +
|
||||
"领奖码:xxxx</div><div class=\"highlight\">请于2016年10月10日前联系行政同事领取</div>")
|
||||
.url("http://www.qq.com")
|
||||
.btnTxt("更多")
|
||||
.build();
|
||||
assertThat(reply.toJson())
|
||||
.isEqualTo("{\"touser\":\"OPENID\",\"msgtype\":\"textcard\",\"textcard\":{\"title\":\"领奖通知\",\"description\":\"<div class=\\\"gray\\\">2016年9月26日</div> <div class=\\\"normal\\\">恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\\\"highlight\\\">请于2016年10月10日前联系行政同事领取</div>\",\"url\":\"http://www.qq.com\",\"btntxt\":\"更多\"},\"safe\":\"0\"}");
|
||||
.isEqualTo("{\"touser\":\"OPENID\",\"msgtype\":\"textcard\",\"textcard\":{\"title\":\"领奖通知\"," +
|
||||
"\"description\":\"<div class=\\\"gray\\\">2016年9月26日</div> <div class=\\\"normal\\\">" +
|
||||
"恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\\\"highlight\\\">请于2016年10月10日前联系行政同事领取</div>\"," +
|
||||
"\"url\":\"http://www.qq.com\",\"btntxt\":\"更多\"},\"safe\":\"0\"}");
|
||||
}
|
||||
|
||||
public void testImageBuild() {
|
||||
@@ -40,9 +46,11 @@ public class WxCpMessageTest {
|
||||
}
|
||||
|
||||
public void testVideoBuild() {
|
||||
WxCpMessage reply = WxCpMessage.VIDEO().toUser("OPENID").title("TITLE").mediaId("MEDIA_ID").thumbMediaId("MEDIA_ID").description("DESCRIPTION").build();
|
||||
WxCpMessage reply = WxCpMessage.VIDEO().toUser("OPENID").title("TITLE").mediaId("MEDIA_ID").thumbMediaId("MEDIA_ID")
|
||||
.description("DESCRIPTION").build();
|
||||
assertThat(reply.toJson())
|
||||
.isEqualTo("{\"touser\":\"OPENID\",\"msgtype\":\"video\",\"safe\":\"0\",\"video\":{\"media_id\":\"MEDIA_ID\",\"thumb_media_id\":\"MEDIA_ID\",\"title\":\"TITLE\",\"description\":\"DESCRIPTION\"}}");
|
||||
.isEqualTo("{\"touser\":\"OPENID\",\"msgtype\":\"video\",\"video\":{\"media_id\":\"MEDIA_ID\"," +
|
||||
"\"thumb_media_id\":\"MEDIA_ID\",\"title\":\"TITLE\",\"description\":\"DESCRIPTION\"},\"safe\":\"0\"}");
|
||||
}
|
||||
|
||||
public void testNewsBuild() {
|
||||
@@ -61,7 +69,10 @@ public class WxCpMessageTest {
|
||||
WxCpMessage reply = WxCpMessage.NEWS().toUser("OPENID").addArticle(article1).addArticle(article2).build();
|
||||
|
||||
assertThat(reply.toJson())
|
||||
.isEqualTo( "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"safe\":\"0\",\"news\":{\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}}");
|
||||
.isEqualTo("{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"news\":{\"articles\":" +
|
||||
"[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}," +
|
||||
"{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}," +
|
||||
"\"safe\":\"0\"}");
|
||||
}
|
||||
|
||||
public void testMpnewsBuild_with_articles() {
|
||||
@@ -88,14 +99,45 @@ public class WxCpMessageTest {
|
||||
WxCpMessage reply = WxCpMessage.MPNEWS().toUser("OPENID").addArticle(article1, article2).build();
|
||||
|
||||
assertThat(reply.toJson())
|
||||
.isEqualTo( "{\"touser\":\"OPENID\",\"msgtype\":\"mpnews\",\"safe\":\"0\",\"mpnews\":{\"articles\":[{\"title\":\"Happy Day\",\"thumb_media_id\":\"thumb\",\"author\":\"aaaaaa\",\"content_source_url\":\"nice url\",\"content\":\"hahaha\",\"digest\":\"digest\",\"show_cover_pic\":\"heihei\"},{\"title\":\"Happy Day\",\"thumb_media_id\":\"thumb\",\"author\":\"aaaaaa\",\"content_source_url\":\"nice url\",\"content\":\"hahaha\",\"digest\":\"digest\",\"show_cover_pic\":\"heihei\"}]}}");
|
||||
.isEqualTo("{\"touser\":\"OPENID\",\"msgtype\":\"mpnews\",\"mpnews\":{\"articles\":" +
|
||||
"[{\"title\":\"Happy Day\",\"thumb_media_id\":\"thumb\",\"author\":\"aaaaaa\"," +
|
||||
"\"content_source_url\":\"nice url\",\"content\":\"hahaha\",\"digest\":\"digest\",\"show_cover_pic\":\"heihei\"}" +
|
||||
",{\"title\":\"Happy Day\",\"thumb_media_id\":\"thumb\",\"author\":\"aaaaaa\"," +
|
||||
"\"content_source_url\":\"nice url\",\"content\":\"hahaha\",\"digest\":\"digest\",\"show_cover_pic\":\"heihei\"}]}," +
|
||||
"\"safe\":\"0\"}");
|
||||
}
|
||||
|
||||
public void testMpnewsBuild_with_media_id() {
|
||||
WxCpMessage reply = WxCpMessage.MPNEWS().toUser("OPENID").mediaId("mmm").build();
|
||||
|
||||
assertThat(reply.toJson())
|
||||
.isEqualTo("{\"touser\":\"OPENID\",\"msgtype\":\"mpnews\",\"safe\":\"0\",\"mpnews\":{\"media_id\":\"mmm\"}}");
|
||||
.isEqualTo("{\"touser\":\"OPENID\",\"msgtype\":\"mpnews\",\"mpnews\":{\"media_id\":\"mmm\"},\"safe\":\"0\"}");
|
||||
}
|
||||
|
||||
public void testTaskCardBuilder() {
|
||||
TaskCardButton button1 = TaskCardButton.builder()
|
||||
.key("yes")
|
||||
.name("批准")
|
||||
.replaceName("已批准")
|
||||
.color("blue")
|
||||
.bold(true)
|
||||
.build();
|
||||
TaskCardButton button2 = TaskCardButton.builder()
|
||||
.key("yes")
|
||||
.name("拒绝")
|
||||
.replaceName("已拒绝")
|
||||
.color("red")
|
||||
.bold(false)
|
||||
.build();
|
||||
WxCpMessage reply = WxCpMessage.TASKCARD().toUser("OPENID")
|
||||
.title("任务卡片")
|
||||
.description("有一条待处理任务")
|
||||
.url("http://www.qq.com")
|
||||
.taskId("task_123")
|
||||
.buttons(Arrays.asList(button1, button2))
|
||||
.build();
|
||||
assertThat(reply.toJson())
|
||||
.isEqualTo("{\"touser\":\"OPENID\",\"msgtype\":\"taskcard\",\"taskcard\":{\"title\":\"任务卡片\",\"description\":\"有一条待处理任务\",\"url\":\"http://www.qq.com\",\"task_id\":\"task_123\",\"btn\":[{\"key\":\"yes\",\"name\":\"批准\",\"replace_name\":\"已批准\",\"color\":\"blue\",\"is_bold\":true},{\"key\":\"yes\",\"name\":\"拒绝\",\"replace_name\":\"已拒绝\",\"color\":\"red\",\"is_bold\":false}]}}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package me.chanjar.weixin.cp.bean;
|
||||
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import org.testng.annotations.*;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
import static me.chanjar.weixin.cp.WxCpConsts.EventType.TASKCARD_CLICK;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
|
||||
@Test
|
||||
public class WxCpXmlMessageTest {
|
||||
@@ -117,4 +119,58 @@ public class WxCpXmlMessageTest {
|
||||
assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "aef52ae501537e552725c5d7f99c1741");
|
||||
assertEquals(wxMessage.getSendPicsInfo().getPicList().get(1).getPicMd5Sum(), "c4564632a4fab91378c39bea6aad6f9e");
|
||||
}
|
||||
|
||||
public void testExtAttr() {
|
||||
|
||||
String xml = "<xml>" +
|
||||
" <ToUserName><![CDATA[w56c9fe3d50ad1ea2]]></ToUserName>" +
|
||||
" <FromUserName><![CDATA[sys]]></FromUserName>" +
|
||||
" <CreateTime>1557241961</CreateTime>" +
|
||||
" <MsgType><![CDATA[event]]></MsgType>" +
|
||||
" <Event><![CDATA[change_contact]]></Event>" +
|
||||
" <ChangeType><![CDATA[update_user]]></ChangeType>" +
|
||||
" <UserID><![CDATA[zhangsan]]></UserID>" +
|
||||
" <ExtAttr>" +
|
||||
" <Item><Name><![CDATA[爱好]]></Name><Value><![CDATA[111]]></Value><Text><Value><![CDATA[111]]></Value></Text></Item>" +
|
||||
" <Item><Name><![CDATA[入职时间]]></Name><Value><![CDATA[11111]]></Value><Text><Value><![CDATA[11111]]></Value></Text></Item>" +
|
||||
" <Item><Name><![CDATA[城市]]></Name><Value><![CDATA[11111]]></Value><Text><Value><![CDATA[11111]]></Value></Text></Item>" +
|
||||
" </ExtAttr>" +
|
||||
" <Address><![CDATA[11111]]></Address>" +
|
||||
"</xml>";
|
||||
WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml);
|
||||
assertEquals(wxMessage.getToUserName(), "w56c9fe3d50ad1ea2");
|
||||
assertEquals(wxMessage.getFromUserName(), "sys");
|
||||
assertEquals(wxMessage.getCreateTime(), new Long(1557241961));
|
||||
assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.EVENT);
|
||||
assertEquals(wxMessage.getEvent(), "change_contact");
|
||||
assertEquals(wxMessage.getChangeType(), "update_user");
|
||||
assertEquals(wxMessage.getUserId(), "zhangsan");
|
||||
assertNotNull(wxMessage.getExtAttrs());
|
||||
assertNotNull(wxMessage.getExtAttrs().getItems());
|
||||
assertEquals(wxMessage.getExtAttrs().getItems().size(), 3);
|
||||
assertEquals(wxMessage.getExtAttrs().getItems().get(0).getName(), "爱好");
|
||||
|
||||
}
|
||||
|
||||
public void testTaskCardEvent() {
|
||||
String xml = "<xml>" +
|
||||
"<ToUserName><![CDATA[toUser]]></ToUserName>" +
|
||||
"<FromUserName><![CDATA[FromUser]]></FromUserName>" +
|
||||
"<CreateTime>123456789</CreateTime>" +
|
||||
"<MsgType><![CDATA[event]]></MsgType>" +
|
||||
"<Event><![CDATA[taskcard_click]]></Event>" +
|
||||
"<EventKey><![CDATA[key111]]></EventKey>" +
|
||||
"<TaskId><![CDATA[taskid111]]></TaskId >" +
|
||||
"<AgentID>1</AgentID>" +
|
||||
"</xml>";
|
||||
WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml);
|
||||
assertEquals(wxMessage.getToUserName(), "toUser");
|
||||
assertEquals(wxMessage.getFromUserName(), "FromUser");
|
||||
assertEquals(wxMessage.getCreateTime(), Long.valueOf(123456789L));
|
||||
assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.EVENT);
|
||||
assertEquals(wxMessage.getAgentId(), Integer.valueOf(1));
|
||||
assertEquals(wxMessage.getEvent(), TASKCARD_CLICK);
|
||||
assertEquals(wxMessage.getEventKey(), "key111");
|
||||
assertEquals(wxMessage.getTaskId(), "taskid111");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,23 @@
|
||||
package me.chanjar.weixin.cp.demo;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import lombok.ToString;
|
||||
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
|
||||
import me.chanjar.weixin.cp.config.WxCpInMemoryConfigStorage;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @author Daniel Qian
|
||||
*/
|
||||
@XStreamAlias("xml")
|
||||
class WxCpDemoInMemoryConfigStorage extends WxCpInMemoryConfigStorage {
|
||||
|
||||
@ToString
|
||||
public class WxCpDemoInMemoryConfigStorage extends WxCpInMemoryConfigStorage {
|
||||
public static WxCpDemoInMemoryConfigStorage fromXml(InputStream is) {
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
xstream.processAnnotations(WxCpDemoInMemoryConfigStorage.class);
|
||||
return (WxCpDemoInMemoryConfigStorage) xstream.fromXML(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SimpleWxConfigProvider [appidOrCorpid=" + this.corpId + ", corpSecret=" + this.corpSecret + ", accessToken=" + this.accessToken
|
||||
+ ", expiresTime=" + this.expiresTime + ", token=" + this.token + ", aesKey=" + this.aesKey + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -76,6 +76,13 @@ public class WxCpUserGsonAdapterTest {
|
||||
|
||||
final WxCpUser user = WxCpUser.fromJson(userJson);
|
||||
assertThat(user).isNotNull();
|
||||
|
||||
assertThat(user.getOrders()).isNotEmpty();
|
||||
assertThat(user.getOrders().length).isEqualTo(2);
|
||||
assertThat(user.getOrders()[0]).isEqualTo(1);
|
||||
assertThat(user.getOrders()[1]).isEqualTo(2);
|
||||
|
||||
|
||||
assertThat(user.getExternalAttrs()).isNotEmpty();
|
||||
|
||||
final WxCpUser.ExternalAttribute externalAttr1 = user.getExternalAttrs().get(0);
|
||||
@@ -100,6 +107,7 @@ public class WxCpUserGsonAdapterTest {
|
||||
@Test
|
||||
public void testSerialize() {
|
||||
WxCpUser user = new WxCpUser();
|
||||
user.setOrders(new Integer[]{1, 2});
|
||||
user.addExternalAttr(WxCpUser.ExternalAttribute.builder()
|
||||
.type(0)
|
||||
.name("文本名称")
|
||||
@@ -119,6 +127,10 @@ public class WxCpUserGsonAdapterTest {
|
||||
.title("my miniprogram")
|
||||
.build());
|
||||
|
||||
assertThat(user.toJson()).isEqualTo("{\"external_profile\":{\"external_attr\":[{\"type\":0,\"name\":\"文本名称\",\"text\":{\"value\":\"文本\"}},{\"type\":1,\"name\":\"网页名称\",\"web\":{\"url\":\"http://www.test.com\",\"title\":\"标题\"}},{\"type\":2,\"name\":\"测试app\",\"miniprogram\":{\"appid\":\"wx8bd80126147df384\",\"pagepath\":\"/index\",\"title\":\"my miniprogram\"}}]}}");
|
||||
assertThat(user.toJson()).isEqualTo("{\"order\":[1,2],\"external_profile\":{\"external_attr\":" +
|
||||
"[{\"type\":0,\"name\":\"文本名称\",\"text\":{\"value\":\"文本\"}}," +
|
||||
"{\"type\":1,\"name\":\"网页名称\",\"web\":{\"url\":\"http://www.test.com\",\"title\":\"标题\"}}," +
|
||||
"{\"type\":2,\"name\":\"测试app\"," +
|
||||
"\"miniprogram\":{\"appid\":\"wx8bd80126147df384\",\"pagepath\":\"/index\",\"title\":\"my miniprogram\"}}]}}");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user