Merge remote-tracking branch 'wechat/develop' into develop

# Conflicts:
#	weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ApplymentsRequest.java
#	weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ApplymentsResult.java
#	weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ApplymentsStatusResult.java
#	weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EcommerceService.java
#	weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java
This commit is contained in:
曾浩 2020-08-24 13:43:47 +08:00
commit cee37531c7
86 changed files with 2462 additions and 2846 deletions

View File

@ -1,4 +1,4 @@
## WxJava - 微信开发 Java SDK开发工具包 [![LICENSE](https://img.shields.io/badge/License-Anti%20996-blue.svg)](https://github.com/996icu/996.ICU/blob/master/LICENSE) [![Badge](https://img.shields.io/badge/Link-996.icu-red.svg)](https://996.icu/#/zh_CN) [![Badge](https://img.shields.io/badge/Link-专属福利-red.svg)](https://mp.weixin.qq.com/s/dfwatgMgARaBjh421Todyg)
## WxJava - 微信开发 Java SDK开发工具包 [![LICENSE](https://img.shields.io/badge/License-Anti%20996-blue.svg)](https://github.com/996icu/996.ICU/blob/master/LICENSE) [![Badge](https://img.shields.io/badge/Link-996.icu-red.svg)](https://996.icu/#/zh_CN)
[![码云Gitee](https://gitee.com/binary/weixin-java-tools/badge/star.svg?theme=blue)](https://gitee.com/binary/weixin-java-tools)
[![Github](http://github-svg-buttons.herokuapp.com/star.svg?user=Wechat-Group&repo=WxJava&style=flat&background=1081C1)](https://github.com/Wechat-Group/WxJava)
@ -23,11 +23,6 @@
<img height="120" src="https://gitee.com/binary/weixin-java-tools/raw/master/images/banners/tcloud.jpg">
</a>
</td>
<td align="right" valign="middle">
<a href="https://mp.weixin.qq.com/s/R30CNEpkELJg4SRkX0mTDA" target="_blank">
<img height="120" src="https://gitee.com/binary/weixin-java-tools/raw/master/images/banners/planB.jpg">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.vultr.com/?ref=7888900-4F" target="_blank">
<img height="120" src="https://gitee.com/binary/weixin-java-tools/raw/master/images/banners/vultr.jpg">
@ -43,11 +38,11 @@
</table>
### 重要信息
1. **2020-05-24 发布 [【3.8.0正式版】](https://mp.weixin.qq.com/s/1YvMLcSOzhDHhIeX1bLRuQ)**
1. **2020-08-24 发布 [【3.9.0正式版】](https://mp.weixin.qq.com/s/1YvMLcSOzhDHhIeX1bLRuQ)**
1. 新手重要提示本项目仅是一个SDK开发工具包未提供Web实现建议使用 `maven``gradle` 引用本项目即可使用本SDK提供的各种功能详情可参考 **[【Demo项目】](demo.md)** 或本项目中的部分单元测试代码;另外微信开发新手请务必阅读[【开发文档 Wiki 首页】](https://github.com/Wechat-Group/WxJava/wiki)的常见问题部分,可以少走很多弯路,节省不少时间。
1. 技术交流群想获得QQ群/微信群/钉钉企业群等信息的同学,请使用微信扫描上面的微信公众号二维码关注 `WxJava` 后点击相关菜单即可获取加入方式,同时也可以在微信中搜索 `weixin-java-tools``WxJava` 后选择正确的公众号进行关注该公众号会及时通知SDK相关更新信息并不定期分享微信Java开发相关技术知识
1. 付费QQ群**注意刚入群会有5分钟禁言稍等片刻即可正常发言** [![加入QQ群](https://img.shields.io/badge/QQ群-343954419-blue.svg)](http://shang.qq.com/wpa/qunwpa?idkey=731dc3e7ea31ebe25376cc1a791445468612c63fd0e9e05399b088ec81fd9e15) 或 [![加入QQ群](https://img.shields.io/badge/QQ群-343954419-blue.svg)](http://jq.qq.com/?_wv=1027&k=40lRskK),或者请自行搜索群号`343954419`进行添加;当然由于某种原因无法入群的,可关注公众号后获取其他群的加入方式;
1. 钉钉技术交流群: `30294972`
1. 钉钉技术交流群: `30294972`(技术交流群),`35724728`通知群实时通知Github项目变更记录
1. 微信开发新手或者Java开发新手在群内提问或新开Issue提问前请先阅读[【提问的智慧】](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md),并确保已查阅过 [【开发文档Wiki】](https://github.com/wechat-group/WxJava/wiki) ,避免浪费大家的宝贵时间;
1. 寻求帮助时需贴代码或大长串异常信息的,请利用 http://paste.ubuntu.com
@ -56,7 +51,7 @@
1. **阅读源码的同学请注意本SDK为简化代码编译时加入了`lombok`支持,如果不了解`lombok`的话,请先学习下相关知识,比如可以阅读[此文章](https://mp.weixin.qq.com/s/cUc-bUcprycADfNepnSwZQ)**
1. 如有新功能需求发现BUG或者由于微信官方接口调整导致的代码问题可以直接在[【Issues】](https://github.com/Wechat-Group/WxJava/issues)页提出issue便于讨论追踪问题
1. 如果需要贡献代码请务必在提交PR之前先仔细阅读[【代码贡献指南】](CONTRIBUTING.md),谢谢理解配合;
1. 本SDK要求的最低JDK版本是1.7还在使用JDK6的用户请参考[【此项目】]( https://github.com/binarywang/weixin-java-tools-for-jdk6) 而其他更早的JDK版本则需要自己改造实现。
1. 目前本`SDK`最新版本要求的`JDK`最低版本是`8`,使用`7`的同学可以使用`WxJava` `3.8.0`及以前版本,而还在使用`JDK`6的用户请参考[【此项目】]( https://github.com/binarywang/weixin-java-tools-for-jdk6) 而其他更早的JDK版本则需要自己改造实现。
1. [开源中国本项目的首页](https://www.oschina.net/p/weixin-java-tools-new),欢迎大家积极留言评分 🙂
1. SDK开发文档请查阅 [【开发文档Wiki】](https://github.com/wechat-group/WxJava/wiki),部分文档可能未能及时更新,如有发现,可以及时上报或者自行修改。
1. **如果本开发工具包对您有所帮助,欢迎对我们的努力进行肯定,可以直接前往[【托管于码云的项目首页】](http://gitee.com/binary/weixin-java-tools),在页尾部分找到“捐助”按钮进行打赏,多多益善 😄。非常感谢各位打赏和捐助的同学!**
@ -73,7 +68,7 @@
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>(不同模块参考下文)</artifactId>
<version>3.8.0</version>
<version>3.9.0</version>
</dependency>
```
@ -123,6 +118,11 @@
- 民医台
- 来一团商家版
- 史必达(史丹利)
- 嘀嗒云印
- 维沃吼吼
- 王朝社区(比亚迪新能源社区)
- 极吼吼手机上门回收换新
#### 公众号:
- 中国电信上海网厅sh_189
@ -134,21 +134,19 @@
- 光环云社群
- 手机排队
- [全民约跑健身便利店](http://www.oneminsport.com/)
- [洽洽食品](https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=gQFM8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAycDRPOXBZbVZib2UxMDAwME0wN2gAAgRIu4RbAwQAAAAA)、[洽洽合伙人](https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=gQFP8jwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyOUpJaU5VcXBlWTAxMDAwME0wN1oAAgSau4RbAwQAAAAA)
- 民医台
- YshopMall
- 好行景区直通车以及全国40多个公众号
- 我奥篮球公众号
#### 企业号/企业微信:
- 洽洽企业号
- HTC企业微信
- 掌上史丹利
#### 其他:
- 高善人力资源
- [小猪餐餐](http://www.xzcancan.com/)
- [餐饮系统](http://canyin.daydao.com)
- 小猪餐餐
- 餐饮系统
- 微信公众号管理系统http://demo.joolun.com
- 锐捷网络Saleslink

View File

@ -28,7 +28,7 @@
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.7</version>
<version>1.4.10-java7</version>
<scope>provided</scope>
<exclusions>
<exclusion>

View File

@ -6,7 +6,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>3.8.9.B</version>
<version>3.9.0</version>
<packaging>pom</packaging>
<name>WxJava - Weixin/Wechat Java SDK</name>
<description>微信开发Java SDK</description>
@ -121,7 +121,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<httpclient.version>4.5</httpclient.version>
<jetty.version>9.4.28.v20200408</jetty.version>
<jetty.version>9.4.31.v20200723</jetty.version>
</properties>
<dependencyManagement>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>3.8.9.B</version>
<version>3.9.0</version>
</parent>
<packaging>pom</packaging>
<artifactId>wx-java-spring-boot-starters</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>3.8.9.B</version>
<version>3.9.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>3.8.9.B</version>
<version>3.9.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -55,130 +55,4 @@ public class WxMpServiceAutoConfiguration {
return new WxMpServiceJoddHttpImpl();
}
@Bean
@Deprecated
public WxMpKefuService wxMpKefuService(WxMpService wxMpService) {
return wxMpService.getKefuService();
}
@Bean
@Deprecated
public WxMpMaterialService wxMpMaterialService(WxMpService wxMpService) {
return wxMpService.getMaterialService();
}
@Bean
@Deprecated
public WxMpMenuService wxMpMenuService(WxMpService wxMpService) {
return wxMpService.getMenuService();
}
@Bean
@Deprecated
public WxMpUserService wxMpUserService(WxMpService wxMpService) {
return wxMpService.getUserService();
}
@Bean
@Deprecated
public WxMpUserTagService wxMpUserTagService(WxMpService wxMpService) {
return wxMpService.getUserTagService();
}
@Bean
@Deprecated
public WxMpQrcodeService wxMpQrcodeService(WxMpService wxMpService) {
return wxMpService.getQrcodeService();
}
@Bean
@Deprecated
public WxMpCardService wxMpCardService(WxMpService wxMpService) {
return wxMpService.getCardService();
}
@Bean
@Deprecated
public WxMpDataCubeService wxMpDataCubeService(WxMpService wxMpService) {
return wxMpService.getDataCubeService();
}
@Bean
@Deprecated
public WxMpUserBlacklistService wxMpUserBlacklistService(WxMpService wxMpService) {
return wxMpService.getBlackListService();
}
@Bean
@Deprecated
public WxMpStoreService wxMpStoreService(WxMpService wxMpService) {
return wxMpService.getStoreService();
}
@Bean
@Deprecated
public WxMpTemplateMsgService wxMpTemplateMsgService(WxMpService wxMpService) {
return wxMpService.getTemplateMsgService();
}
@Bean
@Deprecated
public WxMpSubscribeMsgService wxMpSubscribeMsgService(WxMpService wxMpService) {
return wxMpService.getSubscribeMsgService();
}
@Bean
@Deprecated
public WxMpDeviceService wxMpDeviceService(WxMpService wxMpService) {
return wxMpService.getDeviceService();
}
@Bean
@Deprecated
public WxMpShakeService wxMpShakeService(WxMpService wxMpService) {
return wxMpService.getShakeService();
}
@Bean
@Deprecated
public WxMpMemberCardService wxMpMemberCardService(WxMpService wxMpService) {
return wxMpService.getMemberCardService();
}
@Bean
@Deprecated
public WxMpMassMessageService wxMpMassMessageService(WxMpService wxMpService) {
return wxMpService.getMassMessageService();
}
@Bean
@Deprecated
public WxMpAiOpenService wxMpAiOpenService(WxMpService wxMpService) {
return wxMpService.getAiOpenService();
}
@Bean
@Deprecated
public WxMpWifiService wxMpWifiService(WxMpService wxMpService) {
return wxMpService.getWifiService();
}
@Bean
@Deprecated
public WxMpMarketingService wxMpMarketingService(WxMpService wxMpService) {
return wxMpService.getMarketingService();
}
@Bean
@Deprecated
public WxMpCommentService wxMpCommentService(WxMpService wxMpService) {
return wxMpService.getCommentService();
}
@Bean
@Deprecated
public WxOcrService wxMpOcrService(WxMpService wxMpService) {
return wxMpService.getOcrService();
}
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>3.8.9.B</version>
<version>3.9.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>3.8.9.B</version>
<version>3.9.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>3.8.9.B</version>
<version>3.9.0</version>
</parent>
<artifactId>weixin-graal</artifactId>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>3.8.9.B</version>
<version>3.9.0</version>
</parent>
<artifactId>weixin-java-common</artifactId>

View File

@ -1,14 +1,30 @@
package me.chanjar.weixin.common.api;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static me.chanjar.weixin.common.error.WxMpErrorMsgEnum.*;
/**
* 微信开发所使用到的常量类.
*
* @author Daniel Qian & binarywang
*/
public class WxConsts {
/**
* access_token 相关错误代码
* <pre>
* 发生以下情况时尝试刷新access_token
* 40001 获取access_token时AppSecret错误或者access_token无效
* 42001 access_token超时
* 40014 不合法的access_token请开发者认真比对access_token的有效性如是否过期或查看是否正在为恰当的公众号调用接口
* </pre>
*/
public static final List<Integer> ACCESS_TOKEN_ERROR_CODES = Arrays.asList(CODE_40001.getCode(),
CODE_40014.getCode(), CODE_42001.getCode());
/**
* 微信推送过来的消息的类型和发送给微信xml格式消息的消息类型.
*/
@ -105,6 +121,31 @@ public class WxConsts {
public static final String MINIPROGRAM_NOTICE = "miniprogram_notice";
}
/**
* 群机器人的消息类型.
*/
public static class GroupRobotMsgType {
/**
* 文本消息.
*/
public static final String TEXT = "text";
/**
* 图片消息.
*/
public static final String IMAGE = "image";
/**
* markdown消息.
*/
public static final String MARKDOWN = "markdown";
/**
* 图文消息点击跳转到外链.
*/
public static final String NEWS = "news";
}
/**
* 表示是否是保密消息0表示否1表示是默认0.
*/

View File

@ -4,6 +4,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.Base64;
public class FileUtils {
@ -34,4 +35,32 @@ public class FileUtils {
return createTmpFile(inputStream, name, ext, Files.createTempDirectory("weixin-java-tools-temp").toFile());
}
/**
* 文件流生成base64
*
* @param in 文件流
* @return base64编码
*/
public static String imageToBase64ByStream(InputStream in) {
byte[] data = null;
// 读取图片字节数组
try {
data = new byte[in.available()];
in.read(data);
// 返回Base64编码过的字节数组字符串
return Base64.getEncoder().encodeToString(data);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}

View File

@ -7,7 +7,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>3.8.9.B</version>
<version>3.9.0</version>
</parent>
<artifactId>weixin-java-cp</artifactId>

View File

@ -12,10 +12,6 @@ import java.util.List;
* @author gaigeshen
*/
public interface WxCpChatService {
@Deprecated
String chatCreate(String name, String owner, List<String> users, String chatId) throws WxErrorException;
/**
* 创建群聊会话注意刚创建的群如果没有下发消息在企业微信不会出现该群.
*
@ -28,9 +24,6 @@ public interface WxCpChatService {
*/
String create(String name, String owner, List<String> users, String chatId) throws WxErrorException;
@Deprecated
void chatUpdate(String chatId, String name, String owner, List<String> usersToAdd, List<String> usersToDelete) throws WxErrorException;
/**
* 修改群聊会话.
*
@ -43,9 +36,6 @@ public interface WxCpChatService {
*/
void update(String chatId, String name, String owner, List<String> usersToAdd, List<String> usersToDelete) throws WxErrorException;
@Deprecated
WxCpChat chatGet(String chatId) throws WxErrorException;
/**
* 获取群聊会话.
*

View File

@ -0,0 +1,52 @@
package me.chanjar.weixin.cp.api;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.bean.article.NewArticle;
import java.util.List;
/**
* 微信群机器人消息发送api
* 文档地址https://work.weixin.qq.com/help?doc_id=13376
* 调用地址https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=
*
* @author yr
* @date 2020-8-20
*/
public interface WxCpGroupRobotService {
/**
* 发送text类型的消息
*
* @param content 文本内容最长不超过2048个字节必须是utf8编码
* @param mentionedList userId的列表提醒群中的指定成员(@某个成员)@all表示提醒所有人如果开发者获取不到userId可以使用mentioned_mobile_list
* @param mobileList 手机号列表提醒手机号对应的群成员(@某个成员)@all表示提醒所有人
* @throws WxErrorException 异常
*/
void sendText(String content, List<String> mentionedList, List<String> mobileList) throws WxErrorException;
/**
* 发送markdown类型的消息
*
* @param content markdown内容最长不超过4096个字节必须是utf8编码
* @throws WxErrorException 异常
*/
void sendMarkDown(String content) throws WxErrorException;
/**
* 发送image类型的消息
*
* @param base64 图片内容的base64编码
* @param md5 图片内容base64编码前的md5值
* @throws WxErrorException 异常
*/
void sendImage(String base64, String md5) throws WxErrorException;
/**
* 发送news类型的消息
*
* @param articleList 图文消息支持1到8条图文
* @throws WxErrorException 异常
*/
void sendNews(List<NewArticle> articleList) throws WxErrorException;
}

View File

@ -110,23 +110,6 @@ public interface WxCpOaService {
*/
WxCpApprovalDetailResult getApprovalDetail(@NonNull String spNo) throws WxErrorException;
/**
* <pre>
* 获取审批数据 (已过期, 请使用"批量获取审批单号" && "获取审批申请详情")
* 通过本接口来获取公司一段时间内的审批记录一次拉取调用最多拉取10000个审批记录可以通过多次拉取的方式来满足需求但调用频率不可超过600次/
* API doc : https://work.weixin.qq.com/api/doc#90000/90135/91530
* </pre>
*
* @param startTime 获取审批记录的开始时间
* @param endTime 获取审批记录的结束时间
* @param nextSpnum 第一个拉取的审批单号不填从该时间段的第一个审批单拉取
* @throws WxErrorException .
* @see me.chanjar.weixin.cp.api.WxCpOaService#getApprovalInfo
* @see me.chanjar.weixin.cp.api.WxCpOaService#getApprovalDetail
*/
@Deprecated
WxCpApprovalDataResult getApprovalData(Date startTime, Date endTime, Long nextSpnum) throws WxErrorException;
/**
* 获取公费电话拨打记录
*

View File

@ -173,6 +173,14 @@ public interface WxCpService {
*/
String post(String url, String postData) throws WxErrorException;
/**
* 当不需要自动带accessToken的时候可以用这个发起post请求
*
* @param url 接口地址
* @param postData 请求body字符串
*/
String postWithoutToken(String url, String postData) throws WxErrorException;
/**
* <pre>
* Service没有实现某个API的时候可以用这个
@ -328,6 +336,13 @@ public interface WxCpService {
WxCpOaService getOAService();
/**
* 获取群机器人消息推送服务
*
* @return 群机器人消息推送服务
*/
WxCpGroupRobotService getGroupRobotService();
/**
* http请求对象
*/

View File

@ -17,7 +17,6 @@ import java.util.List;
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public interface WxCpTagService {
/**
* 创建标签.
* <pre>
@ -32,17 +31,6 @@ public interface WxCpTagService {
*/
String create(String name, Integer id) throws WxErrorException;
/**
* 创建标签.
*
* @param tagName 标签名
* @return 标签id
* @throws WxErrorException .
* @deprecated 建议使用 {@link #create(String, Integer)}其中后面的参数可以为空
*/
@Deprecated
String create(String tagName) throws WxErrorException;
/**
* 更新标签.
*

View File

@ -4,8 +4,9 @@ import com.google.common.base.Joiner;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.StandardSessionManager;
@ -51,6 +52,7 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
private WxCpOaService oaService = new WxCpOaServiceImpl(this);
private WxCpTaskCardService taskCardService = new WxCpTaskCardServiceImpl(this);
private WxCpExternalContactService externalContactService = new WxCpExternalContactServiceImpl(this);
private WxCpGroupRobotService groupRobotService = new WxCpGroupRobotServiceImpl(this);
/**
* 全局的是否正在刷新access token的锁.
@ -217,6 +219,11 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
return execute(SimplePostRequestExecutor.create(this), url, postData);
}
@Override
public String postWithoutToken(String url, String postData) throws WxErrorException {
return this.executeNormal(SimplePostRequestExecutor.create(this), url, postData);
}
/**
* 向微信端发送请求在这里执行的策略是当发生access_token过期时才去刷新然后重新执行请求而不是全局定时请求.
*/
@ -271,16 +278,12 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
return result;
} 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) {
if (WxConsts.ACCESS_TOKEN_ERROR_CODES.contains(error.getErrorCode())) {
// 强制设置wxCpConfigStorage它的access token过期了这样在下一次请求里就会刷新access token
this.configStorage.expireAccessToken();
if (this.getWxCpConfigStorage().autoRefreshToken()) {
log.warn("即将重新获取新的access_token错误代码{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
return this.execute(executor, uri, data);
}
}
@ -296,6 +299,27 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
}
}
/**
* 普通请求不自动带accessToken
*/
private <T, E> T executeNormal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
try {
T result = executor.execute(uri, data, WxType.CP);
log.debug("\n【请求地址】: {}\n【请求参数】{}\n【响应数据】{}", uri, data, result);
return result;
} catch (WxErrorException e) {
WxError error = e.getError();
if (error.getErrorCode() != 0) {
log.error("\n【请求地址】: {}\n【请求参数】{}\n【错误信息】{}", uri, data, error);
throw new WxErrorException(error, e);
}
return null;
} catch (IOException e) {
log.error("\n【请求地址】: {}\n【请求参数】{}\n【异常信息】{}", uri, data, e.getMessage());
throw new RuntimeException(e);
}
}
@Override
public void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider) {
this.configStorage = wxConfigProvider;
@ -412,6 +436,11 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
return oaService;
}
@Override
public WxCpGroupRobotService getGroupRobotService() {
return groupRobotService;
}
@Override
public WxCpTaskCardService getTaskCardService() {
return taskCardService;

View File

@ -6,6 +6,7 @@ import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.error.WxCpErrorMsgEnum;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.DataUtils;
@ -222,10 +223,11 @@ public abstract class BaseWxCpTpServiceImpl<H, P> implements WxCpTpService, Requ
* 发生以下情况时尝试刷新suite_access_token
* 42009 suite_access_token已过期
*/
if (error.getErrorCode() == 42009) {
if (error.getErrorCode() == WxCpErrorMsgEnum.CODE_42009.getCode()) {
// 强制设置wxCpTpConfigStorage它的suite access token过期了这样在下一次请求里就会刷新suite access token
this.configStorage.expireSuiteAccessToken();
if (this.getWxCpTpConfigStorage().autoRefreshToken()) {
log.warn("即将重新获取新的access_token错误代码{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
return this.execute(executor, uri, data);
}
}

View File

@ -24,11 +24,10 @@ import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Chat.*;
*/
@RequiredArgsConstructor
public class WxCpChatServiceImpl implements WxCpChatService {
private final WxCpService cpService;
@Override
public String chatCreate(String name, String owner, List<String> users, String chatId) throws WxErrorException {
public String create(String name, String owner, List<String> users, String chatId) throws WxErrorException {
Map<String, Object> data = new HashMap<>(4);
if (StringUtils.isNotBlank(name)) {
data.put("name", name);
@ -48,12 +47,7 @@ public class WxCpChatServiceImpl implements WxCpChatService {
}
@Override
public String create(String name, String owner, List<String> users, String chatId) throws WxErrorException {
return this.chatCreate(name, owner, users, chatId);
}
@Override
public void chatUpdate(String chatId, String name, String owner, List<String> usersToAdd, List<String> usersToDelete)
public void update(String chatId, String name, String owner, List<String> usersToAdd, List<String> usersToDelete)
throws WxErrorException {
Map<String, Object> data = new HashMap<>(5);
if (StringUtils.isNotBlank(chatId)) {
@ -77,24 +71,13 @@ public class WxCpChatServiceImpl implements WxCpChatService {
}
@Override
public void update(String chatId, String name, String owner, List<String> usersToAdd, List<String> usersToDelete)
throws WxErrorException {
chatUpdate(chatId, name, owner, usersToAdd, usersToDelete);
}
@Override
public WxCpChat chatGet(String chatId) throws WxErrorException {
public WxCpChat get(String chatId) throws WxErrorException {
final String url = this.cpService.getWxCpConfigStorage().getApiUrl(APPCHAT_GET_CHATID + chatId);
String result = this.cpService.get(url, null);
final String chatInfo = GsonParser.parse(result).getAsJsonObject("chat_info").toString();
return WxCpGsonBuilder.create().fromJson(chatInfo, WxCpChat.class);
}
@Override
public WxCpChat get(String chatId) throws WxErrorException {
return this.chatGet(chatId);
}
@Override
public void sendMsg(WxCpAppChatMessage message) throws WxErrorException {
this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(APPCHAT_SEND), message.toJson());

View File

@ -0,0 +1,65 @@
package me.chanjar.weixin.cp.api.impl;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpGroupRobotService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpGroupRobotMessage;
import me.chanjar.weixin.cp.bean.article.NewArticle;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
import java.util.List;
/**
* 微信群机器人消息发送api 实现
*
* @author yr
* @date 2020-08-20
*/
@RequiredArgsConstructor
public class WxCpGroupRobotServiceImpl implements WxCpGroupRobotService {
private final WxCpService cpService;
private String getApiUrl() {
WxCpConfigStorage wxCpConfigStorage = cpService.getWxCpConfigStorage();
return wxCpConfigStorage.getApiUrl(WxCpApiPathConsts.WEBHOOK_SEND) + wxCpConfigStorage.getWebhookKey();
}
@Override
public void sendText(String content, List<String> mentionedList, List<String> mobileList) throws WxErrorException {
WxCpGroupRobotMessage message = new WxCpGroupRobotMessage()
.setMsgType(WxConsts.GroupRobotMsgType.TEXT)
.setContent(content)
.setMentionedList(mentionedList)
.setMentionedMobileList(mobileList);
cpService.postWithoutToken(this.getApiUrl(), message.toJson());
}
@Override
public void sendMarkDown(String content) throws WxErrorException {
WxCpGroupRobotMessage message = new WxCpGroupRobotMessage()
.setMsgType(WxConsts.GroupRobotMsgType.MARKDOWN)
.setContent(content);
cpService.postWithoutToken(this.getApiUrl(), message.toJson());
}
@Override
public void sendImage(String base64, String md5) throws WxErrorException {
WxCpGroupRobotMessage message = new WxCpGroupRobotMessage()
.setMsgType(WxConsts.GroupRobotMsgType.IMAGE)
.setBase64(base64)
.setMd5(md5);
cpService.postWithoutToken(this.getApiUrl(), message.toJson());
}
@Override
public void sendNews(List<NewArticle> articleList) throws WxErrorException {
WxCpGroupRobotMessage message = new WxCpGroupRobotMessage()
.setMsgType(WxConsts.GroupRobotMsgType.NEWS)
.setArticles(articleList);
cpService.postWithoutToken(this.getApiUrl(), message.toJson());
}
}

View File

@ -164,20 +164,6 @@ public class WxCpOaServiceImpl implements WxCpOaService {
return WxCpGsonBuilder.create().fromJson(responseContent, WxCpApprovalDetailResult.class);
}
@Override
public WxCpApprovalDataResult getApprovalData(Date startTime, Date endTime, Long nextSpnum) throws WxErrorException {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("starttime", startTime.getTime() / 1000L);
jsonObject.addProperty("endtime", endTime.getTime() / 1000L);
if (nextSpnum != null) {
jsonObject.addProperty("next_spnum", nextSpnum);
}
final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_APPROVAL_DATA);
String responseContent = this.mainService.post(url, jsonObject.toString());
return WxCpGsonBuilder.create().fromJson(responseContent, WxCpApprovalDataResult.class);
}
@Override
public List<WxCpDialRecord> getDialRecord(Date startTime, Date endTime, Integer offset, Integer limit)
throws WxErrorException {

View File

@ -40,13 +40,6 @@ public class WxCpTagServiceImpl implements WxCpTagService {
return this.create(o);
}
@Override
public String create(String tagName) throws WxErrorException {
JsonObject o = new JsonObject();
o.addProperty("tagname", tagName);
return this.create(o);
}
private String create(JsonObject param) throws WxErrorException {
String url = this.mainService.getWxCpConfigStorage().getApiUrl(TAG_CREATE);
String responseContent = this.mainService.post(url, param.toString());

View File

@ -0,0 +1,118 @@
package me.chanjar.weixin.cp.bean;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import me.chanjar.weixin.cp.bean.article.NewArticle;
import java.util.List;
import static me.chanjar.weixin.common.api.WxConsts.GroupRobotMsgType.*;
/**
* 微信群机器人消息
*
* @author yr
* @date 2020-08-20
*/
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@Data
public class WxCpGroupRobotMessage {
/**
* 消息类型
*/
private String msgType;
/**
* 文本内容最长不超过2048个字节markdown内容最长不超过4096个字节必须是utf8编码
* 必填
*/
private String content;
/**
* userid的列表提醒群中的指定成员(@某个成员)@all表示提醒所有人如果开发者获取不到userid可以使用mentioned_mobile_list
*/
private List<String> mentionedList;
/**
* 手机号列表提醒手机号对应的群成员(@某个成员)@all表示提醒所有人
*/
private List<String> mentionedMobileList;
/**
* 图片内容的base64编码
*/
private String base64;
/**
* 图片内容base64编码前的md5值
*/
private String md5;
/**
* 图文消息一个图文消息支持1到8条图文
*/
private List<NewArticle> articles;
public String toJson() {
JsonObject messageJson = new JsonObject();
messageJson.addProperty("msgtype", this.getMsgType());
switch (this.getMsgType()) {
case TEXT: {
JsonObject text = new JsonObject();
JsonArray uidJsonArray = new JsonArray();
JsonArray mobileJsonArray = new JsonArray();
text.addProperty("content", this.getContent());
if (this.getMentionedList() != null) {
for (String item : this.getMentionedList()) {
uidJsonArray.add(item);
}
}
if (this.getMentionedMobileList() != null) {
for (String item : this.getMentionedMobileList()) {
mobileJsonArray.add(item);
}
}
text.add("mentioned_list", uidJsonArray);
text.add("mentioned_mobile_list", mobileJsonArray);
messageJson.add("text", text);
break;
}
case MARKDOWN: {
JsonObject text = new JsonObject();
text.addProperty("content", this.getContent());
messageJson.add("markdown", text);
break;
}
case IMAGE: {
JsonObject text = new JsonObject();
text.addProperty("base64", this.getBase64());
text.addProperty("md5", this.getMd5());
messageJson.add("image", text);
break;
}
case NEWS: {
JsonObject text = new JsonObject();
JsonArray array = new JsonArray();
for (NewArticle article : this.getArticles()) {
JsonObject articleJson = new JsonObject();
articleJson.addProperty("title", article.getTitle());
articleJson.addProperty("description", article.getDescription());
articleJson.addProperty("url", article.getUrl());
articleJson.addProperty("picurl", article.getPicUrl());
array.add(articleJson);
}
text.add("articles", array);
messageJson.add("news", text);
break;
}
default:
}
return messageJson.toString();
}
}

View File

@ -1,69 +0,0 @@
package me.chanjar.weixin.cp.bean.oa;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import java.io.Serializable;
import java.util.Map;
/**
* 企业微信 OA 审批数据.
*
* @author Element
* @date 2019-04-06 14:36
*/
@Deprecated
@Data
public class WxCpApprovalDataResult implements Serializable {
private static final long serialVersionUID = -1046940445840716590L;
@SerializedName("errcode")
private Integer errCode;
@SerializedName("errmsg")
private String errMsg;
private Integer count;
private Integer total;
@SerializedName("next_spnum")
private Long nextSpNum;
private WxCpApprovalData[] data;
@Data
public static class WxCpApprovalData implements Serializable {
private static final long serialVersionUID = -3051785319608491640L;
@SerializedName("spname")
private String spName;
@SerializedName("apply_name")
private String applyName;
@SerializedName("apply_org")
private String applyOrg;
@SerializedName("approval_name")
private String[] approvalName;
@SerializedName("notify_name")
private String[] notifyName;
@SerializedName("sp_status")
private Integer spStatus;
@SerializedName("sp_num")
private Long spNum;
@SerializedName("apply_time")
private Long applyTime;
@SerializedName("apply_user_id")
private String applyUserId;
@SerializedName("comm")
private Map<String, String> comm;
}
}

View File

@ -12,7 +12,6 @@ import java.io.Serializable;
*/
@Data
public class WxCpApprovalDetailResult implements Serializable {
private static final long serialVersionUID = 3909779949756252918L;
@SerializedName("errcode")

View File

@ -11,7 +11,6 @@ import lombok.Data;
*/
@Data
public class WxCpApprovalInfo implements Serializable {
private static final long serialVersionUID = 7387181805254287167L;
@SerializedName("errcode")

View File

@ -107,7 +107,15 @@ public interface WxCpConfigStorage {
/**
* 是否自动刷新token
*
* @return .
*/
boolean autoRefreshToken();
/**
* 获取群机器人webhook的key
*
* @return key
*/
String getWebhookKey();
}

View File

@ -50,6 +50,8 @@ public class WxCpDefaultConfigImpl implements WxCpConfigStorage, Serializable {
private volatile String baseApiUrl;
private volatile String webhookKey;
@Override
public void setBaseApiUrl(String baseUrl) {
this.baseApiUrl = baseUrl;
@ -287,6 +289,11 @@ public class WxCpDefaultConfigImpl implements WxCpConfigStorage, Serializable {
return true;
}
@Override
public String getWebhookKey() {
return this.webhookKey;
}
public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) {
this.apacheHttpClientBuilder = apacheHttpClientBuilder;
}

View File

@ -46,6 +46,8 @@ public class WxCpRedisConfigImpl implements WxCpConfigStorage {
protected volatile String baseApiUrl;
private volatile String webhookKey;
@Override
public void setBaseApiUrl(String baseUrl) {
this.baseApiUrl = baseUrl;
@ -344,6 +346,11 @@ public class WxCpRedisConfigImpl implements WxCpConfigStorage {
return true;
}
@Override
public String getWebhookKey() {
return this.getWebhookKey();
}
public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) {
this.apacheHttpClientBuilder = apacheHttpClientBuilder;
}

View File

@ -21,6 +21,7 @@ public final class WxCpApiPathConsts {
public static final String BATCH_GET_RESULT = "/cgi-bin/batch/getresult?jobid=";
public static final String JSCODE_TO_SESSION = "/cgi-bin/miniprogram/jscode2session";
public static final String GET_TOKEN = "/cgi-bin/gettoken?corpid=%s&corpsecret=%s";
public static final String WEBHOOK_SEND = "/cgi-bin/webhook/send?key=";
public static class Agent {
public static final String AGENT_GET = "/cgi-bin/agent/get?agentid=%d";
@ -67,8 +68,6 @@ public final class WxCpApiPathConsts {
public static final String GET_APPROVAL_INFO = "/cgi-bin/oa/getapprovalinfo";
public static final String GET_APPROVAL_DETAIL = "/cgi-bin/oa/getapprovaldetail";
public static final String GET_DIAL_RECORD = "/cgi-bin/dial/get_dial_record";
@Deprecated
public static final String GET_APPROVAL_DATA = "/cgi-bin/corp/getapprovaldata";
public static final String GET_TEMPLATE_DETAIL = "/cgi-bin/oa/gettemplatedetail";
public static final String APPLY_EVENT = "/cgi-bin/oa/applyevent";
}

View File

@ -38,24 +38,24 @@ public class WxCpChatServiceImplTest {
}
@Test
public void testChatCreate() throws Exception {
final String result = cpService.getChatService().chatCreate("测试群聊", userId,
public void testCreate() throws Exception {
final String result = cpService.getChatService().create("测试群聊", userId,
Arrays.asList(userId, userId), chatId);
assertThat(result).isNotEmpty();
assertThat(result).isEqualTo(chatId);
}
@Test
public void testChatGet() throws Exception {
WxCpChat chat = this.cpService.getChatService().chatGet(chatId);
public void testGet() throws Exception {
WxCpChat chat = this.cpService.getChatService().get(chatId);
System.out.println(chat);
Assert.assertEquals(chat.getName(), "测试群聊");
}
@Test
public void testChatUpdate() throws Exception {
this.cpService.getChatService().chatUpdate(chatId, "", "", Arrays.asList("ZhengWuYao"), null);
WxCpChat chat = this.cpService.getChatService().chatGet(chatId);
public void testUpdate() throws Exception {
this.cpService.getChatService().update(chatId, "", "", Arrays.asList("ZhengWuYao"), null);
WxCpChat chat = this.cpService.getChatService().get(chatId);
System.out.println(chat);
Assert.assertEquals(chat.getUsers().size(), 3);
}

View File

@ -0,0 +1,68 @@
package me.chanjar.weixin.cp.api.impl;
import com.google.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.fs.FileUtils;
import me.chanjar.weixin.cp.api.ApiTestModule;
import me.chanjar.weixin.cp.api.WxCpGroupRobotService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.article.NewArticle;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import java.io.InputStream;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.testng.Assert.*;
/**
* 微信群机器人消息发送api 单元测试
*
* @author yr
* @date 2020-08-20
*/
@Slf4j
@Guice(modules = ApiTestModule.class)
public class WxCpGroupRobotServiceImplTest {
@Inject
protected WxCpService wxService;
private WxCpGroupRobotService robotService;
@BeforeTest
public void setup() {
robotService = wxService.getGroupRobotService();
}
@Test
public void testSendText() throws WxErrorException {
robotService.sendText("Hello World", null, null);
}
@Test
public void testSendMarkDown() throws WxErrorException {
String content = "实时新增用户反馈<font color=\"warning\">132例</font>,请相关同事注意。\n" +
">类型:<font color=\"comment\">用户反馈</font> \n" +
">普通用户反馈:<font color=\"comment\">117例</font> \n" +
">VIP用户反馈:<font color=\"comment\">15例</font>";
robotService.sendMarkDown(content);
}
@Test
public void testSendImage() throws WxErrorException {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("mm.jpeg");
assert inputStream != null;
String base64 = FileUtils.imageToBase64ByStream(inputStream);
String md5 = "1cb2e787063d66e24f5f89e7fc267a4d";
robotService.sendImage(base64, md5);
}
@Test
public void testSendNews() throws WxErrorException {
NewArticle article = new NewArticle("图文消息测试","hello world","http://www.baidu.com","http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png");
robotService.sendNews(Stream.of(article).collect(Collectors.toList()));
}
}

View File

@ -40,7 +40,7 @@ public class WxCpTagServiceImplTest {
@Test
public void testCreate() throws Exception {
this.tagId = this.wxService.getTagService().create("测试标签" + System.currentTimeMillis());
this.tagId = this.wxService.getTagService().create("测试标签" + System.currentTimeMillis(), null);
System.out.println(this.tagId);
}

View File

@ -10,4 +10,5 @@
<departmentId>企业号通讯录的某个部门id</departmentId>
<tagId>企业号通讯录里的某个tagid</tagId>
<oauth2redirectUri>网页授权获取用户信息回调地址</oauth2redirectUri>
<webhookKey>webhook链接地址的key值</webhookKey>
</xml>

View File

@ -1,6 +1,6 @@
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Weixin-java-tool-suite" verbose="1">
<!-- 不再维护 -->
<suite name="WxJava-suite" verbose="1">
<test name="API_Test">
<classes>
<class name="me.chanjar.weixin.cp.api.WxCpBusyRetryTest"/>

View File

@ -7,7 +7,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>3.8.9.B</version>
<version>3.9.0</version>
</parent>
<artifactId>weixin-java-miniapp</artifactId>
@ -87,7 +87,6 @@
<dependency>
<groupId>com.github.jedis-lock</groupId>
<artifactId>jedis-lock</artifactId>
<version>1.0.0</version>
<optional>true</optional>
</dependency>
<dependency>

View File

@ -32,20 +32,6 @@ public interface WxMaMsgService {
*/
boolean sendKefuMsg(WxMaKefuMessage message) throws WxErrorException;
/**
* <pre>
* 发送模板消息
* 详情请见: <a href="https://developers.weixin.qq.com/miniprogram/dev/api-backend/templateMessage.send.html">发送模板消息</a>
* 接口url格式https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
* 小程序模板消息接口将于2020年1月10日下线开发者可使用订阅消息功能
* </pre>
*
* @param templateMessage 模版消息
* @throws WxErrorException .
*/
@Deprecated
void sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException;
/**
* <pre>
* 发送订阅消息

View File

@ -229,13 +229,6 @@ public interface WxMaService extends WxService {
*/
WxMaQrcodeService getQrcodeService();
/**
* 返回模板配置相关接口方法的实现类对象, 以方便调用其各个接口.
*
* @return WxMaTemplateService
*/
WxMaTemplateService getTemplateService();
/**
* 返回订阅消息配置相关接口方法的实现类对象, 以方便调用其各个接口.
*

View File

@ -1,90 +0,0 @@
package cn.binarywang.wx.miniapp.api;
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateAddResult;
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryGetResult;
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryListResult;
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateListResult;
import me.chanjar.weixin.common.error.WxErrorException;
import java.util.List;
/**
* @author IOManlewis.lynn1006@gmail.com
*/
@Deprecated
public interface WxMaTemplateService {
/**
* 获取小程序模板库标题列表.
*/
String TEMPLATE_LIBRARY_LIST_URL = "https://api.weixin.qq.com/cgi-bin/wxopen/template/library/list";
/**
* 获取模板库某个模板标题下关键词库.
*/
String TEMPLATE_LIBRARY_KEYWORD_URL = "https://api.weixin.qq.com/cgi-bin/wxopen/template/library/get";
/**
* 组合模板并添加至帐号下的个人模板库.
*/
String TEMPLATE_ADD_URL = "https://api.weixin.qq.com/cgi-bin/wxopen/template/add";
/**
* 获取帐号下已存在的模板列表.
*/
String TEMPLATE_LIST_URL = "https://api.weixin.qq.com/cgi-bin/wxopen/template/list";
/**
* 删除帐号下的某个模板.
*/
String TEMPLATE_DEL_URL = "https://api.weixin.qq.com/cgi-bin/wxopen/template/del";
/**
* <pre>
* 获取小程序模板库标题列表
*
* 详情请见: <a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1500465446_j4CgR&token=&lang=zh_CN">获取小程序模板库标题列表</a>
* 接口url格式: https://api.weixin.qq.com/cgi-bin/wxopen/template/library/list?access_token=ACCESS_TOKEN
* </pre>
*/
WxMaTemplateLibraryListResult findTemplateLibraryList(int offset, int count) throws WxErrorException;
/**
* <pre>
* 获取模板库某个模板标题下关键词库
*
* 详情请见: <a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1500465446_j4CgR&token=&lang=zh_CN">获取小程序模板库标题列表</a>
* 接口url格式: https://api.weixin.qq.com/cgi-bin/wxopen/template/library/get?access_token=ACCESS_TOKEN
* </pre>
*/
WxMaTemplateLibraryGetResult findTemplateLibraryKeywordList(String id) throws WxErrorException;
/**
* <pre>
* 组合模板并添加至帐号下的个人模板库
*
* 详情请见: <a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1500465446_j4CgR&token=&lang=zh_CN">获取小程序模板库标题列表</a>
* 接口url格式: https://api.weixin.qq.com/cgi-bin/wxopen/template/add?access_token=ACCESS_TOKEN
* </pre>
*/
WxMaTemplateAddResult addTemplate(String id, List<Integer> keywordIdList) throws WxErrorException;
/**
* <pre>
* 获取帐号下已存在的模板列表
*
* 详情请见: <a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1500465446_j4CgR&token=&lang=zh_CN">获取小程序模板库标题列表</a>
* 接口url格式: https://api.weixin.qq.com/cgi-bin/wxopen/template/list?access_token=ACCESS_TOKEN
* </pre>
*/
WxMaTemplateListResult findTemplateList(int offset, int count) throws WxErrorException;
/**
* <pre>
* 删除帐号下的某个模板
*
* 详情请见: <a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1500465446_j4CgR&token=&lang=zh_CN">获取小程序模板库标题列表</a>
* 接口url格式: https://api.weixin.qq.com/cgi-bin/wxopen/template/list?access_token=ACCESS_TOKEN
* </pre>
*/
boolean delTemplate(String templateId) throws WxErrorException;
}

View File

@ -10,6 +10,7 @@ import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.api.WxImgProcService;
import me.chanjar.weixin.common.api.WxOcrService;
import me.chanjar.weixin.common.bean.WxAccessToken;
@ -32,8 +33,6 @@ import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import static cn.binarywang.wx.miniapp.constant.WxMaConstants.ErrorCode.*;
/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>
* @see #doGetAccessTokenRequest
@ -41,13 +40,11 @@ import static cn.binarywang.wx.miniapp.constant.WxMaConstants.ErrorCode.*;
@Slf4j
public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestHttp<H, P> {
private Map<String, WxMaConfig> configMap;
private WxMaConfig wxMaConfig;
private final WxMaMsgService kefuService = new WxMaMsgServiceImpl(this);
private final WxMaMediaService materialService = new WxMaMediaServiceImpl(this);
private final WxMaUserService userService = new WxMaUserServiceImpl(this);
private final WxMaQrcodeService qrCodeService = new WxMaQrcodeServiceImpl(this);
private final WxMaTemplateService templateService = new WxMaTemplateServiceImpl(this);
private final WxMaAnalysisService analysisService = new WxMaAnalysisServiceImpl(this);
private final WxMaCodeService codeService = new WxMaCodeServiceImpl(this);
private final WxMaSettingService settingService = new WxMaSettingServiceImpl(this);
@ -169,8 +166,8 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
/**
* 通过网络请求获取AccessToken
*
* @return
* @throws IOException
* @return .
* @throws IOException .
*/
protected abstract String doGetAccessTokenRequest() throws IOException;
@ -244,12 +241,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
return result;
} catch (WxErrorException e) {
WxError error = e.getError();
/*
* 发生以下情况时尝试刷新access_token
*/
if (error.getErrorCode() == ERR_40001
|| error.getErrorCode() == ERR_42001
|| error.getErrorCode() == ERR_40014) {
if (WxConsts.ACCESS_TOKEN_ERROR_CODES.contains(error.getErrorCode())) {
// 强制设置WxMaConfig的access token过期了这样在下一次请求里就会刷新access token
Lock lock = this.getWxMaConfig().getAccessTokenLock();
lock.lock();
@ -263,6 +255,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
lock.unlock();
}
if (this.getWxMaConfig().autoRefreshToken()) {
log.warn("即将重新获取新的access_token错误代码{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
return this.execute(executor, uri, data);
}
}
@ -281,9 +274,9 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
/**
* 设置当前的AccessToken
*
* @param resultContent
* @return
* @throws WxErrorException
* @param resultContent 响应内容
* @return access token
* @throws WxErrorException 异常
*/
protected String extractAccessToken(String resultContent) throws WxErrorException {
WxMaConfig config = this.getWxMaConfig();
@ -298,7 +291,12 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
@Override
public WxMaConfig getWxMaConfig() {
return this.wxMaConfig;
if (this.configMap.size() == 1) {
// 只有一个小程序直接返回其配置即可
return this.configMap.values().iterator().next();
}
return this.configMap.get(WxMaConfigHolder.get());
}
@Override
@ -400,11 +398,6 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
return this.qrCodeService;
}
@Override
public WxMaTemplateService getTemplateService() {
return this.templateService;
}
@Override
public WxMaSubscribeService getSubscribeService() {
return this.subscribeService;

View File

@ -17,8 +17,7 @@ import me.chanjar.weixin.common.util.json.GsonParser;
*/
@AllArgsConstructor
public class WxMaMsgServiceImpl implements WxMaMsgService {
private WxMaService wxMaService;
private final WxMaService wxMaService;
@Override
public boolean sendKefuMsg(WxMaKefuMessage message) throws WxErrorException {
@ -26,15 +25,6 @@ public class WxMaMsgServiceImpl implements WxMaMsgService {
return responseContent != null;
}
@Override
public void sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException {
String responseContent = this.wxMaService.post(TEMPLATE_MSG_SEND_URL, templateMessage.toJson());
JsonObject jsonObject = GsonParser.parse(responseContent);
if (jsonObject.get(WxMaConstants.ERRCODE).getAsInt() != 0) {
throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
}
}
@Override
public void sendSubscribeMsg(WxMaSubscribeMessage subscribeMessage) throws WxErrorException {
String responseContent = this.wxMaService.post(SUBSCRIBE_MSG_SEND_URL, subscribeMessage.toJson());

View File

@ -1,58 +0,0 @@
package cn.binarywang.wx.miniapp.api.impl;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.WxMaTemplateService;
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateAddResult;
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryGetResult;
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryListResult;
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateListResult;
import com.google.common.collect.ImmutableMap;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import java.util.List;
import java.util.Map;
/**
* @author Binary
*/
@AllArgsConstructor
public class WxMaTemplateServiceImpl implements WxMaTemplateService {
private WxMaService wxMaService;
@Override
public WxMaTemplateLibraryListResult findTemplateLibraryList(int offset, int count) throws WxErrorException {
Map<String, Integer> params = ImmutableMap.of("offset", offset, "count", count);
String responseText = this.wxMaService.post(TEMPLATE_LIBRARY_LIST_URL, WxGsonBuilder.create().toJson(params));
return WxMaTemplateLibraryListResult.fromJson(responseText);
}
@Override
public WxMaTemplateLibraryGetResult findTemplateLibraryKeywordList(String id) throws WxErrorException {
String responseText = this.wxMaService.post(TEMPLATE_LIBRARY_KEYWORD_URL,
WxGsonBuilder.create().toJson(ImmutableMap.of("id", id)));
return WxMaTemplateLibraryGetResult.fromJson(responseText);
}
@Override
public WxMaTemplateAddResult addTemplate(String id, List<Integer> keywordIdList) throws WxErrorException {
String responseText = this.wxMaService.post(TEMPLATE_ADD_URL,
WxGsonBuilder.create().toJson(ImmutableMap.of("id", id, "keyword_id_list", keywordIdList.toArray())));
return WxMaTemplateAddResult.fromJson(responseText);
}
@Override
public WxMaTemplateListResult findTemplateList(int offset, int count) throws WxErrorException {
Map<String, Integer> params = ImmutableMap.of("offset", offset, "count", count);
String responseText = this.wxMaService.post(TEMPLATE_LIST_URL, WxGsonBuilder.create().toJson(params));
return WxMaTemplateListResult.fromJson(responseText);
}
@Override
public boolean delTemplate(String templateId) throws WxErrorException {
Map<String, String> params = ImmutableMap.of("template_id", templateId);
this.wxMaService.post(TEMPLATE_DEL_URL, WxGsonBuilder.create().toJson(params));
return true;
}
}

View File

@ -1,101 +0,0 @@
package cn.binarywang.wx.miniapp.bean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* 模板消息.
* 参考 https://developers.weixin.qq.com/miniprogram/dev/api-backend/templateMessage.send.html
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class WxMaTemplateMessage implements Serializable {
private static final long serialVersionUID = 5063374783759519418L;
/**
* 接收者用户 openid.
* <pre>
* 参数touser
* 是否必填
* 描述 接收者用户 openid
* </pre>
*/
private String toUser;
/**
* 所需下发的模板消息的id.
* <pre>
* 参数template_id
* 是否必填
* 描述 所需下发的模板消息的id
* </pre>
*/
private String templateId;
/**
* 点击模板卡片后的跳转页面仅限本小程序内的页面.
* <pre>
* 参数page
* 是否必填
* 描述 点击模板卡片后的跳转页面仅限本小程序内的页面支持带参数,示例index?foo=bar该字段不填则模板无跳转
* </pre>
*/
private String page;
/**
* 表单提交场景下 submit 事件带上的 formId支付场景下为本次支付的 prepay_id.
* <pre>
* 参数form_id
* 是否必填
* 描述 表单提交场景下 submit 事件带上的 formId支付场景下为本次支付的 prepay_id
* </pre>
*/
private String formId;
/**
* 模板内容不填则下发空模板.
* <pre>
* 参数data
* 是否必填
* 描述 模板内容不填则下发空模板
* </pre>
*/
private List<WxMaTemplateData> data;
/**
* 模板需要放大的关键词不填则默认无放大.
* <pre>
* 参数emphasis_keyword
* 是否必填
* 描述 模板需要放大的关键词不填则默认无放大
* </pre>
*/
private String emphasisKeyword;
public WxMaTemplateMessage addData(WxMaTemplateData datum) {
if (this.data == null) {
this.data = new ArrayList<>();
}
this.data.add(datum);
return this;
}
public String toJson() {
return WxMaGsonBuilder.create().toJson(this);
}
}

View File

@ -12,10 +12,25 @@ import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
*/
public interface WxMaConfig {
/**
* Gets access token.
*
* @return the access token
*/
String getAccessToken();
/**
* Gets access token lock.
*
* @return the access token lock
*/
Lock getAccessTokenLock();
/**
* Is access token expired boolean.
*
* @return the boolean
*/
boolean isAccessTokenExpired();
/**
@ -38,10 +53,25 @@ public interface WxMaConfig {
*/
void updateAccessToken(String accessToken, int expiresInSeconds);
/**
* Gets jsapi ticket.
*
* @return the jsapi ticket
*/
String getJsapiTicket();
/**
* Gets jsapi ticket lock.
*
* @return the jsapi ticket lock
*/
Lock getJsapiTicketLock();
/**
* Is jsapi ticket expired boolean.
*
* @return the boolean
*/
boolean isJsapiTicketExpired();
/**
@ -59,11 +89,23 @@ public interface WxMaConfig {
/**
* 卡券api_ticket.
*
* @return the card api ticket
*/
String getCardApiTicket();
/**
* Gets card api ticket lock.
*
* @return the card api ticket lock
*/
Lock getCardApiTicketLock();
/**
* Is card api ticket expired boolean.
*
* @return the boolean
*/
boolean isCardApiTicketExpired();
/**
@ -74,44 +116,106 @@ public interface WxMaConfig {
/**
* 应该是线程安全的.
*
* @param apiTicket 新的卡券api ticket值
* @param apiTicket 新的卡券api ticket值
* @param expiresInSeconds 过期时间以秒为单位
*/
void updateCardApiTicket(String apiTicket, int expiresInSeconds);
/**
* Gets appid.
*
* @return the appid
*/
String getAppid();
/**
* Gets secret.
*
* @return the secret
*/
String getSecret();
/**
* Gets token.
*
* @return the token
*/
String getToken();
/**
* Gets aes key.
*
* @return the aes key
*/
String getAesKey();
/**
* Gets original id.
*
* @return the original id
*/
String getOriginalId();
/**
* Gets cloud env.
*
* @return the cloud env
*/
String getCloudEnv();
/**
* Gets msg data format.
*
* @return the msg data format
*/
String getMsgDataFormat();
/**
* Gets expires time.
*
* @return the expires time
*/
long getExpiresTime();
/**
* Gets http proxy host.
*
* @return the http proxy host
*/
String getHttpProxyHost();
/**
* Gets http proxy port.
*
* @return the http proxy port
*/
int getHttpProxyPort();
/**
* Gets http proxy username.
*
* @return the http proxy username
*/
String getHttpProxyUsername();
/**
* Gets http proxy password.
*
* @return the http proxy password
*/
String getHttpProxyPassword();
/**
* http client builder
*
* @return ApacheHttpClientBuilder
* @return ApacheHttpClientBuilder apache http client builder
*/
ApacheHttpClientBuilder getApacheHttpClientBuilder();
/**
* 是否自动刷新token
*
* @return the boolean
*/
boolean autoRefreshToken();

View File

@ -53,23 +53,6 @@ public class WxMaConstants {
public static final String MA_PAGE = "miniprogrampage";
}
public static final class ErrorCode {
/**
* 40001 获取access_token时AppSecret错误或者access_token无效.
*/
public static final int ERR_40001 = 40001;
/**
* 42001 access_token超时.
*/
public static final int ERR_42001 = 42001;
/**
* 40014 不合法的access_token请开发者认真比对access_token的有效性如是否过期.
*/
public static final int ERR_40014 = 40014;
}
/**
* 内容安全检测的媒体类型
*/

View File

@ -1,7 +1,6 @@
package cn.binarywang.wx.miniapp.util.json;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
import cn.binarywang.wx.miniapp.bean.WxMaUniformMessage;
import cn.binarywang.wx.miniapp.bean.analysis.WxMaRetainInfo;
import cn.binarywang.wx.miniapp.bean.analysis.WxMaUserPortrait;
@ -19,7 +18,6 @@ public class WxMaGsonBuilder {
static {
INSTANCE.disableHtmlEscaping();
INSTANCE.registerTypeAdapter(WxMaTemplateMessage.class, new WxMaTemplateMessageGsonAdapter());
INSTANCE.registerTypeAdapter(WxMaSubscribeMessage.class, new WxMaSubscribeMessageGsonAdapter());
INSTANCE.registerTypeAdapter(WxMaUniformMessage.class, new WxMaUniformMessageGsonAdapter());
INSTANCE.registerTypeAdapter(WxMaCodeCommitRequest.class, new WxMaCodeCommitRequestGsonAdapter());

View File

@ -1,50 +0,0 @@
package cn.binarywang.wx.miniapp.util.json;
import java.lang.reflect.Type;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateData;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public class WxMaTemplateMessageGsonAdapter implements JsonSerializer<WxMaTemplateMessage> {
@Override
public JsonElement serialize(WxMaTemplateMessage message, Type typeOfSrc, JsonSerializationContext context) {
JsonObject messageJson = new JsonObject();
messageJson.addProperty("touser", message.getToUser());
messageJson.addProperty("template_id", message.getTemplateId());
if (message.getPage() != null) {
messageJson.addProperty("page", message.getPage());
}
if (message.getFormId() != null) {
messageJson.addProperty("form_id", message.getFormId());
}
if (message.getEmphasisKeyword() != null) {
messageJson.addProperty("emphasis_keyword", message.getEmphasisKeyword());
}
JsonObject data = new JsonObject();
messageJson.add("data", data);
if (message.getData() == null) {
return messageJson;
}
for (WxMaTemplateData datum : message.getData()) {
JsonObject dataJson = new JsonObject();
dataJson.addProperty("value", datum.getValue());
data.add(datum.getName(), dataJson);
}
return messageJson;
}
}

View File

@ -40,28 +40,6 @@ public class WxMaMsgServiceImplTest {
this.wxService.getMsgService().sendKefuMsg(message);
}
@Test(invocationCount = 5, threadPoolSize = 3)
public void testSendTemplateMsg() throws WxErrorException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
TestConfig config = (TestConfig) this.wxService.getWxMaConfig();
WxMaTemplateMessage templateMessage = WxMaTemplateMessage.builder()
.toUser(config.getOpenid())
.formId("FORMID")
.page("index")
.data(Lists.newArrayList(
new WxMaTemplateData("keyword1", "339208499"),
new WxMaTemplateData("keyword2", dateFormat.format(new Date())),
new WxMaTemplateData("keyword3", "粤海喜来登酒店"),
new WxMaTemplateData("keyword4", "广州市天河区天河路208号")))
.templateId(config.getTemplateId())
.emphasisKeyword("keyword1.DATA")
.build();
//templateMessage.addData( new WxMaTemplateData("keyword1", "339208499", "#173177"));
this.wxService.getMsgService().sendTemplateMsg(templateMessage);
}
@Test
public void testSendSubscribeMsg() throws WxErrorException {
TestConfig config = (TestConfig) this.wxService.getWxMaConfig();

View File

@ -1,69 +0,0 @@
package cn.binarywang.wx.miniapp.api.impl;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateAddResult;
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryGetResult;
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryListResult;
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateListResult;
import cn.binarywang.wx.miniapp.test.ApiTestModule;
import com.google.inject.Inject;
import org.assertj.core.util.Lists;
import org.testng.Assert;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import java.util.List;
@Test
@Guice(modules = ApiTestModule.class)
public class WxMaTemplateServiceImplTest {
@Inject
protected WxMaService wxService;
@Test
public void testFindTemplateLibraryList() throws Exception {
WxMaTemplateLibraryListResult result = this.wxService.getTemplateService().findTemplateLibraryList(0, 20);
Assert.assertEquals(20, result.getList().size());
}
@Test
public void testFindTemplateLibraryKeywordList() throws Exception {
WxMaTemplateLibraryGetResult result = this.wxService.getTemplateService().findTemplateLibraryKeywordList("AT0004");
Assert.assertEquals("AT0004", result.getId());
Assert.assertEquals("交易提醒", result.getTitle());
Assert.assertEquals(100, result.getKeywordList().size());
}
@Test
public void testAddTemplate() throws Exception {
List<Integer> list = Lists.newArrayList();
list.add(1);
list.add(20);
list.add(84);
WxMaTemplateAddResult result = this.wxService.getTemplateService().addTemplate("AT0004", list);
Assert.assertNotNull(result.getTemplateId());
System.out.println(result);
}
@Test
public void testFindTemplateList() throws Exception {
WxMaTemplateListResult result = this.wxService.getTemplateService().findTemplateList(0, 20);
System.out.println(result);
}
@Test
public void testDelTemplate() throws Exception {
//add
List<Integer> list = Lists.newArrayList();
list.add(1);
list.add(20);
list.add(84);
WxMaTemplateAddResult result = this.wxService.getTemplateService().addTemplate("AT0004", list);
//delete
this.wxService.getTemplateService().delTemplate(result.getTemplateId());
}
}

View File

@ -1,32 +0,0 @@
package cn.binarywang.wx.miniapp.bean;
import org.testng.annotations.*;
import com.google.common.collect.Lists;
import static org.testng.AssertJUnit.*;
/**
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public class WxMaTemplateMessageTest {
@Test
public void testToJson() throws Exception {
WxMaTemplateMessage tm = WxMaTemplateMessage.builder()
.toUser("OPENID")
//.color("aaaaa")
.formId("FORMID")
.page("index")
.data(Lists.newArrayList(
new WxMaTemplateData("keyword1", "339208499", "#173177"),
new WxMaTemplateData("keyword2", "2015年01月05日12:30", "#173177"),
new WxMaTemplateData("keyword3", "粤海喜来登酒店", "#173177"),
new WxMaTemplateData("keyword4", "广州市天河区天河路208号", "#173177")))
.templateId("TEMPLATE_ID")
.emphasisKeyword("keyword1.DATA")
.build();
assertEquals(tm.toJson(), "{\"touser\":\"OPENID\",\"template_id\":\"TEMPLATE_ID\",\"page\":\"index\",\"form_id\":\"FORMID\",\"emphasis_keyword\":\"keyword1.DATA\",\"data\":{\"keyword1\":{\"value\":\"339208499\",\"color\":\"#173177\"},\"keyword2\":{\"value\":\"2015年01月05日12:30\",\"color\":\"#173177\"},\"keyword3\":{\"value\":\"粤海喜来登酒店\",\"color\":\"#173177\"},\"keyword4\":{\"value\":\"广州市天河区天河路208号\",\"color\":\"#173177\"}}}");
}
}

View File

@ -4,15 +4,12 @@ import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
import cn.binarywang.wx.miniapp.bean.WxMaMessage;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateData;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.binarywang.wx.miniapp.constant.WxMaConstants;
import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
import cn.binarywang.wx.miniapp.message.WxMaXmlOutMessage;
import cn.binarywang.wx.miniapp.test.TestConfig;
import com.google.common.collect.Lists;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
@ -97,22 +94,6 @@ public class WxMaDemoServer {
}
};
private static final WxMaMessageHandler templateMsgHandler = new WxMaMessageHandler() {
@Override
public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map<String, Object> context,
WxMaService service, WxSessionManager sessionManager)
throws WxErrorException {
service.getMsgService().sendTemplateMsg(WxMaTemplateMessage.builder()
.templateId(templateId).data(Lists.newArrayList(
new WxMaTemplateData("keyword1", "339208499", "#173177")))
.toUser(wxMessage.getFromUser())
.formId("自己替换可用的formid")
.build());
return null;
}
};
private static final WxMaMessageHandler customerServiceMessageHandler = new WxMaMessageHandler() {
@Override
public WxMaXmlOutMessage handle(WxMaMessage message, Map<String, Object> context, WxMaService service, WxSessionManager sessionManager) {
@ -157,7 +138,6 @@ public class WxMaDemoServer {
router = new WxMaMessageRouter(service);
router.rule().handler(logHandler).next()
.rule().async(false).content("模板").handler(templateMsgHandler).end()
.rule().async(false).content("文本").handler(textHandler).end()
.rule().async(false).content("图片").handler(picHandler).end()
.rule().async(false).content("二维码").handler(qrcodeHandler).end()

View File

@ -7,7 +7,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>3.8.9.B</version>
<version>3.9.0</version>
</parent>
<artifactId>weixin-java-mp</artifactId>

View File

@ -163,70 +163,6 @@ public interface WxMpService extends WxService {
*/
String buildQrConnectUrl(String redirectUri, String scope, String state);
/**
* <pre>
* 构造oauth2授权的url连接.
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息
* </pre>
*
* @param redirectURI 用户授权完成后的重定向链接无需urlencode, 方法内会进行encode
* @param scope scope
* @param state state
* @return url string
* @deprecated use oauth2Service.buildAuthorizationUrl() instead
*/
@Deprecated
String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state);
/**
* <pre>
* 用code换取oauth2的access token.
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息
* </pre>
*
* @param code code
* @return token对象
* @throws WxErrorException .
*/
@Deprecated
WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException;
/**
* <pre>
* 刷新oauth2的access token.
* </pre>
*
* @param refreshToken 刷新token
* @return 新的token对象
* @throws WxErrorException .
*/
@Deprecated
WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException;
/**
* <pre>
* 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以.
* </pre>
*
* @param oAuth2AccessToken token对象
* @param lang zh_CN, zh_TW, en
* @return 用户对象
* @throws WxErrorException .
*/
@Deprecated
WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException;
/**
* <pre>
* 验证oauth2的access token是否有效.
* </pre>
*
* @param oAuth2AccessToken token对象
* @return 是否有效
*/
@Deprecated
boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken);
/**
* <pre>
* 获取微信服务器IP地址

View File

@ -7,6 +7,7 @@ import com.google.gson.JsonObject;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.api.WxImgProcService;
import me.chanjar.weixin.common.api.WxOcrService;
import me.chanjar.weixin.common.bean.WxAccessToken;
@ -220,48 +221,12 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
return WxMpSemanticQueryResult.fromJson(responseContent);
}
@Override
public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) {
return String.format(CONNECT_OAUTH2_AUTHORIZE_URL.getUrl(this.getWxMpConfigStorage()),
this.getWxMpConfigStorage().getAppId(), URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state));
}
@Override
public String buildQrConnectUrl(String redirectUri, String scope, String state) {
return String.format(QRCONNECT_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(),
URIUtil.encodeURIComponent(redirectUri), scope, StringUtils.trimToEmpty(state));
}
private WxMpOAuth2AccessToken getOAuth2AccessToken(String url) throws WxErrorException {
try {
RequestExecutor<String, String> executor = SimpleGetRequestExecutor.create(this);
String responseText = executor.execute(url, null, WxType.MP);
return WxMpOAuth2AccessToken.fromJson(responseText);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException {
return this.oAuth2Service.getAccessToken(code);
}
@Override
public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException {
return this.oAuth2Service.refreshAccessToken(refreshToken);
}
@Override
public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken token, String lang) throws WxErrorException {
return this.oAuth2Service.getUserInfo(token,lang);
}
@Override
public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken token) {
return this.oAuth2Service.validateAccessToken(token);
}
@Override
public String[] getCallbackIP() throws WxErrorException {
String responseContent = this.get(GET_CALLBACK_IP_URL, null);
@ -377,13 +342,7 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
return result;
} catch (WxErrorException e) {
WxError error = e.getError();
/*
* 发生以下情况时尝试刷新access_token
* 40001 获取 access_token AppSecret 错误或者 access_token 无效请开发者认真比对 AppSecret 的正确性或查看是否正在为恰当的公众号调用接口
* 42001 access_token 超时请检查 access_token 的有效期请参考基础支持 - 获取 access_token access_token 的详细机制说明
* 40014 不合法的 access_token 请开发者认真比对 access_token 的有效性如是否过期或查看是否正在为恰当的公众号调用接口
*/
if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001 || error.getErrorCode() == 40014) {
if (WxConsts.ACCESS_TOKEN_ERROR_CODES.contains(error.getErrorCode())) {
// 强制设置wxMpConfigStorage它的access token过期了这样在下一次请求里就会刷新access token
Lock lock = this.getWxMpConfigStorage().getAccessTokenLock();
lock.lock();
@ -397,6 +356,7 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
lock.unlock();
}
if (this.getWxMpConfigStorage().autoRefreshToken()) {
log.warn("即将重新获取新的access_token错误代码{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
return this.execute(executor, uri, data);
}
}

View File

@ -17,7 +17,7 @@ public class DemoOAuth2Handler implements WxMpMessageHandler {
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
String href = "<a href=\"" + wxMpService.oauth2buildAuthorizationUrl(
String href = "<a href=\"" + wxMpService.getOAuth2Service().buildAuthorizationUrl(
wxMpService.getWxMpConfigStorage().getOauth2redirectUri(),
WxConsts.OAuth2Scope.SNSAPI_USERINFO, null) + "\">测试oauth2</a>";
return WxMpXmlOutMessage.TEXT().content(href)

View File

@ -31,15 +31,15 @@ public class WxMpOAuth2Servlet extends HttpServlet {
response.getWriter().println("<h1>code</h1>");
response.getWriter().println(code);
WxMpOAuth2AccessToken wxMpOAuth2AccessToken = this.wxMpService.oauth2getAccessToken(code);
WxMpOAuth2AccessToken wxMpOAuth2AccessToken = this.wxMpService.getOAuth2Service().getAccessToken(code);
response.getWriter().println("<h1>access token</h1>");
response.getWriter().println(wxMpOAuth2AccessToken.toString());
WxMpUser wxMpUser = this.wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken, null);
WxMpUser wxMpUser = this.wxMpService.getOAuth2Service().getUserInfo(wxMpOAuth2AccessToken, null);
response.getWriter().println("<h1>user info</h1>");
response.getWriter().println(wxMpUser.toString());
wxMpOAuth2AccessToken = this.wxMpService.oauth2refreshAccessToken(wxMpOAuth2AccessToken.getRefreshToken());
wxMpOAuth2AccessToken = this.wxMpService.getOAuth2Service().refreshAccessToken(wxMpOAuth2AccessToken.getRefreshToken());
response.getWriter().println("<h1>after refresh</h1>");
response.getWriter().println(wxMpOAuth2AccessToken.toString());

View File

@ -1,7 +1,8 @@
消息机制未实现,下面为通知回调中设置的代码部分
以下代码可通过腾讯全网发布测试用例
```
```Java
@RestController
@RequestMapping("notify")
public class NotifyController extends WechatThridBaseController {

View File

@ -7,7 +7,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>3.8.9.B</version>
<version>3.9.0</version>
</parent>
<artifactId>weixin-java-open</artifactId>

View File

@ -146,14 +146,8 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService {
return getWxOpenService().post(uriWithComponentAccessToken, postData);
} 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
if (WxConsts.ACCESS_TOKEN_ERROR_CODES.contains(error.getErrorCode())) {
// 强制设置access token过期这样在下一次请求里就会刷新access token
Lock lock = this.getWxOpenConfigStorage().getComponentAccessTokenLock();
lock.lock();
try {
@ -167,6 +161,7 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService {
}
if (this.getWxOpenConfigStorage().autoRefreshToken()) {
log.warn("即将重新获取新的access_token错误代码{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
return this.post(uri, postData, accessTokenKey);
}
}
@ -190,13 +185,7 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService {
return getWxOpenService().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) {
if (WxConsts.ACCESS_TOKEN_ERROR_CODES.contains(error.getErrorCode())) {
// 强制设置wxMpConfigStorage它的access token过期了这样在下一次请求里就会刷新access token
Lock lock = this.getWxOpenConfigStorage().getComponentAccessTokenLock();
lock.lock();
@ -210,6 +199,7 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService {
lock.unlock();
}
if (this.getWxOpenConfigStorage().autoRefreshToken()) {
log.warn("即将重新获取新的access_token错误代码{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
return this.get(uri, accessTokenKey);
}
}

View File

@ -31,18 +31,4 @@ public class WxOpenMpServiceImpl extends WxMpServiceImpl {
return wxOpenComponentService.getAuthorizerAccessToken(appId, forceRefresh);
}
@Override
public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException {
return wxOpenComponentService.oauth2getAccessToken(appId, code);
}
@Override
public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException {
return wxOpenComponentService.oauth2refreshAccessToken(appId, refreshToken);
}
@Override
public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) {
return wxOpenComponentService.oauth2buildAuthorizationUrl(appId, redirectURI, scope, state);
}
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>3.8.9.B</version>
<version>3.9.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -74,7 +74,7 @@
<!-- 待优化去掉 -->
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.10.4</version>
<version>2.10.0.pr1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>

View File

@ -8,6 +8,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
@ -18,70 +19,69 @@ import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class ApplymentStateQueryResult {
public class ApplymentStateQueryResult implements Serializable {
private static final long serialVersionUID = 6539090917423486409L;
/**
* 业务申请编号
*/
@SerializedName("business_code")
private String businessCode;
/**
* 微信支付申请单号
*/
@SerializedName("applyment_id")
private String applymentId;
/**
* 特约商户号
*/
@SerializedName("sub_mchid")
private String subMchid;
/**
* 超级管理员签约链接
*/
@SerializedName("sign_url")
private String signUrl;
/**
* 业务申请编号
*/
@SerializedName("business_code")
private String businessCode;
/**
* 微信支付申请单号
*/
@SerializedName("applyment_id")
private String applymentId;
/**
* 特约商户号
*/
@SerializedName("sub_mchid")
private String subMchid;
/**
* 超级管理员签约链接
*/
@SerializedName("sign_url")
private String signUrl;
/**
* 申请单状态
*/
@SerializedName("applyment_state")
private ApplymentStateEnum applymentState;
/**
* 申请状态描述
*/
@SerializedName("applyment_state_msg")
private String applymentStateMsg;
/**
* 驳回原因详情
*/
@SerializedName("audit_detail")
private List<AuditDetail> auditDetail;
/**
* 驳回原因详情
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public static class AuditDetail {
/**
* 申请单状态
*
* 字段名
*/
@SerializedName("applyment_state")
private ApplymentStateEnum applymentState;
@SerializedName("field")
private String field;
/**
* 申请状态描述
* 字段名称
*/
@SerializedName("applyment_state_msg")
private String applymentStateMsg;
@SerializedName("field_name")
private String fieldName;
/**
* 驳回原因详情
* 驳回原因
*/
@SerializedName("audit_detail")
private List<AuditDetail> auditDetail;
@SerializedName("reject_reason")
private String rejectReason;
/**
* 驳回原因详情
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public static class AuditDetail {
/**
* 字段名
*/
@SerializedName("field")
private String field;
/**
* 字段名称
*/
@SerializedName("field_name")
private String fieldName;
/**
* 驳回原因
*/
@SerializedName("reject_reason")
private String rejectReason;
}
}
}

View File

@ -1,13 +1,15 @@
package com.github.binarywang.wxpay.bean.applyment;
import com.github.binarywang.wxpay.bean.applyment.enums.AccountTypeEnum;
import com.github.binarywang.wxpay.v3.SpecEncrypt;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import com.github.binarywang.wxpay.v3.SpecEncrypt;
import java.io.Serializable;
/**
* 修改结算账户请求对象
@ -17,37 +19,38 @@ import com.github.binarywang.wxpay.v3.SpecEncrypt;
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class ModifySettlementRequest {
/**
*账户类型
*/
@SerializedName("account_type")
private AccountTypeEnum accountType;
/**
*开户银行
*/
@SerializedName("account_bank")
private String accountBank;
/**
*开户银行省市编码
*/
@SerializedName("bank_address_code")
private String bankAddressCode;
/**
*开户银行全称含支行
*/
@SerializedName("bank_name")
private String bankName;
/**
*开户银行联行号
*/
@SerializedName("bank_branch_id")
private String bankBranchId;
public class ModifySettlementRequest implements Serializable {
private static final long serialVersionUID = 4568552340365230872L;
/**
* 账户类型
*/
@SerializedName("account_type")
private AccountTypeEnum accountType;
/**
* 开户银行
*/
@SerializedName("account_bank")
private String accountBank;
/**
* 开户银行省市编码
*/
@SerializedName("bank_address_code")
private String bankAddressCode;
/**
* 开户银行全称含支行
*/
@SerializedName("bank_name")
private String bankName;
/**
* 开户银行联行号
*/
@SerializedName("bank_branch_id")
private String bankBranchId;
/**
*银行账号
*/
@SpecEncrypt
@SerializedName("account_number")
private String accountNumber;
/**
* 银行账号
*/
@SpecEncrypt
@SerializedName("account_number")
private String accountNumber;
}

View File

@ -7,6 +7,8 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 查询结算账户返回对象信息
*/
@ -15,37 +17,38 @@ import lombok.experimental.Accessors;
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class SettlementInfoResult {
/**
* 账户类型
*/
@SerializedName("account_type")
private String accountType;
/**
* 开户银行
*/
@SerializedName("account_bank")
private String accountBank;
/**
* 开户银行全称含支行]
*/
@SerializedName("bank_name")
private String bankName;
/**
* 开户银行联行号
*/
@SerializedName("bank_branch_id")
private String bankBranchId;
/**
* 银行账号
*/
@SerializedName("account_number")
private String accountNumber;
/**
* 汇款验证结果
* @see com.github.binarywang.wxpay.bean.applyment.enums.SettlementVerifyResultEnum
*/
@SerializedName("verify_result")
private String verifyResult;
public class SettlementInfoResult implements Serializable {
private static final long serialVersionUID = 4568552340365230872L;
/**
* 账户类型
*/
@SerializedName("account_type")
private String accountType;
/**
* 开户银行
*/
@SerializedName("account_bank")
private String accountBank;
/**
* 开户银行全称含支行]
*/
@SerializedName("bank_name")
private String bankName;
/**
* 开户银行联行号
*/
@SerializedName("bank_branch_id")
private String bankBranchId;
/**
* 银行账号
*/
@SerializedName("account_number")
private String accountNumber;
/**
* 汇款验证结果
*
* @see com.github.binarywang.wxpay.bean.applyment.enums.SettlementVerifyResultEnum
*/
@SerializedName("verify_result")
private String verifyResult;
}

View File

@ -21,11 +21,11 @@ import java.io.Serializable;
@AllArgsConstructor
@Accessors(chain = true)
public class WxPayApplymentCreateResult implements Serializable {
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
/**
* 微信支付申请单号
*/
@SerializedName("applyment_id")
private String applymentId;
/**
* 微信支付申请单号
*/
@SerializedName("applyment_id")
private String applymentId;
}

View File

@ -5,14 +5,14 @@ package com.github.binarywang.wxpay.bean.applyment.enums;
* 银行结算账户枚举类
*/
public enum AccountTypeEnum {
/**
* 对公银行账户
*/
ACCOUNT_TYPE_BUSINESS,
/**
* 对公银行账户
*/
ACCOUNT_TYPE_BUSINESS,
/**
* 经营者个人银行卡
*/
ACCOUNT_TYPE_PRIVATE,
;
/**
* 经营者个人银行卡
*/
ACCOUNT_TYPE_PRIVATE,
;
}

View File

@ -6,37 +6,37 @@ package com.github.binarywang.wxpay.bean.applyment.enums;
* @author zhouyongshen
*/
public enum ApplymentStateEnum {
/**
* 编辑中提交申请发生错误导致请尝试重新提交
*/
APPLYMENT_STATE_EDITTING,
/**
* 审核中申请单正在审核中超级管理员用微信打开签约链接完成绑定微信号后申请单进度将通过微信公众号通知超级管理员引导完成后续步骤
*/
APPLYMENT_STATE_AUDITING,
/**
* 已驳回请按照驳回原因修改申请资料超级管理员用微信打开签约链接完成绑定微信号后续申请单进度将通过微信公众号通知超级管理员
*/
APPLYMENT_STATE_REJECTED,
/**
* 待账户验证请超级管理员使用微信打开返回的签约链接根据页面指引完成账户验证
*/
APPLYMENT_STATE_TO_BE_CONFIRMED,
/**
* 待签约请超级管理员使用微信打开返回的签约链接根据页面指引完成签约
*/
APPLYMENT_STATE_TO_BE_SIGNED,
/**
* 开通权限中系统开通相关权限中请耐心等待
*/
APPLYMENT_STATE_SIGNING,
/**
* 已完成商户入驻申请已完成
*/
APPLYMENT_STATE_FINISHED,
/**
* 已作废申请单已被撤销
*/
APPLYMENT_STATE_CANCELED
/**
* 编辑中提交申请发生错误导致请尝试重新提交
*/
APPLYMENT_STATE_EDITTING,
/**
* 审核中申请单正在审核中超级管理员用微信打开签约链接完成绑定微信号后申请单进度将通过微信公众号通知超级管理员引导完成后续步骤
*/
APPLYMENT_STATE_AUDITING,
/**
* 已驳回请按照驳回原因修改申请资料超级管理员用微信打开签约链接完成绑定微信号后续申请单进度将通过微信公众号通知超级管理员
*/
APPLYMENT_STATE_REJECTED,
/**
* 待账户验证请超级管理员使用微信打开返回的签约链接根据页面指引完成账户验证
*/
APPLYMENT_STATE_TO_BE_CONFIRMED,
/**
* 待签约请超级管理员使用微信打开返回的签约链接根据页面指引完成签约
*/
APPLYMENT_STATE_TO_BE_SIGNED,
/**
* 开通权限中系统开通相关权限中请耐心等待
*/
APPLYMENT_STATE_SIGNING,
/**
* 已完成商户入驻申请已完成
*/
APPLYMENT_STATE_FINISHED,
/**
* 已作废申请单已被撤销
*/
APPLYMENT_STATE_CANCELED
}

View File

@ -5,14 +5,14 @@ package com.github.binarywang.wxpay.bean.applyment.enums;
* 银行结算账户枚举类
*/
public enum BankAccountTypeEnum {
/**
* 对公银行账户
*/
BANK_ACCOUNT_TYPE_CORPORATE,
/**
* 对公银行账户
*/
BANK_ACCOUNT_TYPE_CORPORATE,
/**
* 经营者个人银行卡
*/
BANK_ACCOUNT_TYPE_PERSONAL,
;
/**
* 经营者个人银行卡
*/
BANK_ACCOUNT_TYPE_PERSONAL,
;
}

View File

@ -4,57 +4,57 @@ package com.github.binarywang.wxpay.bean.applyment.enums;
* 登记证书的类型枚举
*/
public enum CertTypeEnum {
/**
* 事业单位法人证书
*/
CERTIFICATE_TYPE_2388,
/**
* 统一社会信用代码证书
*/
CERTIFICATE_TYPE_2389,
/**
* 有偿服务许可证军队医院适用
*/
CERTIFICATE_TYPE_2390,
/**
* 医疗机构执业许可证军队医院适用
*/
CERTIFICATE_TYPE_2391,
/**
* 企业营业执照挂靠企业的党组织适用
*/
CERTIFICATE_TYPE_2392,
/**
* 组织机构代码证政府机关适用
*/
CERTIFICATE_TYPE_2393,
/**
* 社会团体法人登记证书
*/
CERTIFICATE_TYPE_2394,
/**
* 民办非企业单位登记证书
*/
CERTIFICATE_TYPE_2395,
/**
* 基金会法人登记证书
*/
CERTIFICATE_TYPE_2396,
/**
* 慈善组织公开募捐资格证书
*/
CERTIFICATE_TYPE_2397,
/**
* 农民专业合作社法人营业执照
*/
CERTIFICATE_TYPE_2398,
/**
* 宗教活动场所登记证
*/
CERTIFICATE_TYPE_2399,
/**
* 其他证书/批文/证明
*/
CERTIFICATE_TYPE_2400,
;
/**
* 事业单位法人证书
*/
CERTIFICATE_TYPE_2388,
/**
* 统一社会信用代码证书
*/
CERTIFICATE_TYPE_2389,
/**
* 有偿服务许可证军队医院适用
*/
CERTIFICATE_TYPE_2390,
/**
* 医疗机构执业许可证军队医院适用
*/
CERTIFICATE_TYPE_2391,
/**
* 企业营业执照挂靠企业的党组织适用
*/
CERTIFICATE_TYPE_2392,
/**
* 组织机构代码证政府机关适用
*/
CERTIFICATE_TYPE_2393,
/**
* 社会团体法人登记证书
*/
CERTIFICATE_TYPE_2394,
/**
* 民办非企业单位登记证书
*/
CERTIFICATE_TYPE_2395,
/**
* 基金会法人登记证书
*/
CERTIFICATE_TYPE_2396,
/**
* 慈善组织公开募捐资格证书
*/
CERTIFICATE_TYPE_2397,
/**
* 农民专业合作社法人营业执照
*/
CERTIFICATE_TYPE_2398,
/**
* 宗教活动场所登记证
*/
CERTIFICATE_TYPE_2399,
/**
* 其他证书/批文/证明
*/
CERTIFICATE_TYPE_2400,
;
}

View File

@ -5,25 +5,25 @@ package com.github.binarywang.wxpay.bean.applyment.enums;
* 枚举值
*/
public enum IdTypeEnum {
/**
* 中国大陆居民-身份证
*/
IDENTIFICATION_TYPE_IDCARD,
/**
* 其他国家或地区居民-护照
*/
IDENTIFICATION_TYPE_OVERSEA_PASSPORT,
/**
* 中国香港居民-来往内地通行证
*/
IDENTIFICATION_TYPE_HONGKONG_PASSPORT,
/**
* 中国澳门居民-来往内地通行证
*/
IDENTIFICATION_TYPE_MACAO_PASSPORT,
/**
* 中国台湾居民-来往大陆通行证
*/
IDENTIFICATION_TYPE_TAIWAN_PASSPORT,
;
/**
* 中国大陆居民-身份证
*/
IDENTIFICATION_TYPE_IDCARD,
/**
* 其他国家或地区居民-护照
*/
IDENTIFICATION_TYPE_OVERSEA_PASSPORT,
/**
* 中国香港居民-来往内地通行证
*/
IDENTIFICATION_TYPE_HONGKONG_PASSPORT,
/**
* 中国澳门居民-来往内地通行证
*/
IDENTIFICATION_TYPE_MACAO_PASSPORT,
/**
* 中国台湾居民-来往大陆通行证
*/
IDENTIFICATION_TYPE_TAIWAN_PASSPORT,
;
}

View File

@ -4,29 +4,29 @@ package com.github.binarywang.wxpay.bean.applyment.enums;
* 经营场景类型枚举值
*/
public enum SalesScenesTypeEnum {
/**
* 线下门店
*/
SALES_SCENES_STORE,
/**
* 公众号
*/
SALES_SCENES_MP,
/**
* 小程序
*/
SALES_SCENES_MINI_PROGRAM,
/**
* 互联网
*/
SALES_SCENES_WEB,
/**
* APP
*/
SALES_SCENES_APP,
/**
* 企业微信
*/
SALES_SCENES_WEWORK,
;
/**
* 线下门店
*/
SALES_SCENES_STORE,
/**
* 公众号
*/
SALES_SCENES_MP,
/**
* 小程序
*/
SALES_SCENES_MINI_PROGRAM,
/**
* 互联网
*/
SALES_SCENES_WEB,
/**
* APP
*/
SALES_SCENES_APP,
/**
* 企业微信
*/
SALES_SCENES_WEWORK,
;
}

View File

@ -6,18 +6,18 @@ package com.github.binarywang.wxpay.bean.applyment.enums;
* @author zhouyognshen
*/
public enum SettlementVerifyResultEnum {
/**
* 系统汇款验证中商户可发起提现尝试
*/
VERIFYING,
/**
* 系统成功汇款该账户可正常发起提现
*/
VERIFY_SUCCESS,
/**
* 系统汇款失败该账户无法发起提现请检查修改
*/
VERIFY_FAIL,
;
/**
* 系统汇款验证中商户可发起提现尝试
*/
VERIFYING,
/**
* 系统成功汇款该账户可正常发起提现
*/
VERIFY_SUCCESS,
/**
* 系统汇款失败该账户无法发起提现请检查修改
*/
VERIFY_FAIL,
;
}

View File

@ -5,24 +5,26 @@ package com.github.binarywang.wxpay.bean.applyment.enums;
* <pre>
* 商户申请接入时如何选择主体类型 https://kf.qq.com/faq/180910IBZVnQ180910naQ77b.html
* </pre>
*
* @author zhouyongshen
*/
public enum SubjectTypeEnum {
/**
* 个体户营业执照上的主体类型一般为个体户个体工商户个体经营
*/
SUBJECT_TYPE_INDIVIDUAL,
/**
* (企业营业执照上的主体类型一般为有限公司有限责任公司
*/
SUBJECT_TYPE_ENTERPRISE,
/**
* 党政机关及事业单位包括国内各级各类政府机构事业单位等公安党团司法交通旅游工商税务市政医疗教育学校等机构
*/
SUBJECT_TYPE_INSTITUTIONS,
/**
* 其他组织不属于企业政府/事业单位的组织机构如社会团体民办非企业基金会要求机构已办理组织机构代码证
*/
SUBJECT_TYPE_OTHERS,;
/**
* 个体户营业执照上的主体类型一般为个体户个体工商户个体经营
*/
SUBJECT_TYPE_INDIVIDUAL,
/**
* (企业营业执照上的主体类型一般为有限公司有限责任公司
*/
SUBJECT_TYPE_ENTERPRISE,
/**
* 党政机关及事业单位包括国内各级各类政府机构事业单位等公安党团司法交通旅游工商税务市政医疗教育学校等机构
*/
SUBJECT_TYPE_INSTITUTIONS,
/**
* 其他组织不属于企业政府/事业单位的组织机构如社会团体民办非企业基金会要求机构已办理组织机构代码证
*/
SUBJECT_TYPE_OTHERS,
;
}

View File

@ -12,7 +12,7 @@ import java.io.Serializable;
@Data
@NoArgsConstructor
public class ApplymentsResult implements Serializable {
private static final long serialVersionUID = -4549193755252593150L;
/**
* <pre>
* 字段名微信支付申请单号

View File

@ -144,7 +144,8 @@ public class ApplymentsStatusResult implements Serializable {
@Data
@NoArgsConstructor
public static class AccountValidation implements Serializable{
public static class AccountValidation implements Serializable {
private static final long serialVersionUID = 4379880030965808588L;
/**
* <pre>
* 字段名付款户名
@ -275,7 +276,8 @@ public class ApplymentsStatusResult implements Serializable {
@Data
@NoArgsConstructor
public static class AuditDetail implements Serializable{
public static class AuditDetail implements Serializable {
private static final long serialVersionUID = 5446130564359386809L;
/**
* <pre>
* 字段名参数名称

View File

@ -10,18 +10,16 @@ import com.github.binarywang.wxpay.exception.WxPayException;
* @author zhouyongshen
*/
public interface Applyment4SubService {
/**
* 提交申请单API
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/applyment4sub/chapter3_1.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/
*
* @param request 请求对象
* @return WxPayApplymentCreateResult 响应结果
* @throws WxPayException the wx pay exception
*/
WxPayApplymentCreateResult createApply(WxPayApplyment4SubCreateRequest request) throws WxPayException;
/**
* 提交申请单API
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/applyment4sub/chapter3_1.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/
*
* @param request 请求对象
* @return WxPayApplymentCreateResult 响应结果
* @throws WxPayException the wx pay exception
*/
WxPayApplymentCreateResult createApply(WxPayApplyment4SubCreateRequest request) throws WxPayException;
/**
* 通过业务申请编号查询申请状态
@ -29,11 +27,13 @@ public interface Applyment4SubService {
* 接口链接https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/business_code/{business_code}
*
* @param businessCode 业务申请编号
* 1只能由数字字母或下划线组成建议前缀为服务商商户号
* 2服务商自定义的唯一编号
* 3每个编号对应一个申请单每个申请单审核通过后生成一个微信支付商户号
* 4若申请单被驳回可填写相同的业务申请编号即可覆盖修改原申请单信息
* 示例值1900013511_10000
* 1只能由数字字母或下划线组成建议前缀为服务商商户号
* 2服务商自定义的唯一编号
* 3每个编号对应一个申请单每个申请单审核通过后生成一个微信支付商户号
* 4若申请单被驳回可填写相同的业务申请编号即可覆盖修改原申请单信息
* 示例值1900013511_10000
* @return the applyment state query result
* @throws WxPayException the wx pay exception
*/
ApplymentStateQueryResult queryApplyStatusByBusinessCode(String businessCode) throws WxPayException;
@ -43,6 +43,8 @@ public interface Applyment4SubService {
* 接口链接https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/applyment_id/{applyment_id}
*
* @param applymentId 微信支付分的申请单号示例值2000001234567890
* @return the applyment state query result
* @throws WxPayException the wx pay exception
*/
ApplymentStateQueryResult queryApplyStatusByApplymentId(String applymentId) throws WxPayException;
@ -52,6 +54,8 @@ public interface Applyment4SubService {
* 接口链接https://api.mch.weixin.qq.com/v3/apply4sub/sub_merchants/{sub_mchid}/settlement
*
* @param subMchid 本服务商进件已签约的特约商户号
* @return the settlement info result
* @throws WxPayException the wx pay exception
*/
SettlementInfoResult querySettlementBySubMchid(String subMchid) throws WxPayException;
@ -59,9 +63,11 @@ public interface Applyment4SubService {
* 修改结算帐号
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/applyment4sub/chapter3_3.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/apply4sub/sub_merchants/{sub_mchid}/modify-settlement
*
* @param subMchid 特约商户号
* @param request 修改结算账户请求对象信息
* @param request 修改结算账户请求对象信息
* @throws WxPayException the wx pay exception
*/
void modifySettlement(String subMchid,ModifySettlementRequest request) throws WxPayException;
void modifySettlement(String subMchid, ModifySettlementRequest request) throws WxPayException;
}

View File

@ -24,7 +24,8 @@ public interface EcommerceService {
* </pre>
*
* @param request 请求对象
* @return .
* @return . applyments result
* @throws WxPayException the wx pay exception
*/
ApplymentsResult createApply(ApplymentsRequest request) throws WxPayException;
@ -36,7 +37,8 @@ public interface EcommerceService {
* </pre>
*
* @param applymentId 申请单ID
* @return .
* @return . applyments status result
* @throws WxPayException the wx pay exception
*/
ApplymentsStatusResult queryApplyStatusByApplymentId(String applymentId) throws WxPayException;
@ -48,7 +50,8 @@ public interface EcommerceService {
* </pre>
*
* @param outRequestNo 业务申请编号
* @return .
* @return . applyments status result
* @throws WxPayException the wx pay exception
*/
ApplymentsStatusResult queryApplyStatusByOutRequestNo(String outRequestNo) throws WxPayException;

View File

@ -413,30 +413,6 @@ public interface WxPayService {
*/
WxScanPayNotifyResult parseScanPayNotifyResult(String xmlData) throws WxPayException;
/**
* @deprecated 建议使用 {@link RedpackService#sendMiniProgramRedpack(WxPaySendMiniProgramRedpackRequest)}
*/
@Deprecated
WxPaySendMiniProgramRedpackResult sendMiniProgramRedpack(WxPaySendMiniProgramRedpackRequest request) throws WxPayException;
/**
* @deprecated 建议使用 {@link RedpackService#sendRedpack(WxPaySendRedpackRequest)}
*/
@Deprecated
WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxPayException;
/**
* @deprecated 建议使用 {@link RedpackService#queryRedpack(String)}
*/
@Deprecated
WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException;
/**
* @deprecated 建议使用 {@link RedpackService#queryRedpack(WxPayRedpackQueryRequest)}
*/
@Deprecated
WxPayRedpackQueryResult queryRedpack(WxPayRedpackQueryRequest request) throws WxPayException;
/**
* <pre>
* 扫码支付模式一生成二维码的方法

View File

@ -250,27 +250,6 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
}
@Override
public WxPaySendMiniProgramRedpackResult sendMiniProgramRedpack(WxPaySendMiniProgramRedpackRequest request)
throws WxPayException {
return this.redpackService.sendMiniProgramRedpack(request);
}
@Override
public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxPayException {
return this.redpackService.sendRedpack(request);
}
@Override
public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException {
return this.redpackService.queryRedpack(mchBillNo);
}
@Override
public WxPayRedpackQueryResult queryRedpack(WxPayRedpackQueryRequest request) throws WxPayException {
return this.redpackService.queryRedpack(request);
}
@Override
public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxPayException {
WxPayOrderQueryRequest request = new WxPayOrderQueryRequest();

View File

@ -9,21 +9,14 @@ import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.RequiredArgsConstructor;
import java.net.URI;
@RequiredArgsConstructor
public class EcommerceServiceImpl implements EcommerceService {
private static final Gson GSON = new GsonBuilder().create();
private WxPayService payService;
/**
*
* @param payService
*/
public EcommerceServiceImpl(WxPayService payService) {
this.payService = payService;
}
private final WxPayService payService;
@Override
public ApplymentsResult createApply(ApplymentsRequest request) throws WxPayException {

View File

@ -27,7 +27,6 @@ import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import java.math.BigInteger;
import java.net.URI;
import java.nio.charset.StandardCharsets;
@ -129,10 +128,10 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
//v3已经改为通过状态码判断200 204 成功
int statusCode = response.getStatusLine().getStatusCode();
String responseString="{}";
String responseString = "{}";
HttpEntity entity = response.getEntity();
if(entity!=null){
responseString= EntityUtils.toString(entity, StandardCharsets.UTF_8);
if (entity != null) {
responseString = EntityUtils.toString(entity, StandardCharsets.UTF_8);
}
if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
@ -262,7 +261,7 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
}
SSLConnectionSocketFactory connectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
new String[]{"TLSv1"}, null, new DefaultHostnameVerifier());
new DefaultHostnameVerifier());
httpClientBuilder.setSSLSocketFactory(connectionSocketFactory);
}