* 获取企业号应用信息 diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java index 95f747e356..741ee906d5 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java @@ -1,20 +1,20 @@ 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; +import java.util.List; + /** * 群聊服务. * * @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="; + + @Deprecated + String chatCreate(String name, String owner, Listusers, String chatId) throws WxErrorException; /** * 创建群聊会话,注意:刚创建的群,如果没有下发消息,在企业微信不会出现该群. @@ -24,15 +24,13 @@ public interface WxCpChatService { * @param users 群成员id列表。至少2人,至多500人 * @param chatId 群聊的唯一标志,不能与已有的群重复;字符串类型,最长32个字符。只允许字符0-9及字母a-zA-Z。如果不填,系统会随机生成群id * @return 创建的群聊会话chatId - * @throws WxErrorException 发生异常 - */ - String chatCreate(String name, String owner, List users, String chatId) throws WxErrorException; - - /** - * chatCreate 同名方法 + * @throws WxErrorException 异常 */ String create(String name, String owner, List users, String chatId) throws WxErrorException; + @Deprecated + void chatUpdate(String chatId, String name, String owner, List usersToAdd, List usersToDelete) throws WxErrorException; + /** * 修改群聊会话. * @@ -41,26 +39,19 @@ public interface WxCpChatService { * @param owner 新群主的id。若不需更新,请忽略此参数(null or empty) * @param usersToAdd 添加成员的id列表,若不需要更新,则传递空对象或者空集合 * @param usersToDelete 踢出成员的id列表,若不需要更新,则传递空对象或者空集合 - * @throws WxErrorException 发生异常 - */ - void chatUpdate(String chatId, String name, String owner, List usersToAdd, List usersToDelete) throws WxErrorException; - - /** - * chatUpdate 同名方法 + * @throws WxErrorException 异常 */ void update(String chatId, String name, String owner, List usersToAdd, List usersToDelete) throws WxErrorException; + @Deprecated + WxCpChat chatGet(String chatId) throws WxErrorException; + /** * 获取群聊会话. * * @param chatId 群聊编号 * @return 群聊会话 - * @throws WxErrorException 发生异常 - */ - WxCpChat chatGet(String chatId) throws WxErrorException; - - /** - * chatGet 同名方法 + * @throws WxErrorException 异常 */ WxCpChat get(String chatId) throws WxErrorException; @@ -71,6 +62,7 @@ public interface WxCpChatService { * 文档地址:https://work.weixin.qq.com/api/doc#90000/90135/90248 * * @param message 要发送的消息内容对象 + * @throws WxErrorException 异常 */ void sendMsg(WxCpAppChatMessage message) throws WxErrorException; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java index 82e571ac5b..c86816b7f2 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java @@ -1,10 +1,10 @@ package me.chanjar.weixin.cp.api; -import java.util.List; - import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.bean.WxCpDepart; +import java.util.List; + /** * * 部门管理接口 @@ -19,7 +19,7 @@ public interface WxCpDepartmentService { ** 部门管理接口 - 创建部门. * 最多支持创建500个部门 - * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口 + * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90205 ** * @param depart 部门 @@ -30,19 +30,20 @@ public interface WxCpDepartmentService { /** *- * 部门管理接口 - 查询部门. - * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E5.88.97.E8.A1.A8 + * 部门管理接口 - 获取部门列表. + * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90208 ** * @param id 部门id。获取指定部门及其下的子部门。非必需,可为null + * @return 获取的部门列表 * @throws WxErrorException 异常 */ Listlist(Long id) throws WxErrorException; /** * - * 部门管理接口 - 修改部门名. - * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口 + * 部门管理接口 - 更新部门. + * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90206 * 如果id为0(未部门),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误 ** @@ -54,6 +55,8 @@ public interface WxCpDepartmentService { /** ** 部门管理接口 - 删除部门. + * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90207 + * 应用须拥有指定部门的管理权限 ** * @param departId 部门id diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java new file mode 100644 index 0000000000..92f2258696 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java @@ -0,0 +1,58 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo; + +import java.util.List; + +/** + *+ * 外部联系人管理接口,企业微信的外部联系人的接口和通讯录接口已经拆离 + * Created by Joe Cao on 2019/6/14 + *+ * + * @author JoeCao + */ +public interface WxCpExternalContactService { + /** + * 获取外部联系人详情. + *+ * 企业可通过此接口,根据外部联系人的userid,拉取外部联系人详情。权限说明: + * 企业需要使用外部联系人管理secret所获取的accesstoken来调用 + * 第三方应用需拥有“企业客户”权限。 + * 第三方应用调用时,返回的跟进人follow_user仅包含应用可见范围之内的成员。 + *+ * + * @param userId 外部联系人的userid + */ + WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException; + + /** + * 获取外部联系人列表. + *+ * 企业可通过此接口获取指定成员添加的客户列表。 + * 客户是指配置了客户联系功能的成员所添加的外部联系人。 + * 没有配置客户联系功能的成员,所添加的外部联系人将不会作为客户返回。 + * 第三方应用需拥有“企业客户”权限。 + * 第三方应用调用时,返回的跟进人follow_user仅包含应用可见范围之内的成员。 + *+ * + * @param userId 外部联系人的userid + * @return List of External wx id + */ + ListlistExternalContacts(String userId) throws WxErrorException; + + + /** + * 企业和第三方服务商可通过此接口获取配置了客户联系功能的成员(Customer Contact)列表。 + * + * 企业需要使用外部联系人管理secret所获取的accesstoken来调用(accesstoken如何获取?); + * 第三方应用需拥有“企业客户”权限。 + * 第三方应用只能获取到可见范围内的配置了客户联系功能的成员 + *+ * + * @return List of CpUser id + */ + ListlistFollowUser() throws WxErrorException; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java index 31ce6b5991..a51e04e175 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java @@ -1,12 +1,12 @@ package me.chanjar.weixin.cp.api; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.error.WxErrorException; + import java.io.File; import java.io.IOException; import java.io.InputStream; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; -import me.chanjar.weixin.common.error.WxErrorException; - /** * * 媒体管理接口. @@ -16,10 +16,6 @@ * @author Binary Wang */ public interface WxCpMediaService { - String MEDIA_GET_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; - String MEDIA_UPLOAD_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type="; - String IMG_UPLOAD_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg"; - String JSSDK_MEDIA_GET_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk"; /** *diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java index 068c037a48..309b981211 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java @@ -12,6 +12,7 @@ * @author Binary Wang */ public interface WxCpMenuService { + /** ** 自定义菜单创建接口 diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAService.java deleted file mode 100644 index e8cf874eb6..0000000000 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAService.java +++ /dev/null @@ -1,66 +0,0 @@ -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:* * @param code 微信oauth授权返回的代码 - * @return [userid, deviceid] + * @return WxCpOauth2UserInfo + * @throws WxErrorException 异常 * @see #getUserInfo(Integer, String) */ - String[] getUserInfo(String code) throws WxErrorException; + WxCpOauth2UserInfo getUserInfo(String code) throws WxErrorException; /** *- * 企业微信OA相关接口 - * - *- */ -public interface WxCpOAService { - - /** - *- * 获取打卡数据 - * API doc : https://work.weixin.qq.com/api/doc#90000/90135/90262 - *- * - * @param openCheckinDataType 打卡类型。1:上下班打卡;2:外出打卡;3:全部打卡 - * @param starttime 获取打卡记录的开始时间 - * @param endtime 获取打卡记录的结束时间 - * @param userIdList 需要获取打卡记录的用户列表 - */ - ListgetCheckinData(Integer openCheckinDataType, Date starttime, Date endtime, List userIdList) throws WxErrorException; - - /** - * - * 获取打卡规则 - * API doc : https://work.weixin.qq.com/api/doc#90000/90135/90263 - *- * - * @param datetime 需要获取规则的当天日期 - * @param userIdList 需要获取打卡规则的用户列表 - * @return - * @throws WxErrorException - */ - ListgetCheckinOption(Date datetime, List userIdList) throws WxErrorException; - - /** - * - * 获取审批数据 - * 通过本接口来获取公司一段时间内的审批记录。一次拉取调用最多拉取10000个审批记录,可以通过多次拉取的方式来满足需求,但调用频率不可超过600次/分。 - * API doc : https://work.weixin.qq.com/api/doc#90000/90135/91530 - *- * - * @param starttime 获取审批记录的开始时间 - * @param endtime 获取审批记录的结束时间 - * @param nextSpnum 第一个拉取的审批单号,不填从该时间段的第一个审批单拉取 - * @return - * @throws WxErrorException - */ - WxCpApprovalDataResult getApprovalData(Date starttime, Date endtime, Long nextSpnum) throws WxErrorException; - - ListgetDialRecord(Date starttime, Date endtime, Integer offset, Integer limit) throws WxErrorException; - -} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java index 5f3d6daa82..7c42ea63fc 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAuth2Service.java @@ -1,20 +1,22 @@ package me.chanjar.weixin.cp.api; import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo; import me.chanjar.weixin.cp.bean.WxCpUserDetail; /** * - * OAuth2相关管理接口 + * OAuth2相关管理接口. * Created by BinaryWang on 2017/6/24. ** * @author Binary Wang */ public interface WxCpOAuth2Service { + /** *- * 构造oauth2授权的url连接 + * 构造oauth2授权的url连接. ** * @param state 状态码 @@ -24,7 +26,7 @@ public interface WxCpOAuth2Service { /** *- * 构造oauth2授权的url连接 + * 构造oauth2授权的url连接. * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=企业获取code ** @@ -57,16 +59,18 @@ public interface WxCpOAuth2Service { ** 根据code获取成员信息 * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息 * https://work.weixin.qq.com/api/doc#10028/根据code获取成员信息 + * https://work.weixin.qq.com/api/doc#90000/90135/91023 获取访问用户身份 * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。 * * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出 @@ -74,10 +78,11 @@ public interface WxCpOAuth2Service { * * @param agentId 企业号应用的id * @param code 通过成员授权获取到的code,最大为512字节。每次成员授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。 - * @return [UserId, DeviceId, OpenId, user_ticket, expires_in] + * @return WxCpOauth2UserInfo + * @throws WxErrorException 异常 * @see #getUserInfo(String) */ - String[] getUserInfo(Integer agentId, String code) throws WxErrorException; + WxCpOauth2UserInfo getUserInfo(Integer agentId, String code) throws WxErrorException; /** *@@ -92,6 +97,8 @@ public interface WxCpOAuth2Service { ** * @param userTicket 成员票据 + * @return WxCpUserDetail + * @throws WxErrorException 异常 */ WxCpUserDetail getUserDetail(String userTicket) throws WxErrorException; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java new file mode 100644 index 0000000000..c6f90d3e64 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java @@ -0,0 +1,64 @@ +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; + +/** + * 企业微信OA相关接口. + * + * @author Element + * @date 2019-04-06 10:52 + */ +public interface WxCpOaService { + + /** + *+ * 获取打卡数据 + * API doc : https://work.weixin.qq.com/api/doc#90000/90135/90262 + *+ * + * @param openCheckinDataType 打卡类型。1:上下班打卡;2:外出打卡;3:全部打卡 + * @param startTime 获取打卡记录的开始时间 + * @param endTime 获取打卡记录的结束时间 + * @param userIdList 需要获取打卡记录的用户列表 + * @return 打卡数据列表 + * @throws WxErrorException 异常 + */ + ListgetCheckinData(Integer openCheckinDataType, Date startTime, Date endTime, List userIdList) throws WxErrorException; + + /** + * + * 获取打卡规则 + * API doc : https://work.weixin.qq.com/api/doc#90000/90135/90263 + *+ * + * @param datetime 需要获取规则的当天日期 + * @param userIdList 需要获取打卡规则的用户列表 + * @return 打卡规则列表 + * @throws WxErrorException 异常 + */ + ListgetCheckinOption(Date datetime, List userIdList) throws WxErrorException; + + /** + * + * 获取审批数据 + * 通过本接口来获取公司一段时间内的审批记录。一次拉取调用最多拉取10000个审批记录,可以通过多次拉取的方式来满足需求,但调用频率不可超过600次/分。 + * API doc : https://work.weixin.qq.com/api/doc#90000/90135/91530 + *+ * + * @param startTime 获取审批记录的开始时间 + * @param endTime 获取审批记录的结束时间 + * @param nextSpnum 第一个拉取的审批单号,不填从该时间段的第一个审批单拉取 + * @throws WxErrorException 异常 + */ + WxCpApprovalDataResult getApprovalData(Date startTime, Date endTime, Long nextSpnum) throws WxErrorException; + + ListgetDialRecord(Date startTime, Date endTime, Integer offset, Integer limit) throws WxErrorException; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index 364723db87..e25fd63c25 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -13,19 +13,10 @@ import me.chanjar.weixin.cp.config.WxCpConfigStorage; /** - * 微信API的Service + * 微信API的Service. * @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"; - /** * * 验证推送过来的消息的正确性 @@ -293,7 +284,9 @@ public interface WxCpService { * 获取用户相关接口的服务类对象 */ WxCpUserService getUserService(); - + + WxCpExternalContactService getExternalContactService(); + /** * 获取群聊服务 * @@ -310,7 +303,7 @@ public interface WxCpService { WxCpAgentService getAgentService(); - WxCpOAService getOAService(); + WxCpOaService getOAService(); /** * http请求对象 diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java index 9624f9e409..78f1d79139 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java @@ -17,6 +17,7 @@ * @author Binary Wang */ public interface WxCpTagService { + /** * 创建标签. * @@ -51,6 +52,14 @@ public interface WxCpTagService { */ ListlistUsersByTagId(String tagId) throws WxErrorException; + /** + * 获取标签成员. + * 对应: http://qydev.weixin.qq.com/wiki/index.php?title=管理标签 中的get接口 + * + * @param tagId 标签id + */ + WxCpTagGetResult get(String tagId) throws WxErrorException; + /** * 增加标签成员. * @@ -69,13 +78,4 @@ public interface WxCpTagService { */ WxCpTagAddOrRemoveUsersResult removeUsersFromTag(String tagId, List userIds, List partyIds) throws WxErrorException; - - /** - * 获取标签成员. - * 对应: http://qydev.weixin.qq.com/wiki/index.php?title=管理标签 中的get接口 - * - * @param tagId 标签id - */ - WxCpTagGetResult get(String tagId) throws WxErrorException; - } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java index 038c2dd3bf..5bf50d36dc 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java @@ -14,6 +14,7 @@ * @date 2019-05-16 */ public interface WxCpTaskCardService { + /** * * 更新任务卡片消息状态 diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java new file mode 100644 index 0000000000..40ffcf55e2 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java @@ -0,0 +1,169 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.error.WxErrorException; +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.WxCpTpCorp; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; + +/** + * 微信第三方应用API的Service. + * + * @author zhenjun cai + */ +public interface WxCpTpService { + + /** + *+ * 验证推送过来的消息的正确性 + * 详情请见: https://work.weixin.qq.com/api/doc#90000/90139/90968/消息体签名校验 + *+ * + * @param msgSignature 消息签名 + * @param timestamp 时间戳 + * @param nonce 随机数 + * @param data 微信传输过来的数据,有可能是echoStr,有可能是xml消息 + */ + boolean checkSignature(String msgSignature, String timestamp, String nonce, String data); + + /** + * 获取suite_access_token, 不强制刷新suite_access_token + * + * @see #getSuiteAccessToken(boolean) + */ + String getSuiteAccessToken() throws WxErrorException; + + /** + *+ * 获取suite_access_token,本方法线程安全 + * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限 + * 另:本service的所有方法都会在suite_access_token过期是调用此方法 + * 程序员在非必要情况下尽量不要主动调用此方法 + * 详情请见: https://work.weixin.qq.com/api/doc#90001/90143/90600 + *+ * + * @param forceRefresh 强制刷新 + */ + String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException; + + /** + * 获得suite_ticket,不强制刷新suite_ticket + * + * @see #getSuiteTicket(boolean) + */ + String getSuiteTicket() throws WxErrorException; + + /** + *+ * 获得suite_ticket + * 由于suite_ticket是微信服务器定时推送(每10分钟),不能主动获取,如果碰到过期只能抛异常 + * + * 详情请见:https://work.weixin.qq.com/api/doc#90001/90143/90628 + *+ * + * @param forceRefresh 强制刷新 + */ + String getSuiteTicket(boolean forceRefresh) throws WxErrorException; + + /** + * 小程序登录凭证校验 + * + * @param jsCode 登录时获取的 code + */ + WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorException; + + /** + * 获取企业凭证 + * + * @param authCorpid 授权方corpid + * @param permanentCode 永久授权码,通过get_permanent_code获取 + */ + WxAccessToken getCorpToken(String authCorpid, String permanentCode) throws WxErrorException; + + /** + * 获取企业永久授权码 + * + * @param authCode + * @return + */ + WxCpTpCorp getPermanentCode(String authCode) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 + * + * @param url 接口地址 + * @param queryParam 请求参数 + */ + String get(String url, String queryParam) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 + * + * @param url 接口地址 + * @param postData 请求body字符串 + */ + String post(String url, String postData) throws WxErrorException; + + /** + *+ * Service没有实现某个API的时候,可以用这个, + * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。 + * 可以参考,{@link MediaUploadRequestExecutor}的实现方法 + *+ * + * @param executor 执行器 + * @param uri 请求地址 + * @param data 参数 + * @param请求值类型 + * @param 返回值类型 + */ + T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; + + /** + * + * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试 + * 默认:1000ms + *+ * + * @param retrySleepMillis 重试休息时间 + */ + void setRetrySleepMillis(int retrySleepMillis); + + /** + *+ * 设置当微信系统响应系统繁忙时,最大重试次数 + * 默认:5次 + *+ * + * @param maxRetryTimes 最大重试次数 + */ + void setMaxRetryTimes(int maxRetryTimes); + + /** + * 初始化http请求对象 + */ + void initHttp(); + + /** + * 获取WxMpConfigStorage 对象 + * + * @return WxMpConfigStorage + */ + WxCpTpConfigStorage getWxCpTpConfigStorage(); + + /** + * 注入 {@link WxCpTpConfigStorage} 的实现 + * + * @param wxConfigProvider 配置对象 + */ + void setWxCpTpConfigStorage(WxCpTpConfigStorage wxConfigProvider); + + /** + * http请求对象 + */ + RequestHttp, ?> getRequestHttp(); + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java index 310a1efa5e..8cc77a2d55 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java @@ -1,13 +1,13 @@ package me.chanjar.weixin.cp.api; -import java.util.List; -import java.util.Map; - import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.bean.WxCpInviteResult; import me.chanjar.weixin.cp.bean.WxCpUser; import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo; +import java.util.List; +import java.util.Map; + /** ** 用户管理接口 @@ -17,6 +17,7 @@ * @author Binary Wang */ public interface WxCpUserService { + /** ** 用在二次验证的时候. @@ -136,6 +137,23 @@ public interface WxCpUserService { */ String openid2UserId(String openid) throws WxErrorException; + /** + *+ * + * 通过手机号获取其所对应的userid。 + * + * 请求方式:POST(HTTPS) + * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=ACCESS_TOKEN + * + * 文档地址:https://work.weixin.qq.com/api/doc#90001/90143/91693 + *+ * + * @param mobile 手机号码。长度为5~32个字节 + * @return userid mobile对应的成员userid + * @throws WxErrorException . + */ + String getUserId(String mobile) throws WxErrorException; + /** * 获取外部联系人详情. *@@ -146,6 +164,10 @@ public interface WxCpUserService { ** * @param userId 外部联系人的userid + * @return 联系人详情 + * @throws WxErrorException . */ WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException; + + } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java index 3eb99b79d2..c7f10f6b30 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java @@ -5,6 +5,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; @@ -23,6 +24,7 @@ import me.chanjar.weixin.cp.bean.WxCpMessage; import me.chanjar.weixin.cp.bean.WxCpMessageSendResult; import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,22 +33,24 @@ import java.util.HashMap; import java.util.Map; +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.*; + /** * @author chanjarster */ +@Slf4j public abstract class BaseWxCpServiceImplimplements WxCpService, RequestHttp { - protected final Logger log = LoggerFactory.getLogger(this.getClass()); - - private WxCpUserService userService = new WxCpUserServiceImpl(this); - private WxCpChatService chatService = new WxCpChatServiceImpl(this); + private WxCpUserService userService = new WxCpUserServiceImpl(this); + private WxCpChatService chatService = new WxCpChatServiceImpl(this); private WxCpDepartmentService departmentService = new WxCpDepartmentServiceImpl(this); - private WxCpMediaService mediaService = new WxCpMediaServiceImpl(this); - private WxCpMenuService menuService = new WxCpMenuServiceImpl(this); - 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); + private WxCpMediaService mediaService = new WxCpMediaServiceImpl(this); + private WxCpMenuService menuService = new WxCpMenuServiceImpl(this); + 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); + private WxCpExternalContactService externalContactService = new WxCpExternalContactServiceImpl(this); /** * 全局的是否正在刷新access token的锁 @@ -80,7 +84,7 @@ public boolean checkSignature(String msgSignature, String timestamp, String nonc return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data) .equals(msgSignature); } catch (Exception e) { - this.log.error("Checking signature failed, and the reason is :" + e.getMessage()); + log.error("Checking signature failed, and the reason is :" + e.getMessage()); return false; } } @@ -104,7 +108,7 @@ public String getAgentJsapiTicket(boolean forceRefresh) throws WxErrorException if (this.configStorage.isAgentJsapiTicketExpired()) { synchronized (this.globalAgentJsapiTicketRefreshLock) { if (this.configStorage.isAgentJsapiTicketExpired()) { - String responseContent = this.get(WxCpService.GET_AGENT_CONFIG_TICKET, null); + String responseContent = this.get(this.configStorage.getApiUrl(GET_AGENT_CONFIG_TICKET), null); JsonObject jsonObject = new JsonParser().parse(responseContent).getAsJsonObject(); this.configStorage.updateAgentJsapiTicket(jsonObject.get("ticket").getAsString(), jsonObject.get("expires_in").getAsInt()); @@ -129,7 +133,7 @@ public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { if (this.configStorage.isJsapiTicketExpired()) { synchronized (this.globalJsapiTicketRefreshLock) { if (this.configStorage.isJsapiTicketExpired()) { - String responseContent = this.get(WxCpService.GET_JSAPI_TICKET, null); + String responseContent = this.get(this.configStorage.getApiUrl(GET_JSAPI_TICKET), null); JsonObject tmpJsonObject = new JsonParser().parse(responseContent).getAsJsonObject(); this.configStorage.updateJsapiTicket(tmpJsonObject.get("ticket").getAsString(), tmpJsonObject.get("expires_in").getAsInt()); @@ -170,7 +174,7 @@ public WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorExce message.setAgentId(this.getWxCpConfigStorage().getAgentId()); } - return WxCpMessageSendResult.fromJson(this.post(WxCpService.MESSAGE_SEND, message.toJson())); + return WxCpMessageSendResult.fromJson(this.post(this.configStorage.getApiUrl(MESSAGE_SEND), message.toJson())); } @Override @@ -179,13 +183,13 @@ public WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorEx params.put("js_code", jsCode); params.put("grant_type", "authorization_code"); - String result = this.get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params)); + String result = this.get(this.configStorage.getApiUrl(JSCODE_TO_SESSION), Joiner.on("&").withKeyValueSeparator("=").join(params)); return WxCpMaJsCode2SessionResult.fromJson(result); } @Override public String[] getCallbackIp() throws WxErrorException { - String responseContent = get(WxCpService.GET_CALLBACK_IP, null); + String responseContent = get(this.configStorage.getApiUrl(GET_CALLBACK_IP), null); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); JsonArray jsonArray = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); String[] ips = new String[jsonArray.size()]; @@ -216,7 +220,7 @@ public T execute(RequestExecutor executor, String uri, E data) thro return this.executeInternal(executor, uri, data); } catch (WxErrorException e) { if (retryTimes + 1 > this.maxRetryTimes) { - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + log.warn("重试达到最大次数【{}】", this.maxRetryTimes); //最后一次重试失败后,直接抛出异常,不再等待 throw new RuntimeException("微信服务端异常,超出重试次数"); } @@ -228,7 +232,7 @@ public T execute(RequestExecutor executor, String uri, E data) thro if (error.getErrorCode() == -1) { int sleepMillis = this.retrySleepMillis * (1 << retryTimes); try { - this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); + log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); Thread.sleep(sleepMillis); } catch (InterruptedException e1) { Thread.currentThread().interrupt(); @@ -239,7 +243,7 @@ public T execute(RequestExecutor executor, String uri, E data) thro } } while (retryTimes++ < this.maxRetryTimes); - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + log.warn("重试达到最大次数【{}】", this.maxRetryTimes); throw new RuntimeException("微信服务端异常,超出重试次数"); } @@ -255,7 +259,7 @@ protected T executeInternal(RequestExecutor executor, String uri, E try { T result = executor.execute(uriWithAccessToken, data); - this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result); + log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result); return result; } catch (WxErrorException e) { WxError error = e.getError(); @@ -272,12 +276,12 @@ protected T executeInternal(RequestExecutor executor, String uri, E } if (error.getErrorCode() != 0) { - this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error); + log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error); throw new WxErrorException(error, e); } return null; } catch (IOException e) { - this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage()); + log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage()); throw new RuntimeException(e); } } @@ -329,19 +333,19 @@ public WxSessionManager getSessionManager() { public String replaceParty(String mediaId) throws WxErrorException { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("media_id", mediaId); - return post(WxCpService.BATCH_REPLACE_PARTY, jsonObject.toString()); + return post(this.configStorage.getApiUrl(BATCH_REPLACE_PARTY), jsonObject.toString()); } @Override public String replaceUser(String mediaId) throws WxErrorException { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("media_id", mediaId); - return post(WxCpService.BATCH_REPLACE_USER, jsonObject.toString()); + return post(this.configStorage.getApiUrl(BATCH_REPLACE_USER), jsonObject.toString()); } @Override public String getTaskResult(String joinId) throws WxErrorException { - String url = WxCpService.BATCH_GET_RESULT + joinId; + String url = this.configStorage.getApiUrl(BATCH_GET_RESULT + joinId); return get(url, null); } @@ -383,13 +387,18 @@ public WxCpUserService getUserService() { return userService; } + @Override + public WxCpExternalContactService getExternalContactService() { + return externalContactService; + } + @Override public WxCpChatService getChatService() { return chatService; } @Override - public WxCpOAService getOAService() { + public WxCpOaService getOAService() { return oaService; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java new file mode 100644 index 0000000000..92c6ac2985 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java @@ -0,0 +1,239 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.common.base.Joiner; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.WxType; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.DataUtils; +import me.chanjar.weixin.common.util.crypto.SHA1; +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.WxCpTpService; +import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult; +import me.chanjar.weixin.cp.bean.WxCpTpCorp; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * @author zhenjun cai + */ +@Slf4j +public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, RequestHttp { + + /** + * 全局的是否正在刷新access token的锁. + */ + protected final Object globalSuiteAccessTokenRefreshLock = new Object(); + + /** + * 全局的是否正在刷新jsapi_ticket的锁. + */ + protected final Object globalSuiteTicketRefreshLock = new Object(); + + protected WxCpTpConfigStorage configStorage; + + /** + * 临时文件目录. + */ + private File tmpDirFile; + private int retrySleepMillis = 1000; + private int maxRetryTimes = 5; + + @Override + public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) { + try { + return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data) + .equals(msgSignature); + } catch (Exception e) { + log.error("Checking signature failed, and the reason is :" + e.getMessage()); + return false; + } + } + + @Override + public String getSuiteAccessToken() throws WxErrorException { + return getSuiteAccessToken(false); + } + + @Override + public String getSuiteTicket() throws WxErrorException { + return getSuiteTicket(false); + } + + @Override + public String getSuiteTicket(boolean forceRefresh) throws WxErrorException { +// suite ticket由微信服务器推送,不能强制刷新 +// if (forceRefresh) { +// this.configStorage.expireSuiteTicket(); +// } + + if (this.configStorage.isSuiteTicketExpired()) { + // 本地suite ticket 不存在或者过期 + WxError wxError = WxError.fromJson("{\"errcode\":40085, \"errmsg\":\"invaild suite ticket\"}", WxType.CP); + throw new WxErrorException(wxError); + } + return this.configStorage.getSuiteTicket(); + } + + + @Override + public WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorException { + Map params = new HashMap<>(2); + params.put("js_code", jsCode); + params.put("grant_type", "authorization_code"); + + String result = this.get(configStorage.getApiUrl(WxCpApiPathConsts.Tp.JSCODE_TO_SESSION), Joiner.on("&").withKeyValueSeparator("=").join(params)); + return WxCpMaJsCode2SessionResult.fromJson(result); + } + + + @Override + public WxAccessToken getCorpToken(String authCorpid, String permanentCode) throws WxErrorException { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("auth_corpid", authCorpid); + jsonObject.addProperty("permanent_code", permanentCode); + String result = post(configStorage.getApiUrl(WxCpApiPathConsts.Tp.GET_CORP_TOKEN), jsonObject.toString()); + + return WxAccessToken.fromJson(result); + } + + + @Override + public WxCpTpCorp getPermanentCode(String authCode) throws WxErrorException { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("auth_code", authCode); + + String result = post(configStorage.getApiUrl(WxCpApiPathConsts.Tp.GET_PERMANENT_CODE), jsonObject.toString()); + jsonObject = new JsonParser().parse(result).getAsJsonObject(); + WxCpTpCorp wxCpTpCorp = WxCpTpCorp.fromJson(jsonObject.get("auth_corp_info").getAsString()); + wxCpTpCorp.setPermanentCode(jsonObject.get("permanent_code").getAsString()); + return wxCpTpCorp; + } + + @Override + public String get(String url, String queryParam) throws WxErrorException { + return execute(SimpleGetRequestExecutor.create(this), url, queryParam); + } + + @Override + public String post(String url, String postData) throws WxErrorException { + return execute(SimplePostRequestExecutor.create(this), url, postData); + } + + /** + * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求. + */ + @Override + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + int retryTimes = 0; + do { + try { + return this.executeInternal(executor, uri, data); + } catch (WxErrorException e) { + if (retryTimes + 1 > this.maxRetryTimes) { + log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + //最后一次重试失败后,直接抛出异常,不再等待 + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + WxError error = e.getError(); + /* + * -1 系统繁忙, 1000ms后重试 + */ + if (error.getErrorCode() == -1) { + int sleepMillis = this.retrySleepMillis * (1 << retryTimes); + try { + log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); + Thread.sleep(sleepMillis); + } catch (InterruptedException e1) { + Thread.currentThread().interrupt(); + } + } else { + throw e; + } + } + } while (retryTimes++ < this.maxRetryTimes); + + log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + protected T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + E dataForLog = DataUtils.handleDataWithSecret(data); + + if (uri.contains("suite_access_token=")) { + throw new IllegalArgumentException("uri参数中不允许有suite_access_token: " + uri); + } + String suiteAccessToken = getSuiteAccessToken(false); + + String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "suite_access_token=" + suiteAccessToken; + + try { + T result = executor.execute(uriWithAccessToken, data); + log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result); + return result; + } catch (WxErrorException e) { + WxError error = e.getError(); + /* + * 发生以下情况时尝试刷新suite_access_token + * 42009 suite_access_token已过期 + */ + if (error.getErrorCode() == 42009) { + // 强制设置wxCpTpConfigStorage它的suite access token过期了,这样在下一次请求里就会刷新suite access token + this.configStorage.expireSuiteAccessToken(); + return execute(executor, uri, data); + } + + if (error.getErrorCode() != 0) { + log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error); + throw new WxErrorException(error, e); + } + return null; + } catch (IOException e) { + log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage()); + throw new RuntimeException(e); + } + } + + @Override + public void setWxCpTpConfigStorage(WxCpTpConfigStorage wxConfigProvider) { + this.configStorage = wxConfigProvider; + this.initHttp(); + } + + @Override + public void setRetrySleepMillis(int retrySleepMillis) { + this.retrySleepMillis = retrySleepMillis; + } + + + @Override + public void setMaxRetryTimes(int maxRetryTimes) { + this.maxRetryTimes = maxRetryTimes; + } + + public File getTmpDirFile() { + return this.tmpDirFile; + } + + public void setTmpDirFile(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + + @Override + public RequestHttp, ?> getRequestHttp() { + return this; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java index 3a977b81d8..6a9b774691 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java @@ -1,11 +1,9 @@ package me.chanjar.weixin.cp.api.impl; -import java.util.List; - import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; - +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.WxCpAgentService; @@ -13,6 +11,10 @@ import me.chanjar.weixin.cp.bean.WxCpAgent; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import java.util.List; + +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Agent.*; + /** * @@ -22,14 +24,11 @@ * * @author huansinho */ +@RequiredArgsConstructor public class WxCpAgentServiceImpl implements WxCpAgentService { private static final JsonParser JSON_PARSER = new JsonParser(); - private WxCpService mainService; - - public WxCpAgentServiceImpl(WxCpService mainService) { - this.mainService = mainService; - } + private final WxCpService mainService; @Override public WxCpAgent get(Integer agentId) throws WxErrorException { @@ -37,14 +36,13 @@ public WxCpAgent get(Integer agentId) throws WxErrorException { throw new IllegalArgumentException("缺少agentid参数"); } - String url = "https://qyapi.weixin.qq.com/cgi-bin/agent/get?agentid=" + agentId; - String responseContent = this.mainService.get(url, null); + String responseContent = this.mainService.get(String.format(this.mainService.getWxCpConfigStorage().getApiUrl(AGENT_GET), agentId), null); return WxCpAgent.fromJson(responseContent); } @Override public void set(WxCpAgent agentInfo) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/agent/set"; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(AGENT_SET); String responseContent = this.mainService.post(url, agentInfo.toJson()); JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); if (jsonObject.get("errcode").getAsInt() != 0) { @@ -54,7 +52,7 @@ public void set(WxCpAgent agentInfo) throws WxErrorException { @Override public Listlist() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/agent/list"; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(AGENT_LIST); String responseContent = this.mainService.get(url, null); JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); if (jsonObject.get("errcode").getAsInt() != 0) { diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java index 05d298c9ad..bd5baf01dd 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java @@ -1,12 +1,14 @@ package me.chanjar.weixin.cp.api.impl; import com.google.gson.JsonParser; +import lombok.RequiredArgsConstructor; 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.constant.WxCpApiPathConsts; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; import org.apache.commons.lang3.StringUtils; @@ -14,24 +16,18 @@ import java.util.List; import java.util.Map; +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Chat.*; + /** * 群聊服务实现. * * @author gaigeshen */ +@RequiredArgsConstructor public class WxCpChatServiceImpl implements WxCpChatService { private static final JsonParser JSON_PARSER = new JsonParser(); private final WxCpService cpService; - /** - * 创建群聊服务实现的实例. - * - * @param cpService 企业微信的服务 - */ - WxCpChatServiceImpl(WxCpService cpService) { - this.cpService = cpService; - } - @Override public String chatCreate(String name, String owner, List users, String chatId) throws WxErrorException { Map data = new HashMap<>(4); @@ -47,7 +43,7 @@ public String chatCreate(String name, String owner, List users, String c if (StringUtils.isNotBlank(chatId)) { data.put("chatid", chatId); } - String result = this.cpService.post(APPCHAT_CREATE, WxGsonBuilder.create().toJson(data)); + String result = this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(APPCHAT_CREATE), WxGsonBuilder.create().toJson(data)); return new JsonParser().parse(result).getAsJsonObject().get("chatid").getAsString(); } @@ -76,7 +72,7 @@ public void chatUpdate(String chatId, String name, String owner, List us data.put("del_user_list", usersToDelete); } - this.cpService.post(APPCHAT_UPDATE, WxGsonBuilder.create().toJson(data)); + this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(APPCHAT_UPDATE), WxGsonBuilder.create().toJson(data)); } @Override @@ -86,7 +82,7 @@ public void update(String chatId, String name, String owner, List usersT @Override public WxCpChat chatGet(String chatId) throws WxErrorException { - String result = this.cpService.get(APPCHAT_GET_CHATID + chatId, null); + String result = this.cpService.get(this.cpService.getWxCpConfigStorage().getApiUrl(APPCHAT_GET_CHATID + chatId), null); return WxCpGsonBuilder.create() .fromJson(JSON_PARSER.parse(result).getAsJsonObject().getAsJsonObject("chat_info").toString(), WxCpChat.class); } @@ -98,7 +94,7 @@ public WxCpChat get(String chatId) throws WxErrorException { @Override public void sendMsg(WxCpAppChatMessage message) throws WxErrorException { - this.cpService.post("https://qyapi.weixin.qq.com/cgi-bin/appchat/send", message.toJson()); + this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(APPCHAT_SEND), message.toJson()); } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java index 481115fa51..fb2224e335 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java @@ -1,17 +1,21 @@ package me.chanjar.weixin.cp.api.impl; -import java.util.List; - import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.json.GsonHelper; import me.chanjar.weixin.cp.api.WxCpDepartmentService; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpDepart; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import java.util.List; + +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Department.*; + /** * * 部门管理接口 @@ -20,16 +24,13 @@ * * @author Binary Wang */ +@RequiredArgsConstructor public class WxCpDepartmentServiceImpl implements WxCpDepartmentService { - private WxCpService mainService; - - public WxCpDepartmentServiceImpl(WxCpService mainService) { - this.mainService = mainService; - } + private final WxCpService mainService; @Override public Long create(WxCpDepart depart) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create"; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_CREATE); String responseContent = this.mainService.post(url, depart.toJson()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return GsonHelper.getAsLong(tmpJsonElement.getAsJsonObject().get("id")); @@ -37,19 +38,19 @@ public Long create(WxCpDepart depart) throws WxErrorException { @Override public void update(WxCpDepart group) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/update"; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_UPDATE); this.mainService.post(url, group.toJson()); } @Override public void delete(Long departId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId; + String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_DELETE), departId); this.mainService.get(url, null); } @Override public Listlist(Long id) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST); if (id != null) { url += "?id=" + id; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java new file mode 100644 index 0000000000..1891000839 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.cp.api.impl; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpExternalContactService; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo; +import me.chanjar.weixin.cp.bean.WxCpUserExternalContactList; +import me.chanjar.weixin.cp.bean.WxCpUserWithExternalPermission; + +import java.util.List; + +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.ExternalContact.*; + +public class WxCpExternalContactServiceImpl implements WxCpExternalContactService { + private WxCpService mainService; + + public WxCpExternalContactServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException { + String responseContent = this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(GET_EXTERNAL_CONTACT + userId), null); + + return WxCpUserExternalContactInfo.fromJson(responseContent); + } + + @Override + public List listExternalContacts(String userId) throws WxErrorException { + String responseContent = this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(LIST_EXTERNAL_CONTACT + userId), null); + WxCpUserExternalContactList list = WxCpUserExternalContactList.fromJson(responseContent); + return list.getExternalUserId(); + } + + @Override + public List listFollowUser() throws WxErrorException { + String responseContent = this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(GET_FOLLOW_USER_LIST), null); + WxCpUserWithExternalPermission list = WxCpUserWithExternalPermission.fromJson(responseContent); + return list.getFollowUser(); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java index 7a3dc444cf..05e13cfc8a 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java @@ -1,10 +1,6 @@ package me.chanjar.weixin.cp.api.impl; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.UUID; - +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; @@ -12,6 +8,14 @@ import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.cp.api.WxCpMediaService; import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; + +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Media.*; /** * @@ -21,12 +25,9 @@ * * @author Binary Wang */ +@RequiredArgsConstructor public class WxCpMediaServiceImpl implements WxCpMediaService { - private WxCpService mainService; - - public WxCpMediaServiceImpl(WxCpService mainService) { - this.mainService = mainService; - } + private final WxCpService mainService; @Override public WxMediaUploadResult upload(String mediaType, String fileType, InputStream inputStream) @@ -37,7 +38,7 @@ public WxMediaUploadResult upload(String mediaType, String fileType, InputStream @Override public WxMediaUploadResult upload(String mediaType, File file) throws WxErrorException { return this.mainService.execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), - MEDIA_UPLOAD_URL + mediaType, file); + this.mainService.getWxCpConfigStorage().getApiUrl(MEDIA_UPLOAD + mediaType), file); } @Override @@ -45,7 +46,7 @@ public File download(String mediaId) throws WxErrorException { return this.mainService.execute( BaseMediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(), this.mainService.getWxCpConfigStorage().getTmpDirFile()), - MEDIA_GET_URL, "media_id=" + mediaId); + this.mainService.getWxCpConfigStorage().getApiUrl(MEDIA_GET), "media_id=" + mediaId); } @Override @@ -53,13 +54,13 @@ public File getJssdkFile(String mediaId) throws WxErrorException { return this.mainService.execute( BaseMediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(), this.mainService.getWxCpConfigStorage().getTmpDirFile()), - JSSDK_MEDIA_GET_URL, "media_id=" + mediaId); + this.mainService.getWxCpConfigStorage().getApiUrl(JSSDK_MEDIA_GET), "media_id=" + mediaId); } @Override public String uploadImg(File file) throws WxErrorException { final WxMediaUploadResult result = this.mainService - .execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), IMG_UPLOAD_URL, file); + .execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), this.mainService.getWxCpConfigStorage().getApiUrl(IMG_UPLOAD), file); return result.getUrl(); } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java index f58eff4763..85abe71f45 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java @@ -1,24 +1,26 @@ package me.chanjar.weixin.cp.api.impl; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.WxCpMenuService; import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Menu.*; + /** *- * 菜单管理相关接口 + * 菜单管理相关接口. * Created by Binary Wang on 2017-6-25. - * @author Binary Wang *+ * + * @author Binary Wang */ +@RequiredArgsConstructor public class WxCpMenuServiceImpl implements WxCpMenuService { - private WxCpService mainService; - - public WxCpMenuServiceImpl(WxCpService mainService) { - this.mainService = mainService; - } + private final WxCpService mainService; @Override public void create(WxMenu menu) throws WxErrorException { @@ -27,7 +29,7 @@ public void create(WxMenu menu) throws WxErrorException { @Override public void create(Integer agentId, WxMenu menu) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=" + agentId; + String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(MENU_CREATE), agentId); this.mainService.post(url, menu.toJson()); } @@ -38,7 +40,7 @@ public void delete() throws WxErrorException { @Override public void delete(Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + agentId; + String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(MENU_DELETE), agentId); this.mainService.get(url, null); } @@ -49,7 +51,7 @@ public WxMenu get() throws WxErrorException { @Override public WxMenu get(Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + agentId; + String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(MENU_GET), agentId); try { String resultContent = this.mainService.get(url, null); return WxCpGsonBuilder.create().fromJson(resultContent, WxMenu.class); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java index 3507de0769..2005bc36eb 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java @@ -3,30 +3,35 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.URIUtil; import me.chanjar.weixin.common.util.json.GsonHelper; import me.chanjar.weixin.cp.api.WxCpOAuth2Service; import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo; import me.chanjar.weixin.cp.bean.WxCpUserDetail; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import static me.chanjar.weixin.common.api.WxConsts.OAuth2Scope.*; +import static me.chanjar.weixin.common.api.WxConsts.OAuth2Scope.SNSAPI_PRIVATEINFO; +import static me.chanjar.weixin.common.api.WxConsts.OAuth2Scope.SNSAPI_USERINFO; +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.OAuth2.*; + /** *- * + * oauth2相关接口实现类. * Created by Binary Wang on 2017-6-25. - * @author Binary Wang - * - * @author Binary Wang *+ * + * @author Binary Wang */ +@RequiredArgsConstructor public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service { - private WxCpService mainService; - - public WxCpOAuth2ServiceImpl(WxCpService mainService) { - this.mainService = mainService; - } + private final WxCpService mainService; @Override public String buildAuthorizationUrl(String state) { @@ -38,55 +43,54 @@ public String buildAuthorizationUrl(String state) { @Override public String buildAuthorizationUrl(String redirectUri, String state) { - return this.buildAuthorizationUrl(redirectUri, state, WxConsts.OAuth2Scope.SNSAPI_BASE); + return this.buildAuthorizationUrl(redirectUri, state, SNSAPI_BASE); } @Override public String buildAuthorizationUrl(String redirectUri, String state, String scope) { - StringBuilder url = new StringBuilder("https://open.weixin.qq.com/connect/oauth2/authorize?"); - url.append("appid=").append(this.mainService.getWxCpConfigStorage().getCorpId()); + StringBuilder url = new StringBuilder(URL_OAUTH2_AUTHORIZE); + url.append("?appid=").append(this.mainService.getWxCpConfigStorage().getCorpId()); url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectUri)); url.append("&response_type=code"); url.append("&scope=").append(scope); - if (WxConsts.OAuth2Scope.SNSAPI_PRIVATEINFO.equals(scope) - || WxConsts.OAuth2Scope.SNSAPI_USERINFO.equals(scope)) { + if (SNSAPI_PRIVATEINFO.equals(scope) || SNSAPI_USERINFO.equals(scope)) { url.append("&agentid=").append(this.mainService.getWxCpConfigStorage().getAgentId()); } if (state != null) { url.append("&state=").append(state); } + url.append("#wechat_redirect"); return url.toString(); } @Override - public String[] getUserInfo(String code) throws WxErrorException { + public WxCpOauth2UserInfo getUserInfo(String code) throws WxErrorException { return this.getUserInfo(this.mainService.getWxCpConfigStorage().getAgentId(), code); } @Override - public String[] getUserInfo(Integer agentId, String code) throws WxErrorException { - String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?code=%s&agentid=%d", - code, agentId); - String responseText = this.mainService.get(url, null); + public WxCpOauth2UserInfo getUserInfo(Integer agentId, String code) throws WxErrorException { + String responseText = this.mainService.get(String.format(this.mainService.getWxCpConfigStorage().getApiUrl(GET_USER_INFO), code, agentId), null); JsonElement je = new JsonParser().parse(responseText); JsonObject jo = je.getAsJsonObject(); - return new String[]{GsonHelper.getString(jo, "UserId"), - GsonHelper.getString(jo, "DeviceId"), - GsonHelper.getString(jo, "OpenId"), - GsonHelper.getString(jo, "user_ticket"), - GsonHelper.getString(jo, "expires_in") - }; + + return WxCpOauth2UserInfo.builder() + .userId(GsonHelper.getString(jo, "UserId")) + .deviceId(GsonHelper.getString(jo, "DeviceId")) + .openId(GsonHelper.getString(jo, "OpenId")) + .userTicket(GsonHelper.getString(jo, "user_ticket")) + .expiresIn(GsonHelper.getString(jo, "expires_in")) + .build(); } @Override public WxCpUserDetail getUserDetail(String userTicket) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail"; JsonObject param = new JsonObject(); param.addProperty("user_ticket", userTicket); - String responseText = this.mainService.post(url, param.toString()); + String responseText = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(GET_USER_DETAIL), param.toString()); return WxCpGsonBuilder.create().fromJson(responseText, WxCpUserDetail.class); } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java similarity index 70% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAServiceImpl.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java index 2d1ca6ab0b..5d7d758c08 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java @@ -5,36 +5,34 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.cp.api.WxCpOAService; +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.constant.WxCpApiPathConsts; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; import java.util.Date; import java.util.List; +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Oa.*; + /** * @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; - } +@RequiredArgsConstructor +public class WxCpOaServiceImpl implements WxCpOaService { + private final WxCpService mainService; @Override - public ListgetCheckinData(Integer openCheckinDataType, Date starttime, Date endtime, List userIdList) throws WxErrorException { - - if (starttime == null || endtime == null) { + public List getCheckinData(Integer openCheckinDataType, Date startTime, Date endTime, + List userIdList) throws WxErrorException { + if (startTime == null || endTime == null) { throw new RuntimeException("starttime and endtime can't be null"); } @@ -42,15 +40,13 @@ public List getCheckinData(Integer openCheckinDataType, Date st throw new RuntimeException("用户列表不能为空,不超过100个,若用户超过100个,请分批获取"); } - long endtimestamp = endtime.getTime() / 1000L; - long starttimestamp = starttime.getTime() / 1000L; + 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(); @@ -64,7 +60,7 @@ public List getCheckinData(Integer openCheckinDataType, Date st jsonObject.add("useridlist", jsonArray); - String responseContent = this.mainService.post(url, jsonObject.toString()); + String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(GET_CHECKIN_DATA), jsonObject.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() .fromJson( @@ -76,7 +72,6 @@ public List getCheckinData(Integer openCheckinDataType, Date st @Override public List getCheckinOption(Date datetime, List 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"); } @@ -94,7 +89,7 @@ public List getCheckinOption(Date datetime, List user jsonObject.addProperty("datetime", datetime.getTime() / 1000L); jsonObject.add("useridlist", jsonArray); - String responseContent = this.mainService.post(url, jsonObject.toString()); + String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(GET_CHECKIN_OPTION), jsonObject.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() @@ -106,24 +101,20 @@ public List getCheckinOption(Date datetime, List user } @Override - public WxCpApprovalDataResult getApprovalData(Date starttime, Date endtime, Long nextSpnum) throws WxErrorException { - - String url = "https://qyapi.weixin.qq.com/cgi-bin/corp/getapprovaldata"; + public WxCpApprovalDataResult getApprovalData(Date startTime, Date endTime, Long nextSpnum) throws WxErrorException { JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("starttime", starttime.getTime() / 1000L); - jsonObject.addProperty("endtime", endtime.getTime() / 1000L); + 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()); + String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(GET_APPROVAL_DATA), jsonObject.toString()); return WxCpGsonBuilder.create().fromJson(responseContent, WxCpApprovalDataResult.class); } @Override - public List getDialRecord(Date starttime, Date endtime, Integer offset, Integer limit) throws WxErrorException { - - String url = "https://qyapi.weixin.qq.com/cgi-bin/dial/get_dial_record"; + public List getDialRecord(Date startTime, Date endTime, Integer offset, Integer limit) throws WxErrorException { JsonObject jsonObject = new JsonObject(); if (offset == null) { @@ -137,10 +128,10 @@ public List getDialRecord(Date starttime, Date endtime, Integer jsonObject.addProperty("offset", offset); jsonObject.addProperty("limit", limit); - if (starttime != null && endtime != null) { + if (startTime != null && endTime != null) { - long endtimestamp = endtime.getTime() / 1000L; - long starttimestamp = starttime.getTime() / 1000L; + 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天进行查询"); @@ -148,11 +139,9 @@ public List getDialRecord(Date starttime, Date endtime, Integer jsonObject.addProperty("start_time", starttimestamp); jsonObject.addProperty("end_time", endtimestamp); - - } - String responseContent = this.mainService.post(url, jsonObject.toString()); + String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(GET_DIAL_RECORD), jsonObject.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java index 86e237168d..d181af6749 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java @@ -8,8 +8,8 @@ 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 me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -19,9 +19,12 @@ import java.io.IOException; +/** + * @author someone + */ public class WxCpServiceApacheHttpClientImpl extends BaseWxCpServiceImpl { - protected CloseableHttpClient httpClient; - protected HttpHost httpProxy; + private CloseableHttpClient httpClient; + private HttpHost httpProxy; @Override public CloseableHttpClient getRequestHttpClient() { @@ -45,9 +48,8 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { } synchronized (this.globalAccessTokenRefreshLock) { - String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" - + "&corpid=" + this.configStorage.getCorpId() - + "&corpsecret=" + this.configStorage.getCorpSecret(); + String url = String.format(this.configStorage.getApiUrl(WxCpApiPathConsts.GET_TOKEN), this.configStorage.getCorpId(), this.configStorage.getCorpSecret()); + try { HttpGet httpGet = new HttpGet(url); if (this.httpProxy != null) { @@ -56,8 +58,8 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { httpGet.setConfig(config); } String resultContent; - try (CloseableHttpClient httpclient = getRequestHttpClient(); - CloseableHttpResponse response = httpclient.execute(httpGet)) { + try (CloseableHttpClient httpClient = getRequestHttpClient(); + CloseableHttpResponse response = httpClient.execute(httpGet)) { resultContent = new BasicResponseHandler().handleResponse(response); } finally { httpGet.releaseConnection(); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java index 3603a59b17..cc76e9cf4c 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java @@ -1,17 +1,24 @@ package me.chanjar.weixin.cp.api.impl; -import jodd.http.*; +import jodd.http.HttpConnectionProvider; +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.JoddHttp; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; +/** + * @author someone + */ public class WxCpServiceJoddHttpImpl extends BaseWxCpServiceImpl { - protected HttpConnectionProvider httpClient; - protected ProxyInfo httpProxy; - + private HttpConnectionProvider httpClient; + private ProxyInfo httpProxy; @Override public HttpConnectionProvider getRequestHttpClient() { @@ -35,11 +42,8 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { } synchronized (this.globalAccessTokenRefreshLock) { - String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" - + "&corpid=" + this.configStorage.getCorpId() - + "&corpsecret=" + this.configStorage.getCorpSecret(); - - HttpRequest request = HttpRequest.get(url); + HttpRequest request = HttpRequest.get(String.format(this.configStorage.getApiUrl(WxCpApiPathConsts.GET_TOKEN), + this.configStorage.getCorpId(), this.configStorage.getCorpSecret())); if (this.httpProxy != null) { httpClient.useProxy(this.httpProxy); } @@ -60,7 +64,8 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { @Override public void initHttp() { if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) { - httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); + httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(), + configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword()); } httpClient = JoddHttp.httpConnectionProvider; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java index 9163ce03a6..596dc0608e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java @@ -1,5 +1,6 @@ package me.chanjar.weixin.cp.api.impl; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.error.WxError; @@ -11,10 +12,15 @@ import java.io.IOException; -public class WxCpServiceOkHttpImpl extends BaseWxCpServiceImpl { - protected OkHttpClient httpClient; - protected OkHttpProxyInfo httpProxy; +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.GET_TOKEN; +/** + * @author someone + */ +@Slf4j +public class WxCpServiceOkHttpImpl extends BaseWxCpServiceImpl { + private OkHttpClient httpClient; + private OkHttpProxyInfo httpProxy; @Override public OkHttpClient getRequestHttpClient() { @@ -38,35 +44,35 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { } 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); - } + //得到httpClient + OkHttpClient client = getRequestHttpClient(); + //请求的request + Request request = new Request.Builder() + .url(String.format(this.configStorage.getApiUrl(GET_TOKEN), this.configStorage.getCorpId(), this.configStorage.getCorpSecret())) + .get() + .build(); + String resultContent = null; + try { + Response response = client.newCall(request).execute(); + resultContent = response.body().string(); + } catch (IOException e) { + 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()); + 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(); } @Override public void initHttp() { - this.log.debug("WxCpServiceOkHttpImpl initHttp"); + log.debug("WxCpServiceOkHttpImpl initHttp"); //设置代理 if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { httpProxy = OkHttpProxyInfo.httpProxy(configStorage.getHttpProxyHost(), diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOnTpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOnTpImpl.java new file mode 100644 index 0000000000..35eab626a7 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOnTpImpl.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.cp.api.impl; + +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpTpService; + +/** + * + * 默认接口实现类,使用apache httpclient实现,配合第三方应用service使用 + * Created by zhenjun cai. + *+ * + * @author zhenjun cai + */ +@RequiredArgsConstructor +public class WxCpServiceOnTpImpl extends WxCpServiceApacheHttpClientImpl { + private final WxCpTpService wxCpTpService; + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + if (!this.configStorage.isAccessTokenExpired() && !forceRefresh) { + return this.configStorage.getAccessToken(); + } + //access token通过第三方应用service获取 + //corpSecret对应企业永久授权码 + WxAccessToken accessToken = wxCpTpService.getCorpToken(this.configStorage.getCorpId(), this.configStorage.getCorpSecret()); + + this.configStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + return this.configStorage.getAccessToken(); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java index 22bb0fcf96..d0e97c6ec2 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java @@ -1,13 +1,8 @@ package me.chanjar.weixin.cp.api.impl; -import java.util.List; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonPrimitive; +import com.google.gson.*; import com.google.gson.reflect.TypeToken; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.api.WxCpTagService; @@ -15,27 +10,32 @@ import me.chanjar.weixin.cp.bean.WxCpTagAddOrRemoveUsersResult; import me.chanjar.weixin.cp.bean.WxCpTagGetResult; import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import java.util.List; + +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Tag.*; +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Tag.TAG_CREATE; +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Tag.TAG_UPDATE; + /** *- * 标签管理接口 + * 标签管理接口. * Created by Binary Wang on 2017-6-25. - * @author Binary Wang *+ * + * @author Binary Wang */ +@RequiredArgsConstructor public class WxCpTagServiceImpl implements WxCpTagService { - private WxCpService mainService; - - public WxCpTagServiceImpl(WxCpService mainService) { - this.mainService = mainService; - } + private final WxCpService mainService; @Override public String create(String tagName) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/create"; JsonObject o = new JsonObject(); o.addProperty("tagname", tagName); + String url = this.mainService.getWxCpConfigStorage().getApiUrl(TAG_CREATE); String responseContent = this.mainService.post(url, o.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return tmpJsonElement.getAsJsonObject().get("tagid").getAsString(); @@ -43,7 +43,7 @@ public String create(String tagName) throws WxErrorException { @Override public void update(String tagId, String tagName) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/update"; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(TAG_UPDATE); JsonObject o = new JsonObject(); o.addProperty("tagid", tagId); o.addProperty("tagname", tagName); @@ -52,13 +52,13 @@ public void update(String tagId, String tagName) throws WxErrorException { @Override public void delete(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=" + tagId; + String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(TAG_DELETE), tagId); this.mainService.get(url, null); } @Override public ListlistAll() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(TAG_LIST); String responseContent = this.mainService.get(url, null); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() @@ -71,7 +71,7 @@ public List listAll() throws WxErrorException { @Override public List listUsersByTagId(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; + String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(TAG_GET), tagId); String responseContent = this.mainService.get(url, null); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() @@ -84,7 +84,7 @@ public List listUsersByTagId(String tagId) throws WxErrorException { @Override public WxCpTagAddOrRemoveUsersResult addUsers2Tag(String tagId, List userIds, List partyIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers"; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(TAG_ADD_TAG_USERS); JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("tagid", tagId); this.addUserIdsAndPartyIdsToJson(userIds, partyIds, jsonObject); @@ -94,7 +94,7 @@ public WxCpTagAddOrRemoveUsersResult addUsers2Tag(String tagId, List use @Override public WxCpTagAddOrRemoveUsersResult removeUsersFromTag(String tagId, List userIds, List partyIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers"; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(TAG_DEL_TAG_USERS); JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("tagid", tagId); this.addUserIdsAndPartyIdsToJson(userIds, partyIds, jsonObject); @@ -122,15 +122,12 @@ private void addUserIdsAndPartyIdsToJson(List userIds, List part @Override public WxCpTagGetResult get(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get"; - if (tagId != null) { - url += "?tagId=" + tagId; - } else { + if (tagId == null) { throw new IllegalArgumentException("缺少tagId参数"); } + String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(TAG_GET), tagId); String responseContent = this.mainService.get(url, null); - return WxCpTagGetResult.fromJson(responseContent); } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java index 3011320d50..97530a6e9d 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java @@ -5,11 +5,14 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.api.WxCpTaskCardService; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import java.util.HashMap; import java.util.List; import java.util.Map; +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.TaskCard.*; + /** * * 任务卡片管理接口. @@ -33,7 +36,7 @@ public void update(ListuserIds, String taskId, String clickedKey) throw data.put("task_id", taskId); data.put("clicked_key", clickedKey); - String url = "https://qyapi.weixin.qq.com/cgi-bin/message/update_taskcard"; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(UPDATE_TASK_CARD); this.mainService.post(url, WxGsonBuilder.create().toJson(data)); } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java new file mode 100644 index 0000000000..14e75125af --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java @@ -0,0 +1,114 @@ +package me.chanjar.weixin.cp.api.impl; + + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import me.chanjar.weixin.common.WxType; +import me.chanjar.weixin.common.error.WxError; +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.config.WxCpTpConfigStorage; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; +import org.apache.http.Consts; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; + +/** + * @author someone + */ +public class WxCpTpServiceApacheHttpClientImpl extends BaseWxCpTpServiceImpl { + private CloseableHttpClient httpClient; + private HttpHost httpProxy; + + @Override + public CloseableHttpClient getRequestHttpClient() { + return httpClient; + } + + @Override + public HttpHost getRequestHttpProxy() { + return httpProxy; + } + + @Override + public HttpType getRequestType() { + return HttpType.APACHE_HTTP; + } + + @Override + public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException { + if (!this.configStorage.isSuiteAccessTokenExpired() && !forceRefresh) { + return this.configStorage.getSuiteAccessToken(); + } + + synchronized (this.globalSuiteAccessTokenRefreshLock) { + try { + HttpPost httpPost = new HttpPost(configStorage.getApiUrl(WxCpApiPathConsts.Tp.GET_SUITE_TOKEN)); + if (this.httpProxy != null) { + RequestConfig config = RequestConfig.custom() + .setProxy(this.httpProxy).build(); + httpPost.setConfig(config); + } + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("suite_id", this.configStorage.getSuiteId()); + jsonObject.addProperty("suite_secret", this.configStorage.getSuiteSecret()); + jsonObject.addProperty("suite_ticket", this.getSuiteTicket()); + StringEntity entity = new StringEntity(jsonObject.toString(), Consts.UTF_8); + httpPost.setEntity(entity); + + String resultContent; + try (CloseableHttpClient httpclient = getRequestHttpClient(); + CloseableHttpResponse response = httpclient.execute(httpPost)) { + resultContent = new BasicResponseHandler().handleResponse(response); + } finally { + httpPost.releaseConnection(); + } + WxError error = WxError.fromJson(resultContent, WxType.CP); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + jsonObject = new JsonParser().parse(resultContent).getAsJsonObject(); + String suiteAccussToken = jsonObject.get("suite_access_token").getAsString(); + Integer expiresIn = jsonObject.get("expires_in").getAsInt(); + this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return this.configStorage.getSuiteAccessToken(); + } + + @Override + public void initHttp() { + ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage.getApacheHttpClientBuilder(); + if (null == apacheHttpClientBuilder) { + apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); + } + + apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost()) + .httpProxyPort(this.configStorage.getHttpProxyPort()) + .httpProxyUsername(this.configStorage.getHttpProxyUsername()) + .httpProxyPassword(this.configStorage.getHttpProxyPassword()); + + if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) { + this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort()); + } + + this.httpClient = apacheHttpClientBuilder.build(); + } + + @Override + public WxCpTpConfigStorage getWxCpTpConfigStorage() { + return this.configStorage; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceImpl.java new file mode 100644 index 0000000000..f5582021e7 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceImpl.java @@ -0,0 +1,12 @@ +package me.chanjar.weixin.cp.api.impl; + +/** + * + * 默认接口实现类,使用apache httpclient实现 + * Created by zhenjun cai. + *+ * + * @author zhenjun cai + */ +public class WxCpTpServiceImpl extends WxCpTpServiceApacheHttpClientImpl { +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java index 84a16f3496..c75f756635 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java @@ -1,23 +1,23 @@ package me.chanjar.weixin.cp.api.impl; -import java.util.List; -import java.util.Map; - import com.google.common.collect.Maps; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonPrimitive; +import com.google.gson.*; import com.google.gson.reflect.TypeToken; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.api.WxCpUserService; import me.chanjar.weixin.cp.bean.WxCpInviteResult; import me.chanjar.weixin.cp.bean.WxCpUser; import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import java.util.List; +import java.util.Map; + +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.User.*; + /** ** Created by BinaryWang on 2017/6/24. @@ -25,59 +25,54 @@ * * @author Binary Wang */ +@RequiredArgsConstructor public class WxCpUserServiceImpl implements WxCpUserService { - private WxCpService mainService; - - public WxCpUserServiceImpl(WxCpService mainService) { - this.mainService = mainService; - } + private final WxCpService mainService; @Override public void authenticate(String userId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=" + userId; - this.mainService.get(url, null); + this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(USER_AUTHENTICATE + userId), null); } @Override public void create(WxCpUser user) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/create"; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_CREATE); this.mainService.post(url, user.toJson()); } @Override public void update(WxCpUser user) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/update"; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_UPDATE); this.mainService.post(url, user.toJson()); } @Override public void delete(String... userIds) throws WxErrorException { if (userIds.length == 1) { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userIds[0]; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_DELETE + userIds[0]); this.mainService.get(url, null); return; } - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete"; JsonObject jsonObject = new JsonObject(); JsonArray jsonArray = new JsonArray(); - for (String userid : userIds) { - jsonArray.add(new JsonPrimitive(userid)); + for (String userId : userIds) { + jsonArray.add(new JsonPrimitive(userId)); } + jsonObject.add("useridlist", jsonArray); - this.mainService.post(url, jsonObject.toString()); + this.mainService.post(USER_BATCH_DELETE, jsonObject.toString()); } @Override public WxCpUser getById(String userid) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid=" + userid; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_GET + userid); String responseContent = this.mainService.get(url, null); return WxCpUser.fromJson(responseContent); } @Override public ListlistByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId; String params = ""; if (fetchChild != null) { params += "&fetch_child=" + (fetchChild ? "1" : "0"); @@ -88,6 +83,7 @@ public List listByDepartment(Long departId, Boolean fetchChild, Intege params += "&status=0"; } + String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_LIST + departId); String responseContent = this.mainService.get(url, params); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() @@ -99,7 +95,6 @@ public List listByDepartment(Long departId, Boolean fetchChild, Intege @Override public List listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; String params = ""; if (fetchChild != null) { params += "&fetch_child=" + (fetchChild ? "1" : "0"); @@ -110,6 +105,7 @@ public List listSimpleByDepartment(Long departId, Boolean fetchChild, params += "&status=0"; } + String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_SIMPLE_LIST + departId); String responseContent = this.mainService.get(url, params); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() @@ -122,7 +118,6 @@ public List listSimpleByDepartment(Long departId, Boolean fetchChild, @Override public WxCpInviteResult invite(List userIds, List partyIds, List tagIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/invite"; JsonObject jsonObject = new JsonObject(); if (userIds != null) { JsonArray jsonArray = new JsonArray(); @@ -148,12 +143,13 @@ public WxCpInviteResult invite(List userIds, List partyIds, List jsonObject.add("tag", jsonArray); } + String url = this.mainService.getWxCpConfigStorage().getApiUrl(BATCH_INVITE); return WxCpInviteResult.fromJson(this.mainService.post(url, jsonObject.toString())); } @Override public Map userId2Openid(String userId, Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_openid"; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_CONVERT_TO_OPENID); JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("userid", userId); if (agentId != null) { @@ -176,9 +172,19 @@ public Map userId2Openid(String userId, Integer agentId) throws @Override public String openid2UserId(String openid) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_userid"; JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("openid", openid); + String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_CONVERT_TO_USERID); + String responseContent = this.mainService.post(url, jsonObject.toString()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return tmpJsonElement.getAsJsonObject().get("userid").getAsString(); + } + + @Override + public String getUserId(String mobile) throws WxErrorException { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("mobile", mobile); + String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_USER_ID); String responseContent = this.mainService.post(url, jsonObject.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return tmpJsonElement.getAsJsonObject().get("userid").getAsString(); @@ -186,7 +192,7 @@ public String openid2UserId(String openid) throws WxErrorException { @Override public WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/crm/get_external_contact?external_userid=" + userId; + String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_EXTERNAL_CONTACT + userId); String responseContent = this.mainService.get(url, null); return WxCpUserExternalContactInfo.fromJson(responseContent); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAppChatMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAppChatMessage.java index 96639f6c51..0af13a84dd 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAppChatMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAppChatMessage.java @@ -6,7 +6,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import me.chanjar.weixin.cp.WxCpConsts.AppChatMsgType; +import me.chanjar.weixin.cp.constant.WxCpConsts.AppChatMsgType; import me.chanjar.weixin.cp.bean.article.MpnewsArticle; import me.chanjar.weixin.cp.bean.article.NewArticle; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java index a22efd0e45..b07e3d5451 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java @@ -8,11 +8,15 @@ import me.chanjar.weixin.cp.bean.article.NewArticle; import me.chanjar.weixin.cp.bean.messagebuilder.*; import me.chanjar.weixin.cp.bean.taskcard.TaskCardButton; +import me.chanjar.weixin.cp.constant.WxCpConsts; import org.apache.commons.lang3.StringUtils; import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.Map; + +import static me.chanjar.weixin.common.api.WxConsts.KefuMsgType.*; /** * 消息. @@ -40,9 +44,13 @@ public class WxCpMessage implements Serializable { private String btnTxt; private List articles = new ArrayList<>(); private List mpnewsArticles = new ArrayList<>(); + private String appId; + private String page; + private Boolean emphasisFirstItem; + private Map contentItems; /** - * 任务卡片特有的属性 + * 任务卡片特有的属性. */ private String taskId; private List taskButtons = new ArrayList<>(); @@ -117,10 +125,16 @@ public static TaskCardBuilder TASKCARD() { return new TaskCardBuilder(); } + /** + * 获得小程序通知消息builder. + */ + public static MiniProgramNoticeMsgBuilder newMiniProgramNoticeBuilder() { + return new MiniProgramNoticeMsgBuilder(); + } /** * - * 请使用 + * 请使用. * {@link KefuMsgType#TEXT} * {@link KefuMsgType#IMAGE} * {@link KefuMsgType#VOICE} @@ -130,6 +144,7 @@ public static TaskCardBuilder TASKCARD() { * {@link KefuMsgType#MPNEWS} * {@link KefuMsgType#MARKDOWN} * {@link KefuMsgType#TASKCARD} + * {@link KefuMsgType#MINIPROGRAM_NOTICE} ** * @param msgType 消息类型 @@ -169,19 +184,19 @@ public String toJson() { private void handleMsgType(JsonObject messageJson) { switch (this.getMsgType()) { - case KefuMsgType.TEXT: { + case TEXT: { JsonObject text = new JsonObject(); text.addProperty("content", this.getContent()); messageJson.add("text", text); break; } - case KefuMsgType.MARKDOWN: { + case MARKDOWN: { JsonObject text = new JsonObject(); text.addProperty("content", this.getContent()); messageJson.add("markdown", text); break; } - case KefuMsgType.TEXTCARD: { + case TEXTCARD: { JsonObject text = new JsonObject(); text.addProperty("title", this.getTitle()); text.addProperty("description", this.getDescription()); @@ -190,25 +205,25 @@ private void handleMsgType(JsonObject messageJson) { messageJson.add("textcard", text); break; } - case KefuMsgType.IMAGE: { + case IMAGE: { JsonObject image = new JsonObject(); image.addProperty("media_id", this.getMediaId()); messageJson.add("image", image); break; } - case KefuMsgType.FILE: { + case FILE: { JsonObject image = new JsonObject(); image.addProperty("media_id", this.getMediaId()); messageJson.add("file", image); break; } - case KefuMsgType.VOICE: { + case VOICE: { JsonObject voice = new JsonObject(); voice.addProperty("media_id", this.getMediaId()); messageJson.add("voice", voice); break; } - case KefuMsgType.VIDEO: { + case VIDEO: { JsonObject video = new JsonObject(); video.addProperty("media_id", this.getMediaId()); video.addProperty("thumb_media_id", this.getThumbMediaId()); @@ -217,7 +232,7 @@ private void handleMsgType(JsonObject messageJson) { messageJson.add("video", video); break; } - case KefuMsgType.NEWS: { + case NEWS: { JsonObject newsJsonObject = new JsonObject(); JsonArray articleJsonArray = new JsonArray(); for (NewArticle article : this.getArticles()) { @@ -232,7 +247,7 @@ private void handleMsgType(JsonObject messageJson) { messageJson.add("news", newsJsonObject); break; } - case KefuMsgType.MPNEWS: { + case MPNEWS: { JsonObject newsJsonObject = new JsonObject(); if (this.getMediaId() != null) { newsJsonObject.addProperty("media_id", this.getMediaId()); @@ -255,7 +270,7 @@ private void handleMsgType(JsonObject messageJson) { messageJson.add("mpnews", newsJsonObject); break; } - case KefuMsgType.TASKCARD: { + case TASKCARD: { JsonObject text = new JsonObject(); text.addProperty("title", this.getTitle()); text.addProperty("description", this.getDescription()); @@ -291,6 +306,25 @@ private void handleMsgType(JsonObject messageJson) { messageJson.add("taskcard", text); break; } + case MINIPROGRAM_NOTICE: { + JsonObject notice = new JsonObject(); + notice.addProperty("appid", this.getAppId()); + notice.addProperty("page", this.getPage()); + notice.addProperty("description", this.getDescription()); + notice.addProperty("title", this.getTitle()); + notice.addProperty("emphasis_first_item", this.getEmphasisFirstItem()); + JsonArray content = new JsonArray(); + for (Map.Entryitem : this.getContentItems().entrySet()) { + JsonObject articleJson = new JsonObject(); + articleJson.addProperty("key", item.getKey()); + articleJson.addProperty("value", item.getValue()); + content.add(articleJson); + } + notice.add("content_item", content); + + messageJson.add("miniprogram_notice", notice); + break; + } default: { // do nothing } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpOauth2UserInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpOauth2UserInfo.java new file mode 100644 index 0000000000..9122f18d3a --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpOauth2UserInfo.java @@ -0,0 +1,28 @@ +package me.chanjar.weixin.cp.bean; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * + * 用oauth2获取用户信息的结果类 + * Created by BinaryWang on 2019/5/26. + *+ * + * @author Binary Wang + */ +@Data +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class WxCpOauth2UserInfo { + private String openId; + private String deviceId; + private String userId; + private String userTicket; + private String expiresIn; +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagGetResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagGetResult.java index 28cc4807a1..244419b062 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagGetResult.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagGetResult.java @@ -29,19 +29,19 @@ public class WxCpTagGetResult implements Serializable { private String errmsg; /** - * 用户列表 + * 用户列表. */ @SerializedName("userlist") private Listuserlist; /** - * 部门列表 + * 部门列表. */ @SerializedName("partylist") private List partylist; /** - * 标签名称 + * 标签名称. */ @SerializedName("tagname") private String tagname; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpCorp.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpCorp.java new file mode 100644 index 0000000000..9ca59b843d --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpCorp.java @@ -0,0 +1,42 @@ +package me.chanjar.weixin.cp.bean; + +import java.io.Serializable; + +import com.google.gson.annotations.SerializedName; + +import lombok.Data; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +/** + * 微信部门. + * + * @author Daniel Qian + */ +@Data +public class WxCpTpCorp implements Serializable { + + private static final long serialVersionUID = -5028321625140879571L; + @SerializedName("corpid") + private String corpId; + @SerializedName("corp_name") + private String corpName; + @SerializedName("corp_full_name") + private String corpFullName; + @SerializedName("corp_type") + private String corpType; + @SerializedName("corp_square_logo_url") + private String corpSquareLogoUrl; + @SerializedName("corp_user_max") + private String corpUserMax; + @SerializedName("permanent_code") + private String permanentCode; + + public static WxCpTpCorp fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpTpCorp.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlMessage.java new file mode 100644 index 0000000000..53e068dbfe --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlMessage.java @@ -0,0 +1,68 @@ +package me.chanjar.weixin.cp.bean; + +import java.io.Serializable; +import java.util.Map; + +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.util.XmlUtils; +import me.chanjar.weixin.common.util.crypto.WxCryptUtil; +import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; +import me.chanjar.weixin.cp.bean.outxmlbuilder.ImageBuilder; +import me.chanjar.weixin.cp.bean.outxmlbuilder.NewsBuilder; +import me.chanjar.weixin.cp.bean.outxmlbuilder.TextBuilder; +import me.chanjar.weixin.cp.bean.outxmlbuilder.VideoBuilder; +import me.chanjar.weixin.cp.bean.outxmlbuilder.VoiceBuilder; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; +import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; +import me.chanjar.weixin.cp.util.xml.XStreamTransformer; + +/** + * 回调推送的message + * https://work.weixin.qq.com/api/doc#90001/90143/90612 + * + * @author zhenjun cai + */ +@XStreamAlias("xml") +@Slf4j +@Data +public class WxCpTpXmlMessage implements Serializable { + + private static final long serialVersionUID = 6031833682211475786L; + /** + * 使用dom4j解析的存放所有xml属性和值的map. + */ + private Map allFieldsMap; + + @XStreamAlias("SuiteId") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String suiteId; + + @XStreamAlias("InfoType") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String infoType; + + @XStreamAlias("TimeStamp") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String timeStamp; + + @XStreamAlias("SuiteTicket") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String suiteTicket; + + @XStreamAlias("AuthCode") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String authCode; + + public static WxCpTpXmlMessage fromXml(String xml) { + //修改微信变态的消息内容格式,方便解析 + //xml = xml.replace(" ", ""); + final WxCpTpXmlMessage xmlPackage = XStreamTransformer.fromXml(WxCpTpXmlMessage.class, xml); + xmlPackage.setAllFieldsMap(XmlUtils.xml2Map(xml)); + return xmlPackage; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlPackage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlPackage.java new file mode 100644 index 0000000000..82c33f5238 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlPackage.java @@ -0,0 +1,55 @@ +package me.chanjar.weixin.cp.bean; + +import java.io.Serializable; +import java.util.Map; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import lombok.Data; +import me.chanjar.weixin.common.util.XmlUtils; +import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; +import me.chanjar.weixin.cp.bean.outxmlbuilder.ImageBuilder; +import me.chanjar.weixin.cp.bean.outxmlbuilder.NewsBuilder; +import me.chanjar.weixin.cp.bean.outxmlbuilder.TextBuilder; +import me.chanjar.weixin.cp.bean.outxmlbuilder.VideoBuilder; +import me.chanjar.weixin.cp.bean.outxmlbuilder.VoiceBuilder; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; +import me.chanjar.weixin.cp.util.xml.XStreamTransformer; + +/** + * 回调消息包. + * https://work.weixin.qq.com/api/doc#90001/90143/91116 + * + * @author zhenjun cai + */ +@XStreamAlias("xml") +@Data +public class WxCpTpXmlPackage implements Serializable { + + private static final long serialVersionUID = 6031833682211475786L; + /** + * 使用dom4j解析的存放所有xml属性和值的map. + */ + private Map allFieldsMap; + + @XStreamAlias("ToUserName") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String toUserName; + + @XStreamAlias("AgentID") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String agentId; + + @XStreamAlias("Encrypt") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String msgEncrypt; + + public static WxCpTpXmlPackage fromXml(String xml) { + //修改微信变态的消息内容格式,方便解析 + //xml = xml.replace(" ", ""); + final WxCpTpXmlPackage xmlPackage = XStreamTransformer.fromXml(WxCpTpXmlPackage.class, xml); + xmlPackage.setAllFieldsMap(XmlUtils.xml2Map(xml)); + return xmlPackage; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java index dcf4789eba..8f4e4989cc 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java @@ -31,6 +31,11 @@ public class WxCpUser implements Serializable { private Integer status; private Integer enable; private Integer isLeader; + /** + * is_leader_in_dept. + * 个数必须和department一致,表示在所在的部门内是否为上级。1表示为上级,0表示非上级。在审批等应用里可以用来标识上级审批人 + */ + private Integer[] isLeaderInDept; private final List extAttrs = new ArrayList<>(); private Integer hideMobile; private String englishName; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactInfo.java index 466eac4a6e..d099e4eeb6 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactInfo.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactInfo.java @@ -1,16 +1,11 @@ package me.chanjar.weixin.cp.bean; -import java.util.List; - import com.google.gson.annotations.SerializedName; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import lombok.*; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import java.util.List; + /** * * 外部联系人详情 @@ -118,9 +113,26 @@ public static class FollowedUser { private String description; @SerializedName("createtime") private Long createTime; + private String state; + @SerializedName("remark_company") + private String remarkCompany; + @SerializedName("remark_mobiles") + private String[] remarkMobiles; + private Tag[] tags; + } public static WxCpUserExternalContactInfo fromJson(String json) { return WxCpGsonBuilder.create().fromJson(json, WxCpUserExternalContactInfo.class); } + + @Setter + @Getter + public static class Tag { + @SerializedName("group_name") + private String groupName; + @SerializedName("tag_name") + private String tagName; + private int type; + } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactList.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactList.java new file mode 100644 index 0000000000..25e42ffc4a --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactList.java @@ -0,0 +1,58 @@ +package me.chanjar.weixin.cp.bean; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.List; + +/** + *+ * 外部联系人列表 + * Created by Joe Cao on 2019/6/16. + * 参考文档:https://work.weixin.qq.com/api/doc#90001/90143/91570 + *+ * + * @author Joe Cao + */ +public class WxCpUserExternalContactList { + @SerializedName("errcode") + @Expose + private Long errcode; + @SerializedName("errmsg") + @Expose + private String errmsg; + + @SerializedName("external_userid") + @Expose + private ListexternalUserId = null; + + public Long getErrcode() { + return errcode; + } + + public void setErrcode(Long errcode) { + this.errcode = errcode; + } + + public String getErrmsg() { + return errmsg; + } + + public void setErrmsg(String errmsg) { + this.errmsg = errmsg; + } + + + public List getExternalUserId() { + return externalUserId; + } + + public void setExternalUserId(List externalUserId) { + this.externalUserId = externalUserId; + } + + public static WxCpUserExternalContactList fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpUserExternalContactList.class); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserWithExternalPermission.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserWithExternalPermission.java new file mode 100644 index 0000000000..2530c79dc8 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserWithExternalPermission.java @@ -0,0 +1,49 @@ +package me.chanjar.weixin.cp.bean; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.List; + +public class WxCpUserWithExternalPermission { + @SerializedName("errcode") + @Expose + private Long errcode; + @SerializedName("errmsg") + @Expose + private String errmsg; + + @SerializedName("follow_user") + @Expose + private List followUser = null; + + public Long getErrcode() { + return errcode; + } + + public void setErrcode(Long errcode) { + this.errcode = errcode; + } + + public String getErrmsg() { + return errmsg; + } + + public void setErrmsg(String errmsg) { + this.errmsg = errmsg; + } + + public List getFollowUser() { + return followUser; + } + + public void setFollowUser(List followUser) { + this.followUser = followUser; + } + + + public static WxCpUserWithExternalPermission fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpUserWithExternalPermission.class); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java index e6b2be197a..771e57294d 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java @@ -162,7 +162,7 @@ public class WxCpXmlMessage implements Serializable { /** * 通讯录变更事件. - * 请参考常量 me.chanjar.weixin.cp.WxCpConsts.ContactChangeType + * 请参考常量 me.chanjar.weixin.cp.constant.WxCpConsts.ContactChangeType */ @XStreamAlias("ChangeType") @XStreamConverter(value = XStreamCDataConverter.class) @@ -175,6 +175,26 @@ public class WxCpXmlMessage implements Serializable { @XStreamConverter(value = XStreamCDataConverter.class) private String userId; + /** + * 变更信息的外部联系人的userid,注意不是企业成员的帐号. + */ + @XStreamAlias("ExternalUserID") + @XStreamConverter(value = XStreamCDataConverter.class) + private String externalUserId; + + /** + * 添加此用户的「联系我」方式配置的state参数,可用于识别添加此用户的渠道. + */ + @XStreamAlias("State") + @XStreamConverter(value = XStreamCDataConverter.class) + private String state; + + /** + * 欢迎语code,可用于发送欢迎语. + */ + @XStreamAlias("WelcomeCode") + @XStreamConverter(value = XStreamCDataConverter.class) + private String welcomeCode; /** * 新的UserID,变更时推送(userid由系统生成时可更改一次). */ @@ -191,11 +211,11 @@ public class WxCpXmlMessage implements Serializable { private String name; /** - * 成员部门列表. + * 成员部门列表,变更时推送,仅返回该应用有查看权限的部门id. */ @XStreamAlias("Department") @XStreamConverter(value = XStreamCDataConverter.class) - private String department; + private Long[] departments; /** * 手机号码. @@ -244,6 +264,12 @@ public class WxCpXmlMessage implements Serializable { @XStreamAlias("IsLeader") private Integer isLeader; + /** + * 表示所在部门是否为上级,0-否,1-是,顺序与Department字段的部门逐一对应. + */ + @XStreamAlias("IsLeaderInDept") + private Integer[] isLeaderInDept; + /** * 座机. */ @@ -268,7 +294,7 @@ public class WxCpXmlMessage implements Serializable { * 部门Id. */ @XStreamAlias("Id") - private Integer id; + private Long id; /** * 父部门id. diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/MiniProgramNoticeMsgBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/MiniProgramNoticeMsgBuilder.java new file mode 100644 index 0000000000..cf44c0f0f7 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/MiniProgramNoticeMsgBuilder.java @@ -0,0 +1,69 @@ +package me.chanjar.weixin.cp.bean.messagebuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.cp.bean.WxCpMessage; + +import java.util.Map; + +/** + * + * miniprogram_notice 类型的消息 builder + * Created by Binary Wang on 2019/6/16. + *+ * + * @author Binary Wang + */ +public class MiniProgramNoticeMsgBuilder extends BaseBuilder{ + private String title; + private String description; + private String appId; + private String page; + private Boolean emphasisFirstItem; + private Map contentItems; + + public MiniProgramNoticeMsgBuilder() { + this.msgType = WxConsts.KefuMsgType.MINIPROGRAM_NOTICE; + } + + public MiniProgramNoticeMsgBuilder appId(String appId) { + this.appId = appId; + return this; + } + + public MiniProgramNoticeMsgBuilder page(String page) { + this.page = page; + return this; + } + + public MiniProgramNoticeMsgBuilder title(String title) { + this.title = title; + return this; + } + + public MiniProgramNoticeMsgBuilder description(String description) { + this.description = description; + return this; + } + + public MiniProgramNoticeMsgBuilder contentItems(Map contentItems) { + this.contentItems = contentItems; + return this; + } + + public MiniProgramNoticeMsgBuilder emphasisFirstItem(Boolean emphasisFirstItem) { + this.emphasisFirstItem = emphasisFirstItem; + return this; + } + + @Override + public WxCpMessage build() { + WxCpMessage m = super.build(); + m.setContentItems(this.contentItems); + m.setAppId(this.appId); + m.setDescription(this.description); + m.setTitle(this.title); + m.setEmphasisFirstItem(this.emphasisFirstItem); + m.setPage(this.page); + return m; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java index e13738142f..c4dbf8f1a1 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java @@ -6,18 +6,32 @@ import java.io.File; /** - * 微信客户端配置存储 + * 微信客户端配置存储. * * @author Daniel Qian */ public interface WxCpConfigStorage { + /** + * 设置企业微信服务器 baseUrl. + * 默认值是 https://qyapi.weixin.qq.com , 如果使用默认值,则不需要调用 setBaseApiUrl + * + * @param baseUrl 企业微信服务器 Url + */ + void setBaseApiUrl(String baseUrl); + + /** + * 读取企业微信 API Url. + * 支持私有化企业微信服务器. + */ + String getApiUrl(String path); + String getAccessToken(); boolean isAccessTokenExpired(); /** - * 强制将access token过期掉 + * 强制将access token过期掉. */ void expireAccessToken(); @@ -30,12 +44,12 @@ public interface WxCpConfigStorage { boolean isJsapiTicketExpired(); /** - * 强制将jsapi ticket过期掉 + * 强制将jsapi ticket过期掉. */ void expireJsapiTicket(); /** - * 应该是线程安全的 + * 应该是线程安全的. */ void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); @@ -44,12 +58,12 @@ public interface WxCpConfigStorage { boolean isAgentJsapiTicketExpired(); /** - * 强制将jsapi ticket过期掉 + * 强制将jsapi ticket过期掉. */ void expireAgentJsapiTicket(); /** - * 应该是线程安全的 + * 应该是线程安全的. */ void updateAgentJsapiTicket(String jsapiTicket, int expiresInSeconds); @@ -78,7 +92,7 @@ public interface WxCpConfigStorage { File getTmpDirFile(); /** - * http client builder + * http client builder. * * @return ApacheHttpClientBuilder */ diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java new file mode 100644 index 0000000000..fadfb0bda6 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java @@ -0,0 +1,86 @@ +package me.chanjar.weixin.cp.config; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; + +import java.io.File; + +/** + * 微信客户端(第三方应用)配置存储 + * + * @author zhenjun cai + */ +public interface WxCpTpConfigStorage { + + /** + * 设置企业微信服务器 baseUrl. + * 默认值是 https://qyapi.weixin.qq.com , 如果使用默认值,则不需要调用 setBaseApiUrl + * + * @param baseUrl 企业微信服务器 Url + */ + void setBaseApiUrl(String baseUrl); + + /** + * 读取企业微信 API Url. + * 支持私有化企业微信服务器. + */ + String getApiUrl(String path); + + String getSuiteAccessToken(); + + boolean isSuiteAccessTokenExpired(); + + /** + * 强制将suite access token过期掉. + */ + void expireSuiteAccessToken(); + + void updateSuiteAccessToken(WxAccessToken suiteAccessToken); + + void updateSuiteAccessToken(String suiteAccessToken, int expiresIn); + + String getSuiteTicket(); + + boolean isSuiteTicketExpired(); + + /** + * 强制将suite ticket过期掉. + */ + void expireSuiteTicket(); + + /** + * 应该是线程安全的. + */ + void updateSuiteTicket(String suiteTicket, int expiresInSeconds); + + String getCorpId(); + + String getCorpSecret(); + + String getSuiteId(); + + String getSuiteSecret(); + + String getToken(); + + String getAesKey(); + + long getExpiresTime(); + + String getHttpProxyHost(); + + int getHttpProxyPort(); + + String getHttpProxyUsername(); + + String getHttpProxyPassword(); + + File getTmpDirFile(); + + /** + * http client builder. + * + * @return ApacheHttpClientBuilder + */ + ApacheHttpClientBuilder getApacheHttpClientBuilder(); +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java similarity index 79% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java index a501edeb6e..87ed4f611c 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java @@ -1,44 +1,63 @@ -package me.chanjar.weixin.cp.config; +package me.chanjar.weixin.cp.config.impl; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; import java.io.File; +import java.io.Serializable; /** - * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 + * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化. * * @author Daniel Qian */ -public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { +public class WxCpDefaultConfigImpl implements WxCpConfigStorage, Serializable { + private static final long serialVersionUID = 1154541446729462780L; - protected volatile String corpId; - protected volatile String corpSecret; + private volatile String corpId; + private volatile String corpSecret; - protected volatile String token; + private volatile String token; protected volatile String accessToken; - protected volatile String aesKey; + private volatile String aesKey; protected volatile Integer agentId; - protected volatile long expiresTime; + private volatile long expiresTime; - protected volatile String oauth2redirectUri; + private volatile String oauth2redirectUri; - protected volatile String httpProxyHost; - protected volatile int httpProxyPort; - protected volatile String httpProxyUsername; - protected volatile String httpProxyPassword; + private volatile String httpProxyHost; + private volatile int httpProxyPort; + private volatile String httpProxyUsername; + private volatile String httpProxyPassword; - protected volatile String jsapiTicket; - protected volatile long jsapiTicketExpiresTime; + private volatile String jsapiTicket; + private volatile long jsapiTicketExpiresTime; - protected volatile String agentJsapiTicket; - protected volatile long agentJsapiTicketExpiresTime; + private volatile String agentJsapiTicket; + private volatile long agentJsapiTicketExpiresTime; - protected volatile File tmpDirFile; + private volatile File tmpDirFile; private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + private volatile String baseApiUrl; + + @Override + public void setBaseApiUrl(String baseUrl) { + this.baseApiUrl = baseUrl; + } + + @Override + public String getApiUrl(String path) { + if (baseApiUrl == null) { + baseApiUrl = WxCpApiPathConsts.DEFAULT_CP_BASE_URL; + } + return baseApiUrl + path; + } + @Override public String getAccessToken() { return this.accessToken; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java similarity index 89% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java index 7c72de0e1b..ecaa47cc23 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java @@ -1,7 +1,9 @@ -package me.chanjar.weixin.cp.config; +package me.chanjar.weixin.cp.config.impl; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; @@ -16,7 +18,7 @@ * * @author gaigeshen */ -public class WxCpJedisConfigStorage implements WxCpConfigStorage { +public class WxCpRedisConfigImpl implements WxCpConfigStorage { 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"; @@ -38,23 +40,38 @@ public class WxCpJedisConfigStorage implements WxCpConfigStorage { private volatile File tmpDirFile; private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; - public WxCpJedisConfigStorage(JedisPool jedisPool) { + protected volatile String baseApiUrl; + + @Override + public void setBaseApiUrl(String baseUrl) { + this.baseApiUrl = baseUrl; + } + + @Override + public String getApiUrl(String path) { + if (baseApiUrl == null) { + baseApiUrl = WxCpApiPathConsts.DEFAULT_CP_BASE_URL; + } + return baseApiUrl + path; + } + + public WxCpRedisConfigImpl(JedisPool jedisPool) { this.jedisPool = jedisPool; } - public WxCpJedisConfigStorage(String host, int port) { + public WxCpRedisConfigImpl(String host, int port) { jedisPool = new JedisPool(host, port); } - public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port) { + public WxCpRedisConfigImpl(JedisPoolConfig poolConfig, String host, int port) { jedisPool = new JedisPool(poolConfig, host, port); } - public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port, int timeout, String password) { + public WxCpRedisConfigImpl(JedisPoolConfig poolConfig, String host, int port, int timeout, String password) { jedisPool = new JedisPool(poolConfig, host, port, timeout, password); } - public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port, int timeout, String password, int database) { + public WxCpRedisConfigImpl(JedisPoolConfig poolConfig, String host, int port, int timeout, String password, int database) { jedisPool = new JedisPool(poolConfig, host, port, timeout, password, database); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java new file mode 100644 index 0000000000..d8be83c2af --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java @@ -0,0 +1,248 @@ +package me.chanjar.weixin.cp.config.impl; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.File; +import java.io.Serializable; + +/** + * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化. + * + * @author someone + */ +public class WxCpTpDefaultConfigImpl implements WxCpTpConfigStorage, Serializable { + private static final long serialVersionUID = 6678780920621872824L; + + private volatile String corpId; + private volatile String corpSecret; + + private volatile String suiteId; + private volatile String suiteSecret; + + private volatile String token; + private volatile String suiteAccessToken; + private volatile String aesKey; + private volatile long expiresTime; + + private volatile String oauth2redirectUri; + + private volatile String httpProxyHost; + private volatile int httpProxyPort; + private volatile String httpProxyUsername; + private volatile String httpProxyPassword; + + private volatile String suiteTicket; + private volatile long suiteTicketExpiresTime; + + private volatile File tmpDirFile; + + private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + + private volatile String baseApiUrl; + + @Override + public void setBaseApiUrl(String baseUrl) { + this.baseApiUrl = baseUrl; + } + + @Override + public String getApiUrl(String path) { + if (baseApiUrl == null) { + baseApiUrl = "https://qyapi.weixin.qq.com"; + } + return baseApiUrl + path; + } + + @Override + public String getSuiteAccessToken() { + return this.suiteAccessToken; + } + + public void setSuiteAccessToken(String suiteAccessToken) { + this.suiteAccessToken = suiteAccessToken; + } + + @Override + public boolean isSuiteAccessTokenExpired() { + return System.currentTimeMillis() > this.expiresTime; + } + + @Override + public void expireSuiteAccessToken() { + this.expiresTime = 0; + } + + @Override + public synchronized void updateSuiteAccessToken(WxAccessToken suiteAccessToken) { + updateSuiteAccessToken(suiteAccessToken.getAccessToken(), suiteAccessToken.getExpiresIn()); + } + + @Override + public synchronized void updateSuiteAccessToken(String suiteAccessToken, int expiresInSeconds) { + this.suiteAccessToken = suiteAccessToken; + this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + } + + @Override + public String getCorpId() { + return this.corpId; + } + + public void setCorpId(String corpId) { + this.corpId = corpId; + } + + @Override + public String getCorpSecret() { + return this.corpSecret; + } + + public void setCorpSecret(String corpSecret) { + this.corpSecret = corpSecret; + } + + @Override + public String getSuiteTicket() { + return this.suiteTicket; + } + + public void setSuiteTicket(String suiteTicket) { + this.suiteTicket = suiteTicket; + } + + public long getSuiteTicketExpiresTime() { + return this.suiteTicketExpiresTime; + } + + public void setSuiteTicketExpiresTime(long suiteTicketExpiresTime) { + this.suiteTicketExpiresTime = suiteTicketExpiresTime; + } + + @Override + public boolean isSuiteTicketExpired() { + return System.currentTimeMillis() > this.suiteTicketExpiresTime; + } + + @Override + public synchronized void updateSuiteTicket(String suiteTicket, int expiresInSeconds) { + this.suiteTicket = suiteTicket; + // 预留200秒的时间 + this.suiteTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + } + + @Override + public void expireSuiteTicket() { + this.suiteTicketExpiresTime = 0; + } + + @Override + public String getSuiteId() { + return this.suiteId; + } + + public void setSuiteId(String corpId) { + this.suiteId = corpId; + } + + @Override + public String getSuiteSecret() { + return this.suiteSecret; + } + + public void setSuiteSecret(String corpSecret) { + this.suiteSecret = corpSecret; + } + + @Override + public String getToken() { + return this.token; + } + + public void setToken(String token) { + this.token = token; + } + + @Override + public long getExpiresTime() { + return this.expiresTime; + } + + public void setExpiresTime(long expiresTime) { + this.expiresTime = expiresTime; + } + + @Override + public String getAesKey() { + return this.aesKey; + } + + public void setAesKey(String aesKey) { + this.aesKey = aesKey; + } + + public void setOauth2redirectUri(String oauth2redirectUri) { + this.oauth2redirectUri = oauth2redirectUri; + } + + @Override + public String getHttpProxyHost() { + return this.httpProxyHost; + } + + public void setHttpProxyHost(String httpProxyHost) { + this.httpProxyHost = httpProxyHost; + } + + @Override + public int getHttpProxyPort() { + return this.httpProxyPort; + } + + public void setHttpProxyPort(int httpProxyPort) { + this.httpProxyPort = httpProxyPort; + } + + @Override + public String getHttpProxyUsername() { + return this.httpProxyUsername; + } + + public void setHttpProxyUsername(String httpProxyUsername) { + this.httpProxyUsername = httpProxyUsername; + } + + @Override + public String getHttpProxyPassword() { + return this.httpProxyPassword; + } + + public void setHttpProxyPassword(String httpProxyPassword) { + this.httpProxyPassword = httpProxyPassword; + } + + @Override + public String toString() { + return WxCpGsonBuilder.create().toJson(this); + } + + @Override + public File getTmpDirFile() { + return this.tmpDirFile; + } + + public void setTmpDirFile(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + + @Override + public ApacheHttpClientBuilder getApacheHttpClientBuilder() { + return this.apacheHttpClientBuilder; + } + + public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { + this.apacheHttpClientBuilder = apacheHttpClientBuilder; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java new file mode 100644 index 0000000000..6de1a63ac5 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java @@ -0,0 +1,113 @@ +package me.chanjar.weixin.cp.constant; + + +/** + * + * 企业微信api地址常量类 + * Created by BinaryWang on 2019-06-02. + *+ * + * @author Binary Wang + */ +public final class WxCpApiPathConsts { + public static final String DEFAULT_CP_BASE_URL = "https://qyapi.weixin.qq.com"; + + public static final String GET_JSAPI_TICKET = "/cgi-bin/get_jsapi_ticket"; + public static final String GET_AGENT_CONFIG_TICKET = "/cgi-bin/ticket/get?&type=agent_config"; + public static final String MESSAGE_SEND = "/cgi-bin/message/send"; + public static final String GET_CALLBACK_IP = "/cgi-bin/getcallbackip"; + public static final String BATCH_REPLACE_PARTY = "/cgi-bin/batch/replaceparty"; + public static final String BATCH_REPLACE_USER = "/cgi-bin/batch/replaceuser"; + public static final String BATCH_GET_RESULT = "/cgi-bin/batch/getresult?jobid="; + public static final String JSCODE_TO_SESSION = "/cgi-bin/miniprogram/jscode2session"; + public static final String GET_TOKEN = "/cgi-bin/gettoken?&corpid=%s&corpsecret=%s"; + + public static class Agent { + public static final String AGENT_GET = "/cgi-bin/agent/get?agentid=%d"; + public static final String AGENT_SET = "/cgi-bin/agent/set"; + public static final String AGENT_LIST = "/cgi-bin/agent/list"; + } + + public static class OAuth2 { + public static final String GET_USER_INFO = "/cgi-bin/user/getuserinfo?code=%s&agentid=%d"; + public static final String GET_USER_DETAIL = "/cgi-bin/user/getuserdetail"; + public static final String URL_OAUTH2_AUTHORIZE = "https://open.weixin.qq.com/connect/oauth2/authorize"; + } + + public static class Chat { + public static final String APPCHAT_CREATE = "/cgi-bin/appchat/create"; + public static final String APPCHAT_UPDATE = "/cgi-bin/appchat/update"; + public static final String APPCHAT_GET_CHATID = "/cgi-bin/appchat/get?chatid="; + public static final String APPCHAT_SEND = "/cgi-bin/appchat/send"; + } + + public static class Department { + public static final String DEPARTMENT_CREATE = "/cgi-bin/department/create"; + public static final String DEPARTMENT_UPDATE = "/cgi-bin/department/update"; + public static final String DEPARTMENT_DELETE = "/cgi-bin/department/delete?id=%d"; + public static final String DEPARTMENT_LIST = "/cgi-bin/department/list"; + } + + public static class Media { + public static final String MEDIA_GET = "/cgi-bin/media/get"; + public static final String MEDIA_UPLOAD = "/cgi-bin/media/upload?type="; + public static final String IMG_UPLOAD = "/cgi-bin/media/uploadimg"; + public static final String JSSDK_MEDIA_GET = "/cgi-bin/media/get/jssdk"; + } + + public static class Menu { + public static final String MENU_CREATE = "/cgi-bin/menu/create?agentid=%d"; + public static final String MENU_DELETE = "/cgi-bin/menu/delete?agentid=%d"; + public static final String MENU_GET = "/cgi-bin/menu/get?agentid=%d"; + } + + public static class Oa { + public static final String GET_CHECKIN_DATA = "/cgi-bin/checkin/getcheckindata"; + public static final String GET_CHECKIN_OPTION = "/cgi-bin/checkin/getcheckinoption"; + public static final String GET_APPROVAL_DATA = "/cgi-bin/corp/getapprovaldata"; + public static final String GET_DIAL_RECORD = "/cgi-bin/dial/get_dial_record"; + } + + public static class Tag { + public static final String TAG_CREATE = "/cgi-bin/tag/create"; + public static final String TAG_UPDATE = "/cgi-bin/tag/update"; + public static final String TAG_DELETE = "/cgi-bin/tag/delete?tagid=%s"; + public static final String TAG_LIST = "/cgi-bin/tag/list"; + public static final String TAG_GET = "/cgi-bin/tag/get?tagid=%s"; + public static final String TAG_ADD_TAG_USERS = "/cgi-bin/tag/addtagusers"; + public static final String TAG_DEL_TAG_USERS = "/cgi-bin/tag/deltagusers"; + } + + public static class TaskCard { + public static final String UPDATE_TASK_CARD = "/cgi-bin/message/update_taskcard"; + } + + public static class Tp { + public static final String JSCODE_TO_SESSION = "/cgi-bin/service/miniprogram/jscode2session"; + public static final String GET_CORP_TOKEN = "/cgi-bin/service/get_corp_token"; + public static final String GET_PERMANENT_CODE = "/cgi-bin/service/get_permanent_code"; + public static final String GET_SUITE_TOKEN = "/cgi-bin/service/get_suite_token"; + } + + public static class User { + public static final String USER_AUTHENTICATE = "/cgi-bin/user/authsucc?userid="; + public static final String USER_CREATE = "/cgi-bin/user/create"; + public static final String USER_UPDATE = "/cgi-bin/user/update"; + public static final String USER_DELETE = "/cgi-bin/user/delete?userid="; + public static final String USER_BATCH_DELETE = "/cgi-bin/user/batchdelete"; + public static final String USER_GET = "/cgi-bin/user/get?userid="; + public static final String USER_LIST = "/cgi-bin/user/list?department_id="; + public static final String USER_SIMPLE_LIST = "/cgi-bin/user/simplelist?department_id="; + public static final String BATCH_INVITE = "/cgi-bin/batch/invite"; + public static final String USER_CONVERT_TO_OPENID = "/cgi-bin/user/convert_to_openid"; + public static final String USER_CONVERT_TO_USERID = "/cgi-bin/user/convert_to_userid"; + public static final String GET_USER_ID = "/cgi-bin/user/getuserid"; + public static final String GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid="; + } + + public static class ExternalContact { + public static final String GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid="; + public static final String LIST_EXTERNAL_CONTACT = "/cgi-bin/externalcontact/list?userid="; + public static final String GET_FOLLOW_USER_LIST = "/cgi-bin/externalcontact/get_follow_user_list"; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/WxCpConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java similarity index 87% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/WxCpConsts.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java index 87892eccdd..aa4eded451 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/WxCpConsts.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.cp; +package me.chanjar.weixin.cp.constant; /** *@@ -89,6 +89,26 @@ public static class EventType { */ public static final String TASKCARD_CLICK = "taskcard_click"; + /** + * 企业成员添加外部联系人事件推送 + */ + public static final String CHANGE_EXTERNAL_CONTACT = "change_external_contact"; + + + } + + /** + * 企业外部联系人变更事件的CHANGE_TYPE + */ + public static class ExternalContactChangeType { + /** + * 新增外部联系人 + */ + public static final String ADD_EXTERNAL_CONTACT = "add_external_contact"; + /** + * 删除外部联系人 + */ + public static final String DEL_EXTERNAL_CONTACT = "del_external_contact"; } /** diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java new file mode 100644 index 0000000000..453d1700a9 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java @@ -0,0 +1,52 @@ +/** + * 对公众平台发送给公众账号的消息加解密示例代码. + * + * @copyright Copyright (c) 1998-2014 Tencent Inc. + *+ * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + *
+ * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + */ + +// ------------------------------------------------------------------------ + +/** + * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + */ +package me.chanjar.weixin.cp.util.crypto; + +import org.apache.commons.codec.binary.Base64; + +import me.chanjar.weixin.common.util.crypto.WxCryptUtil; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; + +public class WxCpTpCryptUtil extends WxCryptUtil { + + /** + * 构造函数 + * + * @param wxCpConfigStorage + */ + public WxCpTpCryptUtil(WxCpTpConfigStorage wxCpTpConfigStorage) { + /* + * @param token 公众平台上,开发者设置的token + * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey + * @param appidOrCorpid 公众平台corpId + */ + String encodingAesKey = wxCpTpConfigStorage.getAesKey(); + String token = wxCpTpConfigStorage.getToken(); + String corpId = wxCpTpConfigStorage.getCorpId(); + + this.token = token; + this.appidOrCorpid = corpId; + this.aesKey = Base64.decodeBase64(encodingAesKey + "="); + } + + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java index 84ee7c0f2f..ed125c5708 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java @@ -70,6 +70,7 @@ public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationC user.setStatus(GsonHelper.getInteger(o, "status")); user.setEnable(GsonHelper.getInteger(o, "enable")); user.setIsLeader(GsonHelper.getInteger(o, "isleader")); + user.setIsLeaderInDept(GsonHelper.getIntArray(o, "is_leader_in_dept")); user.setHideMobile(GsonHelper.getInteger(o, "hide_mobile")); user.setEnglishName(GsonHelper.getString(o, "english_name")); user.setTelephone(GsonHelper.getString(o, "telephone")); @@ -197,6 +198,13 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon if (user.getIsLeader() != null) { o.addProperty("isleader", user.getIsLeader()); } + if (user.getIsLeaderInDept() != null && user.getIsLeaderInDept().length > 0) { + JsonArray ary = new JsonArray(); + for (int item : user.getIsLeaderInDept()) { + ary.add(item); + } + o.add("is_leader_in_dept", ary); + } if (user.getHideMobile() != null) { o.addProperty("hide_mobile", user.getHideMobile()); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java index 5ef1503df1..3c6174c9d8 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java @@ -1,117 +1,135 @@ -package me.chanjar.weixin.cp.util.xml; - -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -import com.thoughtworks.xstream.XStream; -import me.chanjar.weixin.common.util.xml.XStreamInitializer; -import me.chanjar.weixin.cp.bean.WxCpXmlMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutImageMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutNewsMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutVideoMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutVoiceMessage; - -public class XStreamTransformer { - - protected static final Map
CLASS_2_XSTREAM_INSTANCE = configXStreamInstance(); - - /** - * xml -> pojo - */ - @SuppressWarnings("unchecked") - public static T fromXml(Class clazz, String xml) { - T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(xml); - return object; - } - - @SuppressWarnings("unchecked") - public static T fromXml(Class clazz, InputStream is) { - T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(is); - return object; - } - - /** - * 注册扩展消息的解析器. - * - * @param clz 类型 - * @param xStream xml解析器 - */ - public static void register(Class clz, XStream xStream) { - CLASS_2_XSTREAM_INSTANCE.put(clz, xStream); - } - - /** - * pojo -> xml. - */ - public static String toXml(Class clazz, T object) { - return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); - } - - private static Map configXStreamInstance() { - Map map = new HashMap<>(); - map.put(WxCpXmlMessage.class, configWxCpXmlMessage()); - map.put(WxCpXmlOutNewsMessage.class, configWxCpXmlOutNewsMessage()); - map.put(WxCpXmlOutTextMessage.class, configWxCpXmlOutTextMessage()); - map.put(WxCpXmlOutImageMessage.class, configWxCpXmlOutImageMessage()); - map.put(WxCpXmlOutVideoMessage.class, configWxCpXmlOutVideoMessage()); - map.put(WxCpXmlOutVoiceMessage.class, configWxCpXmlOutVoiceMessage()); - return map; - } - - private static XStream configWxCpXmlMessage() { - XStream xstream = XStreamInitializer.getInstance(); - - xstream.processAnnotations(WxCpXmlMessage.class); - xstream.processAnnotations(WxCpXmlMessage.ScanCodeInfo.class); - xstream.processAnnotations(WxCpXmlMessage.SendPicsInfo.class); - xstream.processAnnotations(WxCpXmlMessage.SendPicsInfo.Item.class); - xstream.processAnnotations(WxCpXmlMessage.SendLocationInfo.class); - return xstream; - } - - private static XStream configWxCpXmlOutImageMessage() { - XStream xstream = XStreamInitializer.getInstance(); - - xstream.processAnnotations(WxCpXmlOutMessage.class); - xstream.processAnnotations(WxCpXmlOutImageMessage.class); - return xstream; - } - - private static XStream configWxCpXmlOutNewsMessage() { - XStream xstream = XStreamInitializer.getInstance(); - - xstream.processAnnotations(WxCpXmlOutMessage.class); - xstream.processAnnotations(WxCpXmlOutNewsMessage.class); - xstream.processAnnotations(WxCpXmlOutNewsMessage.Item.class); - return xstream; - } - - private static XStream configWxCpXmlOutTextMessage() { - XStream xstream = XStreamInitializer.getInstance(); - - xstream.processAnnotations(WxCpXmlOutMessage.class); - xstream.processAnnotations(WxCpXmlOutTextMessage.class); - return xstream; - } - - private static XStream configWxCpXmlOutVideoMessage() { - XStream xstream = XStreamInitializer.getInstance(); - - xstream.processAnnotations(WxCpXmlOutMessage.class); - xstream.processAnnotations(WxCpXmlOutVideoMessage.class); - xstream.processAnnotations(WxCpXmlOutVideoMessage.Video.class); - return xstream; - } - - private static XStream configWxCpXmlOutVoiceMessage() { - XStream xstream = XStreamInitializer.getInstance(); - - xstream.processAnnotations(WxCpXmlOutMessage.class); - xstream.processAnnotations(WxCpXmlOutVoiceMessage.class); - return xstream; - } - -} +package me.chanjar.weixin.cp.util.xml; + +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import com.thoughtworks.xstream.XStream; +import me.chanjar.weixin.common.util.xml.XStreamInitializer; +import me.chanjar.weixin.cp.bean.WxCpTpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpTpXmlPackage; +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutImageMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutNewsMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutVideoMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutVoiceMessage; + +public class XStreamTransformer { + + protected static final Map CLASS_2_XSTREAM_INSTANCE = configXStreamInstance(); + + /** + * xml -> pojo + */ + @SuppressWarnings("unchecked") + public static T fromXml(Class clazz, String xml) { + T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(xml); + return object; + } + + @SuppressWarnings("unchecked") + public static T fromXml(Class clazz, InputStream is) { + T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(is); + return object; + } + + /** + * 注册扩展消息的解析器. + * + * @param clz 类型 + * @param xStream xml解析器 + */ + public static void register(Class clz, XStream xStream) { + CLASS_2_XSTREAM_INSTANCE.put(clz, xStream); + } + + /** + * pojo -> xml. + */ + public static String toXml(Class clazz, T object) { + return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); + } + + private static Map configXStreamInstance() { + Map map = new HashMap<>(); + map.put(WxCpXmlMessage.class, configWxCpXmlMessage()); + map.put(WxCpXmlOutNewsMessage.class, configWxCpXmlOutNewsMessage()); + map.put(WxCpXmlOutTextMessage.class, configWxCpXmlOutTextMessage()); + map.put(WxCpXmlOutImageMessage.class, configWxCpXmlOutImageMessage()); + map.put(WxCpXmlOutVideoMessage.class, configWxCpXmlOutVideoMessage()); + map.put(WxCpXmlOutVoiceMessage.class, configWxCpXmlOutVoiceMessage()); + map.put(WxCpTpXmlPackage.class, configWxCpTpXmlPackage()); + map.put(WxCpTpXmlMessage.class, configWxCpTpXmlMessage()); + return map; + } + + private static XStream configWxCpXmlMessage() { + XStream xstream = XStreamInitializer.getInstance(); + + xstream.processAnnotations(WxCpXmlMessage.class); + xstream.processAnnotations(WxCpXmlMessage.ScanCodeInfo.class); + xstream.processAnnotations(WxCpXmlMessage.SendPicsInfo.class); + xstream.processAnnotations(WxCpXmlMessage.SendPicsInfo.Item.class); + xstream.processAnnotations(WxCpXmlMessage.SendLocationInfo.class); + return xstream; + } + + private static XStream configWxCpXmlOutImageMessage() { + XStream xstream = XStreamInitializer.getInstance(); + + xstream.processAnnotations(WxCpXmlOutMessage.class); + xstream.processAnnotations(WxCpXmlOutImageMessage.class); + return xstream; + } + + private static XStream configWxCpXmlOutNewsMessage() { + XStream xstream = XStreamInitializer.getInstance(); + + xstream.processAnnotations(WxCpXmlOutMessage.class); + xstream.processAnnotations(WxCpXmlOutNewsMessage.class); + xstream.processAnnotations(WxCpXmlOutNewsMessage.Item.class); + return xstream; + } + + private static XStream configWxCpXmlOutTextMessage() { + XStream xstream = XStreamInitializer.getInstance(); + + xstream.processAnnotations(WxCpXmlOutMessage.class); + xstream.processAnnotations(WxCpXmlOutTextMessage.class); + return xstream; + } + + private static XStream configWxCpXmlOutVideoMessage() { + XStream xstream = XStreamInitializer.getInstance(); + + xstream.processAnnotations(WxCpXmlOutMessage.class); + xstream.processAnnotations(WxCpXmlOutVideoMessage.class); + xstream.processAnnotations(WxCpXmlOutVideoMessage.Video.class); + return xstream; + } + + private static XStream configWxCpXmlOutVoiceMessage() { + XStream xstream = XStreamInitializer.getInstance(); + + xstream.processAnnotations(WxCpXmlOutMessage.class); + xstream.processAnnotations(WxCpXmlOutVoiceMessage.class); + return xstream; + } + + private static XStream configWxCpTpXmlPackage() { + XStream xstream = XStreamInitializer.getInstance(); + xstream.processAnnotations(WxCpTpXmlPackage.class); + + return xstream; + } + + private static XStream configWxCpTpXmlMessage() { + XStream xstream = XStreamInitializer.getInstance(); + xstream.processAnnotations(WxCpTpXmlMessage.class); + + return xstream; + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java index c87b6455ac..c15e3af4d1 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java @@ -12,7 +12,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; -import me.chanjar.weixin.cp.config.WxCpInMemoryConfigStorage; +import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl; public class ApiTestModule implements Module { private final Logger log = LoggerFactory.getLogger(this.getClass()); @@ -44,7 +44,7 @@ public void configure(Binder binder) { } @XStreamAlias("xml") - public static class WxXmlCpInMemoryConfigStorage extends WxCpInMemoryConfigStorage { + public static class WxXmlCpInMemoryConfigStorage extends WxCpDefaultConfigImpl { protected String userId; @@ -52,6 +52,8 @@ public static class WxXmlCpInMemoryConfigStorage extends WxCpInMemoryConfigStora protected String tagId; + protected String externalUserId; + public String getUserId() { return this.userId; } @@ -76,12 +78,22 @@ public void setTagId(String tagId) { this.tagId = tagId; } + public String getExternalUserId() { + return externalUserId; + } + + public void setExternalUserId(String externalUserId) { + this.externalUserId = externalUserId; + } + @Override public String toString() { return super.toString() + " > WxXmlCpConfigStorage{" + "userId='" + this.userId + '\'' + ", departmentId='" + this.departmentId + '\'' + ", tagId='" + this.tagId + '\'' + + ", externalUserId='" + this.externalUserId + '\'' + + '}'; } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java index 2e89e5e79d..0bd8a24de3 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java @@ -1,5 +1,6 @@ package me.chanjar.weixin.cp.api; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; @@ -13,8 +14,8 @@ import java.util.concurrent.Future; @Test +@Slf4j public class WxCpBusyRetryTest { - @DataProvider(name = "getService") public Object[][] getService() { WxCpService service = new WxCpServiceImpl() { @@ -23,7 +24,7 @@ public Object[][] getService() { public synchronized T executeInternal( RequestExecutor executor, String uri, E data) throws WxErrorException { - this.log.info("Executed"); + log.info("Executed"); throw new WxErrorException(WxError.builder().errorCode(-1).build()); } }; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java index 5c93f38fb1..d0984565aa 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java @@ -1,5 +1,6 @@ package me.chanjar.weixin.cp.api; +import com.google.common.collect.ImmutableMap; import org.testng.annotations.*; import com.google.inject.Inject; @@ -107,4 +108,27 @@ public void testSendMessage_textCard() throws WxErrorException { System.out.println(messageSendResult.getInvalidUserList()); System.out.println(messageSendResult.getInvalidTagList()); } + + @Test + public void testSendMessage_miniprogram_notice() throws WxErrorException { + WxCpMessage message = WxCpMessage + .newMiniProgramNoticeBuilder() + .toUser(configStorage.getUserId()) + .appId("wx123123123123123") + .page("pages/index?userid=zhangsan&orderid=123123123") + .title("会议室预订成功通知") + .description("4月27日 16:16") + .emphasisFirstItem(true) + .contentItems(ImmutableMap.of("会议室","402", + "会议地点","广州TIT-402会议室", + "会议时间","2018年8月1日 09:00-09:30")) + .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()); + } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImplTest.java index 4ce497243d..90d2f14a44 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImplTest.java @@ -6,7 +6,7 @@ import me.chanjar.weixin.cp.api.WxCpAgentService; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpAgent; -import org.testng.Assert; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import org.testng.annotations.Guice; import org.testng.annotations.Test; @@ -71,7 +71,7 @@ public static class MockTest { @Test public void testGet() throws Exception { String returnJson = "{\"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\": \"\"}"; - when(wxService.get("https://qyapi.weixin.qq.com/cgi-bin/agent/get?agentid=9", null)).thenReturn(returnJson); + when(wxService.get(String.format(wxService.getWxCpConfigStorage().getApiUrl(WxCpApiPathConsts.Agent.AGENT_GET), 9), null)).thenReturn(returnJson); when(wxService.getAgentService()).thenReturn(new WxCpAgentServiceImpl(wxService)); WxCpAgentService wxAgentService = this.wxService.getAgentService(); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java index 4b25985f11..bb4d3904d0 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java @@ -8,7 +8,7 @@ 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.constant.WxCpConsts.AppChatMsgType; import me.chanjar.weixin.cp.api.ApiTestModule; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpAppChatMessage; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java new file mode 100644 index 0000000000..d39fd6e493 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java @@ -0,0 +1,45 @@ +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.WxCpUserExternalContactInfo; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.util.List; + +import static org.testng.Assert.assertNotNull; + +@Guice(modules = ApiTestModule.class) +public class WxCpExternalContactServiceImplTest { + @Inject + private WxCpService wxCpService; + @Inject + protected ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage; + private String userId = "someone" + System.currentTimeMillis(); + + @Test + public void testGetExternalContact() throws WxErrorException { + String externalUserId = this.configStorage.getExternalUserId(); + WxCpUserExternalContactInfo result = this.wxCpService.getExternalContactService().getExternalContact(externalUserId); + System.out.println(result); + assertNotNull(result); + } + + @Test + public void testListExternalContacts() throws WxErrorException { + String userId = this.configStorage.getUserId(); + List ret = this.wxCpService.getExternalContactService().listExternalContacts(userId); + System.out.println(ret); + assertNotNull(ret); + } + + @Test + public void testListExternalWithPermission() throws WxErrorException { + List ret = this.wxCpService.getExternalContactService().listFollowUser(); + System.out.println(ret); + assertNotNull(ret); + } +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImplTest.java index 21801e4b42..4df8756334 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImplTest.java @@ -4,10 +4,13 @@ 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.WxCpOauth2UserInfo; import me.chanjar.weixin.cp.bean.WxCpUserDetail; import org.testng.annotations.Guice; import org.testng.annotations.Test; +import static org.assertj.core.api.Assertions.assertThat; + /** * * Created by BinaryWang on 2018/4/22. @@ -28,6 +31,13 @@ public void testGetUserDetail() throws WxErrorException { @Test public void testGetUserInfo() throws WxErrorException { - this.wxService.getOauth2Service().getUserInfo("abc"); + final WxCpOauth2UserInfo result = this.wxService.getOauth2Service().getUserInfo("abc"); + assertThat(result).isNotNull(); + System.out.println(result); } + + @Test + public void testBuildAuthorizationUrl() { + } + } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java similarity index 97% rename from weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAServiceImplTest.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java index 9497a5626b..4810cd81d9 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java @@ -24,7 +24,7 @@ * @date 2019-04-20 13:46 */ @Guice(modules = ApiTestModule.class) -public class WxCpOAServiceImplTest { +public class WxCpOaServiceImplTest { @Inject protected WxCpService wxService; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java index 5a6e8ccabd..8d21bf17f7 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java @@ -10,6 +10,7 @@ import me.chanjar.weixin.cp.bean.WxCpTagAddOrRemoveUsersResult; import me.chanjar.weixin.cp.bean.WxCpTagGetResult; import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import org.testng.annotations.Guice; import org.testng.annotations.Test; @@ -22,10 +23,10 @@ /** *- * * Created by Binary Wang on 2017-6-25. - * @author Binary Wang *+ * + * @author Binary Wang */ @Guice(modules = ApiTestModule.class) public class WxCpTagServiceImplTest { @@ -35,7 +36,7 @@ public class WxCpTagServiceImplTest { @Inject protected ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage; - protected String tagId; + private String tagId; @Test public void testCreate() throws Exception { @@ -83,7 +84,7 @@ public void testDelete() throws Exception { public void testGet() throws WxErrorException { String apiResultJson = "{\"errcode\": 0,\"errmsg\": \"ok\",\"userlist\": [{\"userid\": \"0124035\",\"name\": \"王五\"},{\"userid\": \"0114035\",\"name\": \"梦雪\"}],\"partylist\": [9576,9567,9566],\"tagname\": \"测试标签-001\"}"; WxCpService wxService = mock(WxCpService.class); - when(wxService.get("https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagId=150", null)).thenReturn(apiResultJson); + when(wxService.get(String.format(wxService.getWxCpConfigStorage().getApiUrl(WxCpApiPathConsts.Tag.TAG_GET), 150), null)).thenReturn(apiResultJson); when(wxService.getTagService()).thenReturn(new WxCpTagServiceImpl(wxService)); WxCpTagService wxCpTagService = wxService.getTagService(); @@ -96,7 +97,6 @@ public void testGet() throws WxErrorException { assertEquals(3, wxCpTagGetResult.getPartylist().size()); assertEquals("测试标签-001", wxCpTagGetResult.getTagname()); - } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java index 2ec33e7ba7..23c86768fd 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java @@ -93,7 +93,7 @@ public void testListSimpleByDepartment() throws Exception { @Test public void testInvite() throws Exception { WxCpInviteResult result = this.wxCpService.getUserService().invite( - Lists.newArrayList(userId), null,null); + Lists.newArrayList(userId), null, null); System.out.println(result); } @@ -111,10 +111,15 @@ public void testOpenid2UserId() throws Exception { assertNotNull(result); } + @Test - public void testGetExternalContact() throws WxErrorException { - WxCpUserExternalContactInfo result = this.wxCpService.getUserService().getExternalContact(userId); + public void testGetUserId() throws WxErrorException { + String result = this.wxCpService.getUserService().getUserId("xxx"); System.out.println(result); assertNotNull(result); } + + @Test + public void testGetExternalContact() { + } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java index 89c0396e08..e6efa04382 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java @@ -1,9 +1,10 @@ package me.chanjar.weixin.cp.bean; import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.cp.constant.WxCpConsts; import org.testng.annotations.Test; -import static me.chanjar.weixin.cp.WxCpConsts.EventType.TASKCARD_CLICK; +import static me.chanjar.weixin.cp.constant.WxCpConsts.EventType.TASKCARD_CLICK; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -106,7 +107,7 @@ public void testSendPicsInfo() { "2 " + "" + "
+ * 详情请见:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/plugin-management/pluginManager.applyPlugin.html + * 或者:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/Plug-ins_Management.html + */ +public interface WxMaPluginService { + + String PLUGIN_URL = "https://api.weixin.qq.com/wxa/plugin"; + + /** + * 向插件开发者发起使用插件的申请 + * + * @param pluginAppId 插件 appId + * @param reason 申请使用理由 + * @throws WxErrorException 异常 + */ + void applyPlugin(String pluginAppId, String reason) throws WxErrorException; + + /** + * 查询已添加的插件 + * + * @return + * @throws WxErrorException + */ + WxMaPluginListResult getPluginList() throws WxErrorException; + + /** + * 删除已添加的插件 + * + * @param pluginAppId 插件 appId + * @throws WxErrorException + */ + void unbindPlugin(String pluginAppId) throws WxErrorException; + + /** + * 快速更新插件版本号(第三方平台代小程序管理插件) + * + * @param pluginAppId 插件 appid + * @param userVersion 升级至版本号,要求此插件版本支持快速更新 + * @throws WxErrorException + */ + void updatePlugin(String pluginAppId, String userVersion) throws WxErrorException; + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java index 578acc56af..52988f36e2 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java @@ -207,6 +207,13 @@ public interface WxMaService { */ WxMaSecCheckService getSecCheckService(); + /** + * 返回插件相关接口服务对象. + * + * @return WxMaPluginService + */ + WxMaPluginService getPluginService(); + /** * 初始化http请求对象. */ diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java index a4abdc04d4..3b7abeeb42 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java @@ -13,11 +13,14 @@ * @author Binary Wang */ public interface WxMaUserService { + String SET_USER_STORAGE = "https://api.weixin.qq.com/wxa/set_user_storage?appid=%s&signature=%s&openid=%s&sig_method=%s"; /** * 获取登录后的session信息. * * @param jsCode 登录时获取的 code + * @return . + * @throws WxErrorException . */ WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException; @@ -34,9 +37,11 @@ public interface WxMaUserService { * 上报用户数据后台接口. *
小游戏可以通过本接口上报key-value数据到用户的CloudStorage。
* 文档参考https://developers.weixin.qq.com/minigame/dev/document/open-api/data/setUserStorage.html - * @param kvMap 要上报的数据 + * + * @param kvMap 要上报的数据 * @param sessionKey 通过wx.login 获得的登录态 - * @param openid + * @param openid . + * @throws WxErrorException . */ void setUserStorage(Map+ * 需要引入依赖jedis-lock,才能使用该类。 + *+ * + * @author winter + */ +public class WxMaRedisConfigImpl implements WxMaConfig { + private static final String ACCESS_TOKEN = "accessToken"; + private static final String JSAPI_TICKET = "jsapiTicket"; + private static final String CARD_API_TICKET = "cardApiTicket"; + + private static final String HASH_VALUE_FIELD = "value"; + private static final String HASH_EXPIRE_FIELD = "expire"; + + private JedisPool jedisPool; + /** + * 微信小程序唯一id,用于拼接存储到redis时的key,防止key重复. + */ + private String maId; + + private volatile String msgDataFormat; + protected volatile String appid; + private volatile String secret; + protected volatile String token; + private volatile String aesKey; + + private volatile String httpProxyHost; + private volatile int httpProxyPort; + private volatile String httpProxyUsername; + private volatile String httpProxyPassword; + + private Lock accessTokenLock; + private Lock jsapiTicketLock; + private Lock cardApiTicketLock; + + /** + * 临时文件目录. + */ + protected volatile File tmpDirFile; + + private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + + private String getRedisKey(String key) { + StringBuilder redisKey = new StringBuilder("maConfig:"); + if (maId == null) { + return redisKey.append(key).toString(); + } else { + return redisKey.append(maId).append(":").append(key).toString(); + } + } + + private String getValueFromRedis(String key) { + try (Jedis jedis = jedisPool.getResource()) { + return jedis.hget(getRedisKey(key), HASH_VALUE_FIELD); + } + } + + private void setValueToRedis(String key, long expiresTime, String value) { + try (Jedis jedis = jedisPool.getResource()) { + Map
- * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker} - * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker} - *- */ - public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) { - this.messageDuplicateChecker = messageDuplicateChecker; - } - /** *
* 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager} @@ -93,16 +80,16 @@ ListgetRules() { } /** - * 开始一个新的Route规则 + * 开始一个新的Route规则. */ public WxMaMessageRouterRule rule() { return new WxMaMessageRouterRule(this); } /** - * 处理微信消息 + * 处理微信消息. */ - public void route(final WxMaMessage wxMessage, final Map context) { + private WxMaXmlOutMessage route(final WxMaMessage wxMessage, final Map context) { final List matchRules = new ArrayList<>(); // 收集匹配的规则 for (final WxMaMessageRouterRule rule : this.rules) { @@ -115,10 +102,11 @@ public void route(final WxMaMessage wxMessage, final Map context } if (matchRules.size() == 0) { - return; + return null; } final List > futures = new ArrayList<>(); + WxMaXmlOutMessage result = null; for (final WxMaMessageRouterRule rule : matchRules) { // 返回最后一个非异步的rule的执行结果 if (rule.isAsync()) { @@ -131,7 +119,7 @@ public void run() { }) ); } else { - rule.service(wxMessage, context, this.wxMaService, this.sessionManager, this.exceptionHandler); + result = rule.service(wxMessage, context, this.wxMaService, this.sessionManager, this.exceptionHandler); // 在同步操作结束,session访问结束 this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser()); sessionEndAccess(wxMessage); @@ -155,18 +143,17 @@ public void run() { } }); } - + return result; } - public void route(final WxMaMessage wxMessage) { - this.route(wxMessage, new HashMap (2)); + public WxMaXmlOutMessage route(final WxMaMessage wxMessage) { + return this.route(wxMessage, new HashMap (2)); } /** - * 对session的访问结束 + * 对session的访问结束. */ - protected void sessionEndAccess(WxMaMessage wxMessage) { - + private void sessionEndAccess(WxMaMessage wxMessage) { InternalSession session = ((InternalSessionManager) this.sessionManager).findSession(wxMessage.getFromUser()); if (session != null) { session.endAccess(); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java index 2e4906ebf1..5ea3fb8a92 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java @@ -16,7 +16,6 @@ * @author Binary Wang */ public class WxMaMessageRouterRule { - private final WxMaMessageRouter routerBuilder; private boolean async = true; @@ -46,7 +45,7 @@ public WxMaMessageRouterRule(WxMaMessageRouter routerBuilder) { } /** - * 设置是否异步执行,默认是true + * 设置是否异步执行,默认是true. */ public WxMaMessageRouterRule async(boolean async) { this.async = async; @@ -54,7 +53,7 @@ public WxMaMessageRouterRule async(boolean async) { } /** - * 如果msgType等于某值 + * 如果msgType等于某值. */ public WxMaMessageRouterRule msgType(String msgType) { this.msgType = msgType; @@ -62,7 +61,7 @@ public WxMaMessageRouterRule msgType(String msgType) { } /** - * 如果event等于某值 + * 如果event等于某值. */ public WxMaMessageRouterRule event(String event) { this.event = event; @@ -70,7 +69,7 @@ public WxMaMessageRouterRule event(String event) { } /** - * 如果eventKey等于某值 + * 如果eventKey等于某值. */ public WxMaMessageRouterRule eventKey(String eventKey) { this.eventKey = eventKey; @@ -78,7 +77,7 @@ public WxMaMessageRouterRule eventKey(String eventKey) { } /** - * 如果content等于某值 + * 如果content等于某值. */ public WxMaMessageRouterRule content(String content) { this.content = content; @@ -86,7 +85,7 @@ public WxMaMessageRouterRule content(String content) { } /** - * 如果content匹配该正则表达式 + * 如果content匹配该正则表达式. */ public WxMaMessageRouterRule rContent(String regex) { this.rContent = regex; @@ -94,7 +93,7 @@ public WxMaMessageRouterRule rContent(String regex) { } /** - * 如果fromUser等于某值 + * 如果fromUser等于某值. */ public WxMaMessageRouterRule fromUser(String fromUser) { this.fromUser = fromUser; @@ -102,7 +101,7 @@ public WxMaMessageRouterRule fromUser(String fromUser) { } /** - * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 + * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候. */ public WxMaMessageRouterRule matcher(WxMaMessageMatcher matcher) { this.matcher = matcher; @@ -110,14 +109,14 @@ public WxMaMessageRouterRule matcher(WxMaMessageMatcher matcher) { } /** - * 设置微信消息拦截器 + * 设置微信消息拦截器. */ public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor) { return interceptor(interceptor, (WxMaMessageInterceptor[]) null); } /** - * 设置微信消息拦截器 + * 设置微信消息拦截器. */ public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor, WxMaMessageInterceptor... otherInterceptors) { this.interceptors.add(interceptor); @@ -130,14 +129,14 @@ public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor, WxM } /** - * 设置微信消息处理器 + * 设置微信消息处理器. */ public WxMaMessageRouterRule handler(WxMaMessageHandler handler) { return handler(handler, (WxMaMessageHandler[]) null); } /** - * 设置微信消息处理器 + * 设置微信消息处理器. */ public WxMaMessageRouterRule handler(WxMaMessageHandler handler, WxMaMessageHandler... otherHandlers) { this.handlers.add(handler); @@ -150,7 +149,7 @@ public WxMaMessageRouterRule handler(WxMaMessageHandler handler, WxMaMessageHand } /** - * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 + * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则. */ public WxMaMessageRouter end() { this.routerBuilder.getRules().add(this); @@ -158,7 +157,7 @@ public WxMaMessageRouter end() { } /** - * 规则结束,但是消息还会进入其他规则 + * 规则结束,但是消息还会进入其他规则. */ public WxMaMessageRouter next() { this.reEnter = true; @@ -166,7 +165,7 @@ public WxMaMessageRouter next() { } /** - * 将微信自定义的事件修正为不区分大小写, + * 将微信自定义的事件修正为不区分大小写. * 比如框架定义的事件常量为click,但微信传递过来的却是CLICK */ protected boolean test(WxMaMessage wxMessage) { @@ -188,9 +187,9 @@ protected boolean test(WxMaMessage wxMessage) { } /** - * 处理微信推送过来的消息 + * 处理微信推送过来的消息. */ - protected void service(WxMaMessage wxMessage, + protected WxMaXmlOutMessage service(WxMaMessage wxMessage, Map context, WxMaService wxMaService, WxSessionManager sessionManager, @@ -199,11 +198,12 @@ protected void service(WxMaMessage wxMessage, context = new HashMap<>(16); } + WxMaXmlOutMessage outMessage = null; try { // 如果拦截器不通过 for (WxMaMessageInterceptor interceptor : this.interceptors) { if (!interceptor.intercept(wxMessage, context, wxMaService, sessionManager)) { - return; + return null; } } @@ -213,11 +213,13 @@ protected void service(WxMaMessage wxMessage, if (handler == null) { continue; } - handler.handle(wxMessage, context, wxMaService, sessionManager); + outMessage = handler.handle(wxMessage, context, wxMaService, sessionManager); } } catch (WxErrorException e) { exceptionHandler.handle(e); } + + return outMessage; } public WxMaMessageRouter getRouterBuilder() { diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java new file mode 100644 index 0000000000..7211e0531a --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java @@ -0,0 +1,60 @@ +package cn.binarywang.wx.miniapp.message; + +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; +import cn.binarywang.wx.miniapp.util.xml.XStreamTransformer; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; + +import java.io.Serializable; + +/** + * 微信小程序输出给微信服务器的消息. + * + * @author Binary Wang + * @date 2019-06-22 + */ +@Data +@XStreamAlias("xml") +@Accessors(chain = true) +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class WxMaXmlOutMessage implements Serializable { + private static final long serialVersionUID = 4241135225946919153L; + + @XStreamAlias("ToUserName") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String toUserName; + + @XStreamAlias("FromUserName") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String fromUserName; + + @XStreamAlias("CreateTime") + protected Long createTime; + + @XStreamAlias("MsgType") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String msgType; + + @SuppressWarnings("unchecked") + public String toXml() { + return XStreamTransformer.toXml((Class ) this.getClass(), this); + } + + /** + * 转换成加密的xml格式. + */ + public String toEncryptedXml(WxMaConfig config) { + String plainXml = toXml(); + WxMaCryptUtils pc = new WxMaCryptUtils(config); + return pc.encrypt(plainXml); + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaPluginServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaPluginServiceImplTest.java new file mode 100644 index 0000000000..ef5882e8f5 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaPluginServiceImplTest.java @@ -0,0 +1,39 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaPluginListResult; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotNull; + +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaPluginServiceImplTest { + @Inject + private WxMaService wxService; + + @Test + public void testApplyPlugin() throws Exception { + this.wxService.getPluginService().applyPlugin("wx4418e3e031e551be", null); + } + + @Test + public void testGetPluginList() throws Exception { + WxMaPluginListResult result = this.wxService.getPluginService().getPluginList(); + assertNotNull(result); + System.out.println(result.toString()); + } + + @Test + public void testUnbindPlugin() throws Exception { + this.wxService.getPluginService().unbindPlugin("wx4418e3e031e551be"); + } + + @Test + public void testUpdatePlugin() throws Exception { + this.wxService.getPluginService().updatePlugin("wx4418e3e031e551be", "2.0.2"); + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java index fe886f4b85..89df244413 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java @@ -1,15 +1,5 @@ package cn.binarywang.wx.miniapp.demo; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; -import java.util.concurrent.locks.ReentrantLock; - -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.servlet.ServletHandler; -import org.eclipse.jetty.servlet.ServletHolder; - import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; @@ -20,11 +10,23 @@ import cn.binarywang.wx.miniapp.constant.WxMaConstants; import cn.binarywang.wx.miniapp.message.WxMaMessageHandler; import cn.binarywang.wx.miniapp.message.WxMaMessageRouter; +import cn.binarywang.wx.miniapp.message.WxMaXmlOutMessage; import cn.binarywang.wx.miniapp.test.TestConfig; import com.google.common.collect.Lists; +import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Calendar; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; /** * @author Binary Wang @@ -33,29 +35,31 @@ public class WxMaDemoServer { private static final WxMaMessageHandler logHandler = new WxMaMessageHandler() { @Override - public void handle(WxMaMessage wxMessage, Map context, - WxMaService service, WxSessionManager sessionManager) throws WxErrorException { + public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { System.out.println("收到消息:" + wxMessage.toString()); service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson()) .toUser(wxMessage.getFromUser()).build()); + return null; } }; private static final WxMaMessageHandler textHandler = new WxMaMessageHandler() { @Override - public void handle(WxMaMessage wxMessage, Map context, - WxMaService service, WxSessionManager sessionManager) + public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息") .toUser(wxMessage.getFromUser()).build()); + return null; } }; private static final WxMaMessageHandler picHandler = new WxMaMessageHandler() { @Override - public void handle(WxMaMessage wxMessage, Map context, - WxMaService service, WxSessionManager sessionManager) throws WxErrorException { + public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { try { WxMediaUploadResult uploadResult = service.getMediaService() .uploadMedia(WxMaConstants.MediaType.IMAGE, "png", @@ -69,13 +73,14 @@ public void handle(WxMaMessage wxMessage, Map context, } catch (WxErrorException e) { e.printStackTrace(); } + return null; } }; private static final WxMaMessageHandler qrcodeHandler = new WxMaMessageHandler() { @Override - public void handle(WxMaMessage wxMessage, Map context, - WxMaService service, WxSessionManager sessionManager) throws WxErrorException { + public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { try { final File file = service.getQrcodeService().createQrcode("123", 430); WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia(WxMaConstants.MediaType.IMAGE, file); @@ -88,13 +93,14 @@ public void handle(WxMaMessage wxMessage, Map context, } catch (WxErrorException e) { e.printStackTrace(); } + return null; } }; private static final WxMaMessageHandler templateMsgHandler = new WxMaMessageHandler() { @Override - public void handle(WxMaMessage wxMessage, Map context, - WxMaService service, WxSessionManager sessionManager) + public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { service.getMsgService().sendTemplateMsg(WxMaTemplateMessage.builder() .templateId(templateId).data(Lists.newArrayList( @@ -102,10 +108,22 @@ public void handle(WxMaMessage wxMessage, Map context, .toUser(wxMessage.getFromUser()) .formId("自己替换可用的formid") .build()); + return null; } }; + private static final WxMaMessageHandler customerServiceMessageHandler = new WxMaMessageHandler() { + @Override + public WxMaXmlOutMessage handle(WxMaMessage message, Map context, WxMaService service, WxSessionManager sessionManager) { + return new WxMaXmlOutMessage() + .setMsgType(WxConsts.XmlMsgType.TRANSFER_CUSTOMER_SERVICE) + .setFromUserName(message.getToUser()) + .setCreateTime(Calendar.getInstance().getTimeInMillis() / 1000) + .setToUserName(message.getFromUser()); + } + }; + private static WxMaConfig config; private static WxMaService service; private static WxMaMessageRouter router; @@ -142,7 +160,8 @@ private static void init() { .rule().async(false).content("模板").handler(templateMsgHandler).end() .rule().async(false).content("文本").handler(textHandler).end() .rule().async(false).content("图片").handler(picHandler).end() - .rule().async(false).content("二维码").handler(qrcodeHandler).end(); + .rule().async(false).content("二维码").handler(qrcodeHandler).end() + .rule().async(false).content("转发客服").handler(customerServiceMessageHandler).end(); } catch (IOException e) { e.printStackTrace(); } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java index 5cadb68925..c209082d45 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java @@ -5,6 +5,8 @@ import cn.binarywang.wx.miniapp.config.WxMaConfig; import cn.binarywang.wx.miniapp.constant.WxMaConstants; import cn.binarywang.wx.miniapp.message.WxMaMessageRouter; +import cn.binarywang.wx.miniapp.message.WxMaXmlOutMessage; +import lombok.AllArgsConstructor; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; @@ -18,19 +20,13 @@ /** * @author Binary Wang */ +@AllArgsConstructor public class WxMaPortalServlet extends HttpServlet { private static final long serialVersionUID = 1L; - private WxMaConfig wxMaConfig; - private WxMaService wxMaService; - private WxMaMessageRouter wxMaMessageRouter; - - WxMaPortalServlet(WxMaConfig wxMaConfig, WxMaService wxMaService, - WxMaMessageRouter wxMaMessageRouter) { - this.wxMaConfig = wxMaConfig; - this.wxMaService = wxMaService; - this.wxMaMessageRouter = wxMaMessageRouter; - } + private WxMaConfig config; + private WxMaService service; + private WxMaMessageRouter messageRouter; @Override protected void service(HttpServletRequest request, HttpServletResponse response) @@ -42,7 +38,7 @@ protected void service(HttpServletRequest request, HttpServletResponse response) String nonce = request.getParameter("nonce"); String timestamp = request.getParameter("timestamp"); - if (!this.wxMaService.checkSignature(timestamp, nonce, signature)) { + if (!this.service.checkSignature(timestamp, nonce, signature)) { // 消息签名不正确,说明不是公众平台发过来的消息 response.getWriter().println("非法请求"); return; @@ -56,7 +52,7 @@ protected void service(HttpServletRequest request, HttpServletResponse response) } String encryptType = request.getParameter("encrypt_type"); - final boolean isJson = Objects.equals(this.wxMaConfig.getMsgDataFormat(), WxMaConstants.MsgDataFormat.JSON); + final boolean isJson = Objects.equals(this.config.getMsgDataFormat(), WxMaConstants.MsgDataFormat.JSON); if (StringUtils.isBlank(encryptType)) { // 明文传输的消息 WxMaMessage inMessage; @@ -66,7 +62,12 @@ protected void service(HttpServletRequest request, HttpServletResponse response) inMessage = WxMaMessage.fromXml(request.getInputStream()); } - this.wxMaMessageRouter.route(inMessage); + final WxMaXmlOutMessage outMessage = this.messageRouter.route(inMessage); + if (outMessage != null) { + response.getWriter().write(outMessage.toXml()); + return; + } + response.getWriter().write("success"); return; } @@ -76,12 +77,16 @@ protected void service(HttpServletRequest request, HttpServletResponse response) String msgSignature = request.getParameter("msg_signature"); WxMaMessage inMessage; if (isJson) { - inMessage = WxMaMessage.fromEncryptedJson(request.getInputStream(), this.wxMaConfig); + inMessage = WxMaMessage.fromEncryptedJson(request.getInputStream(), this.config); } else {//xml - inMessage = WxMaMessage.fromEncryptedXml(request.getInputStream(), this.wxMaConfig, timestamp, nonce, msgSignature); + inMessage = WxMaMessage.fromEncryptedXml(request.getInputStream(), this.config, timestamp, nonce, msgSignature); } - this.wxMaMessageRouter.route(inMessage); + final WxMaXmlOutMessage outMessage = this.messageRouter.route(inMessage); + if (outMessage != null) { + response.getWriter().write(outMessage.toEncryptedXml(this.config)); + return; + } response.getWriter().write("success"); return; } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java index 6cebdeb24b..a9dd465612 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/TestConfig.java @@ -1,6 +1,6 @@ package cn.binarywang.wx.miniapp.test; -import cn.binarywang.wx.miniapp.config.WxMaInMemoryConfig; +import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.util.xml.XStreamInitializer; @@ -13,7 +13,7 @@ * @author Binary Wang */ @XStreamAlias("xml") -public class TestConfig extends WxMaInMemoryConfig { +public class TestConfig extends WxMaDefaultConfigImpl { private String openid; private String kfAccount; diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index ed8c7e75de..8792a55e1c 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java -3.4.0 +3.5.0 weixin-java-mp diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpAiOpenService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpAiOpenService.java index c57ad9d0f5..230910e888 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpAiOpenService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpAiOpenService.java @@ -15,9 +15,6 @@ * @author Binary Wang */ public interface WxMpAiOpenService { - String TRANSLATE_URL = "http://api.weixin.qq.com/cgi-bin/media/voice/translatecontent?lfrom=%s<o=%s"; - String VOICE_UPLOAD_URL = "http://api.weixin.qq.com/cgi-bin/media/voice/addvoicetorecofortext?format=%s&voice_id=%s&lang=%s"; - String VOICE_QUERY_RESULT_URL = "http://api.weixin.qq.com/cgi-bin/media/voice/queryrecoresultfortext"; /** *diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java index 66aeccade7..f5131e8f98 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCardService.java @@ -3,51 +3,33 @@ import me.chanjar.weixin.common.bean.WxCardApiSignature; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.bean.card.*; -import me.chanjar.weixin.mp.bean.card.WxMpCardResult; /** - * 卡券相关接口 + * 卡券相关接口. * * @author YuJian(mgcnrx11 @ hotmail.com) on 01/11/2016 * @author yuanqixun 2018-08-29 */ public interface WxMpCardService { - String CARD_CREATE = "https://api.weixin.qq.com/card/create"; - String CARD_GET = "https://api.weixin.qq.com/card/get"; - String CARD_GET_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card"; - String CARD_CODE_DECRYPT = "https://api.weixin.qq.com/card/code/decrypt"; - String CARD_CODE_GET = "https://api.weixin.qq.com/card/code/get"; - String CARD_CODE_CONSUME = "https://api.weixin.qq.com/card/code/consume"; - String CARD_CODE_MARK = "https://api.weixin.qq.com/card/code/mark"; - String CARD_TEST_WHITELIST = "https://api.weixin.qq.com/card/testwhitelist/set"; - String CARD_QRCODE_CREATE = "https://api.weixin.qq.com/card/qrcode/create"; - String CARD_LANDING_PAGE_CREATE = "https://api.weixin.qq.com/card/landingpage/create"; /** - * 将用户的卡券设置为失效状态 - */ - String CARD_CODE_UNAVAILABLE = "https://api.weixin.qq.com/card/code/unavailable"; - - /** - * 卡券删除 - */ - String CARD_DELETE = "https://api.weixin.qq.com/card/delete"; - - /** - * 得到WxMpService + * 得到WxMpService. + * + * @return WxMpService */ WxMpService getWxMpService(); /** - * 获得卡券api_ticket,不强制刷新卡券api_ticket + * 获得卡券api_ticket,不强制刷新卡券api_ticket. * * @return 卡券api_ticket + * @throws WxErrorException 异常 * @see #getCardApiTicket(boolean) */ String getCardApiTicket() throws WxErrorException; /** *- * 获得卡券api_ticket + * 获得卡券api_ticket. * 获得时会检查卡券apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干 * * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94.9F.E6.88.90.E7.AE.97.E6.B3.95 @@ -55,67 +37,68 @@ public interface WxMpCardService { * * @param forceRefresh 强制刷新 * @return 卡券api_ticket - * @throws WxErrorException + * @throws WxErrorException 异常 */ String getCardApiTicket(boolean forceRefresh) throws WxErrorException; /** *- * 创建调用卡券api时所需要的签名 + * 创建调用卡券api时所需要的签名. * * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD * .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94 * .9F.E6.88.90.E7.AE.97.E6.B3.95 ** - * @param optionalSignParam 参与签名的参数数组。 - * 可以为下列字段:app_id, card_id, card_type, code, openid, location_id + * @param optionalSignParam 参与签名的参数数组。可以为下列字段:app_id, card_id, card_type, code, openid, location_id * 注意:当做wx.chooseCard调用时,必须传入app_id参与签名,否则会造成签名失败导致拉取卡券列表为空 * @return 卡券Api签名对象 + * @throws WxErrorException 异常 */ - WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws - WxErrorException; + WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws WxErrorException; /** - * 卡券Code解码 + * 卡券Code解码. * * @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得 * @return 解密后的Code + * @throws WxErrorException 异常 */ String decryptCardCode(String encryptCode) throws WxErrorException; /** * 卡券Code查询. * 文档地址: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025272&anchor=1 + * * @param cardId 卡券ID代表一类卡券 * @param code 单张卡券的唯一标准 * @param checkConsume 是否校验code核销状态,填入true和false时的code异常状态返回数据不同 * @return WxMpCardResult对象 + * @throws WxErrorException 异常 */ - WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) - throws WxErrorException; + WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) throws WxErrorException; /** * 卡券Code核销。核销失败会抛出异常 * * @param code 单张卡券的唯一标准 - * @return 调用返回的JSON字符串。 - *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 + * @return 调用返回的JSON字符串。可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 + * @throws WxErrorException 异常 */ String consumeCardCode(String code) throws WxErrorException; /** - * 卡券Code核销。核销失败会抛出异常 + * 卡券Code核销。核销失败会抛出异常. * * @param code 单张卡券的唯一标准 * @param cardId 当自定义Code卡券时需要传入card_id - * @return 调用返回的JSON字符串。 - *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 + * @return 调用返回的JSON字符串。可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 + * @throws WxErrorException 异常 */ String consumeCardCode(String code, String cardId) throws WxErrorException; /** - * 卡券Mark接口。 + * 卡券Mark接口. * 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住), * 才能进一步调用核销接口,否则报错。 * @@ -123,82 +106,103 @@ WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) * @param cardId 卡券的ID * @param openId 用券用户的openid * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 + * @throws WxErrorException 异常 */ - void markCardCode(String code, String cardId, String openId, boolean isMark) throws - WxErrorException; + void markCardCode(String code, String cardId, String openId, boolean isMark) throws WxErrorException; /** - * 查看卡券详情接口 + * 查看卡券详情接口. * 详见 https://mp.weixin.qq.com/wiki/14/8dd77aeaee85f922db5f8aa6386d385e.html#.E6.9F.A5.E7.9C.8B.E5.8D.A1.E5.88.B8.E8.AF.A6.E6.83.85 * * @param cardId 卡券的ID * @return 返回的卡券详情JSON字符串 *
[注] 由于返回的JSON格式过于复杂,难以定义其对应格式的Bean并且难以维护,因此只返回String格式的JSON串。 *
可由 com.google.gson.JsonParser#parse 等方法直接取JSON串中的某个字段。 + * @throws WxErrorException 异常 */ String getCardDetail(String cardId) throws WxErrorException; /** - * 添加测试白名单 + * 添加测试白名单. * * @param openid 用户的openid - * @return + * @return string + * @throws WxErrorException 异常 */ String addTestWhiteList(String openid) throws WxErrorException; /** + * 创建卡券. * - * @param cardCreateMessage - * @return - * @throws WxErrorException + * @param cardCreateMessage 请求 + * @return result + * @throws WxErrorException 异常 */ WxMpCardCreateResult createCard(WxMpCardCreateMessage cardCreateMessage) throws WxErrorException; /** - * 创建卡券二维码 + * 创建卡券二维码. * * @param cardId 卡券编号 * @param outerStr 二维码标识 * @return WxMpCardQrcodeCreateResult + * @throws WxErrorException 异常 */ WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr) throws WxErrorException; /** - * 创建卡券二维码 + * 创建卡券二维码. * * @param cardId 卡券编号 * @param outerStr 二维码标识 - * @param expiresIn 失效时间,单位秒,不填默认365天 + * @param expiresIn 指定二维码的有效时间,范围是60 ~ 1800秒。不填默认为365天有效 * @return WxMpCardQrcodeCreateResult + * @throws WxErrorException 异常 */ WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn) throws WxErrorException; /** - * 创建卡券货架 + * 创建卡券二维码. + * + * @param cardId 卡券编号 + * @param outerStr 用户首次领卡时,会通过 领取事件推送 给商户; 对于会员卡的二维码,用户每次扫码打开会员卡后点击任何url,会将该值拼入url中,方便开发者定位扫码来源 + * @param expiresIn 指定二维码的有效时间,范围是60 ~ 1800秒。不填默认为365天有效 + * @param isUniqueCode 指定下发二维码,生成的二维码随机分配一个code,领取后不可再次扫描。填写true或false。默认false,注意填写该字段时,卡券须通过审核且库存不为0。 + * @param code 卡券Code码,use_custom_code字段为true的卡券必须填写,非自定义code和导入code模式的卡券不必填写。 + * @param openid 指定领取者的openid,只有该用户能领取。bind_openid字段为true的卡券必须填写,非指定openid不必填写。 + * @return WxMpCardQrcodeCreateResult + * @throws WxErrorException 异常 + */ + WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn, String openid, + String code, boolean isUniqueCode) throws WxErrorException; + + /** + * 创建卡券货架. * * @param createRequest 货架创建参数 - * @return - * @throws WxErrorException + * @return WxMpCardLandingPageCreateResult + * @throws WxErrorException 异常 */ WxMpCardLandingPageCreateResult createLandingPage(WxMpCardLandingPageCreateRequest createRequest) throws WxErrorException; /** - * 将用户的卡券设置为失效状态 + * 将用户的卡券设置为失效状态. * 详见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025272&anchor=9 * * @param cardId 卡券编号 * @param code 用户会员卡号 * @param reason 设置为失效的原因 - * @return - * @throws WxErrorException + * @return result + * @throws WxErrorException 异常 */ String unavailableCardCode(String cardId, String code, String reason) throws WxErrorException; /** - * 删除卡券接口 - * @param cardId - * @return - * @throws WxErrorException + * 删除卡券接口. + * + * @param cardId 卡券id + * @return 删除结果 + * @throws WxErrorException 异常 */ WxMpCardDeleteResult deleteCard(String cardId) throws WxErrorException; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCommentService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCommentService.java new file mode 100644 index 0000000000..2ba7a09235 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCommentService.java @@ -0,0 +1,22 @@ +package me.chanjar.weixin.mp.api; + +import me.chanjar.weixin.common.error.WxErrorException; + +/** + * 评论数据管理. + * + * @author Binary Wang + * @date 2019-06-16 + */ +public interface WxMpCommentService { + /** + * 打开已群发文章评论. + * https://api.weixin.qq.com/cgi-bin/comment/open?access_token=ACCESS_TOKEN + * 参数 是否必须 类型 说明 + * + * @param msgDataId 群发返回的msg_data_id + * @param index 多图文时,用来指定第几篇图文,从0开始,不带默认操作该msg_data_id的第一篇图文 + * @throws WxErrorException 异常 + */ + void open(Integer msgDataId, Integer index) throws WxErrorException; +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java index fecceea444..c1b35bee5f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java @@ -13,24 +13,6 @@ * @author binarywang (https://github.com/binarywang) */ public interface WxMpDataCubeService { - String GET_USER_SUMMARY = "https://api.weixin.qq.com/datacube/getusersummary"; - String GET_USER_CUMULATE = "https://api.weixin.qq.com/datacube/getusercumulate"; - String GET_ARTICLE_SUMMARY = "https://api.weixin.qq.com/datacube/getarticlesummary"; - String GET_ARTICLE_TOTAL = "https://api.weixin.qq.com/datacube/getarticletotal"; - String GET_USER_READ = "https://api.weixin.qq.com/datacube/getuserread"; - String GET_USER_READ_HOUR = "https://api.weixin.qq.com/datacube/getuserreadhour"; - String GET_USER_SHARE = "https://api.weixin.qq.com/datacube/getusershare"; - String GET_USER_SHARE_HOUR = "https://api.weixin.qq.com/datacube/getusersharehour"; - String GET_UPSTREAM_MSG = "https://api.weixin.qq.com/datacube/getupstreammsg"; - String GET_UPSTREAM_MSG_HOUR = "https://api.weixin.qq.com/datacube/getupstreammsghour"; - String GET_UPSTREAM_MSG_WEEK = "https://api.weixin.qq.com/datacube/getupstreammsgweek"; - String GET_UPSTREAM_MSG_MONTH = "https://api.weixin.qq.com/datacube/getupstreammsgmonth"; - String GET_UPSTREAM_MSG_DIST = "https://api.weixin.qq.com/datacube/getupstreammsgdist"; - String GET_UPSTREAM_MSG_DIST_WEEK = "https://api.weixin.qq.com/datacube/getupstreammsgdistweek"; - String GET_UPSTREAM_MSG_DIST_MONTH = "https://api.weixin.qq.com/datacube/getupstreammsgdistmonth"; - String GET_INTERFACE_SUMMARY = "https://api.weixin.qq.com/datacube/getinterfacesummary"; - String GET_INTERFACE_SUMMARY_HOUR = "https://api.weixin.qq.com/datacube/getinterfacesummaryhour"; - //*******************用户分析数据接口***********************// /** diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java index 8a0fb6a58e..c2ccef5a64 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java @@ -5,6 +5,8 @@ /** * Created by keungtung on 10/12/2016. + * + * @author keungtung */ public interface WxMpDeviceService { /** diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java index 99dcaba99b..3404f5fe2e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java @@ -22,22 +22,6 @@ * @author Binary Wang */ public interface WxMpKefuService { - String MESSAGE_CUSTOM_SEND = "https://api.weixin.qq.com/cgi-bin/message/custom/send"; - String GET_KF_LIST = "https://api.weixin.qq.com/cgi-bin/customservice/getkflist"; - String GET_ONLINE_KF_LIST = "https://api.weixin.qq.com/cgi-bin/customservice/getonlinekflist"; - String KFACCOUNT_ADD = "https://api.weixin.qq.com/customservice/kfaccount/add"; - String KFACCOUNT_UPDATE = "https://api.weixin.qq.com/customservice/kfaccount/update"; - String KFACCOUNT_INVITE_WORKER = "https://api.weixin.qq.com/customservice/kfaccount/inviteworker"; - String KFACCOUNT_UPLOAD_HEAD_IMG = "https://api.weixin.qq.com/customservice/kfaccount/uploadheadimg?kf_account=%s"; - String KFACCOUNT_DEL = "https://api.weixin.qq.com/customservice/kfaccount/del?kf_account=%s"; - String KFSESSION_CREATE = "https://api.weixin.qq.com/customservice/kfsession/create"; - String KFSESSION_CLOSE = "https://api.weixin.qq.com/customservice/kfsession/close"; - String KFSESSION_GET_SESSION = "https://api.weixin.qq.com/customservice/kfsession/getsession?openid=%s"; - String KFSESSION_GET_SESSION_LIST = "https://api.weixin.qq.com/customservice/kfsession/getsessionlist?kf_account=%s"; - String KFSESSION_GET_WAIT_CASE = "https://api.weixin.qq.com/customservice/kfsession/getwaitcase"; - String MSG_RECORD_LIST = "https://api.weixin.qq.com/customservice/msgrecord/getmsglist"; - String CUSTOM_TYPING = "https://api.weixin.qq.com/cgi-bin/message/custom/typing"; - /** ** 发送客服消息 diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java index f59158b2bd..c7daa1f991 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java @@ -11,18 +11,14 @@ import java.util.List; /** - *- * 微信营销接口 - *+ * 微信营销接口. * * @author 007 */ public interface WxMpMarketingService { - String API_URL_PREFIX = "https://api.weixin.qq.com/marketing/"; - /** *- * 创建数据源 + * 创建数据源. * 接口调用请求说明 * https://wximg.qq.com/wxp/pdftool/get.html?id=rkalQXDBM&pa=39 *@@ -35,7 +31,7 @@ public interface WxMpMarketingService { /** *- * 获取数据源信息 + * 获取数据源信息. ** * @param userActionSetId 数据源唯一ID @@ -43,7 +39,7 @@ public interface WxMpMarketingService { ListgetUserActionSets(Long userActionSetId) throws WxErrorException; /** - * 回传数据 + * 回传数据. * 接口调用请求说明 * https://wximg.qq.com/wxp/pdftool/get.html?id=rkalQXDBM&pa=39 * @@ -53,7 +49,7 @@ public interface WxMpMarketingService { /** * - * 获取朋友圈销售线索数据接口 + * 获取朋友圈销售线索数据接口. * 接口调用请求说明 * * http请求方式: POST @@ -65,7 +61,11 @@ public interface WxMpMarketingService { * @param endDate 结束日期 * @param filtering 过滤条件 * @param page 页码,获取指定页数据 - * @param page_size 一页获取的数据条数(1-100) + * @param pageSize 一页获取的数据条数(1-100) + * @return . + * @throws WxErrorException . + * @throws IOException . */ - WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, Listfiltering, Integer page, Integer page_size) throws WxErrorException, IOException; + WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, List filtering, Integer page, Integer pageSize) + throws WxErrorException, IOException; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java index f3e8db9d10..c986e53e34 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java @@ -14,31 +14,6 @@ * @author Binary Wang */ public interface WxMpMassMessageService { - /** - * 上传群发用的图文消息. - */ - String MEDIA_UPLOAD_NEWS_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; - /** - * 上传群发用的视频. - */ - String MEDIA_UPLOAD_VIDEO_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo"; - /** - * 分组群发消息. - */ - String MESSAGE_MASS_SENDALL_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"; - /** - * 按openId列表群发消息. - */ - String MESSAGE_MASS_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/send"; - /** - * 群发消息预览接口. - */ - String MESSAGE_MASS_PREVIEW_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; - /** - * 删除群发接口. - */ - String MESSAGE_MASS_DELETE_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/delete"; - /** * * 上传群发用的图文消息,上传后才能群发图文消息. @@ -85,7 +60,8 @@ public interface WxMpMassMessageService { /** ** 群发消息预览接口. - * 开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版。为了满足第三方平台开发者的需求,在保留对openID预览能力的同时,增加了对指定微信号发送预览的能力,但该能力每日调用次数有限制(100次),请勿滥用。 + * 开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版。为了满足第三方平台开发者的需求, + * 在保留对openID预览能力的同时,增加了对指定微信号发送预览的能力,但该能力每日调用次数有限制(100次),请勿滥用。 * 接口调用请求说明 * http请求方式: POST * https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token=ACCESS_TOKEN diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java index 6d762f1c44..686c86f20d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java @@ -22,19 +22,10 @@ * 即以https://api.weixin.qq.com/cgi-bin/material * 和 https://api.weixin.qq.com/cgi-bin/media开头的接口 *+ * + * @author Binary Wang */ public interface WxMpMaterialService { - String MEDIA_GET_URL = "https://api.weixin.qq.com/cgi-bin/media/get"; - String MEDIA_UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/upload?type=%s"; - String IMG_UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadimg"; - String MATERIAL_ADD_URL = "https://api.weixin.qq.com/cgi-bin/material/add_material?type=%s"; - String NEWS_ADD_URL = "https://api.weixin.qq.com/cgi-bin/material/add_news"; - String MATERIAL_GET_URL = "https://api.weixin.qq.com/cgi-bin/material/get_material"; - String NEWS_UPDATE_URL = "https://api.weixin.qq.com/cgi-bin/material/update_news"; - String MATERIAL_DEL_URL = "https://api.weixin.qq.com/cgi-bin/material/del_material"; - String MATERIAL_GET_COUNT_URL = "https://api.weixin.qq.com/cgi-bin/material/get_materialcount"; - String MATERIAL_BATCHGET_URL = "https://api.weixin.qq.com/cgi-bin/material/batchget_material"; - /** ** 新增临时素材 diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java index 37785365c1..e551f7d989 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java @@ -17,31 +17,6 @@ * @date 2018-08-30 */ public interface WxMpMemberCardService { - String MEMBER_CARD_CREATE = "https://api.weixin.qq.com/card/create"; - String MEMBER_CARD_ACTIVATE = "https://api.weixin.qq.com/card/membercard/activate"; - String MEMBER_CARD_USER_INFO_GET = "https://api.weixin.qq.com/card/membercard/userinfo/get"; - String MEMBER_CARD_UPDATE_USER = "https://api.weixin.qq.com/card/membercard/updateuser"; - /** - * 会员卡激活之微信开卡接口(wx_activate=true情况调用). - */ - String MEMBER_CARD_ACTIVATE_USER_FORM = "https://api.weixin.qq.com/card/membercard/activateuserform/set"; - - /** - * 获取会员卡开卡插件参数. - */ - String MEMBER_CARD_ACTIVATE_URL = "https://api.weixin.qq.com/card/membercard/activate/geturl"; - - /** - * 会员卡信息更新. - */ - String MEMBER_CARD_UPDATE = "https://api.weixin.qq.com/card/update"; - - /** - * 跳转型会员卡开卡字段. - * 获取用户提交资料(wx_activate=true情况调用),开发者根据activate_ticket获取到用户填写的信息 - */ - String MEMBER_CARD_ACTIVATE_TEMP_INFO = "https://api.weixin.qq.com/card/membercard/activatetempinfo/get"; - /** * 得到WxMpService. * diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java index f0fe549575..e7cef4ebb3 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java @@ -6,12 +6,11 @@ import me.chanjar.weixin.mp.bean.menu.WxMpMenu; /** - * 菜单相关操作接口 + * 菜单相关操作接口. * * @author Binary Wang */ public interface WxMpMenuService { - /** ** 自定义菜单创建接口 diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java index 474e3e6950..0c6912c38d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java @@ -8,18 +8,21 @@ import java.util.Map; /** - * 处理微信推送消息的处理器接口 + * 处理微信推送消息的处理器接口. * * @author Daniel Qian */ public interface WxMpMessageHandler { /** - * @param wxMessage + * 处理微信推送消息. + * + * @param wxMessage 微信推送消息 * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 - * @param wxMpService - * @param sessionManager + * @param wxMpService 服务类 + * @param sessionManager session管理器 * @return xml格式的消息,如果在异步规则里处理的话,可以返回null + * @throws WxErrorException 异常 */ WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Mapcontext, diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java index e85a2b65cb..86351e5acc 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java @@ -144,21 +144,21 @@ List getRules() { } /** - * 开始一个新的Route规则 + * 开始一个新的Route规则. */ public WxMpMessageRouterRule rule() { return new WxMpMessageRouterRule(this); } /** - * 处理微信消息 + * 处理微信消息. */ public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage, final Map context) { return route(wxMessage, context, null); } /** - * 处理微信消息 + * 处理微信消息. */ public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage, final Map context, WxMpService wxMpService) { if (wxMpService == null) { @@ -252,7 +252,7 @@ protected boolean isMsgDuplicated(WxMpXmlMessage wxMessage) { } /** - * 对session的访问结束 + * 对session的访问结束. */ protected void sessionEndAccess(WxMpXmlMessage wxMessage) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpOcrService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpOcrService.java new file mode 100644 index 0000000000..1748b55360 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpOcrService.java @@ -0,0 +1,50 @@ +package me.chanjar.weixin.mp.api; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.ocr.WxMpOcrIdCardResult; + +import java.io.File; + +/** + * 基于小程序或 H5 的身份证、银行卡、行驶证 OCR 识别. + * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=21516712284rHWMX + * + * @author Binary Wang + * @date 2019-06-22 + */ +public interface WxMpOcrService { + @AllArgsConstructor + @Getter + enum ImageType { + /** + * 拍照模型,带背景的图片. + */ + PHOTO("photo"), + /** + * 扫描模式,不带背景的图片. + */ + SCAN("scan"); + + private String type; + } + + /** + * 身份证OCR识别接口. + * + * @param imgType 图片类型 + * @param imgUrl 图片url地址 + * @throws WxErrorException . + */ + WxMpOcrIdCardResult idCard(ImageType imgType, String imgUrl) throws WxErrorException; + + /** + * 身份证OCR识别接口. + * + * @param imgType 图片类型 + * @param imgFile 图片文件对象 + * @throws WxErrorException . + */ + WxMpOcrIdCardResult idCard(ImageType imgType, File imgFile) throws WxErrorException; +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java index 131ebf6341..6622159d22 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java @@ -14,7 +14,6 @@ * @author Binary Wang */ public interface WxMpQrcodeService { - /** * * 换取临时二维码ticket diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index a0452ebad7..be8000d339 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -5,13 +5,14 @@ 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.mp.api.impl.BaseWxMpServiceImpl; import me.chanjar.weixin.mp.bean.WxMpSemanticQuery; import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo; import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult; import me.chanjar.weixin.mp.bean.result.WxMpUser; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.enums.TicketType; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; import java.util.Map; @@ -21,61 +22,6 @@ * @author chanjarster */ public interface WxMpService { - /** - * 获取access_token. - */ - String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; - /** - * 获得各种类型的ticket. - */ - String GET_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type="; - /** - * 长链接转短链接接口. - */ - String SHORTURL_API_URL = "https://api.weixin.qq.com/cgi-bin/shorturl"; - /** - * 语义查询接口. - */ - String SEMANTIC_SEMPROXY_SEARCH_URL = "https://api.weixin.qq.com/semantic/semproxy/search"; - /** - * 用code换取oauth2的access token. - */ - String OAUTH2_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"; - /** - * 刷新oauth2的access token. - */ - String OAUTH2_REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s"; - /** - * 用oauth2获取用户信息. - */ - String OAUTH2_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s"; - /** - * 验证oauth2的access token是否有效. - */ - String OAUTH2_VALIDATE_TOKEN_URL = "https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s"; - /** - * 获取微信服务器IP地址. - */ - String GET_CALLBACK_IP_URL = "https://api.weixin.qq.com/cgi-bin/getcallbackip"; - /** - * 第三方使用网站应用授权登录的url. - */ - String QRCONNECT_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"; - /** - * oauth2授权的url连接. - */ - String CONNECT_OAUTH2_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&connect_redirect=1#wechat_redirect"; - - /** - * 获取公众号的自动回复规则. - */ - String GET_CURRENT_AUTOREPLY_INFO_URL = "https://api.weixin.qq.com/cgi-bin/get_current_autoreply_info"; - - /** - * 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零. - */ - String CLEAR_QUOTA_URL = "https://api.weixin.qq.com/cgi-bin/clear_quota"; - /** **/ void setRetrySleepMillis(int retrySleepMillis); @@ -311,12 +307,14 @@ public interface WxMpService { /** * {@link Map* 验证消息的确来自微信服务器. @@ -158,7 +104,7 @@ public interface WxMpService { * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=长链接转短链接接口 **/ - String shortUrl(String long_url) throws WxErrorException; + String shortUrl(String longUrl) throws WxErrorException; /** *@@ -264,11 +210,21 @@ public interface WxMpService { /** * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求. + * + * @param queryParam 参数 + * @param url 请求接口地址 + * @return 接口响应字符串 + * @throws WxErrorException 异常 */ String get(String url, String queryParam) throws WxErrorException; /** * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求. + * + * @param postData 请求参数json值 + * @param url 请求接口地址 + * @return 接口响应字符串 + * @throws WxErrorException 异常 */ String post(String url, String postData) throws WxErrorException; @@ -278,14 +234,54 @@ public interface WxMpService { * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。 * 可以参考,{@link MediaUploadRequestExecutor}的实现方法 *+ * + * @param data 参数数据 + * @param executor 执行器 + * @param url 接口地址 + * @return 结果 + * @throws WxErrorException 异常 */ -T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; + T execute(RequestExecutor executor, String url, E data) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求. + * + * @param queryParam 参数 + * @param url 请求接口地址 + * @return 接口响应字符串 + * @throws WxErrorException 异常 + */ + String get(WxMpApiUrl url, String queryParam) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求. + * + * @param postData 请求参数json值 + * @param url 请求接口地址 + * @return 接口响应字符串 + * @throws WxErrorException 异常 + */ + String post(WxMpApiUrl url, String postData) throws WxErrorException; /** * + * Service没有实现某个API的时候,可以用这个, + * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。 + * 可以参考,{@link MediaUploadRequestExecutor}的实现方法 + *+ * + * @param data 参数数据 + * @param executor 执行器 + * @param url 接口地址 + * @return 结果 + * @throws WxErrorException 异常 + */ +T execute(RequestExecutor executor, WxMpApiUrl url, E data) throws WxErrorException; + + /** * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试. + * * @param retrySleepMillis 默认:1000ms - * } 加入新的 {@link WxMpConfigStorage},适用于动态添加新的微信公众号配置 + * * @param configStorage 新的微信配置 */ void addConfigStorage(String mpId, WxMpConfigStorage configStorage); /** * 从{@link Map } 移除 {@link String mpId} 所对应的 {@link WxMpConfigStorage},适用于动态移除微信公众号配置 + * * @param mpId 对应公众号的标识 */ void removeConfigStorage(String mpId); @@ -324,19 +322,22 @@ public interface WxMpService { /** * 注入多个 {@link WxMpConfigStorage} 的实现. 并为每个 {@link WxMpConfigStorage} 赋予不同的 {@link String mpId} 值 * 随机采用一个{@link String mpId}进行Http初始化操作 + * * @param configStorages WxMpConfigStorage map */ void setMultiConfigStorages(Map configStorages); /** * 注入多个 {@link WxMpConfigStorage} 的实现. 并为每个 {@link WxMpConfigStorage} 赋予不同的 {@link String label} 值 + * * @param configStorages WxMpConfigStorage map - * @param defaultMpId 设置一个{@link WxMpConfigStorage} 所对应的{@link String mpId}进行Http初始化 + * @param defaultMpId 设置一个{@link WxMpConfigStorage} 所对应的{@link String mpId}进行Http初始化 */ void setMultiConfigStorages(Map configStorages, String defaultMpId); /** * 进行相应的公众号切换 + * * @param mpId 公众号标识 * @return 切换是否成功 */ @@ -344,6 +345,7 @@ public interface WxMpService { /** * 进行相应的公众号切换 + * * @param mpId 公众号标识 * @return 切换成功,则返回当前对象,方便链式调用,否则抛出异常 */ @@ -492,6 +494,13 @@ public interface WxMpService { */ WxMpWifiService getWifiService(); + /** + * 返回WIFI接口方法的实现类对象,以方便调用其各个接口. + * + * @return WxMpWifiService + */ + WxMpOcrService getOcrService(); + void setKefuService(WxMpKefuService kefuService); void setMaterialService(WxMpMaterialService materialService); @@ -525,4 +534,15 @@ public interface WxMpService { void setAiOpenService(WxMpAiOpenService aiOpenService); void setMarketingService(WxMpMarketingService marketingService); + + void setOcrService(WxMpOcrService ocrService); + + /** + * 返回评论数据管理接口方法的实现类对象,以方便调用其各个接口. + * + * @return WxMpWifiService + */ + WxMpCommentService getCommentService(); + + void setCommentService(WxMpCommentService commentService); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java index 1f6c3052e7..8c45dadea0 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java @@ -7,12 +7,11 @@ import me.chanjar.weixin.mp.bean.shake.*; /** - * 摇一摇周边的相关接口 + * 摇一摇周边的相关接口. * * @author rememberber */ public interface WxMpShakeService { - /** * * 获取设备及用户信息
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java index 7b0913e688..82eaa5eeb5 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java @@ -8,20 +8,12 @@ import java.util.List; /** - * 门店管理的相关接口代码 - *+ * 门店管理的相关接口代码. * Created by Binary Wang on 2016-09-23. * * @author Binary Wang */ public interface WxMpStoreService
{ - String POI_GET_WX_CATEGORY_URL = "https://api.weixin.qq.com/cgi-bin/poi/getwxcategory"; - String POI_UPDATE_URL = "https://api.weixin.qq.com/cgi-bin/poi/updatepoi"; - String POI_LIST_URL = "https://api.weixin.qq.com/cgi-bin/poi/getpoilist"; - String POI_DEL_URL = "https://api.weixin.qq.com/cgi-bin/poi/delpoi"; - String POI_GET_URL = "https://api.weixin.qq.com/cgi-bin/poi/getpoi"; - String POI_ADD_URL = "https://api.weixin.qq.com/cgi-bin/poi/addpoi"; - /** * * 创建门店 diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpSubscribeMsgService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpSubscribeMsgService.java index 1e91d9a2d6..549018e63b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpSubscribeMsgService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpSubscribeMsgService.java @@ -13,7 +13,6 @@ * @date 2018-01-22 上午11:07 */ public interface WxMpSubscribeMsgService { - /** ** 构造用户订阅一条模板消息授权的url连接 diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java index f57c469c01..656840cbfa 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java @@ -17,7 +17,6 @@ **/ public interface WxMpTemplateMsgService { - /** ** 设置所属行业 diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java index 71b6b17092..00eea89e74 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java @@ -1,25 +1,19 @@ package me.chanjar.weixin.mp.api; -import java.util.List; - import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.bean.WxMpUserQuery; import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid; import me.chanjar.weixin.mp.bean.result.WxMpUser; import me.chanjar.weixin.mp.bean.result.WxMpUserList; +import java.util.List; + /** * 用户管理相关操作接口. * * @author Binary Wang */ public interface WxMpUserService { - String USER_INFO_BATCH_GET_URL = "https://api.weixin.qq.com/cgi-bin/user/info/batchget"; - String USER_GET_URL = "https://api.weixin.qq.com/cgi-bin/user/get"; - String USER_INFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info"; - String USER_INFO_UPDATE_REMARK_URL = "https://api.weixin.qq.com/cgi-bin/user/info/updateremark"; - String USER_CHANGE_OPENID_URL = "http://api.weixin.qq.com/cgi-bin/changeopenid"; - /** ** 设置用户备注名 @@ -87,7 +81,9 @@ public interface WxMpUserService { /** ** 获取用户列表 - * 公众号可通过本接口来获取帐号的关注者列表,关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的)组成。一次拉取调用最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足需求。 + * 公众号可通过本接口来获取帐号的关注者列表, + * 关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的)组成。 + * 一次拉取调用最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足需求。 * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140840&token=&lang=zh_CN * http请求方式: GET(请使用https协议) * 接口地址:https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID @@ -101,11 +97,12 @@ public interface WxMpUserService { ** 微信公众号主体变更迁移用户 openid * 详情请见: http://kf.qq.com/faq/170221aUnmmU170221eUZJNf.html + * http://kf.qq.com/faq/1901177NrqMr190117nqYJze.html * http请求方式: POST * 接口地址:https://api.weixin.qq.com/cgi-bin/changeopenid?access_token=ACCESS_TOKEN ** - * @param fromAppid 原公众号的 appid + * @param fromAppid 原公众号的 appid * @param openidList 需要转换的openid,这些必须是旧账号目前关注的才行,否则会出错;一次最多100个 */ ListchangeOpenid(String fromAppid, List openidList) throws WxErrorException; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java index 031585053e..c1549aff41 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java @@ -13,7 +13,6 @@ * @author Binary Wang */ public interface WxMpUserTagService { - /** * * 创建标签 diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpWifiService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpWifiService.java index 9cda53bbb5..b0876c7686 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpWifiService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpWifiService.java @@ -1,6 +1,7 @@ package me.chanjar.weixin.mp.api; import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.wifi.WxMpWifiShopDataResult; import me.chanjar.weixin.mp.bean.wifi.WxMpWifiShopListResult; /** @@ -21,8 +22,45 @@ public interface WxMpWifiService { * http请求方式: POST * 请求URL:https://api.weixin.qq.com/bizwifi/shop/list?access_token=ACCESS_TOKEN *- * @param pageIndex 分页下标,默认从1开始 + * + * @param pageIndex 分页下标,默认从1开始 * @param pageSize 每页的个数,默认10个,最大20个 + * @return 结果 + * @throws WxErrorException 异常 */ WxMpWifiShopListResult listShop(int pageIndex, int pageSize) throws WxErrorException; + + /** + *+ * 查询门店Wi-Fi信息 + * 通过此接口查询某一门店的详细Wi-Fi信息,包括门店内的设备类型、ssid、密码、设备数量、商家主页URL、顶部常驻入口文案。 + * + * http请求方式: POST + * 请求URL:https://api.weixin.qq.com/bizwifi/shop/get?access_token=ACCESS_TOKEN + * POST数据格式:JSON + *+ * + * @param shopId 门店ID + * @return 结果 + * @throws WxErrorException 异常 + */ + WxMpWifiShopDataResult getShopWifiInfo(int shopId) throws WxErrorException; + + /** + *+ * 修改门店网络信息. + * 通过此接口修改门店的网络信息,包括网络名称(ssid)或密码。需注意: + * 只有门店下已添加Wi-Fi网络信息,才能调用此接口修改网络信息;添加方式请参考“添加密码型设备”和"添加portal型设备”接口文档。 + * 网络信息修改后,密码型设备需同步修改所有设备的ssid或密码;portal型设备需修改所有设备的ssid,并按照《硬件鉴权协议接口》修改“第二步:改造移动端portal页面”中的ssid参数,否则将无法正常连网。 + * 文档地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1457435413 + *+ * + * @param shopId 门店ID + * @param oldSsid 旧的ssid + * @param ssid 无线网络设备的ssid。32个字符以内;ssid支持中文,但可能因设备兼容性问题导致显示乱码,或无法连接等问题,相关风险自行承担! 当门店下是portal型设备时,ssid必填;当门店下是密码型设备时,ssid选填,且ssid和密码必须有一个以大写字母“WX”开头 + * @param password 无线网络设备的密码。8-24个字符;不能包含中文字符; 当门店下是密码型设备时,才可填写password,且ssid和密码必须有一个以大写字母“WX”开头 + * @return 是否更新成功 + * @throws WxErrorException . + */ + boolean updateShopWifiInfo(int shopId, String oldSsid, String ssid, String password) throws WxErrorException; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java index 534ea1390f..f7969eae75 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java @@ -6,6 +6,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; @@ -21,26 +22,27 @@ import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult; import me.chanjar.weixin.mp.bean.result.WxMpUser; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.enums.TicketType; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder; import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Map; import java.util.concurrent.locks.Lock; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.*; + /** * 基础实现类. * * @author someone */ +@Slf4j public abstract class BaseWxMpServiceImplimplements WxMpService, RequestHttp { private static final JsonParser JSON_PARSER = new JsonParser(); - protected final Logger log = LoggerFactory.getLogger(this.getClass()); - protected WxSessionManager sessionManager = new StandardSessionManager(); private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); @@ -61,6 +63,8 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH private WxMpAiOpenService aiOpenService = new WxMpAiOpenServiceImpl(this); private WxMpWifiService wifiService = new WxMpWifiServiceImpl(this); private WxMpMarketingService marketingService = new WxMpMarketingServiceImpl(this); + private WxMpCommentService commentService = new WxMpCommentServiceImpl(this); + private WxMpOcrService ocrService = new WxMpOcrServiceImpl(this); private Map configStorageMap; @@ -73,7 +77,7 @@ public boolean checkSignature(String timestamp, String nonce, String signature) return SHA1.gen(this.getWxMpConfigStorage().getToken(), timestamp, nonce) .equals(signature); } catch (Exception e) { - this.log.error("Checking signature failed, and the reason is :" + e.getMessage()); + log.error("Checking signature failed, and the reason is :" + e.getMessage()); return false; } } @@ -94,7 +98,7 @@ public String getTicket(TicketType type, boolean forceRefresh) throws WxErrorExc if (this.getWxMpConfigStorage().isTicketExpired(type)) { String responseContent = execute(SimpleGetRequestExecutor.create(this), - WxMpService.GET_TICKET_URL + type.getCode(), null); + GET_TICKET_URL.getUrl(this.getWxMpConfigStorage()) + type.getCode(), null); JsonObject tmpJsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); @@ -143,27 +147,27 @@ public String shortUrl(String longUrl) throws WxErrorException { JsonObject o = new JsonObject(); o.addProperty("action", "long2short"); o.addProperty("long_url", longUrl); - String responseContent = this.post(WxMpService.SHORTURL_API_URL, o.toString()); + String responseContent = this.post(SHORTURL_API_URL, o.toString()); JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); return tmpJsonElement.getAsJsonObject().get("short_url").getAsString(); } @Override public WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException { - String responseContent = this.post(WxMpService.SEMANTIC_SEMPROXY_SEARCH_URL, semanticQuery.toJson()); + String responseContent = this.post(SEMANTIC_SEMPROXY_SEARCH_URL, semanticQuery.toJson()); return WxMpSemanticQueryResult.fromJson(responseContent); } @Override public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { - return String.format(WxMpService.CONNECT_OAUTH2_AUTHORIZE_URL, + return String.format(CONNECT_OAUTH2_AUTHORIZE_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(), URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state)); } @Override public String buildQrConnectUrl(String redirectURI, String scope, String state) { - return String.format(WxMpService.QRCONNECT_URL, - this.getWxMpConfigStorage().getAppId(), URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state)); + return String.format(QRCONNECT_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(), + URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state)); } private WxMpOAuth2AccessToken getOAuth2AccessToken(String url) throws WxErrorException { @@ -178,13 +182,14 @@ private WxMpOAuth2AccessToken getOAuth2AccessToken(String url) throws WxErrorExc @Override public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { - String url = String.format(WxMpService.OAUTH2_ACCESS_TOKEN_URL, this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret(), code); + String url = String.format(OAUTH2_ACCESS_TOKEN_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(), + this.getWxMpConfigStorage().getSecret(), code); return this.getOAuth2AccessToken(url); } @Override public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { - String url = String.format(WxMpService.OAUTH2_REFRESH_TOKEN_URL, this.getWxMpConfigStorage().getAppId(), refreshToken); + String url = String.format(OAUTH2_REFRESH_TOKEN_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(), refreshToken); return this.getOAuth2AccessToken(url); } @@ -194,7 +199,7 @@ public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken token, String lang) thro lang = "zh_CN"; } - String url = String.format(WxMpService.OAUTH2_USERINFO_URL, token.getAccessToken(), token.getOpenId(), lang); + String url = String.format(OAUTH2_USERINFO_URL.getUrl(this.getWxMpConfigStorage()), token.getAccessToken(), token.getOpenId(), lang); try { RequestExecutor executor = SimpleGetRequestExecutor.create(this); @@ -207,7 +212,7 @@ public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken token, String lang) thro @Override public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken token) { - String url = String.format(WxMpService.OAUTH2_VALIDATE_TOKEN_URL, token.getAccessToken(), token.getOpenId()); + String url = String.format(OAUTH2_VALIDATE_TOKEN_URL.getUrl(this.getWxMpConfigStorage()), token.getAccessToken(), token.getOpenId()); try { SimpleGetRequestExecutor.create(this).execute(url, null); @@ -221,7 +226,7 @@ public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken token) { @Override public String[] getCallbackIP() throws WxErrorException { - String responseContent = this.get(WxMpService.GET_CALLBACK_IP_URL, null); + String responseContent = this.get(GET_CALLBACK_IP_URL, null); JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); JsonArray ipList = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); String[] ipArray = new String[ipList.size()]; @@ -248,11 +253,26 @@ public String get(String url, String queryParam) throws WxErrorException { return execute(SimpleGetRequestExecutor.create(this), url, queryParam); } + @Override + public String get(WxMpApiUrl url, String queryParam) throws WxErrorException { + return this.get(url.getUrl(this.getWxMpConfigStorage()), queryParam); + } + @Override public String post(String url, String postData) throws WxErrorException { return execute(SimplePostRequestExecutor.create(this), url, postData); } + @Override + public String post(WxMpApiUrl url, String postData) throws WxErrorException { + return this.post(url.getUrl(this.getWxMpConfigStorage()), postData); + } + + @Override + public T execute(RequestExecutor executor, WxMpApiUrl url, E data) throws WxErrorException { + return this.execute(executor, url.getUrl(this.getWxMpConfigStorage()), data); + } + /** * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求. */ @@ -264,7 +284,7 @@ public T execute(RequestExecutor executor, String uri, E data) thro return this.executeInternal(executor, uri, data); } catch (WxErrorException e) { if (retryTimes + 1 > this.maxRetryTimes) { - this.log.warn("重试达到最大次数【{}】", maxRetryTimes); + log.warn("重试达到最大次数【{}】", maxRetryTimes); //最后一次重试失败后,直接抛出异常,不再等待 throw new RuntimeException("微信服务端异常,超出重试次数"); } @@ -274,7 +294,7 @@ public T execute(RequestExecutor executor, String uri, E data) thro if (error.getErrorCode() == -1) { int sleepMillis = this.retrySleepMillis * (1 << retryTimes); try { - this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); + log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); Thread.sleep(sleepMillis); } catch (InterruptedException e1) { throw new RuntimeException(e1); @@ -285,11 +305,11 @@ public T execute(RequestExecutor executor, String uri, E data) thro } } while (retryTimes++ < this.maxRetryTimes); - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + log.warn("重试达到最大次数【{}】", this.maxRetryTimes); throw new RuntimeException("微信服务端异常,超出重试次数"); } - public T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + protected T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { E dataForLog = DataUtils.handleDataWithSecret(data); if (uri.contains("access_token=")) { @@ -302,7 +322,7 @@ public T executeInternal(RequestExecutor executor, String uri, E da try { T result = executor.execute(uriWithAccessToken, data); - this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result); + log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result); return result; } catch (WxErrorException e) { WxError error = e.getError(); @@ -321,12 +341,12 @@ public T executeInternal(RequestExecutor executor, String uri, E da } if (error.getErrorCode() != 0) { - this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error); + log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error); throw new WxErrorException(error, e); } return null; } catch (IOException e) { - this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage()); + log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage()); throw new WxErrorException(WxError.builder().errorMsg(e.getMessage()).build(), e); } } @@ -582,6 +602,11 @@ public WxMpWifiService getWifiService() { return this.wifiService; } + @Override + public WxMpOcrService getOcrService() { + return this.ocrService; + } + @Override public WxMpMarketingService getMarketingService() { return this.marketingService; @@ -591,4 +616,19 @@ public WxMpMarketingService getMarketingService() { public void setMarketingService(WxMpMarketingService marketingService) { this.marketingService = marketingService; } + + @Override + public void setOcrService(WxMpOcrService ocrService) { + this.ocrService = ocrService; + } + + @Override + public WxMpCommentService getCommentService() { + return this.commentService; + } + + @Override + public void setCommentService(WxMpCommentService commentService) { + this.commentService = commentService; + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java index 628b6c55f8..5ac3be31fd 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java @@ -1,8 +1,7 @@ package me.chanjar.weixin.mp.api.impl; -import java.io.File; - import com.google.gson.JsonParser; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; @@ -11,6 +10,10 @@ import me.chanjar.weixin.mp.enums.AiLangType; import me.chanjar.weixin.mp.util.requestexecuter.voice.VoiceUploadRequestExecutor; +import java.io.File; + +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.AiOpen.*; + /** * * Created by BinaryWang on 2018/6/9. @@ -18,13 +21,10 @@ * * @author Binary Wang */ +@RequiredArgsConstructor public class WxMpAiOpenServiceImpl implements WxMpAiOpenService { private static final JsonParser JSON_PARSER = new JsonParser(); - private WxMpService wxMpService; - - public WxMpAiOpenServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public void uploadVoice(String voiceId, AiLangType lang, File voiceFile) throws WxErrorException { @@ -33,7 +33,7 @@ public void uploadVoice(String voiceId, AiLangType lang, File voiceFile) throws } this.wxMpService.execute(VoiceUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), - String.format(VOICE_UPLOAD_URL, "mp3", voiceId, lang.getCode()), + String.format(VOICE_UPLOAD_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), "mp3", voiceId, lang.getCode()), voiceFile); } @@ -45,7 +45,8 @@ public String recogniseVoice(String voiceId, AiLangType lang, File voiceFile) th @Override public String translate(AiLangType langFrom, AiLangType langTo, String content) throws WxErrorException { - String response = this.wxMpService.post(String.format(TRANSLATE_URL, langFrom.getCode(), langTo.getCode()), content); + String response = this.wxMpService.post(String.format(TRANSLATE_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), + langFrom.getCode(), langTo.getCode()), content); WxError error = WxError.fromJson(response, WxType.MP); if (error.getErrorCode() != 0) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java index bdd1990440..ec523f9a25 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java @@ -2,20 +2,21 @@ import com.google.gson.*; import com.google.gson.reflect.TypeToken; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.bean.WxCardApiSignature; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.RandomUtils; -import me.chanjar.weixin.common.util.crypto.SHA1; import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; import me.chanjar.weixin.mp.api.WxMpCardService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.card.*; import me.chanjar.weixin.mp.enums.TicketType; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.Arrays; import java.util.concurrent.locks.Lock; @@ -25,46 +26,22 @@ * * @author BinaryWang */ +@Slf4j +@RequiredArgsConstructor public class WxMpCardServiceImpl implements WxMpCardService { - private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class); - - private WxMpService wxMpService; - private static final Gson GSON = WxMpGsonBuilder.create(); - - public WxMpCardServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public WxMpService getWxMpService() { return this.wxMpService; } - /** - * 获得卡券api_ticket,不强制刷新卡券api_ticket. - * - * @return 卡券api_ticket - * @see #getCardApiTicket(boolean) - */ @Override public String getCardApiTicket() throws WxErrorException { return getCardApiTicket(false); } - /** - *- * 获得卡券api_ticket. - * 获得时会检查卡券apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干 - * - * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD - * .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94 - * .9F.E6.88.90.E7.AE.97.E6.B3.95 - *- * - * @param forceRefresh 强制刷新 - * @return 卡券api_ticket - */ @Override public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { final TicketType type = TicketType.WX_CARD; @@ -78,7 +55,7 @@ public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { if (this.getWxMpService().getWxMpConfigStorage().isTicketExpired(type)) { String responseContent = this.wxMpService.execute(SimpleGetRequestExecutor - .create(this.getWxMpService().getRequestHttp()), CARD_GET_TICKET, null); + .create(this.getWxMpService().getRequestHttp()), WxMpApiUrl.Card.CARD_GET_TICKET, null); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); String cardApiTicket = tmpJsonObject.get("ticket").getAsString(); @@ -91,32 +68,22 @@ public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { return this.getWxMpService().getWxMpConfigStorage().getTicket(type); } - /** - *- * 创建调用卡券api时所需要的签名 - * - * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD - * .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94 - * .9F.E6.88.90.E7.AE.97.E6.B3.95 - *- * - * @param optionalSignParam 参与签名的参数数组。 - * 可以为下列字段:app_id, card_id, card_type, code, openid, location_id - * 注意:当做wx.chooseCard调用时,必须传入app_id参与签名,否则会造成签名失败导致拉取卡券列表为空 - * @return 卡券Api签名对象 - */ @Override - public WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws - WxErrorException { + public WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws WxErrorException { long timestamp = System.currentTimeMillis() / 1000; String nonceStr = RandomUtils.getRandomStr(); String cardApiTicket = getCardApiTicket(false); - String[] signParam = Arrays.copyOf(optionalSignParam, optionalSignParam.length + 3); - signParam[optionalSignParam.length] = String.valueOf(timestamp); - signParam[optionalSignParam.length + 1] = nonceStr; - signParam[optionalSignParam.length + 2] = cardApiTicket; - String signature = SHA1.gen(signParam); + String[] signParams = Arrays.copyOf(optionalSignParam, optionalSignParam.length + 3); + signParams[optionalSignParam.length] = String.valueOf(timestamp); + signParams[optionalSignParam.length + 1] = nonceStr; + signParams[optionalSignParam.length + 2] = cardApiTicket; + StringBuilder sb = new StringBuilder(); + for (String a : signParams) { + sb.append(a); + } + String signature = DigestUtils.sha1Hex(sb.toString()); + WxCardApiSignature cardApiSignature = new WxCardApiSignature(); cardApiSignature.setTimestamp(timestamp); cardApiSignature.setNonceStr(nonceStr); @@ -124,17 +91,11 @@ public WxCardApiSignature createCardApiSignature(String... optionalSignParam) th return cardApiSignature; } - /** - * 卡券Code解码 - * - * @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得 - * @return 解密后的Code - */ @Override public String decryptCardCode(String encryptCode) throws WxErrorException { JsonObject param = new JsonObject(); param.addProperty("encrypt_code", encryptCode); - String responseContent = this.wxMpService.post(CARD_CODE_DECRYPT, param.toString()); + String responseContent = this.wxMpService.post(WxMpApiUrl.Card.CARD_CODE_DECRYPT, param.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); JsonPrimitive jsonPrimitive = tmpJsonObject.getAsJsonPrimitive("code"); @@ -147,33 +108,18 @@ public WxMpCardResult queryCardCode(String cardId, String code, boolean checkCon param.addProperty("card_id", cardId); param.addProperty("code", code); param.addProperty("check_consume", checkConsume); - String responseContent = this.wxMpService.post(CARD_CODE_GET, param.toString()); + String responseContent = this.wxMpService.post(WxMpApiUrl.Card.CARD_CODE_GET, param.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxMpGsonBuilder.create().fromJson(tmpJsonElement, new TypeToken() { }.getType()); } - /** - * 卡券Code核销。核销失败会抛出异常 - * - * @param code 单张卡券的唯一标准 - * @return 调用返回的JSON字符串。 - *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 - */ @Override public String consumeCardCode(String code) throws WxErrorException { return consumeCardCode(code, null); } - /** - * 卡券Code核销。核销失败会抛出异常 - * - * @param code 单张卡券的唯一标准 - * @param cardId 当自定义Code卡券时需要传入card_id - * @return 调用返回的JSON字符串。 - *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 - */ @Override public String consumeCardCode(String code, String cardId) throws WxErrorException { JsonObject param = new JsonObject(); @@ -183,34 +129,23 @@ public String consumeCardCode(String code, String cardId) throws WxErrorExceptio param.addProperty("card_id", cardId); } - return this.wxMpService.post(CARD_CODE_CONSUME, param.toString()); + return this.wxMpService.post(WxMpApiUrl.Card.CARD_CODE_CONSUME, param.toString()); } - /** - * 卡券Mark接口。 - * 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住), - * 才能进一步调用核销接口,否则报错。 - * - * @param code 卡券的code码 - * @param cardId 卡券的ID - * @param openId 用券用户的openid - * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 - */ @Override - public void markCardCode(String code, String cardId, String openId, boolean isMark) throws - WxErrorException { + public void markCardCode(String code, String cardId, String openId, boolean isMark) throws WxErrorException { JsonObject param = new JsonObject(); param.addProperty("code", code); param.addProperty("card_id", cardId); param.addProperty("openid", openId); param.addProperty("is_mark", isMark); - String responseContent = this.getWxMpService().post(CARD_CODE_MARK, param.toString()); + String responseContent = this.getWxMpService().post(WxMpApiUrl.Card.CARD_CODE_MARK, param.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); WxMpCardResult cardResult = WxMpGsonBuilder.create().fromJson(tmpJsonElement, new TypeToken() { }.getType()); if (!"0".equals(cardResult.getErrorCode())) { - this.log.warn("朋友的券mark失败:{}", cardResult.getErrorMsg()); + log.warn("朋友的券mark失败:{}", cardResult.getErrorMsg()); } } @@ -218,7 +153,7 @@ public void markCardCode(String code, String cardId, String openId, boolean isMa public String getCardDetail(String cardId) throws WxErrorException { JsonObject param = new JsonObject(); param.addProperty("card_id", cardId); - String responseContent = this.wxMpService.post(CARD_GET, param.toString()); + String responseContent = this.wxMpService.post(WxMpApiUrl.Card.CARD_GET, param.toString()); // 判断返回值 JsonObject json = (new JsonParser()).parse(responseContent).getAsJsonObject(); @@ -233,76 +168,65 @@ public String getCardDetail(String cardId) throws WxErrorException { return responseContent; } - /** - * 添加测试白名单. - * - * @param openid 用户的openid - */ @Override public String addTestWhiteList(String openid) throws WxErrorException { JsonArray array = new JsonArray(); array.add(openid); JsonObject jsonObject = new JsonObject(); jsonObject.add("openid", array); - String respone = this.wxMpService.post(CARD_TEST_WHITELIST, GSON.toJson(jsonObject)); - return respone; + return this.wxMpService.post(WxMpApiUrl.Card.CARD_TEST_WHITELIST, GSON.toJson(jsonObject)); } @Override public WxMpCardCreateResult createCard(WxMpCardCreateMessage cardCreateMessage) throws WxErrorException { - - String response = this.wxMpService.post(CARD_CREATE, GSON.toJson(cardCreateMessage)); + String response = this.wxMpService.post(WxMpApiUrl.Card.CARD_CREATE, GSON.toJson(cardCreateMessage)); return WxMpCardCreateResult.fromJson(response); } - /** - * 创建卡券二维码. - */ @Override public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr) throws WxErrorException { - return createQrcodeCard(cardId, outerStr, 0); + return this.createQrcodeCard(cardId, outerStr, 0); } - /** - * 创建卡券二维码. - * - * @param cardId 卡券编号 - * @param outerStr 二维码标识 - * @param expiresIn 失效时间,单位秒,不填默认365天 - */ @Override public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn) throws WxErrorException { + return this.createQrcodeCard(cardId, outerStr, expiresIn, null, null, false); + } + + @Override + public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn, String openid, + String code, boolean isUniqueCode) throws WxErrorException { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("action_name", "QR_CARD"); if (expiresIn > 0) { jsonObject.addProperty("expire_seconds", expiresIn); } + JsonObject actionInfoJson = new JsonObject(); JsonObject cardJson = new JsonObject(); + if (openid != null) { + cardJson.addProperty("openid", openid); + } + + if (code != null) { + cardJson.addProperty("code", code); + } + + cardJson.addProperty("is_unique_code", isUniqueCode); cardJson.addProperty("card_id", cardId); cardJson.addProperty("outer_str", outerStr); actionInfoJson.add("card", cardJson); jsonObject.add("action_info", actionInfoJson); - return WxMpCardQrcodeCreateResult.fromJson(this.wxMpService.post(CARD_QRCODE_CREATE, GSON.toJson(jsonObject))); + + return WxMpCardQrcodeCreateResult.fromJson(this.wxMpService.post(WxMpApiUrl.Card.CARD_QRCODE_CREATE, GSON.toJson(jsonObject))); } - /** - * 创建卡券货架接口. - */ @Override public WxMpCardLandingPageCreateResult createLandingPage(WxMpCardLandingPageCreateRequest request) throws WxErrorException { - String response = this.wxMpService.post(CARD_LANDING_PAGE_CREATE, GSON.toJson(request)); + String response = this.wxMpService.post(WxMpApiUrl.Card.CARD_LANDING_PAGE_CREATE, GSON.toJson(request)); return WxMpCardLandingPageCreateResult.fromJson(response); } - /** - * 将用户的卡券设置为失效状态. - * 详见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025272&anchor=9 - * - * @param cardId 卡券编号 - * @param code 用户会员卡号 - * @param reason 设置为失效的原因 - */ @Override public String unavailableCardCode(String cardId, String code, String reason) throws WxErrorException { if (StringUtils.isAnyBlank(cardId, code, reason)) { @@ -312,7 +236,7 @@ public String unavailableCardCode(String cardId, String code, String reason) thr jsonRequest.addProperty("card_id", cardId); jsonRequest.addProperty("code", code); jsonRequest.addProperty("reason", reason); - return this.wxMpService.post(CARD_CODE_UNAVAILABLE, GSON.toJson(jsonRequest)); + return this.wxMpService.post(WxMpApiUrl.Card.CARD_CODE_UNAVAILABLE, GSON.toJson(jsonRequest)); } @Override @@ -322,7 +246,7 @@ public WxMpCardDeleteResult deleteCard(String cardId) throws WxErrorException { } JsonObject param = new JsonObject(); param.addProperty("card_id", cardId); - String response = this.wxMpService.post(CARD_DELETE, param.toString()); + String response = this.wxMpService.post(WxMpApiUrl.Card.CARD_DELETE, param.toString()); return WxMpCardDeleteResult.fromJson(response); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCommentServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCommentServiceImpl.java new file mode 100644 index 0000000000..f58280aeee --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCommentServiceImpl.java @@ -0,0 +1,27 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.gson.JsonObject; +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpCommentService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; + +/** + * @author Binary Wang + * @date 2019-06-16 + */ +@RequiredArgsConstructor +public class WxMpCommentServiceImpl implements WxMpCommentService { + private final WxMpService wxMpService; + + @Override + public void open(Integer msgDataId, Integer index) throws WxErrorException { + JsonObject json = new JsonObject(); + json.addProperty("msg_data_id", msgDataId); + if (index != null) { + json.addProperty("index", index); + } + this.wxMpService.post(WxMpApiUrl.Comment.OPEN, json.toString()); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java index bf60892a1b..a3523c0d77 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java @@ -1,30 +1,30 @@ package me.chanjar.weixin.mp.api.impl; import com.google.gson.JsonObject; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpDataCubeService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.datacube.*; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; import org.apache.commons.lang3.time.FastDateFormat; import java.text.Format; import java.util.Date; import java.util.List; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.DataCube.*; + /** * Created by Binary Wang on 2016/8/23. * * @author binarywang (https://github.com/binarywang) */ +@RequiredArgsConstructor public class WxMpDataCubeServiceImpl implements WxMpDataCubeService { - private final Format dateFormat = FastDateFormat.getInstance("yyyy-MM-dd"); - private WxMpService wxMpService; - - public WxMpDataCubeServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public List getUserSummary(Date beginDate, Date endDate) throws WxErrorException { @@ -69,7 +69,7 @@ public List getUserShareHour(Date beginDate, Date endDa return this.getArticleResults(GET_USER_SHARE_HOUR, beginDate, endDate); } - private List getArticleResults(String url, Date beginDate, Date endDate) throws WxErrorException { + private List getArticleResults(WxMpApiUrl url, Date beginDate, Date endDate) throws WxErrorException { String responseContent = this.wxMpService.post(url, buildParams(beginDate, endDate)); return WxDataCubeArticleResult.fromJson(responseContent); } @@ -109,13 +109,13 @@ public List getUpstreamMsgDistMonth(Date beginDate, Date en return this.getUpstreamMsg(GET_UPSTREAM_MSG_DIST_MONTH, beginDate, endDate); } - private List getUpstreamMsg(String url, Date beginDate, Date endDate) throws WxErrorException { + private List getUpstreamMsg(WxMpApiUrl url, Date beginDate, Date endDate) throws WxErrorException { String responseContent = this.wxMpService.post(url, buildParams(beginDate, endDate)); return WxDataCubeMsgResult.fromJson(responseContent); } @Override - public List getInterfaceSummary(Date beginDate, Date endDate) throws WxErrorException { + public List getInterfaceSummary(Date beginDate, Date endDate) throws WxErrorException { String responseContent = this.wxMpService.post(GET_INTERFACE_SUMMARY, buildParams(beginDate, endDate)); return WxDataCubeInterfaceResult.fromJson(responseContent); } @@ -128,7 +128,7 @@ private String buildParams(Date beginDate, Date endDate) { } @Override - public List getInterfaceSummaryHour(Date beginDate, Date endDate) throws WxErrorException { + public List getInterfaceSummaryHour(Date beginDate, Date endDate) throws WxErrorException { String responseContent = this.wxMpService.post(GET_INTERFACE_SUMMARY_HOUR, buildParams(beginDate, endDate)); return WxDataCubeInterfaceResult.fromJson(responseContent); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java index 3fe464a89e..3aa122a533 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java @@ -1,86 +1,76 @@ package me.chanjar.weixin.mp.api.impl; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpDeviceService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.device.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; + +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Device.*; /** * Created by keungtung on 10/12/2016. + * + * @author keungtung */ +@Slf4j +@RequiredArgsConstructor public class WxMpDeviceServiceImpl implements WxMpDeviceService { - private static final String API_URL_PREFIX = "https://api.weixin.qq.com/device"; - private static Logger log = LoggerFactory.getLogger(WxMpMenuServiceImpl.class); - - private WxMpService wxMpService; - - public WxMpDeviceServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public TransMsgResp transMsg(WxDeviceMsg msg) throws WxErrorException { - String url = API_URL_PREFIX + "/transmsg"; - String response = this.wxMpService.post(url, msg.toJson()); + String response = this.wxMpService.post(DEVICE_TRANSMSG, msg.toJson()); return TransMsgResp.fromJson(response); } @Override public WxDeviceQrCodeResult getQrCode(String productId) throws WxErrorException { - String url = API_URL_PREFIX + "/getqrcode"; - String response = this.wxMpService.get(url, "product_id=" + productId); + String response = this.wxMpService.get(DEVICE_GETQRCODE, "product_id=" + productId); return WxDeviceQrCodeResult.fromJson(response); } @Override public WxDeviceAuthorizeResult authorize(WxDeviceAuthorize wxDeviceAuthorize) throws WxErrorException { - String url = API_URL_PREFIX + "/authorize_device"; - String response = this.wxMpService.post(url, wxDeviceAuthorize.toJson()); + String response = this.wxMpService.post(DEVICE_AUTHORIZE_DEVICE, wxDeviceAuthorize.toJson()); return WxDeviceAuthorizeResult.fromJson(response); } @Override public WxDeviceBindResult bind(WxDeviceBind wxDeviceBind) throws WxErrorException { - String url = API_URL_PREFIX + "/bind"; - String response = this.wxMpService.post(url, wxDeviceBind.toJson()); + String response = this.wxMpService.post(DEVICE_BIND, wxDeviceBind.toJson()); return WxDeviceBindResult.fromJson(response); } @Override public WxDeviceBindResult compelBind(WxDeviceBind wxDeviceBind) throws WxErrorException { - String url = API_URL_PREFIX + "/compel_bind"; - String response = this.wxMpService.post(url, wxDeviceBind.toJson()); + String response = this.wxMpService.post(DEVICE_COMPEL_BIND, wxDeviceBind.toJson()); return WxDeviceBindResult.fromJson(response); } @Override public WxDeviceBindResult unbind(WxDeviceBind wxDeviceBind) throws WxErrorException { - String url = API_URL_PREFIX + "/unbind?"; - String response = this.wxMpService.post(url, wxDeviceBind.toJson()); + String response = this.wxMpService.post(DEVICE_UNBIND, wxDeviceBind.toJson()); return WxDeviceBindResult.fromJson(response); } @Override public WxDeviceBindResult compelUnbind(WxDeviceBind wxDeviceBind) throws WxErrorException { - String url = API_URL_PREFIX + "/compel_unbind?"; - String response = this.wxMpService.post(url, wxDeviceBind.toJson()); + String response = this.wxMpService.post(DEVICE_COMPEL_UNBIND, wxDeviceBind.toJson()); return WxDeviceBindResult.fromJson(response); } @Override public WxDeviceOpenIdResult getOpenId(String deviceType, String deviceId) throws WxErrorException { - String url = API_URL_PREFIX + "/get_openid"; - String response = this.wxMpService.get(url, "device_type=" + deviceType + "&device_id=" + deviceId); + String response = this.wxMpService.get(DEVICE_GET_OPENID, "device_type=" + deviceType + "&device_id=" + deviceId); return WxDeviceOpenIdResult.fromJson(response); } @Override public WxDeviceBindDeviceResult getBindDevice(String openId) throws WxErrorException { - String url = API_URL_PREFIX + "/get_bind_device"; - String response = this.wxMpService.get(url, "openid=" + openId); + String response = this.wxMpService.get(DEVICE_GET_BIND_DEVICE, "openid=" + openId); return WxDeviceBindDeviceResult.fromJson(response); } } - diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java index 7707c567dd..a131e3a9f3 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java @@ -1,12 +1,8 @@ package me.chanjar.weixin.mp.api.impl; -import java.io.File; -import java.util.Date; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.google.gson.JsonObject; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; @@ -16,23 +12,20 @@ import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfSessionRequest; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfList; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfMsgList; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionGetResult; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionList; -import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionWaitCaseList; +import me.chanjar.weixin.mp.bean.kefu.result.*; + +import java.io.File; +import java.util.Date; + +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Kefu.*; /** * @author Binary Wang */ +@Slf4j +@RequiredArgsConstructor public class WxMpKefuServiceImpl implements WxMpKefuService { - protected final Logger log = LoggerFactory.getLogger(this.getClass()); - private WxMpService wxMpService; - - public WxMpKefuServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public boolean sendKefuMessage(WxMpKefuMessage message) throws WxErrorException { @@ -73,13 +66,15 @@ public boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErro @Override public boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) throws WxErrorException { WxMediaUploadResult responseContent = this.wxMpService - .execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), String.format(KFACCOUNT_UPLOAD_HEAD_IMG, kfAccount), imgFile); + .execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), + String.format(KFACCOUNT_UPLOAD_HEAD_IMG.getUrl(this.wxMpService.getWxMpConfigStorage()), kfAccount), imgFile); return responseContent != null; } @Override public boolean kfAccountDel(String kfAccount) throws WxErrorException { - String responseContent = this.wxMpService.get(String.format(KFACCOUNT_DEL, kfAccount), null); + String responseContent = this.wxMpService.get(String.format(KFACCOUNT_DEL.getUrl(this.wxMpService.getWxMpConfigStorage()), + kfAccount), null); return responseContent != null; } @@ -99,13 +94,15 @@ public boolean kfSessionClose(String openid, String kfAccount) throws WxErrorExc @Override public WxMpKfSessionGetResult kfSessionGet(String openid) throws WxErrorException { - String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION, openid), null); + String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION + .getUrl(this.wxMpService.getWxMpConfigStorage()), openid), null); return WxMpKfSessionGetResult.fromJson(responseContent); } @Override public WxMpKfSessionList kfSessionList(String kfAccount) throws WxErrorException { - String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION_LIST, kfAccount), null); + String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION_LIST + .getUrl(this.wxMpService.getWxMpConfigStorage()), kfAccount), null); return WxMpKfSessionList.fromJson(responseContent); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java index 91e7d4c1ba..6ec51e744f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java @@ -4,6 +4,8 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpMarketingService; import me.chanjar.weixin.mp.api.WxMpService; @@ -12,8 +14,6 @@ import me.chanjar.weixin.mp.bean.marketing.WxMpUserAction; import me.chanjar.weixin.mp.bean.marketing.WxMpUserActionSet; import org.apache.commons.lang3.time.DateFormatUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.URLEncoder; @@ -21,48 +21,41 @@ import java.util.Date; import java.util.List; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Marketing.*; + /** * @author 007 */ +@Slf4j +@RequiredArgsConstructor public class WxMpMarketingServiceImpl implements WxMpMarketingService { - protected final Logger log = LoggerFactory.getLogger(this.getClass()); - private WxMpService wxMpService; - - public WxMpMarketingServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public long addUserActionSets(String type, String name, String description) throws WxErrorException { - String url = API_URL_PREFIX + "user_action_sets/add?version=v1.0"; JsonObject json = new JsonObject(); json.addProperty("type", type); json.addProperty("name", name); json.addProperty("description", description); - String responseContent = wxMpService.post(url, json.toString()); + String responseContent = wxMpService.post(USER_ACTION_SETS_ADD, json.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return tmpJsonElement.getAsJsonObject().get("data").getAsJsonObject().get("user_action_set_id").getAsLong(); } @Override public List getUserActionSets(Long userActionSetId) throws WxErrorException { - String url = API_URL_PREFIX + "user_action_sets/get"; - String responseContent = wxMpService.get(url, "version=v1.0&user_action_set_id=" + userActionSetId); + String responseContent = wxMpService.get(USER_ACTION_SETS_GET, "version=v1.0&user_action_set_id=" + userActionSetId); return WxMpUserActionSet.fromJson(responseContent); } @Override public void addUserAction(List actions) throws WxErrorException { - String url = API_URL_PREFIX + "user_actions/add?version=v1.0"; - JsonArray json = new JsonArray(); - for (WxMpUserAction action : actions) { - json.add(action.toJsonObject()); - } - wxMpService.post(url, json.toString()); + wxMpService.post(USER_ACTIONS_ADD, WxMpUserAction.listToJson(actions)); } @Override - public WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, List filtering, Integer page, Integer page_size) throws WxErrorException, IOException { + public WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, List filtering, Integer page, Integer pageSize) + throws WxErrorException, IOException { Date today = new Date(); if (beginDate == null) { beginDate = today; @@ -70,23 +63,21 @@ public WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, List @@ -18,41 +21,38 @@ * * @author Binary Wang */ +@Slf4j +@RequiredArgsConstructor public class WxMpMassMessageServiceImpl implements WxMpMassMessageService { - protected final Logger log = LoggerFactory.getLogger(this.getClass()); - private WxMpService wxMpService; - - public WxMpMassMessageServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { - String responseContent = this.wxMpService.post(MEDIA_UPLOAD_NEWS_URL, news.toJson()); + String responseContent = this.wxMpService.post(MassMessage.MEDIA_UPLOAD_NEWS_URL, news.toJson()); return WxMpMassUploadResult.fromJson(responseContent); } @Override public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException { - String responseContent = this.wxMpService.post(MEDIA_UPLOAD_VIDEO_URL, video.toJson()); + String responseContent = this.wxMpService.post(MassMessage.MEDIA_UPLOAD_VIDEO_URL, video.toJson()); return WxMpMassUploadResult.fromJson(responseContent); } @Override public WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException { - String responseContent = this.wxMpService.post(WxMpMassMessageService.MESSAGE_MASS_SENDALL_URL, message.toJson()); + String responseContent = this.wxMpService.post(MassMessage.MESSAGE_MASS_SENDALL_URL, message.toJson()); return WxMpMassSendResult.fromJson(responseContent); } @Override public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException { - String responseContent = this.wxMpService.post(MESSAGE_MASS_SEND_URL, message.toJson()); + String responseContent = this.wxMpService.post(MassMessage.MESSAGE_MASS_SEND_URL, message.toJson()); return WxMpMassSendResult.fromJson(responseContent); } @Override public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws WxErrorException { - String responseContent = this.wxMpService.post(MESSAGE_MASS_PREVIEW_URL, wxMpMassPreviewMessage.toJson()); + String responseContent = this.wxMpService.post(MassMessage.MESSAGE_MASS_PREVIEW_URL, wxMpMassPreviewMessage.toJson()); return WxMpMassSendResult.fromJson(responseContent); } @@ -61,7 +61,7 @@ public void delete(Long msgId, Integer articleIndex) throws WxErrorException { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("msg_id", msgId); jsonObject.addProperty("article_idx", articleIndex); - this.wxMpService.post(MESSAGE_MASS_DELETE_URL, jsonObject.toString()); + this.wxMpService.post(MassMessage.MESSAGE_MASS_DELETE_URL, jsonObject.toString()); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java index 7929aced0a..2ceec219f7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java @@ -1,12 +1,6 @@ package me.chanjar.weixin.mp.api.impl; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; @@ -18,33 +12,29 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.api.WxMpMaterialService; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; -import me.chanjar.weixin.mp.bean.material.WxMpMaterial; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialArticleUpdate; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialCountResult; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialFileBatchGetResult; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialNewsBatchGetResult; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; -import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; +import me.chanjar.weixin.mp.bean.material.*; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import me.chanjar.weixin.mp.util.requestexecuter.material.MaterialDeleteRequestExecutor; -import me.chanjar.weixin.mp.util.requestexecuter.material.MaterialNewsInfoRequestExecutor; -import me.chanjar.weixin.mp.util.requestexecuter.material.MaterialUploadRequestExecutor; -import me.chanjar.weixin.mp.util.requestexecuter.material.MaterialVideoInfoRequestExecutor; -import me.chanjar.weixin.mp.util.requestexecuter.material.MaterialVoiceAndImageDownloadRequestExecutor; +import me.chanjar.weixin.mp.util.requestexecuter.material.*; import me.chanjar.weixin.mp.util.requestexecuter.media.MediaImgUploadRequestExecutor; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Material.*; + /** * Created by Binary Wang on 2016/7/21. + * + * @author Binary Wang */ +@RequiredArgsConstructor public class WxMpMaterialServiceImpl implements WxMpMaterialService { - - private WxMpService wxMpService; - - public WxMpMaterialServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException { @@ -63,7 +53,7 @@ public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputS @Override public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { - String url = String.format(MEDIA_UPLOAD_URL, mediaType); + String url = String.format(MEDIA_UPLOAD_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), mediaType); return this.wxMpService.execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, file); } @@ -82,7 +72,7 @@ public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException @Override public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException { - String url = String.format(MATERIAL_ADD_URL, mediaType); + String url = String.format(MATERIAL_ADD_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), mediaType); return this.wxMpService.execute(MaterialUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, material); } @@ -98,17 +88,20 @@ public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws @Override public InputStream materialImageOrVoiceDownload(String mediaId) throws WxErrorException { return this.wxMpService.execute(MaterialVoiceAndImageDownloadRequestExecutor - .create(this.wxMpService.getRequestHttp(), this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), MATERIAL_GET_URL, mediaId); + .create(this.wxMpService.getRequestHttp(), this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), + MATERIAL_GET_URL, mediaId); } @Override public WxMpMaterialVideoInfoResult materialVideoInfo(String mediaId) throws WxErrorException { - return this.wxMpService.execute(MaterialVideoInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_GET_URL, mediaId); + return this.wxMpService.execute(MaterialVideoInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), + MATERIAL_GET_URL, mediaId); } @Override public WxMpMaterialNews materialNewsInfo(String mediaId) throws WxErrorException { - return this.wxMpService.execute(MaterialNewsInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_GET_URL, mediaId); + return this.wxMpService.execute(MaterialNewsInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), + MATERIAL_GET_URL, mediaId); } @Override @@ -124,7 +117,8 @@ public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleU @Override public boolean materialDelete(String mediaId) throws WxErrorException { - return this.wxMpService.execute(MaterialDeleteRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_DEL_URL, mediaId); + return this.wxMpService.execute(MaterialDeleteRequestExecutor.create(this.wxMpService.getRequestHttp()), + MATERIAL_DEL_URL, mediaId); } @Override @@ -140,7 +134,7 @@ public WxMpMaterialCountResult materialCount() throws WxErrorException { @Override public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException { - Map params = new HashMap<>(); + Map params = new HashMap<>(4); params.put("type", WxConsts.MaterialType.NEWS); params.put("offset", offset); params.put("count", count); @@ -155,7 +149,7 @@ public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count @Override public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException { - Map params = new HashMap<>(); + Map params = new HashMap<>(4); params.put("type", type); params.put("offset", offset); params.put("count", count); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java index 3eaf61417c..31d9bcf373 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java @@ -5,7 +5,9 @@ import java.util.HashMap; import java.util.Map; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.mp.bean.membercard.*; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; import org.apache.commons.lang3.StringUtils; import com.google.gson.Gson; @@ -40,15 +42,12 @@ * @version 2017/7/8 */ @Slf4j +@RequiredArgsConstructor public class WxMpMemberCardServiceImpl implements WxMpMemberCardService { - private WxMpService wxMpService; + private final WxMpService wxMpService; private static final Gson GSON = WxMpGsonBuilder.create(); - public WxMpMemberCardServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } - @Override public WxMpService getWxMpService() { return this.wxMpService; @@ -70,7 +69,7 @@ public WxMpCardCreateResult createMemberCard(WxMpMemberCardCreateMessage createM return validResult; } - String response = this.wxMpService.post(MEMBER_CARD_CREATE, GSON.toJson(createMessageMessage)); + String response = this.wxMpService.post(WxMpApiUrl.MemberCard.MEMBER_CARD_CREATE, GSON.toJson(createMessageMessage)); return WxMpCardCreateResult.fromJson(response); } @@ -212,7 +211,7 @@ private WxMpCardCreateResult validCheck(WxMpMemberCardCreateMessage createMessag @Override public String activateMemberCard(WxMpMemberCardActivatedMessage activatedMessage) throws WxErrorException { - return this.wxMpService.post(MEMBER_CARD_ACTIVATE, GSON.toJson(activatedMessage)); + return this.wxMpService.post(WxMpApiUrl.MemberCard.MEMBER_CARD_ACTIVATE, GSON.toJson(activatedMessage)); } @Override @@ -221,7 +220,7 @@ public WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) thro jsonObject.addProperty("card_id", cardId); jsonObject.addProperty("code", code); - String responseContent = this.getWxMpService().post(MEMBER_CARD_USER_INFO_GET, jsonObject.toString()); + String responseContent = this.getWxMpService().post(WxMpApiUrl.MemberCard.MEMBER_CARD_USER_INFO_GET, jsonObject.toString()); log.debug("{}", responseContent); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxMpGsonBuilder.create().fromJson(tmpJsonElement, @@ -233,7 +232,7 @@ public WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) thro public WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessage updateUserMessage) throws WxErrorException { - String responseContent = this.getWxMpService().post(MEMBER_CARD_UPDATE_USER, GSON.toJson(updateUserMessage)); + String responseContent = this.getWxMpService().post(WxMpApiUrl.MemberCard.MEMBER_CARD_UPDATE_USER, GSON.toJson(updateUserMessage)); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxMpGsonBuilder.create().fromJson(tmpJsonElement, @@ -243,7 +242,7 @@ public WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessa @Override public MemberCardActivateUserFormResult setActivateUserForm(MemberCardActivateUserFormRequest userFormRequest) throws WxErrorException { - String responseContent = this.getWxMpService().post(MEMBER_CARD_ACTIVATE_USER_FORM, GSON.toJson(userFormRequest)); + String responseContent = this.getWxMpService().post(WxMpApiUrl.MemberCard.MEMBER_CARD_ACTIVATE_USER_FORM, GSON.toJson(userFormRequest)); return MemberCardActivateUserFormResult.fromJson(responseContent); } @@ -252,7 +251,7 @@ public ActivatePluginParam getActivatePluginParam(String cardId, String outStr) JsonObject params = new JsonObject(); params.addProperty("card_id", cardId); params.addProperty("outer_str", outStr); - String response = this.wxMpService.post(MEMBER_CARD_ACTIVATE_URL, GSON.toJson(params)); + String response = this.wxMpService.post(WxMpApiUrl.MemberCard.MEMBER_CARD_ACTIVATE_URL, GSON.toJson(params)); ActivatePluginParamResult result = GSON.fromJson(response, ActivatePluginParamResult.class); if (0 == result.getErrcode()) { String url = result.getUrl(); @@ -273,18 +272,16 @@ public ActivatePluginParam getActivatePluginParam(String cardId, String outStr) @Override public CardUpdateResult updateCardInfo(MemberCardUpdateRequest memberCardUpdateRequest) throws WxErrorException { - String response = this.wxMpService.post(MEMBER_CARD_UPDATE, GSON.toJson(memberCardUpdateRequest)); - CardUpdateResult result = GSON.fromJson(response, CardUpdateResult.class); - return result; + String response = this.wxMpService.post(WxMpApiUrl.MemberCard.MEMBER_CARD_UPDATE, GSON.toJson(memberCardUpdateRequest)); + return GSON.fromJson(response, CardUpdateResult.class); } @Override public WxMpMemberCardActivateTempInfoResult getActivateTempInfo(String activateTicket) throws WxErrorException { JsonObject params = new JsonObject(); params.addProperty("activate_ticket", activateTicket); - String response = this.wxMpService.post(MEMBER_CARD_ACTIVATE_TEMP_INFO, GSON.toJson(params)); - WxMpMemberCardActivateTempInfoResult result = GSON.fromJson(response, WxMpMemberCardActivateTempInfoResult.class); - return result; + String response = this.wxMpService.post(WxMpApiUrl.MemberCard.MEMBER_CARD_ACTIVATE_TEMP_INFO, GSON.toJson(params)); + return GSON.fromJson(response, WxMpMemberCardActivateTempInfoResult.class); } private static String truncateUrlPage(String strURL) { @@ -302,7 +299,7 @@ private static String truncateUrlPage(String strURL) { return strAllParam; } - public static Map parseRequestUrl(String url) { + private static Map parseRequestUrl(String url) { Map mapRequest = new HashMap<>(16); String[] arrSplit; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java index e8dc84766b..2a42a0a590 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java @@ -2,34 +2,34 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpMenuService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult; import me.chanjar.weixin.mp.bean.menu.WxMpMenu; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; + +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Menu.*; /** * Created by Binary Wang on 2016/7/21. + * + * @author Binary Wang */ +@Slf4j +@RequiredArgsConstructor public class WxMpMenuServiceImpl implements WxMpMenuService { - private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/menu"; - private static Logger log = LoggerFactory.getLogger(WxMpMenuServiceImpl.class); - - private WxMpService wxMpService; - - public WxMpMenuServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public String menuCreate(WxMenu menu) throws WxErrorException { String menuJson = menu.toJson(); - String url = API_URL_PREFIX + "/create"; + WxMpApiUrl.Menu url = MENU_CREATE; if (menu.getMatchRule() != null) { - url = API_URL_PREFIX + "/addconditional"; + url = MENU_ADDCONDITIONAL; } log.debug("开始创建菜单:{}", menuJson); @@ -48,9 +48,9 @@ public String menuCreate(WxMenu menu) throws WxErrorException { public String menuCreate(String json) throws WxErrorException { JsonParser jsonParser = new JsonParser(); JsonObject jsonObject = jsonParser.parse(json).getAsJsonObject(); - String url = API_URL_PREFIX + "/create"; + WxMpApiUrl.Menu url = MENU_CREATE; if (jsonObject.get("matchrule") != null) { - url = API_URL_PREFIX + "/addconditional"; + url = MENU_ADDCONDITIONAL; } String result = this.wxMpService.post(url, json); @@ -63,25 +63,22 @@ public String menuCreate(String json) throws WxErrorException { @Override public void menuDelete() throws WxErrorException { - String url = API_URL_PREFIX + "/delete"; - String result = this.wxMpService.get(url, null); + String result = this.wxMpService.get(MENU_DELETE, null); log.debug("删除菜单结果:{}", result); } @Override public void menuDelete(String menuId) throws WxErrorException { - String url = API_URL_PREFIX + "/delconditional"; JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("menuid", menuId); - String result = this.wxMpService.post(url, jsonObject.toString()); + String result = this.wxMpService.post(MENU_DELCONDITIONAL, jsonObject.toString()); log.debug("根据MeunId({})删除个性化菜单结果:{}", menuId, result); } @Override public WxMpMenu menuGet() throws WxErrorException { - String url = API_URL_PREFIX + "/get"; try { - String resultContent = this.wxMpService.get(url, null); + String resultContent = this.wxMpService.get(MENU_GET, null); return WxMpMenu.fromJson(resultContent); } catch (WxErrorException e) { // 46003 不存在的菜单数据 @@ -94,11 +91,10 @@ public WxMpMenu menuGet() throws WxErrorException { @Override public WxMenu menuTryMatch(String userid) throws WxErrorException { - String url = API_URL_PREFIX + "/trymatch"; JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("user_id", userid); try { - String resultContent = this.wxMpService.post(url, jsonObject.toString()); + String resultContent = this.wxMpService.post(MENU_TRYMATCH, jsonObject.toString()); return WxMenu.fromJson(resultContent); } catch (WxErrorException e) { // 46003 不存在的菜单数据;46002 不存在的菜单版本 @@ -112,8 +108,7 @@ public WxMenu menuTryMatch(String userid) throws WxErrorException { @Override public WxMpGetSelfMenuInfoResult getSelfMenuInfo() throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info"; - String resultContent = this.wxMpService.get(url, null); + String resultContent = this.wxMpService.get(GET_CURRENT_SELFMENU_INFO, null); return WxMpGetSelfMenuInfoResult.fromJson(resultContent); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImpl.java new file mode 100644 index 0000000000..4d3c434ec5 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImpl.java @@ -0,0 +1,43 @@ +package me.chanjar.weixin.mp.api.impl; + +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpOcrService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.ocr.WxMpOcrIdCardResult; + +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Ocr.IDCARD; + +/** + * ocr 接口实现. + * + * @author Binary Wang + * @date 2019-06-22 + */ +@RequiredArgsConstructor +public class WxMpOcrServiceImpl implements WxMpOcrService { + private final WxMpService wxMpService; + + @Override + public WxMpOcrIdCardResult idCard(ImageType imgType, String imgUrl) throws WxErrorException { + try { + imgUrl = URLEncoder.encode(imgUrl, StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + // ignore cannot happen + } + + final String result = this.wxMpService.get(String.format(IDCARD.getUrl(this.wxMpService.getWxMpConfigStorage()), + imgType.getType(), imgUrl), null); + return WxMpOcrIdCardResult.fromJson(result); + } + + @Override + public WxMpOcrIdCardResult idCard(ImageType imgType, File imgFile) { + return null; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java index 5783ce7991..a654afb769 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java @@ -1,6 +1,7 @@ package me.chanjar.weixin.mp.api.impl; import com.google.gson.JsonObject; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpQrcodeService; @@ -14,16 +15,16 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Qrcode.*; + /** * Created by Binary Wang on 2016/7/21. + * + * @author Binary Wang */ +@RequiredArgsConstructor public class WxMpQrcodeServiceImpl implements WxMpQrcodeService { - private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/qrcode"; - private WxMpService wxMpService; - - public WxMpQrcodeServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public WxMpQrCodeTicket qrCodeCreateTmpTicket(int sceneId, Integer expireSeconds) throws WxErrorException { @@ -31,37 +32,20 @@ public WxMpQrCodeTicket qrCodeCreateTmpTicket(int sceneId, Integer expireSeconds throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("临时二维码场景值不能为0!").build()); } - //expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。 - if (expireSeconds != null && expireSeconds > 2592000) { - throw new WxErrorException(WxError.builder().errorCode(-1) - .errorMsg("临时二维码有效时间最大不能超过2592000(即30天)!").build()); - } - - if (expireSeconds == null) { - expireSeconds = 30; - } - - String url = API_URL_PREFIX + "/create"; - JsonObject json = new JsonObject(); - json.addProperty("action_name", "QR_SCENE"); - json.addProperty("expire_seconds", expireSeconds); - - JsonObject actionInfo = new JsonObject(); - JsonObject scene = new JsonObject(); - scene.addProperty("scene_id", sceneId); - actionInfo.add("scene", scene); - json.add("action_info", actionInfo); - String responseContent = this.wxMpService.post(url, json.toString()); - return WxMpQrCodeTicket.fromJson(responseContent); + return this.createQrCode("QR_SCENE", null, sceneId, expireSeconds); } - @Override public WxMpQrCodeTicket qrCodeCreateTmpTicket(String sceneStr, Integer expireSeconds) throws WxErrorException { if (StringUtils.isBlank(sceneStr)) { throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("临时二维码场景值不能为空!").build()); } + return this.createQrCode("QR_STR_SCENE", sceneStr, null, expireSeconds); + } + + private WxMpQrCodeTicket createQrCode(String actionName, String sceneStr, Integer sceneId, Integer expireSeconds) + throws WxErrorException { //expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。 if (expireSeconds != null && expireSeconds > 2592000) { throw new WxErrorException(WxError.builder().errorCode(-1) @@ -72,21 +56,31 @@ public WxMpQrCodeTicket qrCodeCreateTmpTicket(String sceneStr, Integer expireSec expireSeconds = 30; } - String url = API_URL_PREFIX + "/create"; + return this.getQrCodeTicket(actionName, sceneStr, sceneId, expireSeconds); + } + + private WxMpQrCodeTicket getQrCodeTicket(String actionName, String sceneStr, Integer sceneId, Integer expireSeconds) + throws WxErrorException { JsonObject json = new JsonObject(); - json.addProperty("action_name", "QR_STR_SCENE"); - json.addProperty("expire_seconds", expireSeconds); + json.addProperty("action_name", actionName); + if (expireSeconds != null) { + json.addProperty("expire_seconds", expireSeconds); + } JsonObject actionInfo = new JsonObject(); JsonObject scene = new JsonObject(); - scene.addProperty("scene_str", sceneStr); + if (sceneStr != null) { + scene.addProperty("scene_str", sceneStr); + } else if (sceneId != null) { + scene.addProperty("scene_id", sceneId); + } + actionInfo.add("scene", scene); json.add("action_info", actionInfo); - String responseContent = this.wxMpService.post(url, json.toString()); + String responseContent = this.wxMpService.post(QRCODE_CREATE, json.toString()); return WxMpQrCodeTicket.fromJson(responseContent); } - @Override public WxMpQrCodeTicket qrCodeCreateLastTicket(int sceneId) throws WxErrorException { if (sceneId < 1 || sceneId > 100000) { @@ -95,43 +89,23 @@ public WxMpQrCodeTicket qrCodeCreateLastTicket(int sceneId) throws WxErrorExcept .build()); } - String url = API_URL_PREFIX + "/create"; - JsonObject json = new JsonObject(); - json.addProperty("action_name", "QR_LIMIT_SCENE"); - JsonObject actionInfo = new JsonObject(); - JsonObject scene = new JsonObject(); - scene.addProperty("scene_id", sceneId); - actionInfo.add("scene", scene); - json.add("action_info", actionInfo); - String responseContent = this.wxMpService.post(url, json.toString()); - return WxMpQrCodeTicket.fromJson(responseContent); + return this.getQrCodeTicket("QR_LIMIT_SCENE", null, sceneId, null); } @Override public WxMpQrCodeTicket qrCodeCreateLastTicket(String sceneStr) throws WxErrorException { - String url = API_URL_PREFIX + "/create"; - JsonObject json = new JsonObject(); - json.addProperty("action_name", "QR_LIMIT_STR_SCENE"); - JsonObject actionInfo = new JsonObject(); - JsonObject scene = new JsonObject(); - scene.addProperty("scene_str", sceneStr); - actionInfo.add("scene", scene); - json.add("action_info", actionInfo); - String responseContent = this.wxMpService.post(url, json.toString()); - return WxMpQrCodeTicket.fromJson(responseContent); + return this.getQrCodeTicket("QR_LIMIT_STR_SCENE", sceneStr, null, null); } @Override public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException { - String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode"; - return this.wxMpService.execute(QrCodeRequestExecutor.create(this.wxMpService.getRequestHttp()), url, ticket); + return this.wxMpService.execute(QrCodeRequestExecutor.create(this.wxMpService.getRequestHttp()), SHOW_QRCODE, ticket); } @Override public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException { - String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s"; try { - String resultUrl = String.format(url, + String resultUrl = String.format(SHOW_QRCODE_WITH_TICKET.getUrl(this.wxMpService.getWxMpConfigStorage()), URLEncoder.encode(ticket, StandardCharsets.UTF_8.name())); if (needShortUrl) { return this.wxMpService.shortUrl(resultUrl); @@ -145,7 +119,7 @@ public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErr @Override public String qrCodePictureUrl(String ticket) throws WxErrorException { - return qrCodePictureUrl(ticket, false); + return this.qrCodePictureUrl(ticket, false); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java index 10e2a5b78f..d13a95b16f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java @@ -7,8 +7,7 @@ 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.mp.api.WxMpConfigStorage; -import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -19,8 +18,12 @@ import java.io.IOException; import java.util.concurrent.locks.Lock; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL; + /** * apache http client方式实现. + * + * @author someone */ public class WxMpServiceHttpClientImpl extends BaseWxMpServiceImpl { private CloseableHttpClient httpClient; @@ -63,20 +66,20 @@ public void initHttp() { @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { - if (!this.getWxMpConfigStorage().isAccessTokenExpired() && !forceRefresh) { - return this.getWxMpConfigStorage().getAccessToken(); + final WxMpConfigStorage config = this.getWxMpConfigStorage(); + if (!config.isAccessTokenExpired() && !forceRefresh) { + return config.getAccessToken(); } - Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); + Lock lock = config.getAccessTokenLock(); lock.lock(); try { - String url = String.format(WxMpService.GET_ACCESS_TOKEN_URL, - this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret()); + String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(config), config.getAppId(), config.getSecret()); try { HttpGet httpGet = new HttpGet(url); if (this.getRequestHttpProxy() != null) { - RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build(); - httpGet.setConfig(config); + RequestConfig requestConfig = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build(); + httpGet.setConfig(requestConfig); } try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) { String resultContent = new BasicResponseHandler().handleResponse(response); @@ -85,8 +88,8 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { throw new WxErrorException(error); } WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); - this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); - return this.getWxMpConfigStorage().getAccessToken(); + config.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + return config.getAccessToken(); } finally { httpGet.releaseConnection(); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java index c00cd43234..a4aeac5add 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java @@ -7,13 +7,16 @@ import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; -import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import java.util.concurrent.locks.Lock; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL; + /** - * jodd-http方式实现 + * jodd-http方式实现. + * + * @author someone */ public class WxMpServiceJoddHttpImpl extends BaseWxMpServiceImpl { private HttpConnectionProvider httpClient; @@ -48,15 +51,15 @@ public void initHttp() { @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { - if (!this.getWxMpConfigStorage().isAccessTokenExpired() && !forceRefresh) { - return this.getWxMpConfigStorage().getAccessToken(); + final WxMpConfigStorage config = this.getWxMpConfigStorage(); + if (!config.isAccessTokenExpired() && !forceRefresh) { + return config.getAccessToken(); } - Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); + Lock lock = config.getAccessTokenLock(); lock.lock(); try { - String url = String.format(WxMpService.GET_ACCESS_TOKEN_URL, - this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret()); + String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(config), config.getAppId(), config.getSecret()); HttpRequest request = HttpRequest.get(url); @@ -73,9 +76,9 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { throw new WxErrorException(error); } WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); - this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + config.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); - return this.getWxMpConfigStorage().getAccessToken(); + return config.getAccessToken(); } finally { lock.unlock(); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java index 89771250ef..f7f2a8e7af 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java @@ -6,15 +6,18 @@ import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; -import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import okhttp3.*; import java.io.IOException; import java.util.concurrent.locks.Lock; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL; + /** - * okhttp实现 + * okhttp实现. + * + * @author someone */ public class WxMpServiceOkHttpImpl extends BaseWxMpServiceImpl { private OkHttpClient httpClient; @@ -37,15 +40,15 @@ public HttpType getRequestType() { @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { - if (!this.getWxMpConfigStorage().isAccessTokenExpired() && !forceRefresh) { - return this.getWxMpConfigStorage().getAccessToken(); + final WxMpConfigStorage config = this.getWxMpConfigStorage(); + if (!config.isAccessTokenExpired() && !forceRefresh) { + return config.getAccessToken(); } - Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); + Lock lock = config.getAccessTokenLock(); lock.lock(); try { - String url = String.format(WxMpService.GET_ACCESS_TOKEN_URL, - this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret()); + String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(config), config.getAppId(), config.getSecret()); Request request = new Request.Builder().url(url).get().build(); Response response = getRequestHttpClient().newCall(request).execute(); @@ -55,9 +58,9 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { throw new WxErrorException(error); } WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); - this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + config.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); - return this.getWxMpConfigStorage().getAccessToken(); + return config.getAccessToken(); } catch (IOException e) { throw new RuntimeException(e); } finally { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java index 6f6beda5ab..95efcb7f5c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java @@ -1,5 +1,6 @@ package me.chanjar.weixin.mp.api.impl; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; @@ -9,59 +10,45 @@ import me.chanjar.weixin.mp.bean.WxMpShakeQuery; import me.chanjar.weixin.mp.bean.shake.*; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.ShakeAround.*; + /** * Created by rememberber on 2017/6/5. * * @author rememberber */ +@RequiredArgsConstructor public class WxMpShakeServiceImpl implements WxMpShakeService { + private final WxMpService wxMpService; - private WxMpService wxMpService; - - public WxMpShakeServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } - - /** - * - * 获取设备及用户信息- * - * @param wxMpShakeQuery 查询参数 - */ @Override public WxMpShakeInfoResult getShakeInfo(WxMpShakeQuery wxMpShakeQuery) throws WxErrorException { - String url = "https://api.weixin.qq.com/shakearound/user/getshakeinfo"; String postData = wxMpShakeQuery.toJsonString(); - String responseContent = this.wxMpService.post(url, postData); + String responseContent = this.wxMpService.post(SHAKEAROUND_USER_GETSHAKEINFO, postData); return WxMpShakeInfoResult.fromJson(responseContent); } @Override - public WxMpShakeAroundPageAddResult pageAdd(WxMpShakeAroundPageAddQuery shakeAroundPageAddQuery) throws WxErrorException { - String url = "https://api.weixin.qq.com/shakearound/page/add"; + public WxMpShakeAroundPageAddResult pageAdd(WxMpShakeAroundPageAddQuery shakeAroundPageAddQuery) + throws WxErrorException { String postData = shakeAroundPageAddQuery.toJsonString(); - String responseContent = this.wxMpService.post(url, postData); + String responseContent = this.wxMpService.post(SHAKEAROUND_PAGE_ADD, postData); return WxMpShakeAroundPageAddResult.fromJson(responseContent); } @Override - public WxError deviceBindPageQuery(WxMpShakeAroundDeviceBindPageQuery shakeAroundDeviceBindPageQuery) throws WxErrorException { - String url = "https://api.weixin.qq.com/shakearound/device/bindpage"; + public WxError deviceBindPageQuery(WxMpShakeAroundDeviceBindPageQuery shakeAroundDeviceBindPageQuery) + throws WxErrorException { String postData = shakeAroundDeviceBindPageQuery.toJsonString(); - String responseContent = this.wxMpService.post(url, postData); + String responseContent = this.wxMpService.post(SHAKEAROUND_DEVICE_BINDPAGE, postData); return WxError.fromJson(responseContent, WxType.MP); } @Override - public WxMpShakeAroundRelationSearchResult relationSearch(WxMpShakeAroundRelationSearchQuery shakeAroundRelationSearchQuery) throws WxErrorException { - String url = "https://api.weixin.qq.com/shakearound/relation/search"; - String postData = shakeAroundRelationSearchQuery.toJsonString(); - String responseContent = this.wxMpService.post(url, postData); + public WxMpShakeAroundRelationSearchResult relationSearch(WxMpShakeAroundRelationSearchQuery searchQuery) + throws WxErrorException { + String postData = searchQuery.toJsonString(); + String responseContent = this.wxMpService.post(SHAKEAROUND_RELATION_SEARCH, postData); return WxMpShakeAroundRelationSearchResult.fromJson(responseContent); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java index 402102064c..913816595c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java @@ -3,6 +3,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; @@ -12,6 +13,7 @@ import me.chanjar.weixin.mp.bean.store.WxMpStoreBaseInfo; import me.chanjar.weixin.mp.bean.store.WxMpStoreInfo; import me.chanjar.weixin.mp.bean.store.WxMpStoreListResult; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; import java.util.List; @@ -21,18 +23,15 @@ * * @author binarywang (https://github.com/binarywang) */ +@RequiredArgsConstructor public class WxMpStoreServiceImpl implements WxMpStoreService { - private WxMpService wxMpService; - - public WxMpStoreServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public void add(WxMpStoreBaseInfo request) throws WxErrorException { BeanUtils.checkRequiredFields(request); - String response = this.wxMpService.post(POI_ADD_URL, request.toJson()); + String response = this.wxMpService.post(WxMpApiUrl.Store.POI_ADD_URL, request.toJson()); WxError wxError = WxError.fromJson(response, WxType.MP); if (wxError.getErrorCode() != 0) { throw new WxErrorException(wxError); @@ -43,7 +42,7 @@ public void add(WxMpStoreBaseInfo request) throws WxErrorException { public WxMpStoreBaseInfo get(String poiId) throws WxErrorException { JsonObject paramObject = new JsonObject(); paramObject.addProperty("poi_id", poiId); - String response = this.wxMpService.post(POI_GET_URL, paramObject.toString()); + String response = this.wxMpService.post(WxMpApiUrl.Store.POI_GET_URL, paramObject.toString()); WxError wxError = WxError.fromJson(response, WxType.MP); if (wxError.getErrorCode() != 0) { throw new WxErrorException(wxError); @@ -56,7 +55,7 @@ public WxMpStoreBaseInfo get(String poiId) throws WxErrorException { public void delete(String poiId) throws WxErrorException { JsonObject paramObject = new JsonObject(); paramObject.addProperty("poi_id", poiId); - String response = this.wxMpService.post(POI_DEL_URL, paramObject.toString()); + String response = this.wxMpService.post(WxMpApiUrl.Store.POI_DEL_URL, paramObject.toString()); WxError wxError = WxError.fromJson(response, WxType.MP); if (wxError.getErrorCode() != 0) { throw new WxErrorException(wxError); @@ -69,7 +68,7 @@ public WxMpStoreListResult list(int begin, int limit) JsonObject params = new JsonObject(); params.addProperty("begin", begin); params.addProperty("limit", limit); - String response = this.wxMpService.post(POI_LIST_URL, params.toString()); + String response = this.wxMpService.post(WxMpApiUrl.Store.POI_LIST_URL, params.toString()); WxError wxError = WxError.fromJson(response, WxType.MP); if (wxError.getErrorCode() != 0) { @@ -102,7 +101,7 @@ public List
- * 获取设备信息,包括UUID、major、minor,以及距离、openID等信息。 - * 详情请见: https://mp.weixin.qq.com/wiki?action=doc&id=mp1443447963 - * http请求方式: POST(请使用https协议) - * 接口地址:https://api.weixin.qq.com/shakearound/user/getshakeinfo?access_token=ACCESS_TOKE - *listAll() throws WxErrorException { @Override public void update(WxMpStoreBaseInfo request) throws WxErrorException { - String response = this.wxMpService.post(POI_UPDATE_URL, request.toJson()); + String response = this.wxMpService.post(WxMpApiUrl.Store.POI_UPDATE_URL, request.toJson()); WxError wxError = WxError.fromJson(response, WxType.MP); if (wxError.getErrorCode() != 0) { throw new WxErrorException(wxError); @@ -111,7 +110,7 @@ public void update(WxMpStoreBaseInfo request) throws WxErrorException { @Override public List listCategories() throws WxErrorException { - String response = this.wxMpService.get(POI_GET_WX_CATEGORY_URL, null); + String response = this.wxMpService.get(WxMpApiUrl.Store.POI_GET_WX_CATEGORY_URL, null); WxError wxError = WxError.fromJson(response, WxType.MP); if (wxError.getErrorCode() != 0) { throw new WxErrorException(wxError); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java index fe1cfb306c..ff99b12c83 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java @@ -1,33 +1,31 @@ package me.chanjar.weixin.mp.api.impl; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.URIUtil; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpSubscribeMsgService; import me.chanjar.weixin.mp.bean.subscribe.WxMpSubscribeMessage; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.SubscribeMsg.SEND_MESSAGE_URL; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.SubscribeMsg.SUBSCRIBE_MESSAGE_AUTHORIZE_URL; + /** + * 一次性订阅消息接口. + * * @author Mklaus * @date 2018-01-22 上午11:19 */ +@RequiredArgsConstructor public class WxMpSubscribeMsgServiceImpl implements WxMpSubscribeMsgService { - private static final String SUBSCRIBE_MESSAGE_AUTHORIZE_URL = - "https://mp.weixin.qq.com/mp/subscribemsg?action=get_confirm&appid=%s&scene=%d&template_id=%s&redirect_url=%s&reserved=%s#wechat_redirect"; - private static final String SEND_MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/subscribe"; - - - private WxMpService wxMpService; - - public WxMpSubscribeMsgServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public String subscribeMsgAuthorizationUrl(String redirectURI, int scene, String reserved) { WxMpConfigStorage storage = this.wxMpService.getWxMpConfigStorage(); - return String.format(SUBSCRIBE_MESSAGE_AUTHORIZE_URL, - storage.getAppId(), scene, storage.getTemplateId(), URIUtil.encodeURIComponent(redirectURI), reserved); + return String.format(SUBSCRIBE_MESSAGE_AUTHORIZE_URL.getUrl(storage), storage.getAppId(), scene, storage.getTemplateId(), + URIUtil.encodeURIComponent(redirectURI), reserved); } @Override diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpTemplateMsgServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpTemplateMsgServiceImpl.java index 472cd0fe8c..4cab8d71eb 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpTemplateMsgServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpTemplateMsgServiceImpl.java @@ -2,6 +2,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; @@ -10,9 +11,12 @@ import me.chanjar.weixin.mp.bean.template.WxMpTemplate; import me.chanjar.weixin.mp.bean.template.WxMpTemplateIndustry; import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; import java.util.List; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.TemplateMsg.*; + /** * * Created by Binary Wang on 2016-10-14. @@ -20,20 +24,15 @@ * * @author Binary Wang */ +@RequiredArgsConstructor public class WxMpTemplateMsgServiceImpl implements WxMpTemplateMsgService { - public static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/template"; private static final JsonParser JSON_PARSER = new JsonParser(); - private WxMpService wxMpService; - - public WxMpTemplateMsgServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public String sendTemplateMsg(WxMpTemplateMessage templateMessage) throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/message/template/send"; - String responseContent = this.wxMpService.post(url, templateMessage.toJson()); + String responseContent = this.wxMpService.post(MESSAGE_TEMPLATE_SEND, templateMessage.toJson()); final JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); if (jsonObject.get("errcode").getAsInt() == 0) { return jsonObject.get("msgid").getAsString(); @@ -48,24 +47,21 @@ public boolean setIndustry(WxMpTemplateIndustry wxMpIndustry) throws WxErrorExce throw new IllegalArgumentException("行业Id不能为空,请核实"); } - String url = API_URL_PREFIX + "/api_set_industry"; - this.wxMpService.post(url, wxMpIndustry.toJson()); + this.wxMpService.post(TEMPLATE_API_SET_INDUSTRY, wxMpIndustry.toJson()); return true; } @Override public WxMpTemplateIndustry getIndustry() throws WxErrorException { - String url = API_URL_PREFIX + "/get_industry"; - String responseContent = this.wxMpService.get(url, null); + String responseContent = this.wxMpService.get(TEMPLATE_GET_INDUSTRY, null); return WxMpTemplateIndustry.fromJson(responseContent); } @Override public String addTemplate(String shortTemplateId) throws WxErrorException { - String url = API_URL_PREFIX + "/api_add_template"; JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("template_id_short", shortTemplateId); - String responseContent = this.wxMpService.post(url, jsonObject.toString()); + String responseContent = this.wxMpService.post(TEMPLATE_API_ADD_TEMPLATE, jsonObject.toString()); final JsonObject result = JSON_PARSER.parse(responseContent).getAsJsonObject(); if (result.get("errcode").getAsInt() == 0) { return result.get("template_id").getAsString(); @@ -76,16 +72,14 @@ public String addTemplate(String shortTemplateId) throws WxErrorException { @Override public ListgetAllPrivateTemplate() throws WxErrorException { - String url = API_URL_PREFIX + "/get_all_private_template"; - return WxMpTemplate.fromJson(this.wxMpService.get(url, null)); + return WxMpTemplate.fromJson(this.wxMpService.get(TEMPLATE_GET_ALL_PRIVATE_TEMPLATE, null)); } @Override public boolean delPrivateTemplate(String templateId) throws WxErrorException { - String url = API_URL_PREFIX + "/del_private_template"; JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("template_id", templateId); - String responseContent = this.wxMpService.post(url, jsonObject.toString()); + String responseContent = this.wxMpService.post(TEMPLATE_DEL_PRIVATE_TEMPLATE, jsonObject.toString()); WxError error = WxError.fromJson(responseContent, WxType.MP); if (error.getErrorCode() == 0) { return true; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java index a6ba958eb5..cd7ac541ae 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java @@ -1,43 +1,42 @@ package me.chanjar.weixin.mp.api.impl; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.google.gson.JsonObject; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpUserBlacklistService; import me.chanjar.weixin.mp.bean.result.WxMpUserBlacklistGetResult; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.UserBlacklist.*; + /** * @author miller */ +@RequiredArgsConstructor public class WxMpUserBlacklistServiceImpl implements WxMpUserBlacklistService { - private static final String API_BLACKLIST_PREFIX = "https://api.weixin.qq.com/cgi-bin/tags/members"; - private WxMpService wxMpService; - - public WxMpUserBlacklistServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public WxMpUserBlacklistGetResult getBlacklist(String nextOpenid) throws WxErrorException { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("begin_openid", nextOpenid); - String url = API_BLACKLIST_PREFIX + "/getblacklist"; - String responseContent = this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, jsonObject.toString()); + String responseContent = this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), + GETBLACKLIST, jsonObject.toString()); return WxMpUserBlacklistGetResult.fromJson(responseContent); } @Override public void pushToBlacklist(List openidList) throws WxErrorException { - Map map = new HashMap<>(); + Map map = new HashMap<>(2); map.put("openid_list", openidList); - String url = API_BLACKLIST_PREFIX + "/batchblacklist"; - this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, + this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), BATCHBLACKLIST, WxMpGsonBuilder.create().toJson(map)); } @@ -45,7 +44,7 @@ public void pushToBlacklist(List openidList) throws WxErrorException { public void pullFromBlacklist(List openidList) throws WxErrorException { Map map = new HashMap<>(2); map.put("openid_list", openidList); - String url = API_BLACKLIST_PREFIX + "/batchunblacklist"; - this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, WxMpGsonBuilder.create().toJson(map)); + this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), BATCHUNBLACKLIST, + WxMpGsonBuilder.create().toJson(map)); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java index d8c8943d36..0c77a93ffc 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java @@ -1,11 +1,7 @@ package me.chanjar.weixin.mp.api.impl; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpUserService; @@ -13,19 +9,23 @@ import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid; import me.chanjar.weixin.mp.bean.result.WxMpUser; import me.chanjar.weixin.mp.bean.result.WxMpUserList; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.User.*; + /** * Created by Binary Wang on 2016/7/21. * * @author BinaryWang */ +@RequiredArgsConstructor public class WxMpUserServiceImpl implements WxMpUserService { - private WxMpService wxMpService; - - public WxMpUserServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public void userUpdateRemark(String openid, String remark) throws WxErrorException { @@ -43,21 +43,19 @@ public WxMpUser userInfo(String openid) throws WxErrorException { @Override public WxMpUser userInfo(String openid, String lang) throws WxErrorException { lang = lang == null ? "zh_CN" : lang; - String responseContent = this.wxMpService.get(USER_INFO_URL, - "openid=" + openid + "&lang=" + lang); + String responseContent = this.wxMpService.get(USER_INFO_URL, "openid=" + openid + "&lang=" + lang); return WxMpUser.fromJson(responseContent); } @Override public WxMpUserList userList(String nextOpenid) throws WxErrorException { - String responseContent = this.wxMpService.get(USER_GET_URL, - nextOpenid == null ? null : "next_openid=" + nextOpenid); + String responseContent = this.wxMpService.get(USER_GET_URL, nextOpenid == null ? null : "next_openid=" + nextOpenid); return WxMpUserList.fromJson(responseContent); } @Override public List changeOpenid(String fromAppid, List openidList) throws WxErrorException { - Map map = new HashMap<>(); + Map map = new HashMap<>(2); map.put("from_appid", fromAppid); map.put("openid_list", openidList); String responseContent = this.wxMpService.post(USER_CHANGE_OPENID_URL, WxMpGsonBuilder.create().toJson(map)); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java index 6a37741b84..bf4696e497 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java @@ -4,6 +4,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; @@ -16,51 +17,43 @@ import java.util.List; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.UserTag.*; + /** * Created by Binary Wang on 2016/9/2. * * @author Binary Wang */ +@RequiredArgsConstructor public class WxMpUserTagServiceImpl implements WxMpUserTagService { - private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/tags"; - - private WxMpService wxMpService; - - public WxMpUserTagServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public WxUserTag tagCreate(String name) throws WxErrorException { - String url = API_URL_PREFIX + "/create"; JsonObject json = new JsonObject(); JsonObject tagJson = new JsonObject(); tagJson.addProperty("name", name); json.add("tag", tagJson); - String responseContent = this.wxMpService.post(url, json.toString()); + String responseContent = this.wxMpService.post(TAGS_CREATE, json.toString()); return WxUserTag.fromJson(responseContent); } @Override public List tagGet() throws WxErrorException { - String url = API_URL_PREFIX + "/get"; - - String responseContent = this.wxMpService.get(url, null); + String responseContent = this.wxMpService.get(TAGS_GET, null); return WxUserTag.listFromJson(responseContent); } @Override public Boolean tagUpdate(Long id, String name) throws WxErrorException { - String url = API_URL_PREFIX + "/update"; - JsonObject json = new JsonObject(); JsonObject tagJson = new JsonObject(); tagJson.addProperty("id", id); tagJson.addProperty("name", name); json.add("tag", tagJson); - String responseContent = this.wxMpService.post(url, json.toString()); + String responseContent = this.wxMpService.post(TAGS_UPDATE, json.toString()); WxError wxError = WxError.fromJson(responseContent, WxType.MP); if (wxError.getErrorCode() == 0) { return true; @@ -71,14 +64,12 @@ public Boolean tagUpdate(Long id, String name) throws WxErrorException { @Override public Boolean tagDelete(Long id) throws WxErrorException { - String url = API_URL_PREFIX + "/delete"; - JsonObject json = new JsonObject(); JsonObject tagJson = new JsonObject(); tagJson.addProperty("id", id); json.add("tag", tagJson); - String responseContent = this.wxMpService.post(url, json.toString()); + String responseContent = this.wxMpService.post(TAGS_DELETE, json.toString()); WxError wxError = WxError.fromJson(responseContent, WxType.MP); if (wxError.getErrorCode() == 0) { return true; @@ -88,23 +79,17 @@ public Boolean tagDelete(Long id) throws WxErrorException { } @Override - public WxTagListUser tagListUser(Long tagId, String nextOpenid) - throws WxErrorException { - String url = "https://api.weixin.qq.com/cgi-bin/user/tag/get"; - + public WxTagListUser tagListUser(Long tagId, String nextOpenid) throws WxErrorException { JsonObject json = new JsonObject(); json.addProperty("tagid", tagId); json.addProperty("next_openid", StringUtils.trimToEmpty(nextOpenid)); - String responseContent = this.wxMpService.post(url, json.toString()); + String responseContent = this.wxMpService.post(TAG_GET, json.toString()); return WxTagListUser.fromJson(responseContent); } @Override - public boolean batchTagging(Long tagId, String[] openids) - throws WxErrorException { - String url = API_URL_PREFIX + "/members/batchtagging"; - + public boolean batchTagging(Long tagId, String[] openids) throws WxErrorException { JsonObject json = new JsonObject(); json.addProperty("tagid", tagId); JsonArray openidArrayJson = new JsonArray(); @@ -113,7 +98,7 @@ public boolean batchTagging(Long tagId, String[] openids) } json.add("openid_list", openidArrayJson); - String responseContent = this.wxMpService.post(url, json.toString()); + String responseContent = this.wxMpService.post(TAGS_MEMBERS_BATCHTAGGING, json.toString()); WxError wxError = WxError.fromJson(responseContent, WxType.MP); if (wxError.getErrorCode() == 0) { return true; @@ -123,10 +108,7 @@ public boolean batchTagging(Long tagId, String[] openids) } @Override - public boolean batchUntagging(Long tagId, String[] openids) - throws WxErrorException { - String url = API_URL_PREFIX + "/members/batchuntagging"; - + public boolean batchUntagging(Long tagId, String[] openids) throws WxErrorException { JsonObject json = new JsonObject(); json.addProperty("tagid", tagId); JsonArray openidArrayJson = new JsonArray(); @@ -135,7 +117,7 @@ public boolean batchUntagging(Long tagId, String[] openids) } json.add("openid_list", openidArrayJson); - String responseContent = this.wxMpService.post(url, json.toString()); + String responseContent = this.wxMpService.post(TAGS_MEMBERS_BATCHUNTAGGING, json.toString()); WxError wxError = WxError.fromJson(responseContent, WxType.MP); if (wxError.getErrorCode() == 0) { return true; @@ -146,12 +128,10 @@ public boolean batchUntagging(Long tagId, String[] openids) @Override public List userTagList(String openid) throws WxErrorException { - String url = API_URL_PREFIX + "/getidlist"; - JsonObject json = new JsonObject(); json.addProperty("openid", openid); - String responseContent = this.wxMpService.post(url, json.toString()); + String responseContent = this.wxMpService.post(TAGS_GETIDLIST, json.toString()); return WxMpGsonBuilder.create().fromJson( new JsonParser().parse(responseContent).getAsJsonObject().get("tagid_list"), diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java index f87c784b89..0b75bb996b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java @@ -1,11 +1,15 @@ package me.chanjar.weixin.mp.api.impl; import com.google.gson.JsonObject; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpWifiService; +import me.chanjar.weixin.mp.bean.wifi.WxMpWifiShopDataResult; import me.chanjar.weixin.mp.bean.wifi.WxMpWifiShopListResult; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Wifi.*; + /** * * Created by BinaryWang on 2018/6/10. @@ -13,19 +17,40 @@ * * @author Binary Wang */ +@RequiredArgsConstructor public class WxMpWifiServiceImpl implements WxMpWifiService { - private WxMpService wxMpService; - - public WxMpWifiServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public WxMpWifiShopListResult listShop(int pageIndex, int pageSize) throws WxErrorException { JsonObject json = new JsonObject(); json.addProperty("pageindex", pageIndex); json.addProperty("pagesize", pageSize); - final String result = this.wxMpService.post("https://api.weixin.qq.com/bizwifi/shop/list", json.toString()); + final String result = this.wxMpService.post(BIZWIFI_SHOP_LIST, json.toString()); return WxMpWifiShopListResult.fromJson(result); } + + @Override + public WxMpWifiShopDataResult getShopWifiInfo(int shopId) throws WxErrorException { + JsonObject json = new JsonObject(); + json.addProperty("shop_id", shopId); + return WxMpWifiShopDataResult.fromJson(this.wxMpService.post(BIZWIFI_SHOP_GET, json.toString())); + } + + @Override + public boolean updateShopWifiInfo(int shopId, String oldSsid, String ssid, String password) throws WxErrorException { + JsonObject json = new JsonObject(); + json.addProperty("shop_id", shopId); + json.addProperty("old_ssid", oldSsid); + json.addProperty("ssid", ssid); + if (password != null) { + json.addProperty("password", password); + } + try { + this.wxMpService.post(BIZWIFI_SHOP_UPDATE, json.toString()); + return true; + } catch (WxErrorException e) { + throw e; + } + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpHostConfig.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpHostConfig.java new file mode 100644 index 0000000000..9fff434e1f --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpHostConfig.java @@ -0,0 +1,56 @@ +package me.chanjar.weixin.mp.bean; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 微信接口地址域名部分的自定义设置信息. + * + * @author Binary Wang + * @date 2019-06-09 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxMpHostConfig { + public static final String API_DEFAULT_HOST_URL = "https://api.weixin.qq.com"; + public static final String MP_DEFAULT_HOST_URL = "https://mp.weixin.qq.com"; + public static final String OPEN_DEFAULT_HOST_URL = "https://open.weixin.qq.com"; + + /** + * 对应于:https://api.weixin.qq.com + */ + private String apiHost; + + /** + * 对应于:https://open.weixin.qq.com + */ + private String openHost; + /** + * 对应于:https://mp.weixin.qq.com + */ + private String mpHost; + + public static String buildUrl(WxMpHostConfig hostConfig, String prefix, String path) { + if (hostConfig == null) { + return prefix + path; + } + + if (hostConfig.getApiHost() != null && prefix.equals(API_DEFAULT_HOST_URL)) { + return hostConfig.getApiHost() + path; + } + + if (hostConfig.getMpHost() != null && prefix.equals(MP_DEFAULT_HOST_URL)) { + return hostConfig.getMpHost() + path; + } + + if (hostConfig.getOpenHost() != null && prefix.equals(OPEN_DEFAULT_HOST_URL)) { + return hostConfig.getOpenHost() + path; + } + + return prefix + path; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java index 0a72814af8..5e0b638e9f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java @@ -7,7 +7,7 @@ import java.io.Serializable; /** - * 按标签群发的消息 + * 按标签群发的消息. * * @author chanjarster */ @@ -16,12 +16,12 @@ public class WxMpMassTagMessage implements Serializable { private static final long serialVersionUID = -6625914040986749286L; /** - * 标签id,如果不设置则就意味着发给所有用户 + * 标签id,如果不设置则就意味着发给所有用户. */ private Long tagId; /** **/ @SerializedName("key") private String key; /** + * . + * * @see #key */ @SerializedName("url") private String url; + /** + * . + * * @see #key */ @SerializedName("value") private String value; + + /** + *- * 消息类型 + * 消息类型. * 请使用 * {@link WxConsts.MassMsgType#IMAGE} * {@link WxConsts.MassMsgType#MPNEWS} @@ -35,17 +35,17 @@ public class WxMpMassTagMessage implements Serializable { private String content; private String mediaId; /** - * 是否群发给所有用户 + * 是否群发给所有用户. */ private boolean isSendAll = false; /** - * 文章被判定为转载时,是否继续进行群发操作。 + * 文章被判定为转载时,是否继续进行群发操作. */ private boolean sendIgnoreReprint = false; /** - * 开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid + * 开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid. */ private String clientMsgId; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Card.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Card.java index c97f88f2fc..506101089c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Card.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Card.java @@ -9,11 +9,10 @@ /** * . * @author leeis - * @Date 2018/12/29 + * @date 2018/12/29 */ @Data public class Card implements Serializable { - private static final long serialVersionUID = -3697110761983756780L; /** diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardDeleteResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardDeleteResult.java index 3dcbc3534c..8eedbebf60 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardDeleteResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardDeleteResult.java @@ -3,11 +3,13 @@ import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * @description 删除卡券结果 - * @author: fanxl - * @date: 2019/1/22 0022 10:24 + * 删除卡券结果. + * + * @author fanxl + * @date 2019/1/22 0022 10:24 */ public class WxMpCardDeleteResult extends BaseWxMpCardResult { + private static final long serialVersionUID = -4367717540650523290L; public static WxMpCardDeleteResult fromJson(String json) { return WxMpGsonBuilder.create().fromJson(json, WxMpCardDeleteResult.class); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java index 560add6042..37beb77e78 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java @@ -1,6 +1,8 @@ package me.chanjar.weixin.mp.bean.kefu; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.mp.builder.kefu.*; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @@ -10,7 +12,7 @@ import java.util.List; /** - * 客服消息 + * 客服消息. * * @author chanjarster */ @@ -32,66 +34,80 @@ public class WxMpKefuMessage implements Serializable { private String mpNewsMediaId; private String miniProgramAppId; private String miniProgramPagePath; + private String headContent; + private String tailContent; private List- * */ public void setMsgType(String msgType) { this.msgType = msgType; @@ -122,6 +138,8 @@ public String toJson() { } @Data + @AllArgsConstructor + @NoArgsConstructor public static class WxArticle implements Serializable { private static final long serialVersionUID = 5145137235440507379L; @@ -130,4 +148,14 @@ public static class WxArticle implements Serializable { private String url; private String picUrl; } + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class MsgMenu implements Serializable { + private static final long serialVersionUID = 7020769047598378839L; + + private String id; + private String content; + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/marketing/WxMpUserAction.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/marketing/WxMpUserAction.java index 69fced907a..ad5f723e53 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/marketing/WxMpUserAction.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/marketing/WxMpUserAction.java @@ -1,39 +1,71 @@ package me.chanjar.weixin.mp.bean.marketing; +import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import java.io.Serializable; +import java.util.List; /** * @author 007 */ @Data +@NoArgsConstructor +@AllArgsConstructor +@Builder public class WxMpUserAction implements Serializable { private static final long serialVersionUID = 7042393762652152209L; + private Long userActionSetId; private String url; - private Boolean actionTime; + private Integer actionTime; private String actionType; + private String leadsType; private String clickId; private Integer actionParam; - public JsonObject toJsonObject() { + private JsonObject toJsonObject() { JsonObject json = new JsonObject(); json.addProperty("user_action_set_id", this.userActionSetId); json.addProperty("url", this.url); json.addProperty("action_time", this.actionTime); + json.addProperty("action_type", this.actionType); + if (this.clickId != null) { JsonObject traceJson = new JsonObject(); traceJson.addProperty("click_id", this.clickId); json.add("trace", traceJson); } + if (this.actionParam != null) { JsonObject actionParamJson = new JsonObject(); actionParamJson.addProperty("value", actionParam); + actionParamJson.addProperty("leads_type", leadsType); json.add("action_param", actionParamJson); } + return json; } + + /** + * list对象转换为json字符串 + * + * @param actions . + * @return . + */ + public static String listToJson(Listarticles = new ArrayList<>(); /** - * 获得文本消息builder + * 菜单消息里的菜单内容. + */ + private List msgMenus = new ArrayList<>(); + + /** + * 获得文本消息builder. */ public static TextBuilder TEXT() { return new TextBuilder(); } /** - * 获得图片消息builder + * 获得图片消息builder. */ public static ImageBuilder IMAGE() { return new ImageBuilder(); } /** - * 获得语音消息builder + * 获得语音消息builder. */ public static VoiceBuilder VOICE() { return new VoiceBuilder(); } /** - * 获得视频消息builder + * 获得视频消息builder. */ public static VideoBuilder VIDEO() { return new VideoBuilder(); } /** - * 获得音乐消息builder + * 获得音乐消息builder. */ public static MusicBuilder MUSIC() { return new MusicBuilder(); } /** - * 获得图文消息(点击跳转到外链)builder + * 获得图文消息(点击跳转到外链)builder. */ public static NewsBuilder NEWS() { return new NewsBuilder(); } /** - * 获得图文消息(点击跳转到图文消息页面)builder + * 获得图文消息(点击跳转到图文消息页面)builder. */ public static MpNewsBuilder MPNEWS() { return new MpNewsBuilder(); } /** - * 获得卡券消息builder + * 获得卡券消息builder. */ public static WxCardBuilder WXCARD() { return new WxCardBuilder(); } /** - * 小程序卡片 + * 获得菜单消息builder. + */ + public static WxMsgMenuBuilder MSGMENU() { + return new WxMsgMenuBuilder(); + } + + /** + * 小程序卡片. */ public static MiniProgramPageBuilder MINIPROGRAMPAGE() { return new MiniProgramPageBuilder(); @@ -110,8 +126,8 @@ public static MiniProgramPageBuilder MINIPROGRAMPAGE() { * {@link WxConsts.KefuMsgType#WXCARD} * {@link WxConsts.KefuMsgType#MINIPROGRAMPAGE} * {@link WxConsts.KefuMsgType#TASKCARD} + * {@link WxConsts.KefuMsgType#MSGMENU} * actions) { + JsonArray array = new JsonArray(); + for (WxMpUserAction action : actions) { + array.add(action.toJsonObject()); + } + + JsonObject result = new JsonObject(); + result.add("actions", array); + return result.toString(); + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java index 4789b47089..f0e0a1049a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/menu/WxMpSelfMenuInfo.java @@ -43,13 +43,13 @@ public static class WxMpSelfMenuButton implements Serializable { @SerializedName("type") private String type; /** - * 菜单名称 + * 菜单名称. */ @SerializedName("name") private String name; /** * - * 对于不同的菜单类型,value的值意义不同。 + * 对于不同的菜单类型,value的值意义不同. * 官网上设置的自定义菜单: *Text:保存文字到value; * Img、voice:保存mediaID到value; @@ -58,29 +58,52 @@ public static class WxMpSelfMenuButton implements Serializable { * View:保存链接到url。 * * 使用API设置的自定义菜单: - *click、scancode_push、scancode_waitmsg、pic_sysphoto、pic_photo_or_album、 pic_weixin、location_select:保存值到key; + * click、scancode_push、scancode_waitmsg、pic_sysphoto、pic_photo_or_album、pic_weixin、location_select:保存值到key; * view:保存链接到url * + * 小程序的appid. + * miniprogram类型必须 + *+ */ + @SerializedName("appid") + private String appId; + /** - * 子菜单信息 + *+ * 小程序的页面路径. + * miniprogram类型必须 + *+ */ + @SerializedName("pagepath") + private String pagePath; + /** + * 子菜单信息. */ @SerializedName("sub_button") private SubButtons subButtons; /** - * 图文消息的信息 + * 图文消息的信息. */ @SerializedName("news_info") private NewsInfo newsInfo; @@ -116,42 +139,41 @@ public String toString() { } @Data - public static class NewsInButton implements Serializable { + public static class NewsInButton implements Serializable { private static final long serialVersionUID = 8701455967664912972L; /** - * 图文消息的标题 + * 图文消息的标题. */ @SerializedName("title") private String title; /** - * 摘要 + * 摘要. */ @SerializedName("digest") private String digest; /** - * 作者 + * 作者. */ @SerializedName("author") private String author; /** - * show_cover - * 是否显示封面,0为不显示,1为显示 + * 是否显示封面,0为不显示,1为显示. */ @SerializedName("show_cover") private Integer showCover; /** - * 封面图片的URL + * 封面图片的URL. */ @SerializedName("cover_url") private String coverUrl; /** - * 正文的URL + * 正文的URL. */ @SerializedName("content_url") private String contentUrl; /** - * 原文的URL,若置空则无查看原文入口 + * 原文的URL,若置空则无查看原文入口. */ @SerializedName("source_url") private String sourceUrl; @@ -160,7 +182,6 @@ public static class NewsInButton implements Serializable { public String toString() { return WxMpGsonBuilder.create().toJson(this); } - } } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java index 368f70e383..bb93976f31 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java @@ -15,7 +15,7 @@ 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.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; import me.chanjar.weixin.mp.util.xml.XStreamTransformer; @@ -528,6 +528,14 @@ public class WxMpXmlMessage implements Serializable { @XStreamConverter(value = XStreamCDataConverter.class) private String deviceId; + /** + * 微信客户端生成的session id,用于request和response对应, + * 因此响应中该字段第三方需要原封不变的带回 + */ + @XStreamAlias("SessionID") + @XStreamConverter(value = XStreamCDataConverter.class) + private String sessionId; + /** * 微信用户账号的OpenID. */ @@ -626,11 +634,17 @@ public class WxMpXmlMessage implements Serializable { private String regionCode; /** - * 审核未通过的原因。 + * 审核未通过的原因. */ @XStreamAlias("ReasonMsg") private String reasonMsg; + /** + * 给用户发菜单消息类型的客服消息后,用户所点击的菜单ID. + */ + @XStreamAlias("bizmsgmenuid") + private String bizMsgMenuId; + public static WxMpXmlMessage fromXml(String xml) { //修改微信变态的消息内容格式,方便解析 xml = xml.replace("
+ * 用法: + * WxMpKefuMessage m = WxMpKefuMessage.MSGMENU().addMenus(lists).headContent(headContent).tailContent(tailContent).toUser(...).build(); + *+ * + * @author billytomato + */ +public final class WxMsgMenuBuilder extends BaseBuilder
+ * 公众号接口api地址 + * Created by BinaryWang on 2019-06-03. + *+ * + * @author Binary Wang + */ +public interface WxMpApiUrl { + + /** + * 得到api完整地址. + * + * @param config 微信公众号配置 + * @return api地址 + */ + String getUrl(WxMpConfigStorage config); + + @AllArgsConstructor + enum Device implements WxMpApiUrl { + /** + * get_bind_device. + */ + DEVICE_GET_BIND_DEVICE(API_DEFAULT_HOST_URL, "/device/get_bind_device"), + /** + * get_openid. + */ + DEVICE_GET_OPENID(API_DEFAULT_HOST_URL, "/device/get_openid"), + /** + * compel_unbind. + */ + DEVICE_COMPEL_UNBIND(API_DEFAULT_HOST_URL, "/device/compel_unbind?"), + /** + * unbind. + */ + DEVICE_UNBIND(API_DEFAULT_HOST_URL, "/device/unbind?"), + /** + * compel_bind. + */ + DEVICE_COMPEL_BIND(API_DEFAULT_HOST_URL, "/device/compel_bind"), + /** + * bind. + */ + DEVICE_BIND(API_DEFAULT_HOST_URL, "/device/bind"), + /** + * authorize_device. + */ + DEVICE_AUTHORIZE_DEVICE(API_DEFAULT_HOST_URL, "/device/authorize_device"), + /** + * getqrcode. + */ + DEVICE_GETQRCODE(API_DEFAULT_HOST_URL, "/device/getqrcode"), + /** + * transmsg. + */ + DEVICE_TRANSMSG(API_DEFAULT_HOST_URL, "/device/transmsg"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + + } + + @AllArgsConstructor + enum Other implements WxMpApiUrl { + /** + * 获取access_token. + */ + GET_ACCESS_TOKEN_URL(API_DEFAULT_HOST_URL, "/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"), + /** + * 获得各种类型的ticket. + */ + GET_TICKET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/ticket/getticket?type="), + /** + * 长链接转短链接接口. + */ + SHORTURL_API_URL(API_DEFAULT_HOST_URL, "/cgi-bin/shorturl"), + /** + * 语义查询接口. + */ + SEMANTIC_SEMPROXY_SEARCH_URL(API_DEFAULT_HOST_URL, "/semantic/semproxy/search"), + /** + * 用code换取oauth2的access token. + */ + OAUTH2_ACCESS_TOKEN_URL(API_DEFAULT_HOST_URL, "/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"), + /** + * 刷新oauth2的access token. + */ + OAUTH2_REFRESH_TOKEN_URL(API_DEFAULT_HOST_URL, "/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s"), + /** + * 用oauth2获取用户信息. + */ + OAUTH2_USERINFO_URL(API_DEFAULT_HOST_URL, "/sns/userinfo?access_token=%s&openid=%s&lang=%s"), + /** + * 验证oauth2的access token是否有效. + */ + OAUTH2_VALIDATE_TOKEN_URL(API_DEFAULT_HOST_URL, "/sns/auth?access_token=%s&openid=%s"), + /** + * 获取微信服务器IP地址. + */ + GET_CALLBACK_IP_URL(API_DEFAULT_HOST_URL, "/cgi-bin/getcallbackip"), + /** + * 第三方使用网站应用授权登录的url. + */ + QRCONNECT_URL(OPEN_DEFAULT_HOST_URL, "/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"), + /** + * oauth2授权的url连接. + */ + CONNECT_OAUTH2_AUTHORIZE_URL(OPEN_DEFAULT_HOST_URL, "/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&connect_redirect=1#wechat_redirect"), + /** + * 获取公众号的自动回复规则. + */ + GET_CURRENT_AUTOREPLY_INFO_URL(API_DEFAULT_HOST_URL, "/cgi-bin/get_current_autoreply_info"), + /** + * 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零. + */ + CLEAR_QUOTA_URL(API_DEFAULT_HOST_URL, "/cgi-bin/clear_quota"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum Marketing implements WxMpApiUrl { + /** + * sets add. + */ + USER_ACTION_SETS_ADD(API_DEFAULT_HOST_URL, "/marketing/user_action_sets/add?version=v1.0"), + /** + * get. + */ + USER_ACTION_SETS_GET(API_DEFAULT_HOST_URL, "/marketing/user_action_sets/get"), + /** + * add. + */ + USER_ACTIONS_ADD(API_DEFAULT_HOST_URL, "/marketing/user_actions/add?version=v1.0"), + /** + * get. + */ + WECHAT_AD_LEADS_GET(API_DEFAULT_HOST_URL, "/marketing/wechat_ad_leads/get"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum Menu implements WxMpApiUrl { + /** + * get_current_selfmenu_info. + */ + GET_CURRENT_SELFMENU_INFO(API_DEFAULT_HOST_URL, "/cgi-bin/get_current_selfmenu_info"), + /** + * trymatch. + */ + MENU_TRYMATCH(API_DEFAULT_HOST_URL, "/cgi-bin/menu/trymatch"), + /** + * get. + */ + MENU_GET(API_DEFAULT_HOST_URL, "/cgi-bin/menu/get"), + /** + * delconditional. + */ + MENU_DELCONDITIONAL(API_DEFAULT_HOST_URL, "/cgi-bin/menu/delconditional"), + /** + * delete. + */ + MENU_DELETE(API_DEFAULT_HOST_URL, "/cgi-bin/menu/delete"), + /** + * create. + */ + MENU_CREATE(API_DEFAULT_HOST_URL, "/cgi-bin/menu/create"), + /** + * addconditional. + */ + MENU_ADDCONDITIONAL(API_DEFAULT_HOST_URL, "/cgi-bin/menu/addconditional"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + + @AllArgsConstructor + enum Qrcode implements WxMpApiUrl { + /** + * create. + */ + QRCODE_CREATE(API_DEFAULT_HOST_URL, "/cgi-bin/qrcode/create"), + /** + * showqrcode. + */ + SHOW_QRCODE(MP_DEFAULT_HOST_URL, "/cgi-bin/showqrcode"), + /** + * showqrcode. + */ + SHOW_QRCODE_WITH_TICKET(MP_DEFAULT_HOST_URL, "/cgi-bin/showqrcode?ticket=%s"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum ShakeAround implements WxMpApiUrl { + /** + * getshakeinfo. + */ + SHAKEAROUND_USER_GETSHAKEINFO(API_DEFAULT_HOST_URL, "/shakearound/user/getshakeinfo"), + /** + * add. + */ + SHAKEAROUND_PAGE_ADD(API_DEFAULT_HOST_URL, "/shakearound/page/add"), + /** + * bindpage. + */ + SHAKEAROUND_DEVICE_BINDPAGE(API_DEFAULT_HOST_URL, "/shakearound/device/bindpage"), + /** + * search. + */ + SHAKEAROUND_RELATION_SEARCH(API_DEFAULT_HOST_URL, "/shakearound/relation/search"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum SubscribeMsg implements WxMpApiUrl { + /** + * subscribemsg. + */ + SUBSCRIBE_MESSAGE_AUTHORIZE_URL(MP_DEFAULT_HOST_URL, "/mp/subscribemsg?action=get_confirm&appid=%s&scene=%d&template_id=%s&redirect_url=%s&reserved=%s#wechat_redirect"), + /** + * subscribe. + */ + SEND_MESSAGE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/template/subscribe"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum TemplateMsg implements WxMpApiUrl { + /** + * send. + */ + MESSAGE_TEMPLATE_SEND(API_DEFAULT_HOST_URL, "/cgi-bin/message/template/send"), + /** + * api_set_industry. + */ + TEMPLATE_API_SET_INDUSTRY(API_DEFAULT_HOST_URL, "/cgi-bin/template/api_set_industry"), + /** + * get_industry. + */ + TEMPLATE_GET_INDUSTRY(API_DEFAULT_HOST_URL, "/cgi-bin/template/get_industry"), + /** + * api_add_template. + */ + TEMPLATE_API_ADD_TEMPLATE(API_DEFAULT_HOST_URL, "/cgi-bin/template/api_add_template"), + /** + * get_all_private_template. + */ + TEMPLATE_GET_ALL_PRIVATE_TEMPLATE(API_DEFAULT_HOST_URL, "/cgi-bin/template/get_all_private_template"), + /** + * del_private_template. + */ + TEMPLATE_DEL_PRIVATE_TEMPLATE(API_DEFAULT_HOST_URL, "/cgi-bin/template/del_private_template"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum UserBlacklist implements WxMpApiUrl { + /** + * getblacklist. + */ + GETBLACKLIST(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/getblacklist"), + /** + * batchblacklist. + */ + BATCHBLACKLIST(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/batchblacklist"), + /** + * batchunblacklist. + */ + BATCHUNBLACKLIST(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/batchunblacklist"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum UserTag implements WxMpApiUrl { + /** + * create. + */ + TAGS_CREATE(API_DEFAULT_HOST_URL, "/cgi-bin/tags/create"), + /** + * get. + */ + TAGS_GET(API_DEFAULT_HOST_URL, "/cgi-bin/tags/get"), + /** + * update. + */ + TAGS_UPDATE(API_DEFAULT_HOST_URL, "/cgi-bin/tags/update"), + /** + * delete. + */ + TAGS_DELETE(API_DEFAULT_HOST_URL, "/cgi-bin/tags/delete"), + /** + * get. + */ + TAG_GET(API_DEFAULT_HOST_URL, "/cgi-bin/user/tag/get"), + /** + * batchtagging. + */ + TAGS_MEMBERS_BATCHTAGGING(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/batchtagging"), + /** + * batchuntagging. + */ + TAGS_MEMBERS_BATCHUNTAGGING(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/batchuntagging"), + /** + * getidlist. + */ + TAGS_GETIDLIST(API_DEFAULT_HOST_URL, "/cgi-bin/tags/getidlist"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum Wifi implements WxMpApiUrl { + /** + * list. + */ + BIZWIFI_SHOP_LIST(API_DEFAULT_HOST_URL, "/bizwifi/shop/list"), + + /** + * get. + */ + BIZWIFI_SHOP_GET(API_DEFAULT_HOST_URL, "/bizwifi/shop/get"), + + /** + * upadte. + */ + BIZWIFI_SHOP_UPDATE(API_DEFAULT_HOST_URL, "/bizwifi/shop/update"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum AiOpen implements WxMpApiUrl { + /** + * translatecontent. + */ + TRANSLATE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/voice/translatecontent?lfrom=%s<o=%s"), + /** + * addvoicetorecofortext. + */ + VOICE_UPLOAD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/voice/addvoicetorecofortext?format=%s&voice_id=%s&lang=%s"), + /** + * queryrecoresultfortext. + */ + VOICE_QUERY_RESULT_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/voice/queryrecoresultfortext"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum Ocr implements WxMpApiUrl { + /** + * 身份证识别. + */ + IDCARD(API_DEFAULT_HOST_URL, "/cv/ocr/idcard?type=%s&img_url=%s"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + if (config == null) { + return buildUrl(null, prefix, path); + } + + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum Card implements WxMpApiUrl { + /** + * create. + */ + CARD_CREATE(API_DEFAULT_HOST_URL, "/card/create"), + /** + * get. + */ + CARD_GET(API_DEFAULT_HOST_URL, "/card/get"), + /** + * wx_card. + */ + CARD_GET_TICKET(API_DEFAULT_HOST_URL, "/cgi-bin/ticket/getticket?type=wx_card"), + /** + * decrypt. + */ + CARD_CODE_DECRYPT(API_DEFAULT_HOST_URL, "/card/code/decrypt"), + /** + * get. + */ + CARD_CODE_GET(API_DEFAULT_HOST_URL, "/card/code/get"), + /** + * consume. + */ + CARD_CODE_CONSUME(API_DEFAULT_HOST_URL, "/card/code/consume"), + /** + * mark. + */ + CARD_CODE_MARK(API_DEFAULT_HOST_URL, "/card/code/mark"), + /** + * set. + */ + CARD_TEST_WHITELIST(API_DEFAULT_HOST_URL, "/card/testwhitelist/set"), + /** + * create. + */ + CARD_QRCODE_CREATE(API_DEFAULT_HOST_URL, "/card/qrcode/create"), + /** + * create. + */ + CARD_LANDING_PAGE_CREATE(API_DEFAULT_HOST_URL, "/card/landingpage/create"), + /** + * 将用户的卡券设置为失效状态. + */ + CARD_CODE_UNAVAILABLE(API_DEFAULT_HOST_URL, "/card/code/unavailable"), + /** + * 卡券删除. + */ + CARD_DELETE(API_DEFAULT_HOST_URL, "/card/delete"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum DataCube implements WxMpApiUrl { + /** + * getusersummary. + */ + GET_USER_SUMMARY(API_DEFAULT_HOST_URL, "/datacube/getusersummary"), + /** + * getusercumulate. + */ + GET_USER_CUMULATE(API_DEFAULT_HOST_URL, "/datacube/getusercumulate"), + /** + * getarticlesummary. + */ + GET_ARTICLE_SUMMARY(API_DEFAULT_HOST_URL, "/datacube/getarticlesummary"), + /** + * getarticletotal. + */ + GET_ARTICLE_TOTAL(API_DEFAULT_HOST_URL, "/datacube/getarticletotal"), + /** + * getuserread. + */ + GET_USER_READ(API_DEFAULT_HOST_URL, "/datacube/getuserread"), + /** + * getuserreadhour. + */ + GET_USER_READ_HOUR(API_DEFAULT_HOST_URL, "/datacube/getuserreadhour"), + /** + * getusershare. + */ + GET_USER_SHARE(API_DEFAULT_HOST_URL, "/datacube/getusershare"), + /** + * getusersharehour. + */ + GET_USER_SHARE_HOUR(API_DEFAULT_HOST_URL, "/datacube/getusersharehour"), + /** + * getupstreammsg. + */ + GET_UPSTREAM_MSG(API_DEFAULT_HOST_URL, "/datacube/getupstreammsg"), + /** + * getupstreammsghour. + */ + GET_UPSTREAM_MSG_HOUR(API_DEFAULT_HOST_URL, "/datacube/getupstreammsghour"), + /** + * getupstreammsgweek. + */ + GET_UPSTREAM_MSG_WEEK(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgweek"), + /** + * getupstreammsgmonth. + */ + GET_UPSTREAM_MSG_MONTH(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgmonth"), + /** + * getupstreammsgdist. + */ + GET_UPSTREAM_MSG_DIST(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgdist"), + /** + * getupstreammsgdistweek. + */ + GET_UPSTREAM_MSG_DIST_WEEK(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgdistweek"), + /** + * getupstreammsgdistmonth. + */ + GET_UPSTREAM_MSG_DIST_MONTH(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgdistmonth"), + /** + * getinterfacesummary. + */ + GET_INTERFACE_SUMMARY(API_DEFAULT_HOST_URL, "/datacube/getinterfacesummary"), + /** + * getinterfacesummaryhour. + */ + GET_INTERFACE_SUMMARY_HOUR(API_DEFAULT_HOST_URL, "/datacube/getinterfacesummaryhour"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum Kefu implements WxMpApiUrl { + /** + * send. + */ + MESSAGE_CUSTOM_SEND(API_DEFAULT_HOST_URL, "/cgi-bin/message/custom/send"), + /** + * getkflist. + */ + GET_KF_LIST(API_DEFAULT_HOST_URL, "/cgi-bin/customservice/getkflist"), + /** + * getonlinekflist. + */ + GET_ONLINE_KF_LIST(API_DEFAULT_HOST_URL, "/cgi-bin/customservice/getonlinekflist"), + /** + * add. + */ + KFACCOUNT_ADD(API_DEFAULT_HOST_URL, "/customservice/kfaccount/add"), + /** + * update. + */ + KFACCOUNT_UPDATE(API_DEFAULT_HOST_URL, "/customservice/kfaccount/update"), + /** + * inviteworker. + */ + KFACCOUNT_INVITE_WORKER(API_DEFAULT_HOST_URL, "/customservice/kfaccount/inviteworker"), + /** + * uploadheadimg. + */ + KFACCOUNT_UPLOAD_HEAD_IMG(API_DEFAULT_HOST_URL, "/customservice/kfaccount/uploadheadimg?kf_account=%s"), + /** + * del kfaccount. + */ + KFACCOUNT_DEL(API_DEFAULT_HOST_URL, "/customservice/kfaccount/del?kf_account=%s"), + /** + * create. + */ + KFSESSION_CREATE(API_DEFAULT_HOST_URL, "/customservice/kfsession/create"), + /** + * close. + */ + KFSESSION_CLOSE(API_DEFAULT_HOST_URL, "/customservice/kfsession/close"), + /** + * getsession. + */ + KFSESSION_GET_SESSION(API_DEFAULT_HOST_URL, "/customservice/kfsession/getsession?openid=%s"), + /** + * getsessionlist. + */ + KFSESSION_GET_SESSION_LIST(API_DEFAULT_HOST_URL, "/customservice/kfsession/getsessionlist?kf_account=%s"), + /** + * getwaitcase. + */ + KFSESSION_GET_WAIT_CASE(API_DEFAULT_HOST_URL, "/customservice/kfsession/getwaitcase"), + /** + * getmsglist. + */ + MSG_RECORD_LIST(API_DEFAULT_HOST_URL, "/customservice/msgrecord/getmsglist"), + /** + * typing. + */ + CUSTOM_TYPING(API_DEFAULT_HOST_URL, "/cgi-bin/message/custom/typing"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum MassMessage implements WxMpApiUrl { + /** + * 上传群发用的图文消息. + */ + MEDIA_UPLOAD_NEWS_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/uploadnews"), + /** + * 上传群发用的视频. + */ + MEDIA_UPLOAD_VIDEO_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/uploadvideo"), + /** + * 分组群发消息. + */ + MESSAGE_MASS_SENDALL_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/mass/sendall"), + /** + * 按openId列表群发消息. + */ + MESSAGE_MASS_SEND_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/mass/send"), + /** + * 群发消息预览接口. + */ + MESSAGE_MASS_PREVIEW_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/mass/preview"), + /** + * 删除群发接口. + */ + MESSAGE_MASS_DELETE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/mass/delete"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum Material implements WxMpApiUrl { + /** + * get. + */ + MEDIA_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/get"), + /** + * upload. + */ + MEDIA_UPLOAD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/upload?type=%s"), + /** + * uploadimg. + */ + IMG_UPLOAD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/uploadimg"), + /** + * add_material. + */ + MATERIAL_ADD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/add_material?type=%s"), + /** + * add_news. + */ + NEWS_ADD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/add_news"), + /** + * get_material. + */ + MATERIAL_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/get_material"), + /** + * update_news. + */ + NEWS_UPDATE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/update_news"), + /** + * del_material. + */ + MATERIAL_DEL_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/del_material"), + /** + * get_materialcount. + */ + MATERIAL_GET_COUNT_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/get_materialcount"), + /** + * batchget_material. + */ + MATERIAL_BATCHGET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/batchget_material"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum MemberCard implements WxMpApiUrl { + /** + * create. + */ + MEMBER_CARD_CREATE(API_DEFAULT_HOST_URL, "/card/create"), + /** + * activate. + */ + MEMBER_CARD_ACTIVATE(API_DEFAULT_HOST_URL, "/card/membercard/activate"), + /** + * get userinfo. + */ + MEMBER_CARD_USER_INFO_GET(API_DEFAULT_HOST_URL, "/card/membercard/userinfo/get"), + /** + * updateuser. + */ + MEMBER_CARD_UPDATE_USER(API_DEFAULT_HOST_URL, "/card/membercard/updateuser"), + /** + * 会员卡激活之微信开卡接口(wx_activate=true情况调用). + */ + MEMBER_CARD_ACTIVATE_USER_FORM(API_DEFAULT_HOST_URL, "/card/membercard/activateuserform/set"), + /** + * 获取会员卡开卡插件参数. + */ + MEMBER_CARD_ACTIVATE_URL(API_DEFAULT_HOST_URL, "/card/membercard/activate/geturl"), + /** + * 会员卡信息更新. + */ + MEMBER_CARD_UPDATE(API_DEFAULT_HOST_URL, "/card/update"), + /** + * 跳转型会员卡开卡字段. + * 获取用户提交资料(wx_activate=true情况调用),开发者根据activate_ticket获取到用户填写的信息 + */ + MEMBER_CARD_ACTIVATE_TEMP_INFO(API_DEFAULT_HOST_URL, "/card/membercard/activatetempinfo/get"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum Store implements WxMpApiUrl { + /** + * getwxcategory. + */ + POI_GET_WX_CATEGORY_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/getwxcategory"), + /** + * updatepoi. + */ + POI_UPDATE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/updatepoi"), + /** + * getpoilist. + */ + POI_LIST_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/getpoilist"), + /** + * delpoi. + */ + POI_DEL_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/delpoi"), + /** + * getpoi. + */ + POI_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/getpoi"), + /** + * addpoi. + */ + POI_ADD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/addpoi"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum User implements WxMpApiUrl { + /** + * batchget. + */ + USER_INFO_BATCH_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/user/info/batchget"), + /** + * get. + */ + USER_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/user/get"), + /** + * info. + */ + USER_INFO_URL(API_DEFAULT_HOST_URL, "/cgi-bin/user/info"), + /** + * updateremark. + */ + USER_INFO_UPDATE_REMARK_URL(API_DEFAULT_HOST_URL, "/cgi-bin/user/info/updateremark"), + /** + * changeopenid. + */ + USER_CHANGE_OPENID_URL(API_DEFAULT_HOST_URL, "/cgi-bin/changeopenid"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } + + @AllArgsConstructor + enum Comment implements WxMpApiUrl { + /** + * 打开已群发文章评论. + */ + OPEN(API_DEFAULT_HOST_URL, "/cgi-bin/comment/open"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + return buildUrl(config.getHostConfig(), prefix, path); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java index d95e8f8f3d..945219acf5 100755 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java @@ -17,7 +17,7 @@ */ package me.chanjar.weixin.mp.util.crypto; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import org.apache.commons.codec.binary.Base64; public class WxMpCryptUtil extends me.chanjar.weixin.common.util.crypto.WxCryptUtil { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java index b16775b40b..1d1ae9095f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java @@ -17,6 +17,9 @@ import me.chanjar.weixin.mp.bean.template.WxMpTemplateIndustry; import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; +/** + * @author someone + */ public class WxMpGsonBuilder { private static final GsonBuilder INSTANCE = new GsonBuilder(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java index 63389866f3..e9e5112d31 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java @@ -1,7 +1,6 @@ package me.chanjar.weixin.mp.util.json; import com.google.gson.*; -import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.api.WxConsts.KefuMsgType; import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import org.apache.commons.lang3.StringUtils; @@ -16,77 +15,89 @@ public JsonElement serialize(WxMpKefuMessage message, Type typeOfSrc, JsonSerial messageJson.addProperty("touser", message.getToUser()); messageJson.addProperty("msgtype", message.getMsgType()); - if (WxConsts.KefuMsgType.TEXT.equals(message.getMsgType())) { - JsonObject text = new JsonObject(); - text.addProperty("content", message.getContent()); - messageJson.add("text", 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.VOICE.equals(message.getMsgType())) { - JsonObject voice = new JsonObject(); - voice.addProperty("media_id", message.getMediaId()); - messageJson.add("voice", voice); - } - - 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.MUSIC.equals(message.getMsgType())) { - JsonObject music = new JsonObject(); - music.addProperty("title", message.getTitle()); - music.addProperty("description", message.getDescription()); - music.addProperty("thumb_media_id", message.getThumbMediaId()); - music.addProperty("musicurl", message.getMusicUrl()); - music.addProperty("hqmusicurl", message.getHqMusicUrl()); - messageJson.add("music", music); - } - - if (WxConsts.KefuMsgType.NEWS.equals(message.getMsgType())) { - JsonObject newsJsonObject = new JsonObject(); - JsonArray articleJsonArray = new JsonArray(); - for (WxMpKefuMessage.WxArticle 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); + switch (message.getMsgType()) { + case KefuMsgType.TEXT: + JsonObject text = new JsonObject(); + text.addProperty("content", message.getContent()); + messageJson.add("text", text); + break; + case KefuMsgType.IMAGE: + JsonObject image = new JsonObject(); + image.addProperty("media_id", message.getMediaId()); + messageJson.add("image", image); + break; + case KefuMsgType.VOICE: + JsonObject voice = new JsonObject(); + voice.addProperty("media_id", message.getMediaId()); + messageJson.add("voice", voice); + break; + case KefuMsgType.VIDEO: + 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); + break; + case KefuMsgType.MUSIC: + JsonObject music = new JsonObject(); + music.addProperty("title", message.getTitle()); + music.addProperty("description", message.getDescription()); + music.addProperty("thumb_media_id", message.getThumbMediaId()); + music.addProperty("musicurl", message.getMusicUrl()); + music.addProperty("hqmusicurl", message.getHqMusicUrl()); + messageJson.add("music", music); + break; + case KefuMsgType.NEWS: + JsonObject newsJsonObject = new JsonObject(); + JsonArray articleJsonArray = new JsonArray(); + for (WxMpKefuMessage.WxArticle 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); + break; + case KefuMsgType.MPNEWS: + JsonObject json = new JsonObject(); + json.addProperty("media_id", message.getMpNewsMediaId()); + messageJson.add("mpnews", json); + break; + case KefuMsgType.WXCARD: + JsonObject wxcard = new JsonObject(); + wxcard.addProperty("card_id", message.getCardId()); + messageJson.add("wxcard", wxcard); + break; + case KefuMsgType.MINIPROGRAMPAGE: + JsonObject miniProgramPage = new JsonObject(); + miniProgramPage.addProperty("title", message.getTitle()); + miniProgramPage.addProperty("appid", message.getMiniProgramAppId()); + miniProgramPage.addProperty("pagepath", message.getMiniProgramPagePath()); + miniProgramPage.addProperty("thumb_media_id", message.getThumbMediaId()); + messageJson.add("miniprogrampage", miniProgramPage); + break; + case KefuMsgType.MSGMENU: { + JsonObject msgmenuJsonObject = new JsonObject(); + JsonArray listJsonArray = new JsonArray(); + for (WxMpKefuMessage.MsgMenu list : message.getMsgMenus()) { + JsonObject listJson = new JsonObject(); + listJson.addProperty("id", list.getId()); + listJson.addProperty("content", list.getContent()); + listJsonArray.add(listJson); + } + msgmenuJsonObject.addProperty("head_content",message.getHeadContent()); + msgmenuJsonObject.add("list", listJsonArray); + msgmenuJsonObject.addProperty("tail_content",message.getTailContent()); + messageJson.add("msgmenu", msgmenuJsonObject); + break; + } + default: { + throw new RuntimeException("非法消息类型,暂不支持"); } - newsJsonObject.add("articles", articleJsonArray); - messageJson.add("news", newsJsonObject); - } - - if (WxConsts.KefuMsgType.MPNEWS.equals(message.getMsgType())) { - JsonObject json = new JsonObject(); - json.addProperty("media_id", message.getMpNewsMediaId()); - messageJson.add("mpnews", json); - } - - if (WxConsts.KefuMsgType.WXCARD.equals(message.getMsgType())) { - JsonObject wxcard = new JsonObject(); - wxcard.addProperty("card_id", message.getCardId()); - messageJson.add("wxcard", wxcard); - } - - if (KefuMsgType.MINIPROGRAMPAGE.equals(message.getMsgType())) { - JsonObject miniProgramPage = new JsonObject(); - miniProgramPage.addProperty("title", message.getTitle()); - miniProgramPage.addProperty("appid", message.getMiniProgramAppId()); - miniProgramPage.addProperty("pagepath", message.getMiniProgramPagePath()); - miniProgramPage.addProperty("thumb_media_id", message.getThumbMediaId()); - messageJson.add("miniprogrampage", miniProgramPage); } if (StringUtils.isNotBlank(message.getKfAccount())) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassTagMessageGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassTagMessageGsonAdapter.java index 3d8f58ffa9..b73540d1f1 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassTagMessageGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassTagMessageGsonAdapter.java @@ -11,7 +11,9 @@ import java.lang.reflect.Type; /** - * @author someone + * 群发消息json转换适配器. + * + * @author chanjarster */ public class WxMpMassTagMessageGsonAdapter implements JsonSerializer
@@ -26,6 +32,66 @@ public class WxMpWifiServiceImplTest { @Test public void testListShop() throws WxErrorException { final WxMpWifiShopListResult result = this.wxService.getWifiService().listShop(1, 2); + assertThat(result).isNotNull(); System.out.println(result); } + + @Test + public void testGetShopWifiInfo() throws WxErrorException { + final WxMpWifiShopDataResult wifiInfo = this.wxService.getWifiService().getShopWifiInfo(123); + assertThat(wifiInfo).isNotNull(); + System.out.println(wifiInfo); + } + + @Test + public void testUpdateShopWifiInfo() throws WxErrorException { + final boolean result = this.wxService.getWifiService() + .updateShopWifiInfo(123, "123", "345", null); + assertThat(result).isTrue(); + } + + public static class MockTest { + private WxMpService wxService = mock(WxMpService.class); + + @Test + public void testGetShopWifiInfo() throws Exception { + String returnJson = "{\n" + + " \"errcode\": 0,\n" + + " \"data\": {\n" + + " \"shop_name\": \"南山店\",\n" + + " \"ssid\": \" WX123\",\n" + + " \"ssid_list\": [\n" + + " \"WX123\",\n" + + " \"WX456\"\n" + + " ],\n" + + " \"ssid_password_list\": [\n" + + " {\n" + + " \"ssid\": \"WX123\",\n" + + " \"password\": \"123456789\"\n" + + " },\n" + + " {\n" + + " \"ssid\": \"WX456\",\n" + + " \"password\": \"21332465dge\"\n" + + " }\n" + + " ],\n" + + " \"password\": \"123456789\",\n" + + " \"protocol_type\": 4,\n" + + " \"ap_count\": 2,\n" + + " \"template_id\": 1,\n" + + " \"homepage_url\": \"http://www.weixin.qq.com/\",\n" + + " \"bar_type\": 1,\n" + + " \"sid\":\"\",\n" + + " \"poi_id\":\"285633617\"\n" + + " }\n" + + "}"; + + when(wxService.post(eq(BIZWIFI_SHOP_GET), anyString())).thenReturn(returnJson); + when(wxService.getWifiService()).thenReturn(new WxMpWifiServiceImpl(wxService)); + + final WxMpWifiShopDataResult wifiInfo = this.wxService.getWifiService().getShopWifiInfo(123); + assertThat(wifiInfo).isNotNull(); + System.out.println(wifiInfo); + + } + } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java index 29c8d2e2b8..cc964e80fd 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java @@ -12,7 +12,7 @@ import com.google.inject.Module; import com.thoughtworks.xstream.XStream; import me.chanjar.weixin.common.util.xml.XStreamInitializer; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; public class ApiTestModule implements Module { diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/TestConfigStorage.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/TestConfigStorage.java index ed6c5cb168..5266beb237 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/TestConfigStorage.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/TestConfigStorage.java @@ -1,13 +1,13 @@ package me.chanjar.weixin.mp.api.test; import com.thoughtworks.xstream.annotations.XStreamAlias; -import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; +import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; import org.apache.commons.lang3.builder.ToStringBuilder; import java.util.concurrent.locks.Lock; @XStreamAlias("xml") -public class TestConfigStorage extends WxMpInMemoryConfigStorage { +public class TestConfigStorage extends WxMpDefaultConfigImpl { private String openid; private String kfAccount; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java index 4f983dde13..ec754875da 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java @@ -141,7 +141,6 @@ public void testNewsBuild() { } public void testMiniProgramPageBuild() { - WxMpKefuMessage reply = WxMpKefuMessage.MINIPROGRAMPAGE() .toUser("OPENID") .title("title") @@ -154,4 +153,17 @@ public void testMiniProgramPageBuild() { "{\"touser\":\"OPENID\",\"msgtype\":\"miniprogrampage\",\"miniprogrampage\":{\"title\":\"title\",\"appid\":\"appid\",\"pagepath\":\"pagepath\",\"thumb_media_id\":\"thumb_media_id\"}}"); } + public void testMsgMenuBuild() { + WxMpKefuMessage reply = WxMpKefuMessage.MSGMENU() + .toUser("OPENID") + .addMenus(new WxMpKefuMessage.MsgMenu("101", "msgmenu1"), + new WxMpKefuMessage.MsgMenu("102", "msgmenu2")) + .headContent("head_content") + .tailContent("tail_content") + .build(); + + Assert.assertEquals(reply.toJson(), + "{\"touser\":\"OPENID\",\"msgtype\":\"msgmenu\",\"msgmenu\":{\"head_content\":\"head_content\",\"list\":[{\"id\":\"101\",\"content\":\"msgmenu1\"},{\"id\":\"102\",\"content\":\"msgmenu2\"}],\"tail_content\":\"tail_content\"}}"); + } + } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/marketing/WxMpUserActionTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/marketing/WxMpUserActionTest.java new file mode 100644 index 0000000000..3d18b1ebbc --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/marketing/WxMpUserActionTest.java @@ -0,0 +1,28 @@ +package me.chanjar.weixin.mp.bean.marketing; + +import com.google.common.collect.Lists; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * 老板加点注释吧. + * + * @author Binary Wang + * @date 2019-07-14 + */ +public class WxMpUserActionTest { + + @Test + public void testListToJson() { + assertThat(WxMpUserAction.listToJson(Lists.newArrayList(WxMpUserAction.builder() + .actionParam(1) + .actionTime(122) + .actionType("haha") + .clickId("111") + .url("1222") + .userActionSetId(111L) + .build() + ))).isEqualTo("{\"actions\":[{\"user_action_set_id\":111,\"url\":\"1222\",\"action_time\":122,\"action_type\":\"haha\",\"trace\":{\"click_id\":\"111\"},\"action_param\":{\"value\":1}}]}"); + } +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResultTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResultTest.java new file mode 100644 index 0000000000..3df5742704 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResultTest.java @@ -0,0 +1,28 @@ +package me.chanjar.weixin.mp.bean.menu; + +import org.testng.annotations.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.testng.Assert.*; + +/** + * @author Binary Wang + * @date 2019-08-05 + */ +public class WxMpGetSelfMenuInfoResultTest { + + @Test + public void testFromJson() { + String json = "{\"is_menu_open\":1,\"selfmenu_info\":{\"button\":[{\"name\":\"学院\",\"sub_button\":{\"list\":[{\"type\":\"miniprogram\",\"name\":\"成语答题王\",\"url\":\"http:\\/\\/host\",\"appid\":\"wxf4dc5b4e7b35dcd1\",\"pagepath\":\"pages\\/index\\/index\"},{\"type\":\"miniprogram\",\"name\":\"大师课程\",\"url\":\"https:\\/\\/host\\/course\\/tutorial\",\"appid\":\"wxfd6acd566482c6cb\",\"pagepath\":\"pages\\/tutorialDetail\\/tutorialDetail\"}]}},{\"type\":\"miniprogram\",\"name\":\"学科商城\",\"url\":\"https:\\/\\/host\\/-dAEuY\",\"appid\":\"wx720f9f1301595564\",\"pagepath\":\"pages\\/home\\/dashboard\\/index\"}]}}"; + final WxMpGetSelfMenuInfoResult selfMenuInfoResult = WxMpGetSelfMenuInfoResult.fromJson(json); + assertThat(selfMenuInfoResult).isNotNull(); + assertThat(selfMenuInfoResult.getIsMenuOpen()).isEqualTo(1); + assertThat(selfMenuInfoResult.getSelfMenuInfo()).isNotNull(); + final Listbuttons = selfMenuInfoResult.getSelfMenuInfo().getButtons(); + assertThat(buttons.size()).isEqualTo(2); + assertThat(buttons.get(1).getAppId()).isEqualTo("wx720f9f1301595564"); + assertThat(buttons.get(1).getPagePath()).isEqualTo("pages/home/dashboard/index"); + } +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java index 30d36920bd..535123bdd7 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java @@ -6,13 +6,13 @@ import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.util.xml.XStreamInitializer; -import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; +import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; /** * @author Daniel Qian */ @XStreamAlias("xml") -class WxMpDemoInMemoryConfigStorage extends WxMpInMemoryConfigStorage { +class WxMpDemoInMemoryConfigStorage extends WxMpDefaultConfigImpl { private static final long serialVersionUID = -3706236839197109704L; public static WxMpDemoInMemoryConfigStorage fromXml(InputStream is) { diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java index d2f4fde881..36f81ae4cc 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.mp.demo; import me.chanjar.weixin.common.api.WxConsts; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpMessageHandler; import me.chanjar.weixin.mp.api.WxMpMessageRouter; import me.chanjar.weixin.mp.api.WxMpService; @@ -27,13 +27,11 @@ public static void main(String[] args) throws Exception { ServletHandler servletHandler = new ServletHandler(); server.setHandler(servletHandler); - ServletHolder endpointServletHolder = new ServletHolder( - new WxMpEndpointServlet(wxMpConfigStorage, wxMpService, - wxMpMessageRouter)); + ServletHolder endpointServletHolder = new ServletHolder(new WxMpEndpointServlet(wxMpConfigStorage, wxMpService, + wxMpMessageRouter)); servletHandler.addServletWithMapping(endpointServletHolder, "/*"); - ServletHolder oauthServletHolder = new ServletHolder( - new WxMpOAuth2Servlet(wxMpService)); + ServletHolder oauthServletHolder = new ServletHolder(new WxMpOAuth2Servlet(wxMpService)); servletHandler.addServletWithMapping(oauthServletHolder, "/oauth2/*"); server.start(); @@ -41,10 +39,8 @@ public static void main(String[] args) throws Exception { } private static void initWeixin() { - try (InputStream is1 = ClassLoader - .getSystemResourceAsStream("test-config.xml")) { - WxMpDemoInMemoryConfigStorage config = WxMpDemoInMemoryConfigStorage - .fromXml(is1); + try (InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml")) { + WxMpDemoInMemoryConfigStorage config = WxMpDemoInMemoryConfigStorage.fromXml(is1); wxMpConfigStorage = config; wxMpService = new WxMpServiceHttpClientImpl(); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpEndpointServlet.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpEndpointServlet.java index 3f32d9c94a..e835e6375c 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpEndpointServlet.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpEndpointServlet.java @@ -1,6 +1,6 @@ package me.chanjar.weixin.mp.demo; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpMessageRouter; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml index a624a38c7f..7a2c2457e4 100644 --- a/weixin-java-open/pom.xml +++ b/weixin-java-open/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java -3.4.0 +3.5.0 weixin-java-open diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java index 4b2ddbc412..2beec638f8 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenComponentService.java @@ -7,10 +7,7 @@ import me.chanjar.weixin.open.bean.WxOpenCreateResult; import me.chanjar.weixin.open.bean.WxOpenMaCodeTemplate; import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage; -import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult; -import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerOptionResult; -import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult; -import me.chanjar.weixin.open.bean.result.WxOpenResult; +import me.chanjar.weixin.open.bean.result.*; import java.util.List; @@ -25,6 +22,7 @@ public interface WxOpenComponentService { String API_GET_AUTHORIZER_INFO_URL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info"; String API_GET_AUTHORIZER_OPTION_URL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_option"; String API_SET_AUTHORIZER_OPTION_URL = "https://api.weixin.qq.com/cgi-bin/component/api_set_authorizer_option"; + String API_GET_AUTHORIZER_LIST = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_list?component_access_token=%s"; String COMPONENT_LOGIN_PAGE_URL = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=%s&pre_auth_code=%s&redirect_uri=%s&auth_type=xxx&biz_appid=xxx"; @@ -126,6 +124,11 @@ public interface WxOpenComponentService { */ WxOpenAuthorizerOptionResult getAuthorizerOption(String authorizerAppid, String optionName) throws WxErrorException; + /** + * 获取所有授权方列表 + */ + WxOpenAuthorizerListResult getAuthorizerList(int begin, int len) throws WxErrorException; + /** * 设置授权方的选项信息 */ diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenConfigStorage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenConfigStorage.java index 066cf8c00f..40833c1b98 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenConfigStorage.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenConfigStorage.java @@ -2,7 +2,7 @@ import cn.binarywang.wx.miniapp.config.WxMaConfig; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java index 64db79b929..c6fd7671bd 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java @@ -52,7 +52,7 @@ public interface WxOpenFastMaService extends WxMaService { /** * 7 换绑小程序管理员接口 */ - String OPEN_COMPONENT_REBIND_ADMIN = "https://api.weixin.qq.com/cgi- bin/account/componentrebindadmin"; + String OPEN_COMPONENT_REBIND_ADMIN = "https://api.weixin.qq.com/cgi-bin/account/componentrebindadmin"; /** * 8.1 获取账号可以设置的所有类目 diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java index 319e12ffa2..03d072cdc3 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java @@ -18,10 +18,7 @@ import me.chanjar.weixin.open.bean.WxOpenMaCodeTemplate; import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo; import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage; -import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult; -import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerOptionResult; -import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult; -import me.chanjar.weixin.open.bean.result.WxOpenResult; +import me.chanjar.weixin.open.bean.result.*; import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -304,6 +301,31 @@ public WxOpenAuthorizerInfoResult getAuthorizerInfo(String authorizerAppid) thro return WxOpenGsonBuilder.create().fromJson(responseContent, WxOpenAuthorizerInfoResult.class); } + @Override + public WxOpenAuthorizerListResult getAuthorizerList(int begin, int len) throws WxErrorException { + + String url = String.format(API_GET_AUTHORIZER_LIST, getComponentAccessToken(false)); + begin = begin < 0 ? 0 : begin; + len = len == 0 ? 10 : len; + + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId()); + jsonObject.addProperty("offset", begin); + jsonObject.addProperty("count", len); + String responseContent = post(url, jsonObject.toString()); + WxOpenAuthorizerListResult ret = WxOpenGsonBuilder.create().fromJson(responseContent, WxOpenAuthorizerListResult.class); + if(ret != null && ret.getList() != null){ + for(Mapdata : ret.getList()){ + String authorizerAppid = data.get("authorizer_appid"); + String refreshToken = data.get("refresh_token"); + if(authorizerAppid != null && refreshToken != null){ + this.getWxOpenConfigStorage().setAuthorizerRefreshToken(authorizerAppid, refreshToken); + } + } + } + return ret; + } + @Override public WxOpenAuthorizerOptionResult getAuthorizerOption(String authorizerAppid, String optionName) throws WxErrorException { JsonObject jsonObject = new JsonObject(); diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java index 1314f37f44..e72fb02b36 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java @@ -208,7 +208,7 @@ public WxOpenResult addCategory (List categoryList) throws WxE public WxOpenResult deleteCategory (int first, int second) throws WxErrorException { JsonObject params = new JsonObject (); params.addProperty ("first", first); - params.addProperty ("Second", second); + params.addProperty ("second", second); String response = post (OPEN_DELETE_CATEGORY, GSON.toJson (params)); return WxOpenGsonBuilder.create ().fromJson (response, WxOpenResult.class); } diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java index da34e808d4..80882b0c47 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java @@ -10,7 +10,8 @@ import cn.binarywang.wx.miniapp.config.WxMaConfig; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; +import me.chanjar.weixin.mp.bean.WxMpHostConfig; import me.chanjar.weixin.mp.enums.TicketType; import me.chanjar.weixin.open.api.WxOpenConfigStorage; import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; @@ -543,10 +544,14 @@ public ApacheHttpClientBuilder getApacheHttpClientBuilder() { return wxOpenConfigStorage.getApacheHttpClientBuilder(); } - @Override public boolean autoRefreshToken() { return true; } + + @Override + public WxMpHostConfig getHostConfig() { + return null; + } } } diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java index a946fb7014..aa845fb223 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.open.api.impl; import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.open.api.WxOpenComponentService; @@ -9,7 +9,7 @@ /** * @author 007 */ -/* package */ class WxOpenMpServiceImpl extends WxMpServiceImpl { +public class WxOpenMpServiceImpl extends WxMpServiceImpl { private WxOpenComponentService wxOpenComponentService; private WxMpConfigStorage wxMpConfigStorage; private String appId; diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceApacheHttpClientImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceApacheHttpClientImpl.java index d9b7b49553..24ee39cc30 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceApacheHttpClientImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceApacheHttpClientImpl.java @@ -6,7 +6,6 @@ import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.open.api.WxOpenConfigStorage; import org.apache.http.HttpHost; import org.apache.http.impl.client.CloseableHttpClient; diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenAuthorizerListResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenAuthorizerListResult.java new file mode 100644 index 0000000000..afe9ea9403 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenAuthorizerListResult.java @@ -0,0 +1,15 @@ +package me.chanjar.weixin.open.bean.result; + +import lombok.Data; + +import java.util.List; +import java.util.Map; + +/** + * @author robgao + */ +@Data +public class WxOpenAuthorizerListResult { + private int totalCount; + private List