getTemplateList() throws WxErrorException;
+
+ /**
+ * 将草稿箱的草稿选为小程序代码模版.
+ *
+ * @param draftId 草稿ID,本字段可通过“获取草稿箱内的所有临时代码草稿”接口获得
+ * @throws WxErrorException 操作失败时抛出,具体错误码请看此接口的注释文档
+ * @see #getTemplateDraftList
+ */
+ void addToTemplate(long draftId) throws WxErrorException;
+
+ /**
+ * 删除指定小程序代码模版.
+ *
+ * @param templateId 要删除的模版ID
+ * @throws WxErrorException 操作失败时抛出,具体错误码请看此接口的注释文档
+ * @see #getTemplateList
+ */
+ void deleteTemplate(long templateId) throws WxErrorException;
+
+ /**
+ * https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1498704199_1bcax&token=6df5e3650041eff2cd3ec3662425ad8d7beec8d9&lang=zh_CN
+ * 创建 开放平台帐号并绑定公众号/小程序.
+ * https://api.weixin.qq.com/cgi-bin/open/create
+ *
+ * @param appId 公众号/小程序的appId
+ * @return .
+ */
+ WxOpenCreateResult createOpenAccount(String appId) throws WxErrorException;
+
+
+ /**
+ * https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/api/account/bind.html
+ * 将公众号/小程序绑定到开放平台帐号下
+ *
+ * @param appId 公众号/小程序的appId
+ * @param openAppid 开放平台帐号 appid,由创建开发平台帐号接口返回
+ */
+ Boolean bindOpenAccount(String appId, String openAppid) throws WxErrorException;
+
+
+ /**
+ * https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/api/account/unbind.html
+ * 将公众号/小程序从开放平台帐号下解绑
+ *
+ * @param appId 公众号/小程序的appId
+ * @param openAppid 开放平台帐号 appid,由创建开发平台帐号接口返回
+ */
+ Boolean unbindOpenAccount(String appId, String openAppid) throws WxErrorException;
+
+
+ /**
+ * https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/api/account/get.html
+ * 获取公众号/小程序所绑定的开放平台帐号
+ *
+ * @param appId 公众号/小程序的appId
+ * @return 开放平台帐号 appid,由创建开发平台帐号接口返回
+ */
+ WxOpenGetResult getOpenAccount(String appId) throws WxErrorException;
+
+ /**
+ * https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=21538208049W8uwq&token=&lang=zh_CN
+ * 第三方平台快速创建小程序.
+ * 注意:创建任务逻辑串行,单次任务结束后才可以使用相同信息下发第二次任务,请注意规避任务阻塞
+ *
+ * @param name 企业名(需与工商部门登记信息一致)
+ * @param code 企业代码
+ * @param codeType 企业代码类型 1:统一社会信用代码(18位) 2:组织机构代码(9位xxxxxxxx-x) 3:营业执照注册号(15位)
+ * @param legalPersonaWechat 法人微信号
+ * @param legalPersonaName 法人姓名(绑定银行卡)
+ * @param componentPhone 第三方联系电话(方便法人与第三方联系)
+ * @return .
+ * @throws WxErrorException .
+ */
+ WxOpenResult fastRegisterWeapp(String name, String code, String codeType, String legalPersonaWechat, String legalPersonaName, String componentPhone) throws WxErrorException;
+
+ /**
+ * https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=21538208049W8uwq&token=&lang=zh_CN
+ * 查询第三方平台快速创建小程序的任务状态
+ * 注意:该接口只提供当下任务结果查询,不建议过分依赖该接口查询所创建小程序。
+ * 小程序的成功状态可在第三方服务器中自行对账、查询。
+ * 不要频繁调用search接口,消息接收需通过服务器查看。调用search接口会消耗接口整体调用quato
+ *
+ * @param name 企业名(需与工商部门登记信息一致)
+ * @param legalPersonaWechat 法人微信号
+ * @param legalPersonaName 法人姓名(绑定银行卡)
+ * @throws WxErrorException .
+ */
+ WxOpenResult fastRegisterWeappSearch(String name, String legalPersonaWechat, String legalPersonaName) throws WxErrorException;
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/TtOpenMaService.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/TtOpenMaService.java
new file mode 100644
index 0000000..130512f
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/TtOpenMaService.java
@@ -0,0 +1,486 @@
+package com.iformall.service.toutiao.api;
+
+import com.iformall.service.toutiao.miniapp.TtMaService;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.open.bean.ma.WxMaOpenCommitExtInfo;
+import me.chanjar.weixin.open.bean.message.WxOpenMaSubmitAuditMessage;
+import me.chanjar.weixin.open.bean.result.*;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * 微信开放平台代小程序实现服务能力
+ * https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1489144594_DhNoV&token=&lang=zh_CN
+ *
+ *
+ * @author yqx
+ * @date 2018/9/12
+ */
+public interface TtOpenMaService extends TtMaService {
+
+ /**
+ * 设置小程序服务器域名.
+ *
+ *
+ * 授权给第三方的小程序,其服务器域名只可以为第三方的服务器,当小程序通过第三方发布代码上线后,小程序原先自己配置的服务器域名将被删除,
+ * 只保留第三方平台的域名,所以第三方平台在代替小程序发布代码之前,需要调用接口为小程序添加第三方自身的域名。
+ * 提示:需要先将域名登记到第三方平台的小程序服务器域名中,才可以调用接口进行配置
+ *
+ */
+ String API_MODIFY_DOMAIN = "https://api.weixin.qq.com/wxa/modify_domain";
+
+ /**
+ * 设置小程序业务域名(仅供第三方代小程序调用)
+ *
+ * 授权给第三方的小程序,其业务域名只可以为第三方的服务器,当小程序通过第三方发布代码上线后,小程序原先自己配置的业务域名将被删除,
+ * 只保留第三方平台的域名,所以第三方平台在代替小程序发布代码之前,需要调用接口为小程序添加业务域名。
+ * 提示:
+ * 1、需要先将域名登记到第三方平台的小程序业务域名中,才可以调用接口进行配置。
+ * 2、为授权的小程序配置域名时支持配置子域名,例如第三方登记的业务域名如为qq.com,则可以直接将qq.com及其子域名(如xxx.qq.com)也配置到授权的小程序中。
+ *
+ */
+ String API_SET_WEBVIEW_DOMAIN = "https://api.weixin.qq.com/wxa/setwebviewdomain";
+
+ /**
+ * 获取帐号基本信息
+ *
+ * GET请求
+ * 注意:需要使用1.3环节获取到的新创建小程序appid及authorization_code换取authorizer_refresh_token进而得到authorizer_access_token。
+ *
+ */
+ String API_GET_ACCOUNT_BASICINFO = "https://api.weixin.qq.com/cgi-bin/account/getaccountbasicinfo";
+
+ /**
+ * 绑定微信用户为小程序体验者
+ */
+ String API_BIND_TESTER = "https://api.weixin.qq.com/wxa/bind_tester";
+
+
+ /**
+ * 解除绑定微信用户为小程序体验者
+ */
+ String API_UNBIND_TESTER = "https://api.weixin.qq.com/wxa/unbind_tester";
+
+
+ /**
+ * 获取体验者列表
+ */
+ String API_GET_TESTERLIST = "https://api.weixin.qq.com/wxa/memberauth";
+
+ /**
+ * 以下接口基础信息设置
+ *
+ * https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=21517799059ZSEMr&token=6f965b5daf30a98a6bbd2a386faea5c934e929bf&lang=zh_CN
+ *
+ */
+
+ /**
+ * 1. 设置小程序隐私设置(是否可被搜索)
+ */
+ String API_CHANGE_WXA_SEARCH_STATUS = "https://api.weixin.qq.com/wxa/changewxasearchstatus";
+
+ /**
+ * 2. 查询小程序当前隐私设置(是否可被搜索)
+ */
+ String API_GET_WXA_SEARCH_STATUS = "https://api.weixin.qq.com/wxa/getwxasearchstatus";
+
+ /**
+ * 3.1. 获取展示的公众号信息
+ */
+ String API_GET_SHOW_WXA_ITEM = "https://api.weixin.qq.com/wxa/getshowwxaitem";
+
+ /**
+ * 3.2 设置展示的公众号
+ */
+ String API_UPDATE_SHOW_WXA_ITEM = "https://api.weixin.qq.com/wxa/updateshowwxaitem";
+
+
+ /**
+ * 以下接口为三方平台代小程序实现的代码管理功能
+ *
+ * https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1489140610_Uavc4&token=fe774228c66725425675810097f9e48d0737a4bf&lang=zh_CN
+ *
+ */
+
+ /**
+ * 1. 为授权的小程序帐号上传小程序代码
+ */
+ String API_CODE_COMMIT = "https://api.weixin.qq.com/wxa/commit";
+
+ /**
+ * 2. 获取体验小程序的体验二维码
+ */
+ String API_TEST_QRCODE = "https://api.weixin.qq.com/wxa/get_qrcode";
+
+ /**
+ * 3. 获取授权小程序帐号的可选类目
+ */
+ String API_GET_CATEGORY = "https://api.weixin.qq.com/wxa/get_category";
+
+ /**
+ * 4. 获取小程序的第三方提交代码的页面配置(仅供第三方开发者代小程序调用)
+ */
+ String API_GET_PAGE = "https://api.weixin.qq.com/wxa/get_page";
+
+ /**
+ * 5. 将第三方提交的代码包提交审核(仅供第三方开发者代小程序调用)
+ */
+ String API_SUBMIT_AUDIT = "https://api.weixin.qq.com/wxa/submit_audit";
+
+ /**
+ * 7. 查询某个指定版本的审核状态(仅供第三方代小程序调用)
+ */
+ String API_GET_AUDIT_STATUS = "https://api.weixin.qq.com/wxa/get_auditstatus";
+
+ /**
+ * 8. 查询最新一次提交的审核状态(仅供第三方代小程序调用)
+ */
+ String API_GET_LATEST_AUDIT_STATUS = "https://api.weixin.qq.com/wxa/get_latest_auditstatus";
+
+ /**
+ * 9. 发布已通过审核的小程序(仅供第三方代小程序调用)
+ */
+ String API_RELEASE = "https://api.weixin.qq.com/wxa/release";
+
+ /**
+ * 10. 修改小程序线上代码的可见状态(仅供第三方代小程序调用)
+ */
+ String API_CHANGE_VISITSTATUS = "https://api.weixin.qq.com/wxa/change_visitstatus";
+
+ /**
+ * 11.小程序版本回退(仅供第三方代小程序调用)
+ */
+ String API_REVERT_CODE_RELEASE = "https://api.weixin.qq.com/wxa/revertcoderelease";
+
+ /**
+ * 12.查询当前设置的最低基础库版本及各版本用户占比 (仅供第三方代小程序调用)
+ */
+ String API_GET_WEAPP_SUPPORT_VERSION = "https://api.weixin.qq.com/cgi-bin/wxopen/getweappsupportversion";
+
+ /**
+ * 13.设置最低基础库版本(仅供第三方代小程序调用)
+ */
+ String API_SET_WEAPP_SUPPORT_VERSION = "https://api.weixin.qq.com/cgi-bin/wxopen/setweappsupportversion";
+
+ /**
+ * 14.设置小程序“扫普通链接二维码打开小程序”能力
+ *
+ * https://mp.weixin.qq.com/debug/wxadoc/introduction/qrcode.html
+ */
+ /**
+ * 14.1 增加或修改二维码规则
+ */
+ String API_QRCODE_JUMP_ADD = "https://api.weixin.qq.com/cgi-bin/wxopen/qrcodejumpadd";
+
+ /**
+ * 14.2 获取已设置的二维码规则
+ */
+ String API_QRCODE_JUMP_GET = "https://api.weixin.qq.com/cgi-bin/wxopen/qrcodejumpget";
+
+ /**
+ * 14.3 获取校验文件名称及内容
+ */
+ String API_QRCODE_JUMP_DOWNLOAD = "https://api.weixin.qq.com/cgi-bin/wxopen/qrcodejumpdownload";
+
+ /**
+ * 14.4 删除已设置的二维码规则
+ */
+ String API_QRCODE_JUMP_DELETE = "https://api.weixin.qq.com/cgi-bin/wxopen/qrcodejumpdelete";
+
+ /**
+ * 14.5 发布已设置的二维码规则
+ */
+ String API_QRCODE_JUMP_PUBLISH = "https://api.weixin.qq.com/cgi-bin/wxopen/qrcodejumppublish";
+
+ /**
+ * 15.小程序审核撤回
+ *
+ * 单个帐号每天审核撤回次数最多不超过1次,一个月不超过10次。
+ *
+ */
+ String API_UNDO_CODE_AUDIT = "https://api.weixin.qq.com/wxa/undocodeaudit";
+
+ /**
+ * 16.1 小程序分阶段发布-分阶段发布接口
+ */
+ String API_GRAY_RELEASE = "https://api.weixin.qq.com/wxa/grayrelease";
+
+ /**
+ * 16.2 小程序分阶段发布-取消分阶段发布
+ */
+ String API_REVERT_GRAY_RELEASE = "https://api.weixin.qq.com/wxa/revertgrayrelease";
+
+ /**
+ * 16.3 小程序分阶段发布-查询当前分阶段发布详情
+ */
+ String API_GET_GRAY_RELEASE_PLAN = "https://api.weixin.qq.com/wxa/getgrayreleaseplan";
+
+
+ /**
+ * 查询服务商的当月提审限额和加急次数(Quota)
+ */
+ String API_QUERY_QUOTA = "https://api.weixin.qq.com/wxa/queryquota";
+
+ /**
+ * 加急审核申请
+ */
+ String API_SPEED_AUDIT = "https://api.weixin.qq.com/wxa/speedupaudit";
+
+
+ /**
+ * 获得小程序的域名配置信息
+ */
+ WxOpenMaDomainResult getDomain() throws WxErrorException;
+
+ /**
+ * 修改域名
+ *
+ * @param action delete删除, set覆盖, get获取
+ */
+ WxOpenMaDomainResult modifyDomain(String action, List requestdomainList, List wsrequestdomainList, List uploaddomainList, List downloaddomainList) throws WxErrorException;
+
+ /**
+ * 获取小程序的业务域名
+ *
+ * @return 直接返回字符串
+ */
+ String getWebViewDomain() throws WxErrorException;
+
+ /**
+ * 获取小程序的业务域名
+ *
+ * @return
+ */
+ public WxOpenMaWebDomainResult getWebViewDomainInfo() throws WxErrorException;
+
+ /**
+ * 设置小程序的业务域名
+ *
+ * @param action add添加, delete删除, set覆盖
+ * @return 直接返回字符串
+ */
+ String setWebViewDomain(String action, List domainList) throws WxErrorException;
+
+
+ /**
+ * 设置小程序的业务域名
+ *
+ * @param action add添加, delete删除, set覆盖
+ * @param domainList
+ * @return
+ */
+ WxOpenMaWebDomainResult setWebViewDomainInfo(String action, List domainList) throws WxErrorException;
+
+ /**
+ * 获取小程序的信息
+ */
+ String getAccountBasicInfo() throws WxErrorException;
+
+ /**
+ * 绑定小程序体验者
+ *
+ * @param wechatid 体验者微信号(不是openid)
+ * @return
+ * @throws WxErrorException
+ */
+ WxOpenMaBindTesterResult bindTester(String wechatid) throws WxErrorException;
+
+ /**
+ * 解除绑定小程序体验者
+ *
+ * @param wechatid 体验者微信号(不是openid)
+ */
+ WxOpenResult unbindTester(String wechatid) throws WxErrorException;
+
+ /**
+ * 解除绑定小程序体验者,其他平台绑定的体验者无法获取到wechatid,可用此方法解绑,详见文档
+ * https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/unbind_tester.html
+ *
+ * @param userstr 人员对应的唯一字符串, 可通过获取已绑定的体验者列表获取人员对应的字符串
+ */
+ WxOpenResult unbindTesterByUserstr(String userstr) throws WxErrorException;
+
+ /**
+ * 获得体验者列表
+ */
+ WxOpenMaTesterListResult getTesterList() throws WxErrorException;
+
+
+ /**
+ * 设置小程序隐私设置(是否可被搜索)
+ *
+ * @param status 1表示不可搜索,0表示可搜索
+ */
+ public WxOpenResult changeWxaSearchStatus(Integer status) throws WxErrorException;
+
+
+ /**
+ * 2. 查询小程序当前隐私设置(是否可被搜索)
+ */
+ public WxOpenMaSearchStatusResult getWxaSearchStatus() throws WxErrorException;
+
+ /**
+ * 3.1 获取展示的公众号信息
+ */
+ public WxOpenMaShowItemResult getShowWxaItem() throws WxErrorException;
+
+
+ /**
+ * 3.2 设置展示的公众号
+ *
+ * @param flag 0 关闭,1 开启
+ * @param mpappid 如果开启,需要传新的公众号appid
+ */
+ public WxOpenResult updateShowwxaitem(Integer flag, String mpappid) throws WxErrorException;
+
+ /**
+ * 1、为授权的小程序帐号上传小程序代码
+ *
+ * @param templateId 代码模板ID
+ * @param userVersion 用户定义版本
+ * @param userDesc 用户定义版本描述
+ * @param extInfo 第三方自定义的配置
+ */
+ WxOpenResult codeCommit(Long templateId, String userVersion, String userDesc, WxMaOpenCommitExtInfo extInfo) throws WxErrorException;
+
+ /**
+ * 获取体验小程序的体验二维码
+ */
+ File getTestQrcode(String pagePath, Map params) throws WxErrorException;
+
+ /**
+ * 获取授权小程序帐号的可选类目
+ *
+ * 注意:该接口可获取已设置的二级类目及用于代码审核的可选三级类目。
+ *
+ */
+ WxOpenMaCategoryListResult getCategoryList() throws WxErrorException;
+
+ /**
+ * 获取小程序的第三方提交代码的页面配置(仅供第三方开发者代小程序调用)
+ *
+ * @return
+ * @throws WxErrorException
+ */
+ WxOpenMaPageListResult getPageList() throws WxErrorException;
+
+ /**
+ * 将第三方提交的代码包提交审核(仅供第三方开发者代小程序调用)
+ */
+ WxOpenMaSubmitAuditResult submitAudit(WxOpenMaSubmitAuditMessage submitAuditMessage) throws WxErrorException;
+
+ /**
+ * 查询某个指定版本的审核状态(仅供第三方代小程序调用)
+ */
+ WxOpenMaQueryAuditResult getAuditStatus(Long auditid) throws WxErrorException;
+
+ /**
+ * 查询最新一次提交的审核状态(仅供第三方代小程序调用).
+ */
+ WxOpenMaQueryAuditResult getLatestAuditStatus() throws WxErrorException;
+
+ /**
+ * 发布已通过审核的小程序(仅供第三方代小程序调用).
+ */
+ WxOpenResult releaesAudited() throws WxErrorException;
+
+ /**
+ * 10. 修改小程序线上代码的可见状态(仅供第三方代小程序调用)
+ */
+ public WxOpenResult changeVisitstatus(String action) throws WxErrorException;
+
+
+ /**
+ * 11. 小程序版本回退(仅供第三方代小程序调用)
+ */
+ WxOpenResult revertCodeReleaes() throws WxErrorException;
+
+ /**
+ * 15. 小程序审核撤回
+ * 单个帐号每天审核撤回次数最多不超过1次,一个月不超过10次。
+ */
+ WxOpenResult undoCodeAudit() throws WxErrorException;
+
+ /**
+ * 查询当前设置的最低基础库版本及各版本用户占比 (仅供第三方代小程序调用)
+ */
+ String getSupportVersion() throws WxErrorException;
+
+ /**
+ * 查询当前设置的最低基础库版本及各版本用户占比 (仅供第三方代小程序调用)
+ */
+ WxOpenMaWeappSupportVersionResult getSupportVersionInfo() throws WxErrorException;
+
+ /**
+ * 设置最低基础库版本(仅供第三方代小程序调用)
+ */
+ String setSupportVersion(String version) throws WxErrorException;
+
+ /**
+ * 设置最低基础库版本(仅供第三方代小程序调用)
+ */
+ WxOpenResult setSupportVersionInfo(String version) throws WxErrorException;
+
+ /**
+ * 16. 小程序分阶段发布 - 1)分阶段发布接口
+ */
+ WxOpenResult grayrelease(Integer grayPercentage) throws WxErrorException;
+
+ /**
+ * 16. 小程序分阶段发布 - 2)取消分阶段发布
+ */
+ WxOpenResult revertgrayrelease() throws WxErrorException;
+
+ /**
+ * 16. 小程序分阶段发布 - 3)查询当前分阶段发布详情
+ */
+ WxOpenMaGrayReleasePlanResult getgrayreleaseplan() throws WxErrorException;
+
+
+ /**
+ * 查询服务商的当月提审限额和加急次数(Quota)
+ * https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/code/query_quota.html
+ */
+ WxOpenMaQueryQuotaResult queryQuota() throws WxErrorException;
+
+ /**
+ * 加急审核申请
+ * 有加急次数的第三方可以通过该接口,对已经提审的小程序进行加急操作,加急后的小程序预计2-12小时内审完。
+ */
+ Boolean speedAudit(Long auditid) throws WxErrorException;
+
+ /**
+ * (1)增加或修改二维码规则
+ */
+ WxOpenResult addQrcodeJump(WxQrcodeJumpRule wxQrcodeJumpRule) throws WxErrorException;
+
+ /**
+ * (2)获取已设置的二维码规则
+ */
+ WxGetQrcodeJumpResult getQrcodeJump() throws WxErrorException;
+
+ /**
+ * (3)获取校验文件名称及内容
+ */
+ WxDownlooadQrcodeJumpResult downloadQrcodeJump() throws WxErrorException;
+
+ /**
+ * (4)删除已设置的二维码规则
+ */
+ WxOpenResult deleteQrcodeJump(String prefix) throws WxErrorException;
+
+ /**
+ * (5)发布已设置的二维码规则
+ */
+ WxOpenResult publishQrcodeJump(String prefix) throws WxErrorException;
+
+// /**
+// * 小程序用户隐私保护指引服务
+// *
+// * @return 小程序用户隐私保护指引服务
+// */
+// WxOpenMaPrivacyService getPrivacyService();
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/TtOpenService.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/TtOpenService.java
new file mode 100644
index 0000000..9b47cd1
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/TtOpenService.java
@@ -0,0 +1,23 @@
+package com.iformall.service.toutiao.api;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.open.api.WxOpenConfigStorage;
+
+public interface TtOpenService {
+
+ TtOpenComponentService getTtOpenComponentService();
+
+ WxOpenConfigStorage getWxOpenConfigStorage();
+
+ void setWxOpenConfigStorage(WxOpenConfigStorage wxOpenConfigStorage);
+
+ /**
+ * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求
+ */
+ String get(String url, String queryParam) throws WxErrorException;
+
+ /**
+ * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求
+ */
+ String post(String url, String postData) throws WxErrorException;
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenAuthorizationInfo.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenAuthorizationInfo.java
new file mode 100644
index 0000000..8610d2c
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenAuthorizationInfo.java
@@ -0,0 +1,23 @@
+package com.iformall.service.toutiao.api.bean;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ *
+ */
+@Data
+public class TtOpenAuthorizationInfo implements Serializable {
+
+ private static final long serialVersionUID = -8354370210668120305L;
+
+ private String authorizerAppid;
+ private String authorizerAccessToken;
+ private int expiresIn;
+ private String authorizerRefreshToken;
+ private int refreshExpiresIn;
+
+ private List authorizePermission;
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenAuthorizationInfoGsonAdapter.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenAuthorizationInfoGsonAdapter.java
new file mode 100644
index 0000000..3d0de7e
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenAuthorizationInfoGsonAdapter.java
@@ -0,0 +1,43 @@
+package com.iformall.service.toutiao.api.bean;
+
+import com.google.gson.*;
+import me.chanjar.weixin.common.util.json.GsonHelper;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author 007
+ */
+public class TtOpenAuthorizationInfoGsonAdapter implements JsonDeserializer {
+
+ @Override
+ public TtOpenAuthorizationInfo deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
+ TtOpenAuthorizationInfo authorizationInfo = new TtOpenAuthorizationInfo();
+ JsonObject jsonObject = jsonElement.getAsJsonObject();
+ authorizationInfo.setAuthorizerAppid(GsonHelper.getString(jsonObject, "authorizer_appid"));
+ authorizationInfo.setAuthorizerAccessToken(GsonHelper.getString(jsonObject, "authorizer_access_token"));
+ authorizationInfo.setExpiresIn(GsonHelper.getPrimitiveInteger(jsonObject, "expires_in"));
+ authorizationInfo.setAuthorizerRefreshToken(GsonHelper.getString(jsonObject, "authorizer_refresh_token"));
+ authorizationInfo.setRefreshExpiresIn(GsonHelper.getPrimitiveInteger(jsonObject, "refresh_expires_in"));
+
+ List funcInfo = new ArrayList<>();
+ JsonArray jsonArray = GsonHelper.getAsJsonArray(jsonObject.get("authorize_permission"));
+ if (jsonArray != null && !jsonArray.isJsonNull()) {
+ for (int i = 0; i < jsonArray.size(); i++) {
+ jsonObject = jsonArray.get(i).getAsJsonObject();
+ if (jsonObject == null || jsonObject.isJsonNull()) {
+ continue;
+ }
+ Integer id = GsonHelper.getInteger(jsonObject, "id");
+ if (id == null) {
+ continue;
+ }
+ funcInfo.add(id);
+ }
+ }
+ authorizationInfo.setAuthorizePermission(funcInfo);
+ return authorizationInfo;
+ }
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenGsonBuilder.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenGsonBuilder.java
new file mode 100644
index 0000000..2f9ff8a
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenGsonBuilder.java
@@ -0,0 +1,26 @@
+package com.iformall.service.toutiao.api.bean;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.iformall.service.toutiao.miniapp.bean.TtMaSubscribeMessage;
+import com.iformall.service.toutiao.miniapp.bean.TtMaSubscribeMessageGsonAdapter;
+
+/**
+ * @author
+ */
+public class TtOpenGsonBuilder {
+ private static final GsonBuilder INSTANCE = new GsonBuilder();
+
+ static {
+ INSTANCE.disableHtmlEscaping();
+ INSTANCE.registerTypeAdapter(TtOpenTicket.class, new TtOpenTicketGsonAdapter());
+ INSTANCE.registerTypeAdapter(TtOpenAuthorizationInfo.class, new TtOpenAuthorizationInfoGsonAdapter());
+ INSTANCE.registerTypeAdapter(TtOpenRetrieveCode.class, new TtOpenRetrieveCodeGsonAdapter());
+
+ }
+
+ public static Gson create() {
+ return INSTANCE.create();
+ }
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenRetrieveCode.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenRetrieveCode.java
new file mode 100644
index 0000000..fd6abed
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenRetrieveCode.java
@@ -0,0 +1,19 @@
+package com.iformall.service.toutiao.api.bean;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ *
+ */
+@Data
+public class TtOpenRetrieveCode implements Serializable {
+
+ private static final long serialVersionUID = -2169528610814376819L;
+
+ private String authorizationCode;
+ private int expiresIn;
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenRetrieveCodeGsonAdapter.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenRetrieveCodeGsonAdapter.java
new file mode 100644
index 0000000..1c44363
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenRetrieveCodeGsonAdapter.java
@@ -0,0 +1,24 @@
+package com.iformall.service.toutiao.api.bean;
+
+import com.google.gson.*;
+import me.chanjar.weixin.common.util.json.GsonHelper;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author 007
+ */
+public class TtOpenRetrieveCodeGsonAdapter implements JsonDeserializer {
+
+ @Override
+ public TtOpenRetrieveCode deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
+ TtOpenRetrieveCode retrieveCode = new TtOpenRetrieveCode();
+ JsonObject jsonObject = jsonElement.getAsJsonObject();
+ retrieveCode.setAuthorizationCode(GsonHelper.getString(jsonObject, "authorization_code"));
+ retrieveCode.setExpiresIn(GsonHelper.getPrimitiveInteger(jsonObject, "expires_in"));
+
+ return retrieveCode;
+ }
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenTicket.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenTicket.java
new file mode 100644
index 0000000..95d151f
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenTicket.java
@@ -0,0 +1,40 @@
+package com.iformall.service.toutiao.api.bean;
+
+import com.iformall.service.toutiao.miniapp.bean.TtMaGsonBuilder;
+import lombok.*;
+
+import java.io.Serializable;
+
+/**
+ * @author S
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class TtOpenTicket implements Serializable {
+
+ private static final long serialVersionUID = -44544979421396117L;
+
+ private String accessToken;
+
+ private String ticket;
+
+ private String fromUserName;
+
+ //2019-01-14 12:45:10
+ private String createTime;
+
+ private String msgType;
+
+ private String event;
+
+ private String componentAppId;
+
+
+ public static TtOpenTicket fromJson(String json) {
+ return TtMaGsonBuilder.create().fromJson(json, TtOpenTicket.class);
+ }
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenTicketGsonAdapter.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenTicketGsonAdapter.java
new file mode 100644
index 0000000..bcc2dca
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/bean/TtOpenTicketGsonAdapter.java
@@ -0,0 +1,34 @@
+package com.iformall.service.toutiao.api.bean;
+
+import com.google.gson.*;
+import com.iformall.service.toutiao.miniapp.bean.TtMaSubscribeMessage;
+import me.chanjar.weixin.common.util.json.GsonHelper;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * .
+ *
+ * @author S
+ */
+public class TtOpenTicketGsonAdapter implements JsonDeserializer {
+
+ @Override
+ public TtOpenTicket deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+ return convertFromJson(json.getAsJsonObject());
+ }
+
+ protected TtOpenTicket convertFromJson(JsonObject json) {
+ TtOpenTicket openTicket = new TtOpenTicket();
+ openTicket.setTicket(GsonHelper.getString(json,"Ticket"));
+ openTicket.setFromUserName(GsonHelper.getString(json,"FromUserName"));
+ openTicket.setCreateTime(GsonHelper.getString(json,"CreateTime"));
+ openTicket.setMsgType(GsonHelper.getString(json,"MsgType"));
+ openTicket.setEvent(GsonHelper.getString(json,"Event"));
+ return openTicket;
+ }
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenComponentServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenComponentServiceImpl.java
new file mode 100644
index 0000000..4dd8167
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenComponentServiceImpl.java
@@ -0,0 +1,517 @@
+package com.iformall.service.toutiao.api.impl;
+
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.reflect.TypeToken;
+import com.iformall.service.toutiao.api.TtOpenComponentService;
+import com.iformall.service.toutiao.api.TtOpenMaService;
+import com.iformall.service.toutiao.api.TtOpenService;
+import com.iformall.service.toutiao.api.bean.TtOpenAuthorizationInfo;
+import com.iformall.service.toutiao.api.bean.TtOpenGsonBuilder;
+import com.iformall.service.toutiao.api.bean.TtOpenRetrieveCode;
+import com.iformall.service.toutiao.api.bean.TtOpenTicket;
+import com.iformall.service.toutiao.utils.MsgDecrypt;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.crypto.SHA1;
+import me.chanjar.weixin.common.util.http.URIUtil;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
+import me.chanjar.weixin.open.api.WxOpenConfigStorage;
+import me.chanjar.weixin.open.bean.*;
+import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo;
+import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage;
+import me.chanjar.weixin.open.bean.result.*;
+import me.chanjar.weixin.open.util.WxOpenCryptUtil;
+import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * @author
+ */
+public class TtOpenComponentServiceImpl implements TtOpenComponentService {
+ private static final JsonParser JSON_PARSER = new JsonParser();
+ private static final Map TT_OPEN_MA_SERVICE_MAP = new ConcurrentHashMap<>();
+
+ protected final Logger log = LoggerFactory.getLogger(this.getClass());
+ private TtOpenService ttOpenService;
+
+ public TtOpenComponentServiceImpl(TtOpenService ttOpenService) {
+ this.ttOpenService = ttOpenService;
+ }
+
+ enum RequestMethod {
+ POST,GET
+ }
+
+ @Override
+ public TtOpenMaService getTtMaServiceByAppid(String appId) {
+ TtOpenMaService ttOpenMaService = TT_OPEN_MA_SERVICE_MAP.get(appId);
+ if (ttOpenMaService == null) {
+ synchronized (TT_OPEN_MA_SERVICE_MAP) {
+ ttOpenMaService = TT_OPEN_MA_SERVICE_MAP.get(appId);
+ if (ttOpenMaService == null) {
+ ttOpenMaService = new TtOpenMaServiceImpl(this, appId, getWxOpenConfigStorage().getWxMaConfig(appId));
+ TT_OPEN_MA_SERVICE_MAP.put(appId, ttOpenMaService);
+ }
+ }
+ }
+ return ttOpenMaService;
+ }
+
+ public TtOpenService getTtOpenService() {
+ return ttOpenService;
+ }
+
+ @Override
+ public WxOpenConfigStorage getWxOpenConfigStorage() {
+ return ttOpenService.getWxOpenConfigStorage();
+ }
+
+ @Override
+ public boolean checkSignature(String timestamp, String nonce, String encrypt, String signature) {
+ try {
+ return SHA1.gen(getWxOpenConfigStorage().getComponentToken(), timestamp, nonce, encrypt)
+ .equals(signature);
+ } catch (Exception e) {
+ this.log.error("Checking signature failed, and the reason is :" + e.getMessage());
+ return false;
+ }
+ }
+
+ @Override
+ public TtOpenTicket decrypt(String encrypt) {
+ try {
+ MsgDecrypt msgDecrypt = new MsgDecrypt(getWxOpenConfigStorage().getComponentAesKey());
+ String plainText = msgDecrypt.decrypt(encrypt);
+ log.info("解密信息----------------------------------------"+ plainText);
+ TtOpenTicket openTicket = TtOpenTicket.fromJson(plainText);
+ openTicket.setComponentAppId(getWxOpenConfigStorage().getComponentAppId());
+ return openTicket;
+ } catch (Exception e) {
+ this.log.error("Checking signature failed, and the reason is :" + e.getMessage());
+ return null;
+ }
+
+ }
+
+ @Override
+ public String getComponentAccessToken(boolean forceRefresh) throws WxErrorException {
+ final WxOpenConfigStorage config = this.getWxOpenConfigStorage();
+ if (!config.isComponentAccessTokenExpired() && !forceRefresh) {
+ return config.getComponentAccessToken();
+ }
+ Lock lock = config.getComponentAccessTokenLock();
+ lock.lock();
+ try {
+ if (!config.isComponentAccessTokenExpired() && !forceRefresh) {
+ return config.getComponentAccessToken();
+ }
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId());
+ jsonObject.addProperty("component_appsecret", getWxOpenConfigStorage().getComponentAppSecret());
+ jsonObject.addProperty("component_ticket", getWxOpenConfigStorage().getComponentVerifyTicket());
+
+ String responseContent = this.getTtOpenService().get(API_COMPONENT_TOKEN_URL, jsonObject.toString());
+ WxOpenComponentAccessToken componentAccessToken = WxOpenComponentAccessToken.fromJson(responseContent);
+ config.updateComponentAccessToken(componentAccessToken);
+ return config.getComponentAccessToken();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public String post(String uri, String postData,String tokenKeyName) throws WxErrorException {
+ //"component_access_token"
+ return postByCommonAccessToken(uri, postData, tokenKeyName);
+ }
+
+ @Override
+ public String get(String uri,String tokenKeyName) throws WxErrorException {
+ //"component_access_token"
+ return getByCommonAccessToken(uri, tokenKeyName);
+ }
+
+ private String getByCommonAccessToken(String uri, String accessTokenKey) throws WxErrorException {
+ String componentAccessToken = getComponentAccessToken(false);
+ return excuteRequet(uri, accessTokenKey, componentAccessToken, null, true, RequestMethod.GET);
+ }
+ private String postByCommonAccessToken(String uri, String postData ,String accessTokenKey) throws WxErrorException {
+ String componentAccessToken = getComponentAccessToken(false);
+ return excuteRequet(uri, accessTokenKey, componentAccessToken, postData, true, RequestMethod.POST);
+ }
+
+ @Override
+ public String getByAppAccessToken(String appId,String uri, String accessTokenKey) throws WxErrorException {
+ String accessToken = getAuthorizerAccessToken(appId,false);
+ return excuteRequet(uri, accessTokenKey, accessToken, null, true, RequestMethod.GET);
+ }
+
+ @Override
+ public String postByAppAccessToken(String appId,String uri,String postData, String accessTokenKey) throws WxErrorException {
+ String accessToken = getAuthorizerAccessToken(appId, false);
+ return excuteRequet(uri, accessTokenKey, accessToken, postData, true, RequestMethod.POST);
+ }
+
+ private String post(String uri, String postData, String accessTokenKey,String accessTokenValue, boolean isCommpontAccessToken) throws WxErrorException {
+ return excuteRequet(uri, accessTokenKey, accessTokenValue, postData, isCommpontAccessToken, RequestMethod.POST);
+ }
+
+ private String get(String uri, String accessTokenKey,String accessTokenValue, boolean isCommpontAccessToken) throws WxErrorException {
+ return excuteRequet(uri, accessTokenKey, accessTokenValue, null, isCommpontAccessToken, RequestMethod.GET);
+ }
+
+ @Override
+ public String getPreAuthUrl(String redirectUri) throws WxErrorException {
+ return createPreAuthUrl(redirectUri);
+ }
+
+ /**
+ * 创建预授权链接
+ *
+ * @param redirectURI
+ * @return
+ * @throws WxErrorException
+ */
+ private String createPreAuthUrl(String redirectURI) throws WxErrorException {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId());
+ String responseContent = post(API_CREATE_PREAUTHCODE_URL, jsonObject.toString(),"component_access_token");
+ jsonObject = WxGsonBuilder.create().fromJson(responseContent, JsonObject.class);
+
+ StringBuilder preAuthUrl = new StringBuilder(String.format(COMPONENT_LOGIN_PAGE_URL,
+ getWxOpenConfigStorage().getComponentAppId(),
+ jsonObject.get("pre_auth_code").getAsString(),
+ URIUtil.encodeURIComponent(redirectURI)));
+ String preAuthUrlStr = preAuthUrl.toString();
+ return preAuthUrlStr;
+ }
+
+
+ @Override
+ public String route(final TtOpenTicket ticket) throws WxErrorException {
+ if (ticket == null) {
+ throw new NullPointerException("message is empty");
+ }
+ if (StringUtils.equalsIgnoreCase(ticket.getMsgType(), "Ticket")) {
+ getWxOpenConfigStorage().setComponentVerifyTicket(ticket.getTicket());
+ return "success";
+ }
+ return "";
+ }
+
+ @Override
+ public TtOpenAuthorizationInfo getQueryAuth(String authorizationCode) throws WxErrorException {
+ String uri = API_QUERY_AUTH_URL + "?component_appid=" + getWxOpenConfigStorage().getComponentAppId() +
+ "&authorization_code=" + authorizationCode +
+ "&grant_type=app_to_tp_authorization_code";
+
+ String responseContent = get(uri,"component_access_token");
+ TtOpenAuthorizationInfo queryAuth = TtOpenGsonBuilder.create().fromJson(responseContent, TtOpenAuthorizationInfo.class);
+ if (queryAuth == null) {
+ return queryAuth;
+ }
+
+ if (queryAuth.getAuthorizerAccessToken() != null) {
+ getWxOpenConfigStorage().updateAuthorizerAccessToken(queryAuth.getAuthorizerAppid(),
+ queryAuth.getAuthorizerAccessToken(), queryAuth.getExpiresIn());
+ }
+ if (queryAuth.getAuthorizerRefreshToken() != null) {
+ getWxOpenConfigStorage().setAuthorizerRefreshToken(queryAuth.getAuthorizerAppid(), queryAuth.getAuthorizerRefreshToken());
+ }
+ return queryAuth;
+ }
+
+ @Override
+ public String retrieveCode(String authorizationCode) throws WxErrorException {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId());
+ jsonObject.addProperty("authorization_appid", authorizationCode);
+ String responseContent = post(RETRIEVE_AUTHORIZER_TOKEN_URL, jsonObject.toString(), "component_access_token");
+ TtOpenRetrieveCode retrieveCode = TtOpenGsonBuilder.create().fromJson(responseContent, TtOpenRetrieveCode.class);
+ if(retrieveCode == null){
+ return null;
+ }
+ return retrieveCode.getAuthorizationCode();
+ }
+
+// @Override
+// public WxOpenAuthorizerInfoResult getAuthorizerInfo(String authorizerAppid) throws WxErrorException {
+// JsonObject jsonObject = new JsonObject();
+// jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId());
+// jsonObject.addProperty("authorizer_appid", authorizerAppid);
+// String responseContent = post(API_GET_AUTHORIZER_INFO_URL, jsonObject.toString(),"component_access_token");
+// return WxOpenGsonBuilder.create().fromJson(responseContent, WxOpenAuthorizerInfoResult.class);
+// }
+
+ @Override
+ public WxOpenAuthorizerListResult getAuthorizerList(int begin, int len) throws WxErrorException {
+ 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(API_GET_AUTHORIZER_LIST, jsonObject.toString(),"component_access_token");
+ WxOpenAuthorizerListResult ret = WxOpenGsonBuilder.create().fromJson(responseContent, WxOpenAuthorizerListResult.class);
+ if (ret != null && ret.getList() != null) {
+ for (Map data : 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();
+ jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId());
+ jsonObject.addProperty("authorizer_appid", authorizerAppid);
+ jsonObject.addProperty("option_name", optionName);
+ String responseContent = post(API_GET_AUTHORIZER_OPTION_URL, jsonObject.toString(),"component_access_token");
+ return WxOpenGsonBuilder.create().fromJson(responseContent, WxOpenAuthorizerOptionResult.class);
+ }
+
+ @Override
+ public void setAuthorizerOption(String authorizerAppid, String optionName, String optionValue) throws WxErrorException {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId());
+ jsonObject.addProperty("authorizer_appid", authorizerAppid);
+ jsonObject.addProperty("option_name", optionName);
+ jsonObject.addProperty("option_value", optionValue);
+ post(API_SET_AUTHORIZER_OPTION_URL, jsonObject.toString(),"component_access_token");
+ }
+
+ @Override
+ public String getAuthorizerAccessToken(String appId, boolean forceRefresh) throws WxErrorException {
+ WxOpenConfigStorage config = getWxOpenConfigStorage();
+ if (!config.isAuthorizerAccessTokenExpired(appId) && !forceRefresh) {
+ return config.getAuthorizerAccessToken(appId);
+ }
+ Lock lock = config.getWxMpConfigStorage(appId).getAccessTokenLock();
+ lock.lock();
+ try {
+ if (!config.isAuthorizerAccessTokenExpired(appId) && !forceRefresh) {
+ return config.getAuthorizerAccessToken(appId);
+ }
+
+ String uri = API_AUTHORIZER_TOKEN_URL + "?component_appid=" + getWxOpenConfigStorage().getComponentAppId() +
+ "&authorizer_refresh_token=" + getWxOpenConfigStorage().getAuthorizerRefreshToken(appId) +
+ "&grant_type=app_to_tp_refresh_token";
+
+ String responseContent = get(uri,"component_access_token");
+
+ TtOpenAuthorizationInfo queryAuth = TtOpenGsonBuilder.create().fromJson(responseContent, TtOpenAuthorizationInfo.class);
+ if (queryAuth.getAuthorizerAccessToken() != null) {
+ config.updateAuthorizerAccessToken(queryAuth.getAuthorizerAppid(),
+ queryAuth.getAuthorizerAccessToken(), queryAuth.getExpiresIn());
+ }
+ if (queryAuth.getAuthorizerRefreshToken() != null) {
+ config.setAuthorizerRefreshToken(queryAuth.getAuthorizerAppid(), queryAuth.getAuthorizerRefreshToken());
+ }
+ return config.getAuthorizerAccessToken(appId);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public WxMpOAuth2AccessToken oauth2getAccessToken(String appId, String code) throws WxErrorException {
+ String url = String.format(OAUTH2_ACCESS_TOKEN_URL, appId, code, getWxOpenConfigStorage().getComponentAppId());
+ String responseContent = get(url,"component_access_token");
+ return WxMpOAuth2AccessToken.fromJson(responseContent);
+ }
+
+ @Override
+ public WxMpOAuth2AccessToken oauth2refreshAccessToken(String appId, String refreshToken) throws WxErrorException {
+ String url = String.format(OAUTH2_REFRESH_TOKEN_URL, appId, refreshToken, getWxOpenConfigStorage().getComponentAppId());
+ String responseContent = get(url,"component_access_token");
+ return WxMpOAuth2AccessToken.fromJson(responseContent);
+ }
+
+ @Override
+ public String oauth2buildAuthorizationUrl(String appId, String redirectURI, String scope, String state) {
+ return String.format(CONNECT_OAUTH2_AUTHORIZE_URL,
+ appId, URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state), getWxOpenConfigStorage().getComponentAppId());
+ }
+
+ @Override
+ public WxMaJscode2SessionResult miniappJscode2Session(String appId, String jsCode) throws WxErrorException {
+ String url = String.format(MINIAPP_JSCODE_2_SESSION, appId, jsCode, getWxOpenConfigStorage().getComponentAppId());
+ String responseContent = get(url,"component_access_token");
+ return WxMaJscode2SessionResult.fromJson(responseContent);
+ }
+
+ @Override
+ public List getTemplateDraftList() throws WxErrorException {
+ String responseContent = get(GET_TEMPLATE_DRAFT_LIST_URL, "access_token");
+ JsonObject response = JSON_PARSER.parse(StringUtils.defaultString(responseContent, "{}")).getAsJsonObject();
+ boolean hasDraftList = response.has("draft_list");
+ if (hasDraftList) {
+ return WxOpenGsonBuilder.create().fromJson(response.getAsJsonArray("draft_list"),
+ new TypeToken>() {
+ }.getType());
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public List getTemplateList() throws WxErrorException {
+ String responseContent = get(GET_TEMPLATE_LIST_URL, "access_token");
+ JsonObject response = JSON_PARSER.parse(StringUtils.defaultString(responseContent, "{}")).getAsJsonObject();
+ boolean hasTemplateList = response.has("template_list");
+ if (hasTemplateList) {
+ return WxOpenGsonBuilder.create().fromJson(response.getAsJsonArray("template_list"),
+ new TypeToken>() {
+ }.getType());
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void addToTemplate(long draftId) throws WxErrorException {
+ JsonObject param = new JsonObject();
+ param.addProperty("draft_id", draftId);
+ post(ADD_TO_TEMPLATE_URL, param.toString(), "access_token");
+ }
+
+ @Override
+ public void deleteTemplate(long templateId) throws WxErrorException {
+ JsonObject param = new JsonObject();
+ param.addProperty("template_id", templateId);
+ post(DELETE_TEMPLATE_URL, param.toString(), "access_token");
+ }
+
+ @Override
+ public WxOpenCreateResult createOpenAccount(String appId) throws WxErrorException {
+ JsonObject param = new JsonObject();
+ param.addProperty("appid", appId);
+
+ String json = postByAppAccessToken(appId, CREATE_OPEN_URL, param.toString(), "access_token");
+
+ return WxOpenCreateResult.fromJson(json);
+ }
+
+
+
+ private String excuteRequet(String uri,String tokenKey,String tokenValue,String postData,boolean isCompontAccessToken,RequestMethod method) throws WxErrorException {
+ String uriWithComponentAccessToken = uri + (uri.contains("?") ? "&" : "?") + tokenKey + "=" + tokenValue;
+ try {
+ if (method == RequestMethod.POST) {
+ return getTtOpenService().post(uriWithComponentAccessToken, postData);
+ }else {
+ return getTtOpenService().get(uriWithComponentAccessToken, null);
+ }
+ } catch (WxErrorException e) {
+ WxError error = e.getError();
+ /*
+ * 发生以下情况时尝试刷新access_token
+ * 40001 获取access_token时AppSecret错误,或者access_token无效
+ * 42001 access_token超时
+ * 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期),或查看是否正在为恰当的公众号调用接口
+ */
+ if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001 || error.getErrorCode() == 40014) {
+ // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token
+ Lock lock = this.getWxOpenConfigStorage().getComponentAccessTokenLock();
+ lock.lock();
+ try {
+ if (isCompontAccessToken && StringUtils.equals(tokenValue, this.getWxOpenConfigStorage().getComponentAccessToken())) {
+ this.getWxOpenConfigStorage().expireComponentAccessToken();
+ }
+ } catch (Exception ex) {
+ if (isCompontAccessToken) {
+ this.getWxOpenConfigStorage().expireComponentAccessToken();
+ }
+ } finally {
+ lock.unlock();
+ }
+
+ if (isCompontAccessToken && this.getWxOpenConfigStorage().autoRefreshToken()) {
+ if (method == RequestMethod.POST) {
+ return this.post(uri, postData, tokenKey);
+ }else {
+ return this.get(uri, tokenKey);
+ }
+ }
+
+ }
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error, e);
+ }
+ return null;
+ }
+ }
+
+
+ @Override
+ public Boolean bindOpenAccount(String appId, String openAppid) throws WxErrorException {
+ JsonObject param = new JsonObject();
+ param.addProperty("appid", appId);
+ param.addProperty("open_appid", openAppid);
+
+ String json = postByAppAccessToken(appId, BIND_OPEN_URL, param.toString(), "access_token");
+
+ return WxOpenResult.fromJson(json).isSuccess();
+ }
+
+
+ @Override
+ public Boolean unbindOpenAccount(String appId, String openAppid) throws WxErrorException {
+ JsonObject param = new JsonObject();
+ param.addProperty("appid", appId);
+ param.addProperty("open_appid", openAppid);
+
+ String json = postByAppAccessToken(appId, UNBIND_OPEN_URL, param.toString(), "access_token");
+
+ return WxOpenResult.fromJson(json).isSuccess();
+ }
+
+
+ @Override
+ public WxOpenGetResult getOpenAccount(String appId) throws WxErrorException {
+ JsonObject param = new JsonObject();
+ param.addProperty("appid", appId);
+
+ String json = postByAppAccessToken(appId, GET_OPEN_URL, param.toString(), "access_token");
+ return WxOpenGetResult.fromJson(json);
+ }
+
+
+ @Override
+ public WxOpenResult fastRegisterWeapp(String name, String code, String codeType, String legalPersonaWechat, String legalPersonaName, String componentPhone) throws WxErrorException {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("name", name);
+ jsonObject.addProperty("code", code);
+ jsonObject.addProperty("code_type", codeType);
+ jsonObject.addProperty("legal_persona_wechat", legalPersonaWechat);
+ jsonObject.addProperty("legal_persona_name", legalPersonaName);
+ jsonObject.addProperty("component_phone", componentPhone);
+ String response = post(FAST_REGISTER_WEAPP_URL, jsonObject.toString(), "component_access_token");
+ return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+ @Override
+ public WxOpenResult fastRegisterWeappSearch(String name, String legalPersonaWechat, String legalPersonaName) throws WxErrorException {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("name", name);
+ jsonObject.addProperty("legal_persona_wechat", legalPersonaWechat);
+ jsonObject.addProperty("legal_persona_name", legalPersonaName);
+ String response = post(FAST_REGISTER_WEAPP_SEARCH_URL, jsonObject.toString(), "component_access_token");
+ return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenMaServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenMaServiceImpl.java
new file mode 100644
index 0000000..ad49821
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenMaServiceImpl.java
@@ -0,0 +1,643 @@
+package com.iformall.service.toutiao.api.impl;
+
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.iformall.service.toutiao.api.TtOpenComponentService;
+import com.iformall.service.toutiao.api.TtOpenMaService;
+import com.iformall.service.toutiao.miniapp.impl.TtMaServiceImpl;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.open.bean.ma.WxMaOpenCommitExtInfo;
+import me.chanjar.weixin.open.bean.ma.WxMaQrcodeParam;
+import me.chanjar.weixin.open.bean.message.WxOpenMaSubmitAuditMessage;
+import me.chanjar.weixin.open.bean.result.*;
+import me.chanjar.weixin.open.executor.MaQrCodeRequestExecutor;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author 007
+ *
+ * 增加开放平台代小程序管理服务能力
+ * 说明:这里让这个服务公开便于调用者模拟本地测试服务
+ *
+ * @author yqx
+ * @date 2018-09-12
+ */
+public class TtOpenMaServiceImpl extends TtMaServiceImpl implements TtOpenMaService {
+ private TtOpenComponentService ttOpenComponentService;
+ private WxMaConfig wxMaConfig;
+ private String appId;
+
+
+ public TtOpenMaServiceImpl(TtOpenComponentService ttOpenComponentService, String appId, WxMaConfig wxMaConfig) {
+ this.ttOpenComponentService = ttOpenComponentService;
+ this.appId = appId;
+ this.wxMaConfig = wxMaConfig;
+ initHttp();
+ }
+
+ @Override
+ public WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException {
+ return ttOpenComponentService.miniappJscode2Session(appId, jsCode);
+ }
+
+ @Override
+ public WxMaConfig getWxMaConfig() {
+ return wxMaConfig;
+ }
+
+ @Override
+ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
+ return ttOpenComponentService.getAuthorizerAccessToken(appId, forceRefresh);
+ }
+
+ /**
+ * 获得小程序的域名配置信息
+ *
+ * @return
+ */
+ @Override
+ public WxOpenMaDomainResult getDomain() throws WxErrorException {
+ return modifyDomain("get", null, null, null, null);
+ }
+
+ /**
+ * 修改服务器域名
+ *
+ * @param action delete删除, set覆盖, get获取
+ * @param requestdomainList
+ * @param wsrequestdomainList
+ * @param uploaddomainList
+ * @param downloaddomainList
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenMaDomainResult modifyDomain(String action, List requestdomainList, List wsrequestdomainList, List uploaddomainList, List downloaddomainList) throws WxErrorException {
+
+// if (!"get".equals(action) && (requestdomainList == null || wsrequestdomainList == null || uploaddomainList == null || downloaddomainList == null)) {
+// throw new WxErrorException(WxError.builder().errorCode(44004).errorMsg("域名参数不能为空").build());
+// }
+ JsonObject requestJson = new JsonObject();
+ requestJson.addProperty("action", action);
+ if (!"get".equals(action)) {
+ requestJson.add("requestdomain", toJsonArray(requestdomainList));
+ requestJson.add("wsrequestdomain", toJsonArray(wsrequestdomainList));
+ requestJson.add("uploaddomain", toJsonArray(uploaddomainList));
+ requestJson.add("downloaddomain", toJsonArray(downloaddomainList));
+ }
+ String response = post(API_MODIFY_DOMAIN, GSON.toJson(requestJson));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaDomainResult.class);
+ }
+
+ /**
+ * 获取小程序的业务域名
+ *
+ * @return
+ */
+ @Override
+ public String getWebViewDomain() throws WxErrorException {
+ return setWebViewDomain("get", null);
+ }
+
+ /**
+ * 获取小程序的业务域名
+ *
+ * @return
+ */
+ @Override
+ public WxOpenMaWebDomainResult getWebViewDomainInfo() throws WxErrorException {
+ return setWebViewDomainInfo("get", null);
+ }
+
+ /**
+ * 设置小程序的业务域名
+ *
+ * @param action add添加, delete删除, set覆盖
+ * @param domainList
+ * @return
+ */
+ @Override
+ public String setWebViewDomain(String action, List domainList) throws WxErrorException {
+ JsonObject requestJson = new JsonObject();
+ requestJson.addProperty("action", action);
+ if (!"get".equals(action)) {
+ requestJson.add("webviewdomain", toJsonArray(domainList));
+ }
+ String response = post(API_SET_WEBVIEW_DOMAIN, GSON.toJson(requestJson));
+ //TODO 转化为对象返回
+ return response;
+ }
+
+
+ /**
+ * 设置小程序的业务域名
+ *
+ * @param action add添加, delete删除, set覆盖
+ * @return
+ */
+ @Override
+ public WxOpenMaWebDomainResult setWebViewDomainInfo(String action, List domainList) throws WxErrorException {
+ String response = this.setWebViewDomain(action, domainList);
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaWebDomainResult.class);
+ }
+
+
+ /**
+ * 获取小程序的信息,GET请求
+ *
+ * 注意:这里不能直接用小程序的access_token
+ * //TODO 待调整
+ *
+ *
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public String getAccountBasicInfo() throws WxErrorException {
+ String response = get(API_GET_ACCOUNT_BASICINFO, "");
+ return response;
+ }
+
+
+ /**
+ * 绑定小程序体验者
+ *
+ * @param wechatid 体验者微信号(不是openid)
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenMaBindTesterResult bindTester(String wechatid) throws WxErrorException {
+ JsonObject paramJson = new JsonObject();
+ paramJson.addProperty("wechatid", wechatid);
+ String response = post(API_BIND_TESTER, GSON.toJson(paramJson));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaBindTesterResult.class);
+ }
+
+ /**
+ * 解除绑定小程序体验者
+ *
+ * @param wechatid 体验者微信号(不是openid)
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenResult unbindTester(String wechatid) throws WxErrorException {
+ JsonObject paramJson = new JsonObject();
+ paramJson.addProperty("wechatid", wechatid);
+ String response = post(API_UNBIND_TESTER, GSON.toJson(paramJson));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+ /**
+ * 解除绑定小程序体验者
+ * @param userstr 人员对应的唯一字符串, 可通过获取已绑定的体验者列表获取人员对应的字符串
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenResult unbindTesterByUserstr(String userstr) throws WxErrorException {
+ JsonObject paramJson = new JsonObject();
+ paramJson.addProperty("userstr", userstr);
+ String response = post(API_UNBIND_TESTER, GSON.toJson(paramJson));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+ /**
+ * 获得体验者列表
+ *
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenMaTesterListResult getTesterList() throws WxErrorException {
+ JsonObject paramJson = new JsonObject();
+ paramJson.addProperty("action", "get_experiencer");
+ String response = post(API_GET_TESTERLIST, GSON.toJson(paramJson));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaTesterListResult.class);
+ }
+
+
+ /**
+ * 设置小程序隐私设置(是否可被搜索)
+ *
+ * @param status 1表示不可搜索,0表示可搜索
+ */
+ @Override
+ public WxOpenResult changeWxaSearchStatus(Integer status) throws WxErrorException {
+ JsonObject paramJson = new JsonObject();
+ paramJson.addProperty("status", status);
+ String response = post(API_CHANGE_WXA_SEARCH_STATUS, GSON.toJson(paramJson));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+
+ /**
+ * 2. 查询小程序当前隐私设置(是否可被搜索)
+ */
+ @Override
+ public WxOpenMaSearchStatusResult getWxaSearchStatus() throws WxErrorException {
+ String response = get(API_GET_WXA_SEARCH_STATUS, null);
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaSearchStatusResult.class);
+ }
+
+
+ /**
+ * 3.1 获取展示的公众号信息
+ */
+ @Override
+ public WxOpenMaShowItemResult getShowWxaItem() throws WxErrorException {
+ String response = get(API_GET_SHOW_WXA_ITEM, null);
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaShowItemResult.class);
+ }
+
+
+ /**
+ * 3.2 设置展示的公众号
+ *
+ * @param flag 0 关闭,1 开启
+ * @param mpappid 如果开启,需要传新的公众号appid
+ */
+ @Override
+ public WxOpenResult updateShowwxaitem(Integer flag, String mpappid) throws WxErrorException {
+ JsonObject paramJson = new JsonObject();
+ paramJson.addProperty("wxa_subscribe_biz_flag", flag);
+ paramJson.addProperty("appid", mpappid);
+ String response = post(API_UPDATE_SHOW_WXA_ITEM, GSON.toJson(paramJson));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+
+ /**
+ * 1、为授权的小程序帐号上传小程序代码
+ *
+ * @param templateId 代码模板ID
+ * @param userVersion 用户定义版本
+ * @param userDesc 用户定义版本描述
+ * @param extInfo 第三方自定义的配置
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenResult codeCommit(Long templateId, String userVersion, String userDesc, WxMaOpenCommitExtInfo extInfo) throws WxErrorException {
+ JsonObject params = new JsonObject();
+ params.addProperty("template_id", templateId);
+ params.addProperty("user_version", userVersion);
+ params.addProperty("user_desc", userDesc);
+ //注意:ext_json必须是字符串类型
+ params.addProperty("ext_json", GSON.toJson(extInfo));
+ String response = post(API_CODE_COMMIT, GSON.toJson(params));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+ /**
+ * 获取体验小程序的体验二维码
+ *
+ * @param pagePath
+ * @param params
+ * @return
+ */
+ @Override
+ public File getTestQrcode(String pagePath, Map params) throws WxErrorException {
+ WxMaQrcodeParam qrcodeParam = WxMaQrcodeParam.create(pagePath);
+ qrcodeParam.addPageParam(params);
+ return execute(MaQrCodeRequestExecutor.create(getRequestHttp()), API_TEST_QRCODE, qrcodeParam);
+ }
+
+ /**
+ * 获取授权小程序帐号的可选类目
+ *
+ * 注意:该接口可获取已设置的二级类目及用于代码审核的可选三级类目。
+ *
+ *
+ * @return WxOpenMaCategoryListResult
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenMaCategoryListResult getCategoryList() throws WxErrorException {
+ String response = get(API_GET_CATEGORY, null);
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaCategoryListResult.class);
+ }
+
+ /**
+ * 获取小程序的第三方提交代码的页面配置(仅供第三方开发者代小程序调用)
+ *
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenMaPageListResult getPageList() throws WxErrorException {
+ String response = get(API_GET_PAGE, null);
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaPageListResult.class);
+ }
+
+ /**
+ * 将第三方提交的代码包提交审核(仅供第三方开发者代小程序调用)
+ *
+ * @param submitAuditMessage
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenMaSubmitAuditResult submitAudit(WxOpenMaSubmitAuditMessage submitAuditMessage) throws WxErrorException {
+ String response = post(API_SUBMIT_AUDIT, GSON.toJson(submitAuditMessage));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaSubmitAuditResult.class);
+ }
+
+ /**
+ * 7. 查询某个指定版本的审核状态(仅供第三方代小程序调用)
+ *
+ * @param auditid
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenMaQueryAuditResult getAuditStatus(Long auditid) throws WxErrorException {
+ JsonObject params = new JsonObject();
+ params.addProperty("auditid", auditid);
+ String response = post(API_GET_AUDIT_STATUS, GSON.toJson(params));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaQueryAuditResult.class);
+ }
+
+ /**
+ * 8. 查询最新一次提交的审核状态(仅供第三方代小程序调用)
+ *
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenMaQueryAuditResult getLatestAuditStatus() throws WxErrorException {
+ String response = get(API_GET_LATEST_AUDIT_STATUS, null);
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaQueryAuditResult.class);
+ }
+
+ /**
+ * 9. 发布已通过审核的小程序(仅供第三方代小程序调用)
+ *
+ * 请填写空的数据包,POST的json数据包为空即可。
+ *
+ *
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenResult releaesAudited() throws WxErrorException {
+ JsonObject params = new JsonObject();
+ String response = post(API_RELEASE, GSON.toJson(params));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+
+ /**
+ * 10. 修改小程序线上代码的可见状态(仅供第三方代小程序调用)
+ *
+ * @param action 设置可访问状态,发布后默认可访问,close为不可见,open为可见
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenResult changeVisitstatus(String action) throws WxErrorException {
+ JsonObject params = new JsonObject();
+ params.addProperty("action", action);
+ String response = post(API_CHANGE_VISITSTATUS, GSON.toJson(params));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+
+ /**
+ * 11. 小程序版本回退(仅供第三方代小程序调用)
+ *
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenResult revertCodeReleaes() throws WxErrorException {
+ String response = get(API_REVERT_CODE_RELEASE, null);
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+
+ /**
+ * 15. 小程序审核撤回
+ *
+ * 单个帐号每天审核撤回次数最多不超过1次,一个月不超过10次。
+ *
+ *
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenResult undoCodeAudit() throws WxErrorException {
+ String response = get(API_UNDO_CODE_AUDIT, null);
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+ /**
+ * 12. 查询当前设置的最低基础库版本及各版本用户占比 (仅供第三方代小程序调用)
+ *
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public String getSupportVersion() throws WxErrorException {
+ JsonObject params = new JsonObject();
+ String response = post(API_GET_WEAPP_SUPPORT_VERSION, GSON.toJson(params));
+ return response;
+ }
+
+
+ /**
+ * 12. 查询当前设置的最低基础库版本及各版本用户占比 (仅供第三方代小程序调用)
+ *
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenMaWeappSupportVersionResult getSupportVersionInfo() throws WxErrorException {
+ String response = this.getSupportVersion();
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaWeappSupportVersionResult.class);
+ }
+
+ /**
+ * 13. 设置最低基础库版本(仅供第三方代小程序调用)
+ *
+ * @param version
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public String setSupportVersion(String version) throws WxErrorException {
+ JsonObject params = new JsonObject();
+ params.addProperty("version", version);
+ String response = post(API_SET_WEAPP_SUPPORT_VERSION, GSON.toJson(params));
+ return response;
+ }
+
+
+ /**
+ * 13. 设置最低基础库版本(仅供第三方代小程序调用)
+ *
+ * @param version
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenResult setSupportVersionInfo(String version) throws WxErrorException {
+ String response = this.setSupportVersion(version);
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+
+ /**
+ * 16. 小程序分阶段发布 - 1)分阶段发布接口
+ *
+ * @param grayPercentage 灰度的百分比,1到100的整数
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenResult grayrelease(Integer grayPercentage) throws WxErrorException {
+ JsonObject params = new JsonObject();
+ params.addProperty("gray_percentage", grayPercentage);
+ String response = post(API_GRAY_RELEASE, GSON.toJson(params));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+
+ /**
+ * 16. 小程序分阶段发布 - 2)取消分阶段发布
+ *
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+
+ public WxOpenResult revertgrayrelease() throws WxErrorException {
+ String response = get(API_REVERT_GRAY_RELEASE, null);
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+
+ /**
+ * 16. 小程序分阶段发布 - 3)查询当前分阶段发布详情
+ *
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenMaGrayReleasePlanResult getgrayreleaseplan() throws WxErrorException {
+ String response = get(API_GET_GRAY_RELEASE_PLAN, null);
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaGrayReleasePlanResult.class);
+ }
+
+
+ /**
+ * 查询服务商的当月提审限额和加急次数(Quota)
+ * https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/code/query_quota.html
+ */
+ @Override
+ public WxOpenMaQueryQuotaResult queryQuota() throws WxErrorException {
+ String response = get(API_QUERY_QUOTA, null);
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenMaQueryQuotaResult.class);
+ }
+
+
+
+ /**
+ * 加急审核申请
+ * 有加急次数的第三方可以通过该接口,对已经提审的小程序进行加急操作,加急后的小程序预计2-12小时内审完。
+ */
+ @Override
+ public Boolean speedAudit(Long auditid) throws WxErrorException {
+ JsonObject params = new JsonObject();
+ params.addProperty("auditid", auditid);
+ String response = post(API_SPEED_AUDIT, GSON.toJson(params));
+ WxOpenResult result = WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ return result.isSuccess();
+ }
+
+
+ /**
+ * (1)增加或修改二维码规则
+ * @param wxQrcodeJumpRule
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenResult addQrcodeJump(WxQrcodeJumpRule wxQrcodeJumpRule) throws WxErrorException {
+ String response = post(API_QRCODE_JUMP_ADD, GSON.toJson(wxQrcodeJumpRule));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+ /**
+ * (2)获取已设置的二维码规则
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxGetQrcodeJumpResult getQrcodeJump() throws WxErrorException {
+ String response = post(API_QRCODE_JUMP_GET, "{}");
+ return WxMaGsonBuilder.create().fromJson(response, WxGetQrcodeJumpResult.class);
+ }
+
+ /**
+ * (3)获取校验文件名称及内容
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxDownlooadQrcodeJumpResult downloadQrcodeJump() throws WxErrorException {
+ String response = post(API_QRCODE_JUMP_DOWNLOAD, "{}");
+ return WxMaGsonBuilder.create().fromJson(response, WxDownlooadQrcodeJumpResult.class);
+ }
+
+ /**
+ * (4)删除已设置的二维码规则
+ * @param prefix
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenResult deleteQrcodeJump(String prefix) throws WxErrorException {
+ JsonObject params = new JsonObject();
+ params.addProperty("prefix", prefix);
+ String response = post(API_QRCODE_JUMP_DELETE, GSON.toJson(params));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+ /**
+ * (5)发布已设置的二维码规则
+ * @param prefix
+ * @return
+ * @throws WxErrorException
+ */
+ @Override
+ public WxOpenResult publishQrcodeJump(String prefix) throws WxErrorException {
+ JsonObject params = new JsonObject();
+ params.addProperty("prefix", prefix);
+ String response = post(API_QRCODE_JUMP_PUBLISH, GSON.toJson(params));
+ return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class);
+ }
+
+ /**
+ * 将字符串对象转化为GsonArray对象
+ *
+ * @param strList
+ * @return
+ */
+ private JsonArray toJsonArray(List strList) {
+ JsonArray jsonArray = new JsonArray();
+ if (strList != null && !strList.isEmpty()) {
+ for (String str : strList) {
+ jsonArray.add(str);
+ }
+ }
+ return jsonArray;
+ }
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenServiceAbstractImpl.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenServiceAbstractImpl.java
new file mode 100644
index 0000000..6309e26
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenServiceAbstractImpl.java
@@ -0,0 +1,62 @@
+package com.iformall.service.toutiao.api.impl;
+
+import com.iformall.service.toutiao.api.TtOpenComponentService;
+import com.iformall.service.toutiao.api.TtOpenService;
+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.RequestExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.open.api.WxOpenConfigStorage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+/**
+ * @author
+ */
+public abstract class TtOpenServiceAbstractImpl implements TtOpenService, RequestHttp {
+ private final Logger log = LoggerFactory.getLogger(this.getClass());
+ private TtOpenComponentService ttOpenComponentService = new TtOpenComponentServiceImpl(this);
+ private WxOpenConfigStorage wxOpenConfigStorage;
+
+ @Override
+ public TtOpenComponentService getTtOpenComponentService() {
+ return ttOpenComponentService;
+ }
+
+ @Override
+ public WxOpenConfigStorage getWxOpenConfigStorage() {
+ return wxOpenConfigStorage;
+ }
+
+ @Override
+ public void setWxOpenConfigStorage(WxOpenConfigStorage wxOpenConfigStorage) {
+ this.wxOpenConfigStorage = wxOpenConfigStorage;
+ this.initHttp();
+ }
+
+ /**
+ * 初始化 RequestHttp.
+ */
+ public abstract void initHttp();
+
+ protected T execute(RequestExecutor executor, String uri, E data) throws WxErrorException {
+ try {
+ T result = executor.execute(uri, data, WxType.Open);
+ this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uri, data, result);
+ return result;
+ } catch (WxErrorException e) {
+ WxError error = e.getError();
+ if (error.getErrorCode() != 0) {
+ this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uri, data, error);
+ throw new WxErrorException(error, e);
+ }
+ return null;
+ } catch (IOException e) {
+ this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uri, data, e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenServiceApacheHttpClientImpl.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenServiceApacheHttpClientImpl.java
new file mode 100644
index 0000000..42665ad
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenServiceApacheHttpClientImpl.java
@@ -0,0 +1,67 @@
+package com.iformall.service.toutiao.api.impl;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
+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.open.api.WxOpenConfigStorage;
+import org.apache.http.HttpHost;
+import org.apache.http.impl.client.CloseableHttpClient;
+
+/**
+ * apache-http方式实现
+ *
+ * @author 007
+ */
+public class TtOpenServiceApacheHttpClientImpl extends TtOpenServiceAbstractImpl {
+ private CloseableHttpClient httpClient;
+ private HttpHost httpProxy;
+
+ @Override
+ public void initHttp() {
+ WxOpenConfigStorage configStorage = this.getWxOpenConfigStorage();
+ ApacheHttpClientBuilder apacheHttpClientBuilder = configStorage.getApacheHttpClientBuilder();
+ if (null == apacheHttpClientBuilder) {
+ apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get();
+ }
+
+ apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost())
+ .httpProxyPort(configStorage.getHttpProxyPort())
+ .httpProxyUsername(configStorage.getHttpProxyUsername())
+ .httpProxyPassword(configStorage.getHttpProxyPassword());
+
+ if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) {
+ this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort());
+ }
+
+ this.httpClient = apacheHttpClientBuilder.build();
+
+ }
+
+ @Override
+ public CloseableHttpClient getRequestHttpClient() {
+ return httpClient;
+ }
+
+ @Override
+ public HttpHost getRequestHttpProxy() {
+ return httpProxy;
+ }
+
+ @Override
+ public HttpType getRequestType() {
+ return HttpType.APACHE_HTTP;
+ }
+
+ @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);
+ }
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenServiceImpl.java
new file mode 100644
index 0000000..cbd3ffa
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/api/impl/TtOpenServiceImpl.java
@@ -0,0 +1,8 @@
+package com.iformall.service.toutiao.api.impl;
+
+/**
+ * @author
+ */
+public class TtOpenServiceImpl extends TtOpenServiceApacheHttpClientImpl {
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaMsgService.java b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaMsgService.java
new file mode 100644
index 0000000..243277e
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaMsgService.java
@@ -0,0 +1,28 @@
+package com.iformall.service.toutiao.miniapp;
+
+import com.iformall.service.toutiao.miniapp.bean.TtMaSubscribeMessage;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ *
+ * 消息发送接口
+ *
+ *
+ * @author Binary Wang
+ */
+public interface TtMaMsgService {
+
+ String SUBSCRIBE_MSG_SEND_URL = "https://developer.toutiao.com/api/apps/subscribe_notification/developer/v1/notify";
+
+ /**
+ *
+ * 发送订阅消息
+ * https://microapp.bytedance.com/docs/zh-CN/mini-app/develop/server/subscribe-notification/notify/
+ *
+ *
+ * @param subscribeMessage 订阅消息
+ * @throws WxErrorException .
+ */
+ void sendSubscribeMsg(TtMaSubscribeMessage subscribeMessage) throws WxErrorException;
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaQrcode.java b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaQrcode.java
new file mode 100644
index 0000000..2a83715
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaQrcode.java
@@ -0,0 +1,39 @@
+package com.iformall.service.toutiao.miniapp;
+
+import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper;
+import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * @author Binary Wang
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class TtMaQrcode extends AbstractWxMaQrcodeWrapper implements Serializable {
+
+ private static final long serialVersionUID = 5777119669111011584L;
+
+ private String access_token;
+
+ private String appname;
+ private String path;
+ private int width = 430;
+
+ public TtMaQrcode(String appname, String path, int width) {
+ this.appname = appname;
+ this.path = path;
+ this.width = width;
+ }
+
+ public static TtMaQrcode fromJson(String json) {
+ return WxMaGsonBuilder.create().fromJson(json, TtMaQrcode.class);
+ }
+
+ @Override
+ public String toString() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaQrcodeService.java b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaQrcodeService.java
new file mode 100644
index 0000000..0a19e7e
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaQrcodeService.java
@@ -0,0 +1,31 @@
+package com.iformall.service.toutiao.miniapp;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+
+import java.io.File;
+
+/**
+ *
+ * 二维码相关操作接口.
+ *
+ *
+ *
+ * @author Binary Wang
+ */
+public interface TtMaQrcodeService {
+
+ String GET_TTACODE_URL = "https://developer.toutiao.com/api/apps/qrcode";
+
+
+ /**
+ * 接口A: 获取小程序码.
+ *
+ * @param path 不能为空,最大长度 128 字节
+ * @param width 默认430 二维码的宽度
+ * @return 文件对象
+ * @throws WxErrorException 异常
+ */
+ File createTtaCode(String appname, String path, int width) throws WxErrorException;
+
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaService.java b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaService.java
new file mode 100644
index 0000000..0066647
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaService.java
@@ -0,0 +1,132 @@
+package com.iformall.service.toutiao.miniapp;
+
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import cn.binarywang.wx.miniapp.config.WxMaConfig;
+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;
+
+/**
+ * @author Binary Wang
+ */
+public interface TtMaService {
+ /**
+ * 获取access_token.
+ */
+ String GET_ACCESS_TOKEN_URL = "https://developer.toutiao.com/api/apps/token?grant_type=client_credential&appid=%s&secret=%s";
+
+ String JSCODE_TO_SESSION_URL = "https://developer.toutiao.com/api/apps/jscode2session";
+
+ String ORDER_PUSH = "https://developer.toutiao.com/api/apps/order/v2/push";
+
+ /**
+ * 获取登录后的session信息.
+ *
+ * @param jsCode 登录时获取的 code
+ */
+ WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException;
+
+ /**
+ *
+ * 验证消息的确来自微信服务器.
+ * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN
+ *
+ */
+ boolean checkSignature(String timestamp, String nonce, String signature);
+
+ /**
+ *
+ * 获取access_token,本方法线程安全.
+ * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限
+ *
+ * 另:本service的所有方法都会在access_token过期是调用此方法
+ *
+ * 程序员在非必要情况下尽量不要主动调用此方法
+ *
+ * 详情请见: https://microapp.bytedance.com/docs/zh-CN/mini-app/develop/server/interface-request-credential/get-access-token
+ *
+ *
+ * @param forceRefresh 强制刷新
+ */
+ String getAccessToken(boolean forceRefresh) throws WxErrorException;
+
+ /**
+ * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求.
+ */
+ String get(String url, String queryParam) throws WxErrorException;
+
+ /**
+ * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求.
+ */
+ String post(String url, String postData) throws WxErrorException;
+
+ /**
+ * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求.
+ */
+ String post(String url, Object obj) throws WxErrorException;
+
+ /**
+ *
+ * Service没有实现某个API的时候,可以用这个,
+ * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
+ * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
+ *
+ */
+ T execute(RequestExecutor executor, String uri, E data) throws WxErrorException;
+
+ /**
+ *
+ * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试.
+ * 默认:1000ms
+ *
+ */
+ void setRetrySleepMillis(int retrySleepMillis);
+
+ /**
+ *
+ * 设置当微信系统响应系统繁忙时,最大重试次数.
+ * 默认:5次
+ *
+ */
+ void setMaxRetryTimes(int maxRetryTimes);
+
+ /**
+ * 获取WxMaConfig 对象.
+ *
+ * @return WxMaConfig
+ */
+ WxMaConfig getWxMaConfig();
+
+ /**
+ * 注入 {@link WxMaConfig} 的实现.
+ */
+ void setWxMaConfig(WxMaConfig wxConfigProvider);
+
+ /**
+ * 初始化http请求对象.
+ */
+ void initHttp();
+
+ /**
+ * 请求http请求相关信息.
+ */
+ RequestHttp getRequestHttp();
+
+ /**
+ * 返回用户相关接口方法的实现类对象,以方便调用其各个接口.
+ *
+ * @return TtMaUserService
+ */
+ TtMaUserService getUserService();
+
+ /**
+ * 返回用户相关接口方法的实现类对象,以方便调用其各个接口.
+ *
+ * @return TtMaUserService
+ */
+ TtMaQrcodeService getQrcodeService();
+
+ TtMaMsgService getMsgService();
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaUserService.java b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaUserService.java
new file mode 100644
index 0000000..5f437c6
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtMaUserService.java
@@ -0,0 +1,52 @@
+package com.iformall.service.toutiao.miniapp;
+
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
+import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * 用户信息相关操作接口.
+ *
+ * @author Binary Wang
+ */
+public interface TtMaUserService {
+
+ /**
+ * 获取登录后的session信息.
+ *
+ * @param jsCode 登录时获取的 code
+ * @return .
+ * @throws WxErrorException .
+ */
+ WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException;
+
+ /**
+ * 解密用户敏感数据.
+ *
+ * @param sessionKey 会话密钥
+ * @param encryptedData 消息密文
+ * @param ivStr 加密算法的初始向量
+ */
+ WxMaUserInfo getUserInfo(String sessionKey, String encryptedData, String ivStr);
+
+ /**
+ * 解密用户手机号信息.
+ *
+ * @param sessionKey 会话密钥
+ * @param encryptedData 消息密文
+ * @param ivStr 加密算法的初始向量
+ * @return .
+ */
+ WxMaPhoneNumberInfo getPhoneNoInfo(String sessionKey, String encryptedData, String ivStr);
+
+ /**
+ * 验证用户信息完整性.
+ *
+ * @param sessionKey 会话密钥
+ * @param rawData 微信用户基本信息
+ * @param signature 数据签名
+ * @return .
+ */
+ boolean checkUserInfo(String sessionKey, String rawData, String signature);
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtQrcodeRequestExecutor.java b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtQrcodeRequestExecutor.java
new file mode 100644
index 0000000..8ddf348
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/TtQrcodeRequestExecutor.java
@@ -0,0 +1,69 @@
+package com.iformall.service.toutiao.miniapp;
+
+import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper;
+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.fs.FileUtils;
+import me.chanjar.weixin.common.util.http.RequestExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler;
+import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
+import org.apache.http.Header;
+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.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.UUID;
+
+/**
+ * @author Binary Wang
+ */
+public class TtQrcodeRequestExecutor implements RequestExecutor {
+ protected RequestHttp requestHttp;
+
+ public TtQrcodeRequestExecutor(RequestHttp requestHttp) {
+ this.requestHttp = requestHttp;
+ }
+
+ @Override
+ public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler handler, WxType wxType) throws WxErrorException, IOException {
+ handler.handle(this.execute(uri, data, wxType));
+ }
+
+ @Override
+ public File execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper, WxType wxType) throws WxErrorException, IOException {
+ HttpPost httpPost = new HttpPost(uri);
+ if (requestHttp.getRequestHttpProxy() != null) {
+ httpPost.setConfig(
+ RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build()
+ );
+ }
+ httpPost.addHeader("Content-Type","application/json");
+
+ httpPost.setEntity(new StringEntity(qrcodeWrapper.toJson()));
+
+ try (final CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost);
+ final InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) {
+ Header[] contentTypeHeader = response.getHeaders("Content-Type");
+ if (contentTypeHeader != null && contentTypeHeader.length > 0
+ && ContentType.APPLICATION_JSON.getMimeType()
+ .equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) {
+ String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
+ throw new WxErrorException(WxError.fromJson(responseContent, wxType));
+ }
+
+ return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg");
+ } finally {
+ httpPost.releaseConnection();
+ }
+ }
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/bean/TtMaGsonBuilder.java b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/bean/TtMaGsonBuilder.java
new file mode 100644
index 0000000..7c3b89a
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/bean/TtMaGsonBuilder.java
@@ -0,0 +1,21 @@
+package com.iformall.service.toutiao.miniapp.bean;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/**
+ * @author Binary Wang
+ */
+public class TtMaGsonBuilder {
+ private static final GsonBuilder INSTANCE = new GsonBuilder();
+
+ static {
+ INSTANCE.disableHtmlEscaping();
+ INSTANCE.registerTypeAdapter(TtMaSubscribeMessage.class, new TtMaSubscribeMessageGsonAdapter());
+ }
+
+ public static Gson create() {
+ return INSTANCE.create();
+ }
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/bean/TtMaSubscribeMessage.java b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/bean/TtMaSubscribeMessage.java
new file mode 100644
index 0000000..8874721
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/bean/TtMaSubscribeMessage.java
@@ -0,0 +1,70 @@
+package com.iformall.service.toutiao.miniapp.bean;
+
+import com.google.gson.JsonObject;
+import lombok.*;
+
+import java.io.Serializable;
+
+/**
+ * 订阅消息.
+
+ * @author S
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class TtMaSubscribeMessage implements Serializable {
+
+ private static final long serialVersionUID = -5931206947637944325L;
+
+ private String accessToken;
+
+ private String appId;
+
+ /**
+ * 接收者(用户)的 openid.
+ *
+ * 参数:touser
+ * 是否必填: 是
+ * 描述: 接收者(用户)的 openid
+ *
+ */
+ private String openId;
+
+ /**
+ * 所需下发的模板消息的id.
+ *
+ * 参数:template_id
+ * 是否必填: 是
+ * 描述: 所需下发的模板消息的id
+ *
+ */
+ private String tplId;
+
+ /**
+ * 点击模板卡片后的跳转页面,仅限本小程序内的页面.
+ *
+ * 参数:page
+ * 是否必填: 否
+ * 描述: 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
+ *
+ */
+ private String page;
+
+ /**
+ * 模板内容,不填则下发空模板.
+ *
+ * 参数:data
+ * 是否必填: 是
+ * 描述: 模板内容,不填则下发空模板
+ *
+ */
+ private JsonObject data;
+
+ public String toJson() {
+ return TtMaGsonBuilder.create().toJson(this);
+ }
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/bean/TtMaSubscribeMessageGsonAdapter.java b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/bean/TtMaSubscribeMessageGsonAdapter.java
new file mode 100644
index 0000000..238e58e
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/bean/TtMaSubscribeMessageGsonAdapter.java
@@ -0,0 +1,33 @@
+package com.iformall.service.toutiao.miniapp.bean;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+import java.lang.reflect.Type;
+
+/**
+ * .
+ *
+ * @author S
+ */
+public class TtMaSubscribeMessageGsonAdapter implements JsonSerializer {
+ @Override
+ public JsonElement serialize(TtMaSubscribeMessage message, Type typeOfSrc, JsonSerializationContext context) {
+ JsonObject messageJson = new JsonObject();
+
+ messageJson.addProperty("access_token", message.getAccessToken());
+ messageJson.addProperty("app_id", message.getAppId());
+ messageJson.addProperty("tpl_id", message.getTplId());
+ messageJson.addProperty("open_id", message.getOpenId());
+ if (message.getPage() != null) {
+ messageJson.addProperty("page", message.getPage());
+ }
+
+ messageJson.add("data", message.getData());
+
+ return messageJson;
+ }
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/impl/TtMaMsgServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/impl/TtMaMsgServiceImpl.java
new file mode 100644
index 0000000..388189f
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/impl/TtMaMsgServiceImpl.java
@@ -0,0 +1,30 @@
+package com.iformall.service.toutiao.miniapp.impl;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.iformall.service.toutiao.miniapp.TtMaMsgService;
+import com.iformall.service.toutiao.miniapp.TtMaService;
+import com.iformall.service.toutiao.miniapp.bean.TtMaSubscribeMessage;
+import lombok.AllArgsConstructor;
+import me.chanjar.weixin.common.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * @author Binary Wang
+ */
+@AllArgsConstructor
+public class TtMaMsgServiceImpl implements TtMaMsgService {
+ private static final JsonParser JSON_PARSER = new JsonParser();
+ private TtMaService ttMaService;
+
+ @Override
+ public void sendSubscribeMsg(TtMaSubscribeMessage subscribeMessage) throws WxErrorException {
+ String responseContent = this.ttMaService.post(SUBSCRIBE_MSG_SEND_URL, subscribeMessage);
+ JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject();
+ if (jsonObject.get("err_no").getAsInt() != 0) {
+ throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
+ }
+ }
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/impl/TtMaQrcodeServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/impl/TtMaQrcodeServiceImpl.java
new file mode 100644
index 0000000..d6c61c3
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/impl/TtMaQrcodeServiceImpl.java
@@ -0,0 +1,26 @@
+package com.iformall.service.toutiao.miniapp.impl;
+
+import com.iformall.service.toutiao.miniapp.TtMaQrcode;
+import com.iformall.service.toutiao.miniapp.TtMaQrcodeService;
+import com.iformall.service.toutiao.miniapp.TtMaService;
+import com.iformall.service.toutiao.miniapp.TtQrcodeRequestExecutor;
+import lombok.AllArgsConstructor;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+import java.io.File;
+
+/**
+ * @author Binary Wang
+ */
+@AllArgsConstructor
+public class TtMaQrcodeServiceImpl implements TtMaQrcodeService {
+
+ private TtMaService ttMaService;
+
+ @Override
+ public File createTtaCode(String appname, String path, int width) throws WxErrorException {
+ final TtQrcodeRequestExecutor executor = new TtQrcodeRequestExecutor(this.ttMaService.getRequestHttp());
+ return this.ttMaService.execute(executor, GET_TTACODE_URL, new TtMaQrcode(appname,path, width));
+ }
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/impl/TtMaServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/impl/TtMaServiceImpl.java
new file mode 100644
index 0000000..b7233a6
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/impl/TtMaServiceImpl.java
@@ -0,0 +1,312 @@
+package com.iformall.service.toutiao.miniapp.impl;
+
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import com.google.common.base.Joiner;
+import com.google.gson.Gson;
+import com.google.gson.JsonParser;
+import com.iformall.service.toutiao.miniapp.TtMaMsgService;
+import com.iformall.service.toutiao.miniapp.TtMaQrcodeService;
+import com.iformall.service.toutiao.miniapp.TtMaService;
+import com.iformall.service.toutiao.miniapp.TtMaUserService;
+import com.iformall.service.toutiao.miniapp.bean.TtMaGsonBuilder;
+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.*;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
+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.HttpGet;
+import org.apache.http.impl.client.BasicResponseHandler;
+import org.apache.http.impl.client.CloseableHttpClient;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+
+import static cn.binarywang.wx.miniapp.constant.WxMaConstants.ErrorCode.*;
+
+/**
+ * @author
+ */
+@Slf4j
+public class TtMaServiceImpl implements TtMaService, RequestHttp {
+ private static final JsonParser JSON_PARSER = new JsonParser();
+ private CloseableHttpClient httpClient;
+ private HttpHost httpProxy;
+ private WxMaConfig wxMaConfig;
+
+ private TtMaUserService userService = new TtMaUserServiceImpl(this);
+ private TtMaQrcodeService qrcodeService = new TtMaQrcodeServiceImpl(this);
+ private TtMaMsgService msgService = new TtMaMsgServiceImpl(this);
+
+ private int retrySleepMillis = 1000;
+ private int maxRetryTimes = 5;
+
+ protected static final Gson GSON = new Gson();
+
+ @Override
+ public CloseableHttpClient getRequestHttpClient() {
+ return httpClient;
+ }
+
+ @Override
+ public HttpHost getRequestHttpProxy() {
+ return httpProxy;
+ }
+
+ @Override
+ public HttpType getRequestType() {
+ return HttpType.APACHE_HTTP;
+ }
+
+ @Override
+ public void initHttp() {
+ WxMaConfig configStorage = this.getWxMaConfig();
+ ApacheHttpClientBuilder apacheHttpClientBuilder = configStorage.getApacheHttpClientBuilder();
+ if (null == apacheHttpClientBuilder) {
+ apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get();
+ }
+
+ apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost())
+ .httpProxyPort(configStorage.getHttpProxyPort())
+ .httpProxyUsername(configStorage.getHttpProxyUsername())
+ .httpProxyPassword(configStorage.getHttpProxyPassword());
+
+ if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) {
+ this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort());
+ }
+
+ this.httpClient = apacheHttpClientBuilder.build();
+ }
+
+ @Override
+ public RequestHttp getRequestHttp() {
+ return this;
+ }
+
+ @Override
+ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
+ if (!this.getWxMaConfig().isAccessTokenExpired() && !forceRefresh) {
+ return this.getWxMaConfig().getAccessToken();
+ }
+
+ Lock lock = this.getWxMaConfig().getAccessTokenLock();
+ lock.lock();
+ try {
+ String url = String.format(this.GET_ACCESS_TOKEN_URL, this.getWxMaConfig().getAppid(),
+ this.getWxMaConfig().getSecret());
+ try {
+ HttpGet httpGet = new HttpGet(url);
+ if (this.getRequestHttpProxy() != null) {
+ RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+ httpGet.setConfig(config);
+ }
+ try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) {
+ String resultContent = new BasicResponseHandler().handleResponse(response);
+ WxError error = WxError.fromJson(resultContent, WxType.MiniApp);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+ WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
+ this.getWxMaConfig().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
+
+ return this.getWxMaConfig().getAccessToken();
+ } finally {
+ httpGet.releaseConnection();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ } finally {
+ lock.unlock();
+ }
+
+ }
+
+
+
+ @Override
+ public WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException {
+ final WxMaConfig config = getWxMaConfig();
+ Map params = new HashMap<>(8);
+ params.put("appid", config.getAppid());
+ params.put("secret", config.getSecret());
+ params.put("code", jsCode);
+
+ String result = get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params));
+ return WxMaJscode2SessionResult.fromJson(result);
+ }
+
+ @Override
+ public boolean checkSignature(String timestamp, String nonce, String signature) {
+ try {
+ return SHA1.gen(this.getWxMaConfig().getToken(), timestamp, nonce).equals(signature);
+ } catch (Exception e) {
+ log.error("Checking signature failed, and the reason is :" + e.getMessage());
+ return false;
+ }
+ }
+
+ @Override
+ public String get(String url, String queryParam) throws WxErrorException {
+ if (url.contains("access_token=")) {
+ throw new IllegalArgumentException("uri参数中不允许有access_token: " + url);
+ }
+ String accessToken = getAccessToken(false);
+ String uriWithAccessToken = url + (url.contains("?") ? "&" : "?") + "access_token=" + accessToken;
+
+ return execute(SimpleGetRequestExecutor.create(this), uriWithAccessToken, queryParam);
+ }
+
+ @Override
+ public String post(String url, String postData) throws WxErrorException {
+
+ if (url.contains("access_token=")) {
+ throw new IllegalArgumentException("uri参数中不允许有access_token: " + url);
+ }
+ String accessToken = getAccessToken(false);
+ String uriWithAccessToken = url + (url.contains("?") ? "&" : "?") + "access_token=" + accessToken;
+
+ return execute(SimplePostRequestExecutor.create(this), uriWithAccessToken, postData);
+ }
+
+ @Override
+ public String post(String url, Object obj) throws WxErrorException {
+ if (url.contains("access_token=")) {
+ throw new IllegalArgumentException("uri参数中不允许有access_token: " + url);
+ }
+ try {
+ String accessToken = getAccessToken(false);
+ Class> aClass = obj.getClass();
+ if(!aClass.equals(String.class)){
+ if(aClass.equals(HashMap.class)){
+ ((HashMap) obj).put("access_token",accessToken);
+ }else{
+ Field accessToken1 = aClass.getDeclaredField("accessToken");
+ accessToken1.setAccessible(true);
+ accessToken1.set(obj,accessToken);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ log.error("【请求参数】:{}添加accessToken失败" + obj.getClass());
+ }
+ return this.execute(SimplePostRequestExecutor.create(this), url, TtMaGsonBuilder.create().toJson(obj));
+ }
+
+ /**
+ * 向微信端发送请求,在这里执行的策略是当发生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("重试达到最大次数【{}】", maxRetryTimes);
+ //最后一次重试失败后,直接抛出异常,不再等待
+ throw new RuntimeException("微信服务端异常,超出重试次数");
+ }
+
+ WxError error = e.getError();
+ // -1 系统繁忙, 1000ms后重试
+ if (error.getErrorCode() == -1) {
+ int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
+ try {
+ log.warn("微信系统繁忙,{} 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("微信服务端异常,超出重试次数");
+ }
+
+ private T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException {
+ E dataForLog = DataUtils.handleDataWithSecret(data);
+
+ try {
+ T result = executor.execute(uri, data, WxType.MiniApp);
+ log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uri, data, result);
+ return result;
+ } catch (WxErrorException e) {
+ WxError error = e.getError();
+ /*
+ * 发生以下情况时尝试刷新access_token
+ */
+ if (error.getErrorCode() == ERR_40001
+ || error.getErrorCode() == ERR_42001
+ || error.getErrorCode() == ERR_40014) {
+ // 强制设置WxMaConfig的access token过期了,这样在下一次请求里就会刷新access token
+ this.getWxMaConfig().expireAccessToken();
+ if (this.getWxMaConfig().autoRefreshToken()) {
+ return this.execute(executor, uri, data);
+ }
+ }
+
+ if (error.getErrorCode() != 0) {
+ log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uri, dataForLog, error);
+ throw new WxErrorException(error, e);
+ }
+ return null;
+ } catch (IOException e) {
+ log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uri, dataForLog, e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public WxMaConfig getWxMaConfig() {
+ return this.wxMaConfig;
+ }
+
+ @Override
+ public void setWxMaConfig(WxMaConfig wxConfigProvider) {
+ this.wxMaConfig = wxConfigProvider;
+ this.initHttp();
+ }
+
+ @Override
+ public void setRetrySleepMillis(int retrySleepMillis) {
+ this.retrySleepMillis = retrySleepMillis;
+ }
+
+ @Override
+ public void setMaxRetryTimes(int maxRetryTimes) {
+ this.maxRetryTimes = maxRetryTimes;
+ }
+
+ @Override
+ public TtMaUserService getUserService() {
+ return this.userService;
+ }
+
+ @Override
+ public TtMaQrcodeService getQrcodeService() {
+ return this.qrcodeService;
+ }
+
+ @Override
+ public TtMaMsgService getMsgService() {
+ return this.msgService;
+ }
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/impl/TtMaUserServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/impl/TtMaUserServiceImpl.java
new file mode 100644
index 0000000..5b8b66e
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/miniapp/impl/TtMaUserServiceImpl.java
@@ -0,0 +1,41 @@
+package com.iformall.service.toutiao.miniapp.impl;
+
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
+import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
+import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils;
+import com.iformall.service.toutiao.miniapp.TtMaService;
+import com.iformall.service.toutiao.miniapp.TtMaUserService;
+import lombok.AllArgsConstructor;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.apache.commons.codec.digest.DigestUtils;
+
+/**
+ * @author Binary Wang
+ */
+@AllArgsConstructor
+public class TtMaUserServiceImpl implements TtMaUserService {
+ private TtMaService service;
+
+ @Override
+ public WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException {
+ return service.jsCode2SessionInfo(jsCode);
+ }
+
+ @Override
+ public WxMaUserInfo getUserInfo(String sessionKey, String encryptedData, String ivStr) {
+ return WxMaUserInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr));
+ }
+
+ @Override
+ public WxMaPhoneNumberInfo getPhoneNoInfo(String sessionKey, String encryptedData, String ivStr) {
+ return WxMaPhoneNumberInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr));
+ }
+
+ @Override
+ public boolean checkUserInfo(String sessionKey, String rawData, String signature) {
+ final String generatedSignature = DigestUtils.sha1Hex(rawData + sessionKey);
+ return generatedSignature.equals(signature);
+ }
+
+}
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/utils/MsgDecrypt.java b/mallinkService/src/main/java/com/iformall/service/toutiao/utils/MsgDecrypt.java
new file mode 100644
index 0000000..1aa241c
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/utils/MsgDecrypt.java
@@ -0,0 +1,88 @@
+package com.iformall.service.toutiao.utils;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.commons.codec.binary.Base64;
+
+
+public class MsgDecrypt {
+
+ private Cipher cipher;
+ static int RANDOM_BYTES_POS = 32;
+
+ public MsgDecrypt(String encodingAesKey) throws Exception {
+ //AES key长度固定
+ if (encodingAesKey.length() != 43) {
+ throw new Exception("AES key 长度不合法");
+ }
+ byte[] aesKey = Base64.decodeBase64(encodingAesKey + "=");
+
+ SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
+ IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
+ Cipher encCipher = Cipher.getInstance("AES/CBC/NoPadding");
+ encCipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
+
+ cipher = Cipher.getInstance("AES/CBC/NoPadding");
+ cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
+ }
+
+ //将四个byte解析为一个32位的数字,数字的值也就是消息体的String格式下的长度
+ private int getLength(byte[] orderBytes) {
+ ByteBuffer buf = ByteBuffer.wrap(orderBytes);
+ buf.order(ByteOrder.BIG_ENDIAN);
+ return buf.getInt();
+ }
+
+ private byte[] decode(byte[] decrypted) {
+ int pad = decrypted[decrypted.length - 1];
+ if (pad < 1 || pad > 32) {
+ pad = 0;
+ }
+ return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
+ }
+
+ public String decrypt(String text) throws Exception {
+ byte[] original;
+ try {
+ byte[] encrypted = Base64.decodeBase64(text);
+ original = cipher.doFinal(encrypted);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new Exception("解码异常");
+ }
+
+ String Content;
+ String AppId;
+ try {
+ byte[] bytes = this.decode(original);
+
+ //byte数组的第32、33、34、35个元素代表了消息体的真实字符个数,也就是长度
+ byte[] pos = Arrays.copyOfRange(bytes, RANDOM_BYTES_POS, RANDOM_BYTES_POS + 4);
+ int msgLength = getLength(pos);
+
+ //根据解析出来的消息体长度值,截取真实的消息体
+ Content = new String(Arrays.copyOfRange(bytes, RANDOM_BYTES_POS + 4, RANDOM_BYTES_POS + 4 + msgLength), StandardCharsets.UTF_8);
+ //byte数组截去真实消息后,末尾剩下的字符就是appid
+ AppId = new String(Arrays.copyOfRange(bytes, RANDOM_BYTES_POS + 4 + msgLength, bytes.length), StandardCharsets.UTF_8);
+
+// System.out.println("Content: " + Content);
+// System.out.println("ThirdParty AppID: " + AppId);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new Exception("Buffer异常");
+ }
+ return Content;
+ }
+
+ public static void main(String[] args) throws Exception {
+ MsgDecrypt test = new MsgDecrypt("XXX");
+ test.decrypt("XXX");
+ }
+}
\ No newline at end of file
diff --git a/mallinkService/src/main/java/com/iformall/service/toutiao/utils/ServerVerification.java b/mallinkService/src/main/java/com/iformall/service/toutiao/utils/ServerVerification.java
new file mode 100644
index 0000000..b521248
--- /dev/null
+++ b/mallinkService/src/main/java/com/iformall/service/toutiao/utils/ServerVerification.java
@@ -0,0 +1,55 @@
+package com.iformall.service.toutiao.utils;
+
+import java.util.Arrays;
+import java.security.MessageDigest;
+
+public class ServerVerification {
+
+ private String getMsgSignature(String tpToken, String timestamp, String nonce, String encrypt) throws Exception {
+ String[] values = new String[] {tpToken, timestamp, nonce, encrypt};
+ Arrays.sort(values);
+
+ StringBuilder sb = new StringBuilder();
+ for (String value : values) {
+ sb.append(value);
+ }
+
+ String str = sb.toString();
+
+ try {
+ //指定sha1算法
+ MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
+ messageDigest.update(str.getBytes());
+
+ //获取字节数组
+ byte[] messageDigestByte = messageDigest.digest();
+
+ StringBuilder hexStr = new StringBuilder();
+ // 字节数组转换为十六进制数
+ for (byte b : messageDigestByte) {
+ String shaHex = Integer.toHexString(b & 0xFF);
+ if (shaHex.length() < 2) {
+ hexStr.append(0);
+ }
+ hexStr.append(shaHex);
+ }
+
+ return hexStr.toString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new Exception("不能生成签名");
+ }
+ }
+
+ private void verify(String msgSignature, String newMsgSignature) {
+ boolean res = msgSignature.equals(newMsgSignature);
+ System.out.println(res);
+ }
+
+ public static void main(String[] args) throws Exception {
+ ServerVerification test = new ServerVerification();
+ String msgSignature = "XXX";
+ String newMsgSignature = test.getMsgSignature("XXX", "XXX", "XXX", "XXX");
+ test.verify(msgSignature, newMsgSignature);
+ }
+}
diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/TtAuthController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/TtAuthController.java
new file mode 100644
index 0000000..6e7eef0
--- /dev/null
+++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/TtAuthController.java
@@ -0,0 +1,131 @@
+package com.iformall.controller;
+
+import com.iformall.common.ResultData;
+import com.iformall.domain.po.WxAuthorizerInfo;
+import com.iformall.domain.vo.WxWeappInfo;
+import com.iformall.enums.EnumAppPlat;
+import com.iformall.enums.EnumWxAuthorizationStatus;
+import com.iformall.service.WxAuthorizerInfoService;
+import com.iformall.service.toutiao.FmTtOpenService;
+import com.iformall.service.toutiao.api.bean.TtOpenAuthorizationInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Stormeye Wu
+ */
+@Controller
+@RequestMapping("/wt_auth")
+@Api(description = "微信第三方开放平台授权相关接口")
+public class TtAuthController {
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ @Autowired
+ protected FmTtOpenService openService;
+
+ @Autowired
+ private WxAuthorizerInfoService authorizerInfoService;
+
+ @ApiOperation(value = "获取授权跳转页", notes = "")
+ @GetMapping("/goto_auth_url_show")
+ @ResponseBody
+ public String gotoPreAuthUrlShow() {
+ return "" +
+ "" +
+ "go" +
+ "" +
+ "";
+ }
+
+ @ApiOperation(value = "授权跳转页", notes = "")
+ @GetMapping("/goto_auth_url")
+ public void gotoPreAuthUrl(HttpServletRequest request, HttpServletResponse response) {
+ String host = request.getHeader("host");
+ String url = "https://" + host + "/T/wt_auth/jump";
+ try {
+ url = openService.getTtOpenComponentService().getPreAuthUrl(url);
+ response.sendRedirect(url);
+ } catch (WxErrorException | IOException e) {
+ logger.error("gotoPreAuthUrl", e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ @ApiOperation(value = "授权", notes = "")
+ @GetMapping("/jump")
+ @ResponseBody
+ public void jump(@RequestParam("auth_code") String authorizationCode) {
+ try {
+ TtOpenAuthorizationInfo queryAuthResult = openService.getTtOpenComponentService().getQueryAuth(authorizationCode);
+ logger.info("getQueryAuth", queryAuthResult);
+// WxOpenAuthorizerInfoResult openAuthorizerInfoResult = openService.getTtOpenComponentService().getAuthorizerInfo(
+// queryAuthResult.getAuthorizerAppid());
+// logger.info(openAuthorizerInfoResult.toString());
+ // save auth info
+ authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo(){
+ {
+ setAuthorizerAppid(queryAuthResult.getAuthorizerAppid());
+ setRefreshToken(queryAuthResult.getAuthorizerRefreshToken());
+ setAccessToken(queryAuthResult.getAuthorizerAccessToken());
+ setAccessTokenExpire(new Date(Long.valueOf(System.currentTimeMillis() + queryAuthResult.getExpiresIn()*1000)));
+ setAuthorizationStatus(EnumWxAuthorizationStatus.AUTHORIZED.getCode());
+ setAuthTime(new Date());
+ }
+ });
+ } catch (WxErrorException e) {
+ logger.error("gotoPreAuthUrl", e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ @ApiOperation(value = "刷新", notes = "")
+ @GetMapping("/retrieve")
+ @ResponseBody
+ public ResultData retrieve() {
+
+ WxWeappInfo weappInfo = new WxWeappInfo();
+ weappInfo.setPlat(EnumAppPlat.TOUTIAO.getCode());
+ List list = authorizerInfoService.getList(weappInfo);
+ if(list != null && list.size() > 0){
+ for (WxWeappInfo info: list) {
+ try {
+ String code = openService.getTtOpenComponentService().retrieveCode(info.getAuthorizerAppid());
+
+ TtOpenAuthorizationInfo queryAuthResult = openService.getTtOpenComponentService().getQueryAuth(code);
+ logger.info("getQueryAuth", queryAuthResult);
+ // save auth info
+ authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo(){
+ {
+ setAuthorizerAppid(queryAuthResult.getAuthorizerAppid());
+ setRefreshToken(queryAuthResult.getAuthorizerRefreshToken());
+ setAccessToken(queryAuthResult.getAuthorizerAccessToken());
+ setAccessTokenExpire(new Date(Long.valueOf(System.currentTimeMillis() + queryAuthResult.getExpiresIn()*1000)));
+ setAuthorizationStatus(EnumWxAuthorizationStatus.AUTHORIZED.getCode());
+ setAuthTime(new Date());
+ }
+ });
+ } catch (WxErrorException e) {
+ logger.error(info.getAuthorizerAppid()+"找回授权码", e);
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ return new ResultData();
+ }
+
+}
diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/TtCalllbackController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/TtCalllbackController.java
new file mode 100644
index 0000000..2a86dc9
--- /dev/null
+++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/TtCalllbackController.java
@@ -0,0 +1,388 @@
+package com.iformall.controller;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.iformall.common.Result;
+import com.iformall.common.ResultData;
+import com.iformall.controller.base.BaseController;
+import com.iformall.domain.po.WxAuthorizerInfo;
+import com.iformall.domain.po.WxComponentVerifyTicket;
+import com.iformall.enums.EnumWxAuthorizationStatus;
+import com.iformall.service.WxAuthorizerInfoService;
+import com.iformall.service.WxComponentVerifyTicketService;
+import com.iformall.service.toutiao.FmTtOpenService;
+import com.iformall.service.toutiao.api.bean.TtOpenTicket;
+import com.iformall.utils.DateUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import me.chanjar.weixin.open.bean.WxOpenCreateResult;
+import me.chanjar.weixin.open.bean.WxOpenGetResult;
+import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage;
+import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult;
+import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerListResult;
+import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.util.Date;
+import java.util.Map;
+
+@Controller
+@RequestMapping("/ttOpen")
+@Api(description = "头条第三方开放平台回调相关接口")
+public class TtCalllbackController extends BaseController {
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Autowired
+ protected FmTtOpenService openService;
+
+ @Autowired
+ private WxComponentVerifyTicketService componentVerifyTicketService;
+
+ @Autowired
+ private WxAuthorizerInfoService authorizerInfoService;
+
+ @PostMapping(value = "/notify")
+ @ApiOperation("接收ticket回调")
+ @ResponseBody
+ public String receiveTicket(HttpServletRequest request) throws IOException {
+ logger.info("[" + getIpAddr() + "]接收微信回调 /ttOpen/notify");
+
+ String nonce = request.getParameter("Nonce");
+ String timestamp = request.getParameter("TimeStamp");
+// String signature = request.getParameter("signature");
+ String encrypt = request.getParameter("Encrypt");
+ String msgSignature = request.getParameter("MsgSignature");
+
+ if (!openService.getTtOpenComponentService().checkSignature(timestamp, nonce, encrypt, msgSignature)) {
+ throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
+ }
+ // aes加密的消息, 解密
+ TtOpenTicket openTicket = openService.getTtOpenComponentService().decrypt(encrypt);
+ // 处理
+ handleTicket(openTicket);
+ return "success";
+ }
+
+ /**
+ * 处理ticket消息
+ * @param
+ * @return
+ */
+ private void handleTicket(TtOpenTicket ticket) {
+ try {
+ String out = openService.getTtOpenComponentService().route(ticket);
+ this.logger.info("组装回复信息:{}", out);
+ } catch (WxErrorException e) {
+ this.logger.error("notify", e);
+ }
+ if (StringUtils.equalsIgnoreCase(ticket.getMsgType(), "Ticket")) {
+ // 保存component_verify_ticket
+ componentVerifyTicketService.saveOrUpdate(new WxComponentVerifyTicket() {
+ {
+ setComponentVerifyTicket(ticket.getTicket());
+ setCreateTime(DateUtils.stringToDate(ticket.getCreateTime(),"yyyy-MM-dd HH:mm:ss"));
+ setComponentAppid(ticket.getComponentAppId());
+ setDeadline(new Date(Long.valueOf(System.currentTimeMillis() + (60 * 60 * 1000))));
+ }
+ });
+ }
+ }
+
+// /**
+// * 处理小程序审核消息
+// * @param inMessage
+// * @return
+// */
+// private boolean handleWeappAuditedMessage(WxOpenXmlMessage inMessage) {
+// // 审核通过
+// try {
+// WxOpenQueryAuthResult queryAuthResult = openService.getWxOpenComponentService().getQueryAuth(inMessage.getAuthorizationCode());
+// logger.info("getQueryAuth", queryAuthResult);
+//
+// WxOpenAuthorizerInfoResult openAuthorizerInfoResult = openService.getWxOpenComponentService().getAuthorizerInfo(
+// queryAuthResult.getAuthorizationInfo().getAuthorizerAppid());
+// logger.info(openAuthorizerInfoResult.toString());
+// // save auth info
+// authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo() {
+// {
+// setAuthorizerAppid(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerAppid());
+// setAlias(openAuthorizerInfoResult.getAuthorizerInfo().getAlias());
+// setHeadImg(openAuthorizerInfoResult.getAuthorizerInfo().getHeadImg());
+// setQrcodeUrl(openAuthorizerInfoResult.getAuthorizerInfo().getQrcodeUrl());
+// setRefreshToken(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerRefreshToken());
+// setAccessToken(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerAccessToken());
+// setAccessTokenExpire(new Date(Long.valueOf(System.currentTimeMillis() + openAuthorizerInfoResult.getAuthorizationInfo().getExpiresIn()*1000)));
+// setAuthorizationStatus(EnumWxAuthorizationStatus.AUTHORIZED.getCode());
+// setAuthTime(new Date());
+// }
+// });
+// return true;
+// } catch (WxErrorException e) {
+// logger.error(e.getMessage());
+// }
+// return false;
+// }
+
+ @RequestMapping(value = "/{appId}/callback")
+ @ApiOperation("消息回调")
+ public void callback(@PathVariable("appId") String appId, HttpServletRequest request, HttpServletResponse response) throws IOException {
+ logger.info("[" + getIpAddr() + "]接收微信APP回调 /{appId}/callback");
+ String timestamp = request.getParameter("timestamp");
+ String nonce = request.getParameter("nonce");
+ String signature = request.getParameter("signature");
+ String encType = request.getParameter("encrypt_type");
+ String openid = request.getParameter("openid");
+ String msgSignature = request.getParameter("msg_signature");
+
+ // 第三方平台一定接收的是加密的消息
+ if (!StringUtils.equalsIgnoreCase("aes", encType)
+ || !openService.getTtOpenComponentService().checkSignature(timestamp, nonce,encType, signature)) {
+ throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
+ }
+
+// String resultxml = getRequestXML(request);
+
+// logger.info("接收微信APP回调:[appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}],"
+// + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
+// appId, openid, signature, encType, msgSignature, timestamp, nonce, resultxml);
+
+
+// String out = "";
+// // aes加密的消息, 解密
+// WxMpXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedMpXml(resultxml,
+// openService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
+// logger.info("接收微信APP回调,消息解密后内容为:\n{}", inMessage.toString());
+
+
+
+// // 实际 消息 处理
+// //handleCallbackMessage(appId, response, inMessage);
+// WxMpXmlOutMessage outMessage = openService.getWxOpenMessageRouter().route(inMessage, appId);
+// if(outMessage == null) {
+// PrintWriter printWriter = response.getWriter();
+// wechatWriteSuccess(printWriter);
+// }
+ PrintWriter printWriter = response.getWriter();
+ wechatWriteSuccess(printWriter);
+ }
+
+ private void wechatWriteSuccess(PrintWriter printWriter) {
+ printWriter.print("success");
+ printWriter.flush();
+ printWriter.close();
+ }
+
+// /**
+// * 测试账号特殊处理
+// * @param appId
+// * @param response
+// * @param inMessage
+// * @throws IOException
+// */
+// private void handleWechatTest(@PathVariable("appId") String appId, HttpServletResponse response, WxMpXmlMessage inMessage) throws IOException {
+// String out;
+// try {
+// if (StringUtils.equals(inMessage.getMsgType(), "text")) {
+// if (StringUtils.equals(inMessage.getContent(), "TESTCOMPONENT_MSG_TYPE_TEXT")) {
+// out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(
+// WxMpXmlOutMessage.TEXT().content("TESTCOMPONENT_MSG_TYPE_TEXT_callback")
+// .fromUser(inMessage.getToUser())
+// .toUser(inMessage.getFromUser())
+// .build(),
+// openService.getWxOpenConfigStorage()
+// );
+// } else if (StringUtils.startsWith(inMessage.getContent(), "QUERY_AUTH_CODE:")) {
+// String msg = inMessage.getContent().replace("QUERY_AUTH_CODE:", "") + "_from_api";
+// WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(msg).toUser(inMessage.getFromUser()).build();
+// openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
+// }
+// } else if (StringUtils.equals(inMessage.getMsgType(), "event")) {
+// WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(inMessage.getEvent() + "from_callback").toUser(inMessage.getFromUser()).build();
+// openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
+// }
+// } catch (WxErrorException e) {
+// logger.error("callback", e);
+// }
+// }
+//
+// private String getRequestXML(HttpServletRequest request) throws IOException {
+// InputStream inStream = request.getInputStream();
+// ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
+// byte[] buffer = new byte[1024];
+// int len = 0;
+// while ((len = inStream.read(buffer)) != -1) {
+// outSteam.write(buffer, 0, len);
+// }
+// String resultxml = new String(outSteam.toByteArray(), Charset.forName("UTF-8"));
+// logger.info(resultxml);
+//
+// outSteam.close();
+// inStream.close();
+// return resultxml;
+// }
+//
+// private void getThreadCount( int i) {
+// ThreadGroup group = Thread.currentThread().getThreadGroup();
+// ThreadGroup topGroup = group;
+// // 遍历线程组树,获取根线程组
+// while (group != null) {
+// topGroup = group;
+// group = group.getParent();
+// }
+// // 激活的线程数加倍
+// int activeCount = topGroup.activeCount();
+// // copy into a list that is the exact size
+// logger.info("Thread list size == " + i + " : " + activeCount);
+//
+// }
+//
+//
+// @GetMapping(value = "/createOpenPlatform")
+// @ApiOperation("创建微信开放平台")
+// public ResultData createOpenPlatform(@RequestParam(value = "appId") String appId) {
+// Gson gson = new GsonBuilder().create();
+// try {
+// WxOpenCreateResult ret = openService.getWxOpenComponentService().createOpenAccount(appId);
+// logger.info(ret.toString());
+// if (ret.isSuccess()) {
+// WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId);
+// if (authorizerInfo != null) {
+// authorizerInfo.setId(authorizerInfo.getId());
+// authorizerInfo.setOpenAppid(ret.getOpenAppid());
+// authorizerInfoService.updateOpenAppid(authorizerInfo);
+// }
+// }
+// return new ResultData(ret.toString());
+// } catch (WxErrorException e) {
+// logger.error(e.getMessage());
+// return new ResultData(Result.ERROR, e.getMessage());
+// }
+// }
+//
+// @GetMapping(value = "/bindOpenPlatform")
+// @ApiOperation("绑定微信开放平台")
+// public ResultData bindOpenPlatform(@RequestParam(value = "appId") String appId, @RequestParam(value = "openAppId") String openAppId) {
+// Gson gson = new GsonBuilder().create();
+// try {
+// Boolean ret = openService.getWxOpenComponentService().bindOpenAccount(appId, openAppId);
+// if (ret) {
+// WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId);
+// if (authorizerInfo != null) {
+// authorizerInfo.setId(authorizerInfo.getId());
+// authorizerInfo.setOpenAppid(openAppId);
+// authorizerInfoService.updateOpenAppid(authorizerInfo);
+// }
+// return new ResultData();
+// }
+// return new ResultData(Result.ERROR, ret.toString());
+// } catch (WxErrorException e) {
+// logger.error(e.getMessage());
+// return new ResultData(Result.ERROR, e.getMessage());
+// }
+// }
+//
+// @GetMapping(value = "/unbindOpenPlatform")
+// @ApiOperation("解绑微信开放平台")
+// public ResultData unbindOpenPlatform(@RequestParam(value = "appId") String appId, @RequestParam(value = "openAppId") String openAppId) {
+// Gson gson = new GsonBuilder().create();
+// try {
+// Boolean ret = openService.getWxOpenComponentService().unbindOpenAccount(appId, openAppId);
+// if (ret) {
+// WxAuthorizerInfo authorizerInfo = new WxAuthorizerInfo();
+// authorizerInfo.setAuthorizerAppid(appId);
+// authorizerInfoService.removeOpenAppid(authorizerInfo);
+// return new ResultData();
+// }
+// return new ResultData(Result.ERROR, ret.toString());
+// } catch (WxErrorException e) {
+// logger.error(e.getMessage());
+// return new ResultData(Result.ERROR, e.getMessage());
+// }
+// }
+//
+// @GetMapping(value = "/getOpenPlatform")
+// @ApiOperation("获取微信开放平台appId")
+// public ResultData getOpenPlatform(@RequestParam(value = "appId") String appId) {
+// Gson gson = new GsonBuilder().create();
+// try {
+// WxOpenGetResult ret = openService.getWxOpenComponentService().getOpenAccount(appId);
+// logger.info(ret.toString());
+// if (ret.isSuccess()) {
+// WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId);
+// if (authorizerInfo != null) {
+// if(StringUtils.isBlank(authorizerInfo.getOpenAppid()) && StringUtils.isNotBlank(ret.getOpenAppid())) {
+// authorizerInfo.setId(authorizerInfo.getId());
+// authorizerInfo.setOpenAppid(ret.getOpenAppid());
+// authorizerInfoService.updateOpenAppid(authorizerInfo);
+// }
+// }
+// return new ResultData(ret.getOpenAppid());
+// }
+// return new ResultData(Result.ERROR, ret.toString());
+// } catch (WxErrorException e) {
+// logger.error(e.getMessage());
+// return new ResultData(Result.ERROR, e.getMessage());
+// }
+// }
+//
+// @GetMapping(value = "/clearQuota")
+// @ApiOperation("代公众号清零quota,每个公众号每个月有10次清零机会,包括在微信公众平台上的清零以及调用API进行清零")
+// public ResultData clearQuota(@RequestParam(value = "appId") String appId) {
+// try {
+// openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).clearQuota(appId);
+// return new ResultData();
+// } catch (WxErrorException e) {
+// logger.error(e.getMessage());
+// return new ResultData(Result.ERROR, e.getMessage());
+// }
+// }
+//
+// @GetMapping(value = "/getAuthorizerList")
+// @ApiOperation("拉取当前所有已授权的帐号基本信息")
+// public ResultData getAuthorizerList() {
+// try {
+// WxOpenAuthorizerListResult authorizerListResult = openService.getWxOpenComponentService().getAuthorizerList(0, 100);
+// logger.info("getAuthorizerList: " + authorizerListResult);
+// if(authorizerListResult.getTotalCount() > 0) {
+// for (Map data : authorizerListResult.getList()) {
+// String appId = data.get("authorizer_appid");
+// String refreshToken = data.get("refresh_token");
+// Long authTime = Long.valueOf(data.get("auth_time"));
+// Date authDate = new Date(authTime*1000);
+//
+// if(StringUtils.isBlank(refreshToken)) {
+// continue;
+// }
+//
+// WxAuthorizerInfo authorizerInfo = new WxAuthorizerInfo();
+// authorizerInfo.setAuthorizerAppid(appId);
+// authorizerInfo.setRefreshToken(refreshToken);
+// authorizerInfo.setAuthTime(authDate);
+// authorizerInfoService.updateAuthAppidInfo(authorizerInfo);
+//
+// openService.getWxOpenComponentService().getWxOpenConfigStorage().setAuthorizerRefreshToken(appId, refreshToken);
+// }
+// }
+// return new ResultData(authorizerListResult.toString());
+// } catch (WxErrorException e) {
+// logger.error(e.getMessage());
+// return new ResultData(Result.ERROR, e.getMessage());
+// }
+// }
+}
diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatAuthController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatAuthController.java
deleted file mode 100644
index e3da84e..0000000
--- a/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatAuthController.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package com.iformall.controller;
-
-import com.iformall.domain.po.WxAuthorizerInfo;
-import com.iformall.enums.EnumWxAuthorizationStatus;
-import com.iformall.service.WxAuthorizerInfoService;
-import com.iformall.service.wechat.FmOpenService;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult;
-import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.*;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.util.Date;
-
-/**
- * Stormeye Wu
- */
-@Controller
-@RequestMapping("/wt_auth")
-@Api(description = "微信第三方开放平台授权相关接口")
-public class WechatAuthController {
- private final Logger logger = LoggerFactory.getLogger(getClass());
- @Autowired
- private FmOpenService openService;
-
- @Autowired
- private WxAuthorizerInfoService authorizerInfoService;
-
- @ApiOperation(value = "获取授权跳转页", notes = "")
- @GetMapping("/goto_auth_url_show")
- @ResponseBody
- public String gotoPreAuthUrlShow() {
- return "" +
- "" +
- "go" +
- "" +
- "";
- }
-
- @ApiOperation(value = "授权跳转页", notes = "")
- @GetMapping("/goto_auth_url")
- public void gotoPreAuthUrl(HttpServletRequest request, HttpServletResponse response) {
- String host = request.getHeader("host");
- String url = "https://" + host + "/O/wt_auth/jump";
- try {
- url = openService.getWxOpenComponentService().getPreAuthUrl(url);
- response.sendRedirect(url);
- } catch (WxErrorException | IOException e) {
- logger.error("gotoPreAuthUrl", e);
- throw new RuntimeException(e);
- }
- }
-
- @ApiOperation(value = "授权", notes = "")
- @GetMapping("/jump")
- @ResponseBody
- public void jump(@RequestParam("auth_code") String authorizationCode) {
- try {
- WxOpenQueryAuthResult queryAuthResult = openService.getWxOpenComponentService().getQueryAuth(authorizationCode);
- logger.info("getQueryAuth", queryAuthResult);
- WxOpenAuthorizerInfoResult openAuthorizerInfoResult = openService.getWxOpenComponentService().getAuthorizerInfo(
- queryAuthResult.getAuthorizationInfo().getAuthorizerAppid());
- logger.info(openAuthorizerInfoResult.toString());
- // save auth info
- authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo(){
- {
- setAuthorizerAppid(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerAppid());
- setAlias(openAuthorizerInfoResult.getAuthorizerInfo().getAlias());
- setHeadImg(openAuthorizerInfoResult.getAuthorizerInfo().getHeadImg());
- setQrcodeUrl(openAuthorizerInfoResult.getAuthorizerInfo().getQrcodeUrl());
- setRefreshToken(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerRefreshToken());
- setAccessToken(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerAccessToken());
- setAccessTokenExpire(new Date(Long.valueOf(System.currentTimeMillis() + openAuthorizerInfoResult.getAuthorizationInfo().getExpiresIn()*1000)));
- setAuthorizationStatus(EnumWxAuthorizationStatus.AUTHORIZED.getCode());
- setAuthTime(new Date());
- }
- });
- } catch (WxErrorException e) {
- logger.error("gotoPreAuthUrl", e);
- throw new RuntimeException(e);
- }
- }
-
- @ApiOperation(value = "手机跳转链接url", notes = "")
- @GetMapping("/getMobilePreAuthUrl")
- @ResponseBody
- public String getMobilePreAuthUrl(HttpServletRequest request, HttpServletResponse response) {
- String host = request.getHeader("host");
- String url = "https://" + host + "/O/wt_auth/jump";
- try {
- url = openService.getWxOpenComponentService().getMobilePreAuthUrl(url);
- return url;
- } catch (WxErrorException e) {
- logger.error("getMobilePreAuthUrl", e);
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatCalllbackController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatCalllbackController.java
deleted file mode 100644
index 484e14c..0000000
--- a/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatCalllbackController.java
+++ /dev/null
@@ -1,415 +0,0 @@
-package com.iformall.controller;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.iformall.common.Result;
-import com.iformall.common.ResultData;
-import com.iformall.controller.base.BaseController;
-import com.iformall.domain.po.*;
-import com.iformall.enums.*;
-import com.iformall.service.*;
-import com.iformall.service.wechat.FmOpenService;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
-import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
-import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
-import me.chanjar.weixin.open.bean.WxOpenCreateResult;
-import me.chanjar.weixin.open.bean.WxOpenGetResult;
-import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage;
-import me.chanjar.weixin.open.bean.result.*;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.*;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.nio.charset.Charset;
-import java.util.Date;
-import java.util.Map;
-
-@Controller
-@RequestMapping("/wxOpen")
-@Api(description = "微信第三方开放平台回调相关接口")
-public class WechatCalllbackController extends BaseController {
- private final Logger logger = LoggerFactory.getLogger(this.getClass());
-
- @Autowired
- protected FmOpenService openService;
-
- @Autowired
- private WxComponentVerifyTicketService componentVerifyTicketService;
-
- @Autowired
- private WxAuthorizerInfoService authorizerInfoService;
-
- @PostMapping(value = "/notify")
- @ApiOperation("接收ticket回调")
- @ResponseBody
- public String receiveTicket(HttpServletRequest request) throws IOException {
- logger.info("[" + getIpAddr() + "]接收微信回调 /wxOpen/notify");
-
- String timestamp = request.getParameter("timestamp");
- String nonce = request.getParameter("nonce");
- String signature = request.getParameter("signature");
- String encType = request.getParameter("encrypt_type");
- String msgSignature = request.getParameter("msg_signature");
-
- if (!StringUtils.equalsIgnoreCase("aes", encType)
- || !openService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
- throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
- }
-
- String resultxml = getRequestXML(request);
-
- logger.info("\n接收微信回调:[signature=[{}], encType=[{}], msgSignature=[{}],"
- + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
- signature, encType, msgSignature, timestamp, nonce, resultxml);
-
- // aes加密的消息, 解密
- WxOpenXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedXml(resultxml,
- openService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
- this.logger.info("接收微信回调,消息解密后内容为:{} ", inMessage.toString());
-
- // 处理
- handleTicket(inMessage);
- return "success";
- }
-
- /**
- * 处理ticket消息
- * @param inMessage
- * @return
- */
- private void handleTicket(WxOpenXmlMessage inMessage) {
- try {
- String out = openService.getWxOpenComponentService().route(inMessage);
- this.logger.info("组装回复信息:{}", out);
- } catch (WxErrorException e) {
- this.logger.error("notify", e);
- }
- if (inMessage.getInfoType().equalsIgnoreCase(EnumWxAuthorizationInfoType.COMPONENT_VERIFY_TICKET.getMessage())) {
- // 保存component_verify_ticket
- componentVerifyTicketService.saveOrUpdate(new WxComponentVerifyTicket() {
- {
- setComponentVerifyTicket(inMessage.getComponentVerifyTicket());
- setCreateTime(new Date(Long.valueOf(inMessage.getCreateTime() * 1000)));
- setComponentAppid(inMessage.getAppId());
- setDeadline(new Date(Long.valueOf(System.currentTimeMillis() + (60 * 60 * 1000))));
- }
- });
- } else if (inMessage.getInfoType().equalsIgnoreCase(EnumWxAuthorizationInfoType.AUTHORIZED.getMessage()) ||
- inMessage.getInfoType().equalsIgnoreCase(EnumWxAuthorizationInfoType.UPDATEAUTHORIZED.getMessage())) {
- // 审核通过
- handleWeappAuditedMessage(inMessage);
- } else if (inMessage.getInfoType().equals(EnumWxAuthorizationInfoType.UNAUTHORIZED.getMessage())) {
- // 授权取消
- authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo() {
- {
- setAuthorizerAppid(inMessage.getAuthorizerAppid());
- setAuthorizationStatus(EnumWxAuthorizationStatus.UNAUTHORIZED.getCode());
- setAuthTime(new Date());
- }
- });
- }
- }
-
- /**
- * 处理小程序审核消息
- * @param inMessage
- * @return
- */
- private boolean handleWeappAuditedMessage(WxOpenXmlMessage inMessage) {
- // 审核通过
- try {
- WxOpenQueryAuthResult queryAuthResult = openService.getWxOpenComponentService().getQueryAuth(inMessage.getAuthorizationCode());
- logger.info("getQueryAuth", queryAuthResult);
-
- WxOpenAuthorizerInfoResult openAuthorizerInfoResult = openService.getWxOpenComponentService().getAuthorizerInfo(
- queryAuthResult.getAuthorizationInfo().getAuthorizerAppid());
- logger.info(openAuthorizerInfoResult.toString());
- // save auth info
- authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo() {
- {
- setAuthorizerAppid(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerAppid());
- setAlias(openAuthorizerInfoResult.getAuthorizerInfo().getAlias());
- setHeadImg(openAuthorizerInfoResult.getAuthorizerInfo().getHeadImg());
- setQrcodeUrl(openAuthorizerInfoResult.getAuthorizerInfo().getQrcodeUrl());
- setRefreshToken(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerRefreshToken());
- setAccessToken(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerAccessToken());
- setAccessTokenExpire(new Date(Long.valueOf(System.currentTimeMillis() + openAuthorizerInfoResult.getAuthorizationInfo().getExpiresIn()*1000)));
- setAuthorizationStatus(EnumWxAuthorizationStatus.AUTHORIZED.getCode());
- setAuthTime(new Date());
- }
- });
- return true;
- } catch (WxErrorException e) {
- logger.error(e.getMessage());
- }
- return false;
- }
-
- @RequestMapping(value = "/{appId}/callback")
- @ApiOperation("消息回调")
- public void callback(@PathVariable("appId") String appId, HttpServletRequest request, HttpServletResponse response) throws IOException {
- logger.info("[" + getIpAddr() + "]接收微信APP回调 /{appId}/callback");
- String timestamp = request.getParameter("timestamp");
- String nonce = request.getParameter("nonce");
- String signature = request.getParameter("signature");
- String encType = request.getParameter("encrypt_type");
- String openid = request.getParameter("openid");
- String msgSignature = request.getParameter("msg_signature");
-
- // 第三方平台一定接收的是加密的消息
- if (!StringUtils.equalsIgnoreCase("aes", encType)
- || !openService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
- throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
- }
-
- String resultxml = getRequestXML(request);
-
- logger.info("接收微信APP回调:[appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}],"
- + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
- appId, openid, signature, encType, msgSignature, timestamp, nonce, resultxml);
-
-
- String out = "";
- // aes加密的消息, 解密
- WxMpXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedMpXml(resultxml,
- openService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
- logger.info("接收微信APP回调,消息解密后内容为:\n{}", inMessage.toString());
-
- // 全网发布测试用例
- if (StringUtils.equalsAnyIgnoreCase(appId, "wx570bc396a51b8ff8", "wxd101a85aa106f53e")) {
- handleWechatTest(appId, response, inMessage);
- PrintWriter printWriter = response.getWriter();
- wechatWriteSuccess(printWriter);
- return;
- }
-
- // 实际 消息 处理
- //handleCallbackMessage(appId, response, inMessage);
- WxMpXmlOutMessage outMessage = openService.getWxOpenMessageRouter().route(inMessage, appId);
- if(outMessage == null) {
- PrintWriter printWriter = response.getWriter();
- wechatWriteSuccess(printWriter);
- }
- PrintWriter printWriter = response.getWriter();
- wechatWriteSuccess(printWriter);
- }
-
- private void wechatWriteSuccess(PrintWriter printWriter) {
- printWriter.print("success");
- printWriter.flush();
- printWriter.close();
- }
-
- /**
- * 测试账号特殊处理
- * @param appId
- * @param response
- * @param inMessage
- * @throws IOException
- */
- private void handleWechatTest(@PathVariable("appId") String appId, HttpServletResponse response, WxMpXmlMessage inMessage) throws IOException {
- String out;
- try {
- if (StringUtils.equals(inMessage.getMsgType(), "text")) {
- if (StringUtils.equals(inMessage.getContent(), "TESTCOMPONENT_MSG_TYPE_TEXT")) {
- out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(
- WxMpXmlOutMessage.TEXT().content("TESTCOMPONENT_MSG_TYPE_TEXT_callback")
- .fromUser(inMessage.getToUser())
- .toUser(inMessage.getFromUser())
- .build(),
- openService.getWxOpenConfigStorage()
- );
- } else if (StringUtils.startsWith(inMessage.getContent(), "QUERY_AUTH_CODE:")) {
- String msg = inMessage.getContent().replace("QUERY_AUTH_CODE:", "") + "_from_api";
- WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(msg).toUser(inMessage.getFromUser()).build();
- openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
- }
- } else if (StringUtils.equals(inMessage.getMsgType(), "event")) {
- WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(inMessage.getEvent() + "from_callback").toUser(inMessage.getFromUser()).build();
- openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
- }
- } catch (WxErrorException e) {
- logger.error("callback", e);
- }
- }
-
- private String getRequestXML(HttpServletRequest request) throws IOException {
- InputStream inStream = request.getInputStream();
- ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
- byte[] buffer = new byte[1024];
- int len = 0;
- while ((len = inStream.read(buffer)) != -1) {
- outSteam.write(buffer, 0, len);
- }
- String resultxml = new String(outSteam.toByteArray(), Charset.forName("UTF-8"));
- logger.info(resultxml);
-
- outSteam.close();
- inStream.close();
- return resultxml;
- }
-
- private void getThreadCount( int i) {
- ThreadGroup group = Thread.currentThread().getThreadGroup();
- ThreadGroup topGroup = group;
- // 遍历线程组树,获取根线程组
- while (group != null) {
- topGroup = group;
- group = group.getParent();
- }
- // 激活的线程数加倍
- int activeCount = topGroup.activeCount();
- // copy into a list that is the exact size
- logger.info("Thread list size == " + i + " : " + activeCount);
-
- }
-
-
- @GetMapping(value = "/createOpenPlatform")
- @ApiOperation("创建微信开放平台")
- public ResultData createOpenPlatform(@RequestParam(value = "appId") String appId) {
- Gson gson = new GsonBuilder().create();
- try {
- WxOpenCreateResult ret = openService.getWxOpenComponentService().createOpenAccount(appId);
- logger.info(ret.toString());
- if (ret.isSuccess()) {
- WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId);
- if (authorizerInfo != null) {
- authorizerInfo.setId(authorizerInfo.getId());
- authorizerInfo.setOpenAppid(ret.getOpenAppid());
- authorizerInfoService.updateOpenAppid(authorizerInfo);
- }
- }
- return new ResultData(ret.toString());
- } catch (WxErrorException e) {
- logger.error(e.getMessage());
- return new ResultData(Result.ERROR, e.getMessage());
- }
- }
-
- @GetMapping(value = "/bindOpenPlatform")
- @ApiOperation("绑定微信开放平台")
- public ResultData bindOpenPlatform(@RequestParam(value = "appId") String appId, @RequestParam(value = "openAppId") String openAppId) {
- Gson gson = new GsonBuilder().create();
- try {
- Boolean ret = openService.getWxOpenComponentService().bindOpenAccount(appId, openAppId);
- if (ret) {
- WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId);
- if (authorizerInfo != null) {
- authorizerInfo.setId(authorizerInfo.getId());
- authorizerInfo.setOpenAppid(openAppId);
- authorizerInfoService.updateOpenAppid(authorizerInfo);
- }
- return new ResultData();
- }
- return new ResultData(Result.ERROR, ret.toString());
- } catch (WxErrorException e) {
- logger.error(e.getMessage());
- return new ResultData(Result.ERROR, e.getMessage());
- }
- }
-
- @GetMapping(value = "/unbindOpenPlatform")
- @ApiOperation("解绑微信开放平台")
- public ResultData unbindOpenPlatform(@RequestParam(value = "appId") String appId, @RequestParam(value = "openAppId") String openAppId) {
- Gson gson = new GsonBuilder().create();
- try {
- Boolean ret = openService.getWxOpenComponentService().unbindOpenAccount(appId, openAppId);
- if (ret) {
- WxAuthorizerInfo authorizerInfo = new WxAuthorizerInfo();
- authorizerInfo.setAuthorizerAppid(appId);
- authorizerInfoService.removeOpenAppid(authorizerInfo);
- return new ResultData();
- }
- return new ResultData(Result.ERROR, ret.toString());
- } catch (WxErrorException e) {
- logger.error(e.getMessage());
- return new ResultData(Result.ERROR, e.getMessage());
- }
- }
-
- @GetMapping(value = "/getOpenPlatform")
- @ApiOperation("获取微信开放平台appId")
- public ResultData getOpenPlatform(@RequestParam(value = "appId") String appId) {
- Gson gson = new GsonBuilder().create();
- try {
- WxOpenGetResult ret = openService.getWxOpenComponentService().getOpenAccount(appId);
- logger.info(ret.toString());
- if (ret.isSuccess()) {
- WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId);
- if (authorizerInfo != null) {
- if(StringUtils.isBlank(authorizerInfo.getOpenAppid()) && StringUtils.isNotBlank(ret.getOpenAppid())) {
- authorizerInfo.setId(authorizerInfo.getId());
- authorizerInfo.setOpenAppid(ret.getOpenAppid());
- authorizerInfoService.updateOpenAppid(authorizerInfo);
- }
- }
- return new ResultData(ret.getOpenAppid());
- }
- return new ResultData(Result.ERROR, ret.toString());
- } catch (WxErrorException e) {
- logger.error(e.getMessage());
- return new ResultData(Result.ERROR, e.getMessage());
- }
- }
-
- @GetMapping(value = "/clearQuota")
- @ApiOperation("代公众号清零quota,每个公众号每个月有10次清零机会,包括在微信公众平台上的清零以及调用API进行清零")
- public ResultData clearQuota(@RequestParam(value = "appId") String appId) {
- try {
- openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).clearQuota(appId);
- return new ResultData();
- } catch (WxErrorException e) {
- logger.error(e.getMessage());
- return new ResultData(Result.ERROR, e.getMessage());
- }
- }
-
- @GetMapping(value = "/getAuthorizerList")
- @ApiOperation("拉取当前所有已授权的帐号基本信息")
- public ResultData getAuthorizerList() {
- try {
- WxOpenAuthorizerListResult authorizerListResult = openService.getWxOpenComponentService().getAuthorizerList(0, 100);
- logger.info("getAuthorizerList: " + authorizerListResult);
- if(authorizerListResult.getTotalCount() > 0) {
- for (Map data : authorizerListResult.getList()) {
- String appId = data.get("authorizer_appid");
- String refreshToken = data.get("refresh_token");
- Long authTime = Long.valueOf(data.get("auth_time"));
- Date authDate = new Date(authTime*1000);
-
- if(StringUtils.isBlank(refreshToken)) {
- continue;
- }
-
- WxAuthorizerInfo authorizerInfo = new WxAuthorizerInfo();
- authorizerInfo.setAuthorizerAppid(appId);
- authorizerInfo.setRefreshToken(refreshToken);
- authorizerInfo.setAuthTime(authDate);
- authorizerInfoService.updateAuthAppidInfo(authorizerInfo);
-
- openService.getWxOpenComponentService().getWxOpenConfigStorage().setAuthorizerRefreshToken(appId, refreshToken);
- }
- }
- return new ResultData(authorizerListResult.toString());
- } catch (WxErrorException e) {
- logger.error(e.getMessage());
- return new ResultData(Result.ERROR, e.getMessage());
- }
- }
-}
diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/WxWeappInfoController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/WxWeappInfoController.java
index 1bd88f8..73df4af 100644
--- a/mlToutiaoOpen/src/main/java/com/iformall/controller/WxWeappInfoController.java
+++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/WxWeappInfoController.java
@@ -98,6 +98,7 @@ public class WxWeappInfoController extends BaseController {
weappInfo.setName(null);
}
}
+ weappInfo.setPlat(EnumAppPlat.TOUTIAO.getCode());
weappInfo.setSortColumns(BaseEntity.SortField.TenantId_ASC,BaseEntity.SortField.Type_ASC,BaseEntity.SortField.Name_ASC);
final PageInfo page = authorizerInfoService.listVoAsPage(weappInfo, pageNum, pageSize);
return new ResultData(page);
diff --git a/mlToutiaoOpen/src/main/resources/application-dev.yml b/mlToutiaoOpen/src/main/resources/application-dev.yml
index 79628f4..95e7ceb 100644
--- a/mlToutiaoOpen/src/main/resources/application-dev.yml
+++ b/mlToutiaoOpen/src/main/resources/application-dev.yml
@@ -82,15 +82,11 @@ aws:
# min-idle: 10
wechat:
- web:
- appId: "wx091907dd0bfd3f6b"
- secret: "2a2ca10738998b9ef92c1fe8a4d366a6"
- url: "https://admintest.malls.iformall.com"
open:
- componentAppId: wxdfc8fb4e62d6b52b
- componentSecret: 98daa62b316dd6feabaad708327ce233
- componentToken: formall2018
- componentAesKey: htKq8EjBMPNndfZQK9JiFojFaqFwFpw42VfeWFtx7HN
+ componentAppId: tt146862d58b42b88c
+ componentSecret: d681a8873b81276dc93fd499bbf0bcbafb82b31c
+ componentToken: iformallDouyinAuthorizeToken
+ componentAesKey: iformallDouyinEntryKey202204082101028888888
redis:
host: 101.200.130.134
port: 6379
diff --git a/mlToutiaoOpen/src/main/resources/application-prod.yml b/mlToutiaoOpen/src/main/resources/application-prod.yml
index b0ff82e..569f536 100644
--- a/mlToutiaoOpen/src/main/resources/application-prod.yml
+++ b/mlToutiaoOpen/src/main/resources/application-prod.yml
@@ -77,10 +77,10 @@ aws:
wechat:
open:
- componentAppId: ENC(b3JG0MUZgQfz5Zj+DC2ZM1zDeLOiGTmmeokfe2O8kaM=)
- componentSecret: ENC(QVyc4BPGdnSjXGs2ivgpDBE1v8wPWHLLRMYI7Vv8uYwC0SiZHQz0QpyyQV/b48Pb)
- componentToken: ENC(rkxj0733WxFFDLgA9x01m2s5Fi2L+0PC)
- componentAesKey: ENC(EIbJUBpbYOrLb4YQ/HXLQmxlxgAqIp2ZmpnGICC8pu5xiTz3Cqfkbwd2S8raCcK/IvYcX2GmedI=)
+ componentAppId: tt146862d58b42b88c
+ componentSecret: d681a8873b81276dc93fd499bbf0bcbafb82b31c
+ componentToken: iformallDouyinAuthorizeToken
+ componentAesKey: iformallDouyinEntryKey202204082101028888888
redis:
host: r-2zeaglwf13qqmnllj5.redis.rds.aliyuncs.com
port: 6379