+ * http请求响应回调处理接口. + * Created by Binary Wang on 2018/12/8. + *+ * + * @param
大部分代码拷贝自:DefaultApacheHttpClientBuilder
@@ -292,6 +292,7 @@ public void run() { } } } catch (InterruptedException ignore) { + Thread.currentThread().interrupt(); } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java index 2ce8750822..779a844aa9 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java @@ -25,7 +25,6 @@ * Created by ecoolper on 2017/5/5. */ public class ApacheMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutordiff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java index 19e6de4492..31ce6b5991 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java @@ -19,6 +19,7 @@ public interface WxCpMediaService { String MEDIA_GET_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; String MEDIA_UPLOAD_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?type="; String IMG_UPLOAD_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg"; + String JSSDK_MEDIA_GET_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk"; /** *@@ -59,6 +60,21 @@ WxMediaUploadResult upload(String mediaType, String fileType, InputStream inputS */ File download(String mediaId) throws WxErrorException; + /** + *+ * 获取高清语音素材. + * 可以使用本接口获取从JSSDK的uploadVoice接口上传的临时语音素材,格式为speex,16K采样率。该音频比上文的临时素材获取接口(格式为amr,8K采样率)更加清晰,适合用作语音识别等对音质要求较高的业务。 + * 请求方式:GET(HTTPS) + * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk?access_token=ACCESS_TOKEN&media_id=MEDIA_ID + * 仅企业微信2.4及以上版本支持。 + * 文档地址:https://work.weixin.qq.com/api/doc#90000/90135/90255 + *+ * + * @param mediaId 媒体id + * @return 保存到本地的临时文件 + */ + File getJssdkFile(String mediaId) throws WxErrorException; + /** ** 上传图片. @@ -69,7 +85,7 @@ WxMediaUploadResult upload(String mediaType, String fileType, InputStream inputS ** * @param file 上传的文件对象 - * @return 返回图片url + * @return 返回图片url */ String uploadImg(File file) throws WxErrorException; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index 3e33c4eb55..afda991b55 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -7,7 +7,8 @@ import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.cp.bean.*; +import me.chanjar.weixin.cp.bean.WxCpMessage; +import me.chanjar.weixin.cp.bean.WxCpMessageSendResult; import me.chanjar.weixin.cp.config.WxCpConfigStorage; /** @@ -241,13 +242,20 @@ public interface WxCpService { * 获取用户相关接口的服务类对象 */ WxCpUserService getUserService(); + + /** + * 获取群聊服务 + * + * @return 群聊服务 + */ + WxCpChatService getChatService(); WxCpAgentService getAgentService(); /** * http请求对象 */ - RequestHttp getRequestHttp(); + RequestHttp, ?> getRequestHttp(); void setUserService(WxCpUserService userService); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java index 9f9317256e..310a1efa5e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java @@ -38,7 +38,7 @@ public interface WxCpUserService { * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 */ - ListlistByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + List listByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException; /** * @@ -51,7 +51,7 @@ public interface WxCpUserService { * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 */ - ListlistSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; + List listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException; /** * 新建用户. diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java index e4914134c1..3a977b81d8 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentServiceImpl.java @@ -1,9 +1,11 @@ package me.chanjar.weixin.cp.api.impl; -import com.google.gson.Gson; +import java.util.List; + import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; + import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.WxCpAgentService; @@ -11,8 +13,6 @@ import me.chanjar.weixin.cp.bean.WxCpAgent; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; -import java.util.List; - /** * diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java new file mode 100644 index 0000000000..b8e894fb9b --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java @@ -0,0 +1,83 @@ +package me.chanjar.weixin.cp.api.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; + +import com.google.gson.JsonParser; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.cp.api.WxCpChatService; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpChat; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +/** + * 群聊服务实现 + * + * @author gaigeshen + */ +public class WxCpChatServiceImpl implements WxCpChatService { + + private final WxCpService internalService; + + /** + * 创建群聊服务实现的实例 + * + * @param internalService 企业微信的服务 + */ + public WxCpChatServiceImpl(WxCpService internalService) { + this.internalService = internalService; + } + + @Override + public String chatCreate(String name, String owner, Listusers, String chatId) throws WxErrorException { + Map data = new HashMap<>(4); + if (StringUtils.isNotBlank(name)) { + data.put("name", name); + } + if (StringUtils.isNotBlank(owner)) { + data.put("owner", owner); + } + if (users != null) { + data.put("userlist", users); + } + if (StringUtils.isNotBlank(chatId)) { + data.put("chatid", chatId); + } + String result = internalService.post("https://qyapi.weixin.qq.com/cgi-bin/appchat/create", WxGsonBuilder.create().toJson(data)); + return new JsonParser().parse(result).getAsJsonObject().get("chatid").getAsString(); + } + + @Override + public void chatUpdate(String chatId, String name, String owner, List usersToAdd, List usersToDelete) throws WxErrorException { + Map data = new HashMap<>(5); + if (StringUtils.isNotBlank(chatId)) { + data.put("chatid", chatId); + } + if (StringUtils.isNotBlank(name)) { + data.put("name", name); + } + if (StringUtils.isNotBlank(owner)) { + data.put("owner", owner); + } + if (usersToAdd != null && !usersToAdd.isEmpty()) { + data.put("add_user_list", usersToAdd); + } + if (usersToDelete != null && !usersToDelete.isEmpty()) { + data.put("del_user_list", usersToDelete); + } + internalService.post("https://qyapi.weixin.qq.com/cgi-bin/appchat/update", WxGsonBuilder.create().toJson(data)); + } + + @Override + public WxCpChat chatGet(String chatId) throws WxErrorException { + String result = internalService.get("https://qyapi.weixin.qq.com/cgi-bin/appchat/get?chatid=" + chatId, null); + return WxCpGsonBuilder.create().fromJson( + new JsonParser().parse(result).getAsJsonObject().getAsJsonObject("chat_info").toString(), WxCpChat.class); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java index 5d623b2ad4..481115fa51 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java @@ -28,11 +28,11 @@ public WxCpDepartmentServiceImpl(WxCpService mainService) { } @Override - public Integer create(WxCpDepart depart) throws WxErrorException { + public Long create(WxCpDepart depart) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create"; String responseContent = this.mainService.post(url, depart.toJson()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); - return GsonHelper.getAsInteger(tmpJsonElement.getAsJsonObject().get("id")); + return GsonHelper.getAsLong(tmpJsonElement.getAsJsonObject().get("id")); } @Override diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java index c3dc477495..7a3dc444cf 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java @@ -48,6 +48,14 @@ public File download(String mediaId) throws WxErrorException { MEDIA_GET_URL, "media_id=" + mediaId); } + @Override + public File getJssdkFile(String mediaId) throws WxErrorException { + return this.mainService.execute( + BaseMediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(), + this.mainService.getWxCpConfigStorage().getTmpDirFile()), + JSSDK_MEDIA_GET_URL, "media_id=" + mediaId); + } + @Override public String uploadImg(File file) throws WxErrorException { final WxMediaUploadResult result = this.mainService diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java index 0c66e0ef77..f0c15109b9 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceAbstractImpl.java @@ -1,9 +1,16 @@ package me.chanjar.weixin.cp.api.impl; +import java.io.File; +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; + import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; @@ -17,19 +24,24 @@ import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; -import me.chanjar.weixin.cp.api.*; -import me.chanjar.weixin.cp.bean.*; +import me.chanjar.weixin.cp.api.WxCpAgentService; +import me.chanjar.weixin.cp.api.WxCpChatService; +import me.chanjar.weixin.cp.api.WxCpDepartmentService; +import me.chanjar.weixin.cp.api.WxCpMediaService; +import me.chanjar.weixin.cp.api.WxCpMenuService; +import me.chanjar.weixin.cp.api.WxCpOAuth2Service; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.api.WxCpTagService; +import me.chanjar.weixin.cp.api.WxCpUserService; +import me.chanjar.weixin.cp.bean.WxCpMessage; +import me.chanjar.weixin.cp.bean.WxCpMessageSendResult; import me.chanjar.weixin.cp.config.WxCpConfigStorage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; public abstract class WxCpServiceAbstractImpl implements WxCpService, RequestHttp { protected final Logger log = LoggerFactory.getLogger(this.getClass()); private WxCpUserService userService = new WxCpUserServiceImpl(this); + private WxCpChatService chatService = new WxCpChatServiceImpl(this); private WxCpDepartmentService departmentService = new WxCpDepartmentServiceImpl(this); private WxCpMediaService mediaService = new WxCpMediaServiceImpl(this); private WxCpMenuService menuService = new WxCpMenuServiceImpl(this); @@ -184,7 +196,7 @@ public T execute(RequestExecutor executor, String uri, E data) thro this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); Thread.sleep(sleepMillis); } catch (InterruptedException e1) { - throw new RuntimeException(e1); + Thread.currentThread().interrupt(); } } else { throw e; @@ -334,7 +346,12 @@ public WxCpUserService getUserService() { } @Override - public RequestHttp getRequestHttp() { + public WxCpChatService getChatService() { + return chatService; + } + + @Override + public RequestHttp, ?> getRequestHttp() { return this; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java index 4f6990cc18..84a16f3496 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImpl.java @@ -76,7 +76,7 @@ public WxCpUser getById(String userid) throws WxErrorException { } @Override - public List listByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { + public List listByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId; String params = ""; if (fetchChild != null) { @@ -98,7 +98,7 @@ public List listByDepartment(Integer departId, Boolean fetchChild, Int } @Override - public List listSimpleByDepartment(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { + public List listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; String params = ""; if (fetchChild != null) { diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpChat.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpChat.java new file mode 100644 index 0000000000..1f593e4746 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpChat.java @@ -0,0 +1,20 @@ +package me.chanjar.weixin.cp.bean; + +import java.util.List; + +import lombok.Data; + +/** + * 群聊 + * + * @author gaigeshen + */ +@Data +public class WxCpChat { + + private String id; + private String name; + private String owner; + private List users; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java index cab4970b18..90d67b07bc 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java @@ -3,8 +3,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.Serializable; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.apache.commons.io.IOUtils; @@ -13,6 +15,7 @@ import lombok.Data; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.util.XmlUtils; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; import me.chanjar.weixin.cp.config.WxCpConfigStorage; import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; @@ -35,6 +38,11 @@ public class WxCpXmlMessage implements Serializable { private static final long serialVersionUID = -1042994982179476410L; + /** + * 使用dom4j解析的存放所有xml属性和值的map. + */ + private Map allFieldsMap; + /////////////////////// // 以下都是微信推送过来的消息的xml的element所对应的属性 /////////////////////// @@ -348,7 +356,9 @@ public class WxCpXmlMessage implements Serializable { protected static WxCpXmlMessage fromXml(String xml) { //修改微信变态的消息内容格式,方便解析 xml = xml.replace(" ", ""); - return XStreamTransformer.fromXml(WxCpXmlMessage.class, xml); + final WxCpXmlMessage xmlMessage = XStreamTransformer.fromXml(WxCpXmlMessage.class, xml); + xmlMessage.setAllFieldsMap(XmlUtils.xml2Map(xml)); + return xmlMessage; } protected static WxCpXmlMessage fromXml(InputStream is) { @@ -369,7 +379,7 @@ public static WxCpXmlMessage fromEncryptedXml(String encryptedXml, WxCpConfigSto public static WxCpXmlMessage fromEncryptedXml(InputStream is, WxCpConfigStorage wxCpConfigStorage, String timestamp, String nonce, String msgSignature) { try { - return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxCpConfigStorage, timestamp, nonce, msgSignature); + return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8), wxCpConfigStorage, timestamp, nonce, msgSignature); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java index 99e4fd4573..6b778be66c 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java @@ -1,5 +1,18 @@ package me.chanjar.weixin.cp.message; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import me.chanjar.weixin.common.api.WxErrorExceptionHandler; import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; @@ -11,18 +24,6 @@ import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; /** * @@ -195,6 +196,7 @@ public void run() { sessionEndAccess(wxMessage); } catch (InterruptedException e) { WxCpMessageRouter.this.log.error("Error happened when wait task finish", e); + Thread.currentThread().interrupt(); } catch (ExecutionException e) { WxCpMessageRouter.this.log.error("Error happened when wait task finish", e); } @@ -207,12 +209,11 @@ public void run() { /** - * 处理微信消息 + * 处理微信消息. * - * @param wxMessage */ public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) { - return this.route(wxMessage, new HashMap()); + return this.route(wxMessage, new HashMap (2)); } protected boolean isDuplicateMessage(WxCpXmlMessage wxMessage) { diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java new file mode 100644 index 0000000000..0e97181a3a --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java @@ -0,0 +1,77 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.cp.util.json; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.cp.bean.WxCpChat; + +/** + * 群聊适配器 + * + * @author gaigeshen + */ +public class WxCpChatGsonAdapter implements JsonSerializer , JsonDeserializer { + + @Override + public JsonElement serialize(WxCpChat chat, Type typeOfSrc, JsonSerializationContext context) { + JsonObject json = new JsonObject(); + if (chat.getId() != null) { + json.addProperty("chatid", chat.getId()); + } + if (chat.getName() != null) { + json.addProperty("name", chat.getName()); + } + if (chat.getOwner() != null) { + json.addProperty("owner", chat.getOwner()); + } + if (chat.getUsers() != null) { + JsonArray users = new JsonArray(); + for (String user : chat.getUsers()) { + users.add(user); + } + json.add("userlist", users); + } + return json; + } + + @Override + public WxCpChat deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject chatJson = json.getAsJsonObject(); + + WxCpChat chat = new WxCpChat(); + chat.setId(GsonHelper.getAsString(chatJson.get("chatid"))); + chat.setName(GsonHelper.getAsString(chatJson.get("name"))); + chat.setOwner(GsonHelper.getAsString(chatJson.get("owner"))); + + JsonArray usersJson = chatJson.getAsJsonArray("userlist"); + if (usersJson != null) { + List users = new ArrayList<>(usersJson.size()); + chat.setUsers(users); + for (JsonElement userJson : usersJson) { + users.add(userJson.getAsString()); + } + } + + return chat; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java index 6ff49bf0a0..654d55111b 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java @@ -5,6 +5,7 @@ import me.chanjar.weixin.common.bean.menu.WxMenu; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.util.json.WxErrorAdapter; +import me.chanjar.weixin.cp.bean.WxCpChat; import me.chanjar.weixin.cp.bean.WxCpDepart; import me.chanjar.weixin.cp.bean.WxCpMessage; import me.chanjar.weixin.cp.bean.WxCpTag; @@ -20,6 +21,7 @@ public class WxCpGsonBuilder { static { INSTANCE.disableHtmlEscaping(); INSTANCE.registerTypeAdapter(WxCpMessage.class, new WxCpMessageGsonAdapter()); + INSTANCE.registerTypeAdapter(WxCpChat.class, new WxCpChatGsonAdapter()); INSTANCE.registerTypeAdapter(WxCpDepart.class, new WxCpDepartGsonAdapter()); INSTANCE.registerTypeAdapter(WxCpUser.class, new WxCpUserGsonAdapter()); INSTANCE.registerTypeAdapter(WxError.class, new WxErrorAdapter()); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java new file mode 100644 index 0000000000..8317a45ebb --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java @@ -0,0 +1,46 @@ +package me.chanjar.weixin.cp.api.impl; + +import java.util.Arrays; + +import me.chanjar.weixin.cp.bean.WxCpChat; +import org.testng.Assert; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import com.google.inject.Inject; + +import me.chanjar.weixin.cp.api.ApiTestModule; +import me.chanjar.weixin.cp.api.WxCpService; + +/** + * 测试群聊服务 + * + * @author gaigeshen + */ +@Guice(modules = ApiTestModule.class) +public class WxCpChatServiceImplTest { + + @Inject + private WxCpService wxCpService; + + @Test + public void create() throws Exception { + wxCpService.getChatService().chatCreate("测试群聊", "gaige_shen", Arrays.asList("gaige_shen", "ZhangXiaoMing"), "mychatid"); + } + + @Test + public void get() throws Exception { + WxCpChat chat = wxCpService.getChatService().chatGet("mychatid"); + System.out.println(chat); + Assert.assertEquals(chat.getName(), "测试群聊"); + } + + @Test + public void update() throws Exception { + wxCpService.getChatService().chatUpdate("mychatid", "", "", Arrays.asList("ZhengWuYao"), null); + WxCpChat chat = wxCpService.getChatService().chatGet("mychatid"); + System.out.println(chat); + Assert.assertEquals(chat.getUsers().size(), 3); + } + +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImplTest.java index 097a6ee71f..57957d3fb6 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImplTest.java @@ -31,7 +31,7 @@ public void testCreate() throws Exception { cpDepart.setName("子部门" + System.currentTimeMillis()); cpDepart.setParentId(1L); cpDepart.setOrder(1L); - Integer departId = this.wxCpService.getDepartmentService().create(cpDepart); + Long departId = this.wxCpService.getDepartmentService().create(cpDepart); System.out.println(departId); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java index d7242a7703..70873c49cf 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java @@ -36,7 +36,8 @@ public class WxCpMediaServiceImplTest { public Object[][] mediaData() { return new Object[][]{ new Object[]{WxConsts.MediaFileType.IMAGE, TestConstants.FILE_JPG, "mm.jpeg"}, - new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_MP3, "mm.mp3"},//{"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"} + //new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_MP3, "mm.mp3"}, + // {"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"} new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_AMR, "mm.amr"}, new Object[]{WxConsts.MediaFileType.VIDEO, TestConstants.FILE_MP4, "mm.mp4"}, new Object[]{WxConsts.MediaFileType.FILE, TestConstants.FILE_JPG, "mm.jpeg"} @@ -47,8 +48,9 @@ public Object[][] mediaData() { public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName)) { WxMediaUploadResult res = this.wxService.getMediaService().upload(mediaType, fileType, inputStream); - assertNotNull(res.getType()); - assertNotNull(res.getCreatedAt()); + assertThat(res).isNotNull(); + assertThat(res.getType()).isNotEmpty(); + assertThat(res.getCreatedAt()).isGreaterThan(0); assertTrue(res.getMediaId() != null || res.getThumbMediaId() != null); if (res.getMediaId() != null) { @@ -70,9 +72,9 @@ public Object[][] downloadMedia() { } @Test(dependsOnMethods = {"testUploadMedia"}, dataProvider = "downloadMedia") - public void testDownloadMedia(String media_id) throws WxErrorException { - File file = this.wxService.getMediaService().download(media_id); - assertNotNull(file); + public void testDownload(String mediaId) throws WxErrorException { + File file = this.wxService.getMediaService().download(mediaId); + assertThat(file).isNotNull(); System.out.println(file); } @@ -82,4 +84,11 @@ public void testUploadImg() throws WxErrorException { String res = this.wxService.getMediaService().uploadImg(new File(url.getFile())); assertThat(res).isNotEmpty(); } + + @Test + public void testGetJssdkFile() throws WxErrorException { + File file = this.wxService.getMediaService().getJssdkFile("...."); + assertThat(file).isNotNull(); + System.out.println(file); + } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java index 6b67112095..f473fe6be7 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java @@ -74,7 +74,7 @@ public void testGetById() throws Exception { @Test public void testListByDepartment() throws Exception { - List users = this.wxCpService.getUserService().listByDepartment(1, true, 0); + List users = this.wxCpService.getUserService().listByDepartment(1L, true, 0); assertNotEquals(users.size(), 0); for (WxCpUser user : users) { System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE)); @@ -83,7 +83,7 @@ public void testListByDepartment() throws Exception { @Test public void testListSimpleByDepartment() throws Exception { - List users = this.wxCpService.getUserService().listSimpleByDepartment(1, true, 0); + List users = this.wxCpService.getUserService().listSimpleByDepartment(1L, true, 0); assertNotEquals(users.size(), 0); for (WxCpUser user : users) { System.out.println(ToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE)); diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index b8e8d51056..7c0b2ce85c 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -6,11 +6,11 @@ 4.0.0 com.github.binarywang -weixin-java-parent -3.2.4.B +wx-java +3.3.1.B weixin-java-miniapp -Weixin Java Tools - MiniApp +WxJava - MiniApp 微信小程序Java SDK diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java index 2903737486..f2c9e8f1dc 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaQrcodeService.java @@ -1,10 +1,10 @@ package cn.binarywang.wx.miniapp.api; +import java.io.File; + import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor; import me.chanjar.weixin.common.error.WxErrorException; -import java.io.File; - /** * * 二维码相关操作接口. @@ -32,24 +32,87 @@ public interface WxMaQrcodeService { * * @param path 不能为空,最大长度 128 字节 * @param width 默认430 二维码的宽度 + * @return 文件内容字节数组 + * @throws WxErrorException 异常 + */ + byte[] createQrcodeBytes(String path, int width) throws WxErrorException; + + /** + * 接口C: 获取小程序页面二维码. + ** - * @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) + * @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~, + * 其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) + * @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面 + * @param width 默认false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 + * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 + * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} + * @param isHyaline 是否需要透明底色, is_hyaline 为true时,生成透明底色的小程序码 + * @return 文件内容字节数组 + * @throws WxErrorException 异常 + */ + byte[] createWxaCodeUnlimitBytes(String scene, String page, int width, boolean autoColor, + WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException; + + /** + * 接口B: 获取小程序码(永久有效、数量暂无限制). + *+ * 适用于需要的码数量较少的业务场景 + * 通过该接口,仅能生成已发布的小程序的二维码。 + * 可以在开发者工具预览时生成开发版的带参二维码。 + * 带参二维码只有 100000 个,请谨慎调用。 + *+ * + * @param path 不能为空,最大长度 128 字节 + * @param width 默认430 二维码的宽度 + * @return 文件对象 + * @throws WxErrorException 异常 */ File createQrcode(String path, int width) throws WxErrorException; + /** + * 接口C: 获取小程序页面二维码. + *+ * 适用于需要的码数量较少的业务场景 + * 通过该接口,仅能生成已发布的小程序的二维码。 + * 可以在开发者工具预览时生成开发版的带参二维码。 + * 带参二维码只有 100000 个,请谨慎调用。 + *+ * + * @param path 不能为空,最大长度 128 字节 + * @return 文件对象 + * @throws WxErrorException 异常 + */ File createQrcode(String path) throws WxErrorException; /** * 接口A: 获取小程序码. * - * @param path 不能为空,最大长度 128 字节 - * @param width 默认430 二维码的宽度 - * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 - * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} - * @param is_hyaline 是否需要透明底色, is_hyaline 为true时,生成透明底色的小程序码 + * @param path 不能为空,最大长度 128 字节 + * @param width 默认430 二维码的宽度 + * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 + * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} + * @param isHyaline 是否需要透明底色, isHyaline 为true时,生成透明底色的小程序码 + * @return 文件内容字节数组 + * @throws WxErrorException 异常 + */ + byte[] createWxaCodeBytes(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) + throws WxErrorException; + + /** + * 接口A: 获取小程序码. + * + * @param path 不能为空,最大长度 128 字节 + * @param width 默认430 二维码的宽度 + * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 + * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} + * @param isHyaline 是否需要透明底色, isHyaline 为true时,生成透明底色的小程序码 + * @return 文件对象 + * @throws WxErrorException 异常 */ - File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean is_hyaline) throws WxErrorException; + File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) + throws WxErrorException; + /** + * 接口A: 获取小程序码. + * + * @param path 不能为空,最大长度 128 字节 + * @param width 默认430 二维码的宽度 + * @return 文件对象 + * @throws WxErrorException 异常 + */ File createWxaCode(String path, int width) throws WxErrorException; + /** + * 接口A: 获取小程序码. + * + * @param path 不能为空,最大长度 128 字节 + * @return 文件对象 + * @throws WxErrorException 异常 + */ File createWxaCode(String path) throws WxErrorException; /** @@ -61,15 +124,56 @@ public interface WxMaQrcodeService { * 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode *+ * 通过该接口生成的小程序码,永久有效,数量暂无限制。 + * 用户扫描该码进入小程序后,将统一打开首页,开发者需在对应页面根据获取的码中 scene 字段的值,再做处理逻辑。 + * 使用如下代码可以获取到二维码中的 scene 字段的值。 + * 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode + *+ * + * @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~, + * 其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) * @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面 * @param width 默认false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 * @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 * @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} * @param isHyaline 是否需要透明底色, is_hyaline 为true时,生成透明底色的小程序码 + * @return 文件对象 + * @throws WxErrorException 异常 */ - File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException; + File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, + WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException; + /** + * 接口B: 获取小程序码(永久有效、数量暂无限制). + *+ * 通过该接口生成的小程序码,永久有效,数量暂无限制。 + * 用户扫描该码进入小程序后,将统一打开首页,开发者需在对应页面根据获取的码中 scene 字段的值,再做处理逻辑。 + * 使用如下代码可以获取到二维码中的 scene 字段的值。 + * 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode + *+ * + * @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~, + * 其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) + * @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面 + * @return 文件对象 + * @throws WxErrorException 异常 + */ File createWxaCodeUnlimit(String scene, String page) throws WxErrorException; } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaSecCheckService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaSecCheckService.java new file mode 100644 index 0000000000..842d0662fe --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaSecCheckService.java @@ -0,0 +1,43 @@ +package cn.binarywang.wx.miniapp.api; + +import java.io.File; + +import me.chanjar.weixin.common.error.WxErrorException; + +/** + *+ * 内容安全相关接口. + * Created by Binary Wang on 2018/11/24. + *+ * + * @author Binary Wang + */ +public interface WxMaSecCheckService { + + String IMG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/img_sec_check"; + + String MSG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/msg_sec_check"; + + /** + *+ * 校验一张图片是否含有违法违规内容. + * 应用场景举例: + * 1)图片智能鉴黄:涉及拍照的工具类应用(如美拍,识图类应用)用户拍照上传检测;电商类商品上架图片检测;媒体类用户文章里的图片检测等; + * 2)敏感人脸识别:用户头像;媒体类用户文章里的图片检测;社交类用户上传的图片检测等。频率限制:单个 appId 调用上限为 1000 次/分钟,100,000 次/天 + * 详情请见: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/sec-check/imgSecCheck.html + *+ */ + boolean checkImage(File file) throws WxErrorException; + + /** + *+ * 检查一段文本是否含有违法违规内容。 + * 应用场景举例: + * 用户个人资料违规文字检测; + * 媒体新闻类用户发表文章,评论内容检测; + * 游戏类用户编辑上传的素材(如答题类小游戏用户上传的问题及答案)检测等。 频率限制:单个 appId 调用上限为 4000 次/分钟,2,000,000 次/天* + * 详情请见: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/sec-check/msgSecCheck.html + *+ */ + boolean checkMessage(String msgString); +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java index 8d5fbc3c2b..efa53939a8 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java @@ -1,7 +1,5 @@ package cn.binarywang.wx.miniapp.api; -import java.io.File; - import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import cn.binarywang.wx.miniapp.config.WxMaConfig; import me.chanjar.weixin.common.error.WxErrorException; @@ -20,17 +18,6 @@ public interface WxMaService { String JSCODE_TO_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session"; - String IMG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/img_sec_check"; - - /** - *- * 校验一张图片是否含有违法违规内容. - * 应用场景举例:1)图片智能鉴黄:涉及拍照的工具类应用(如美拍,识图类应用)用户拍照上传检测;电商类商品上架图片检测;媒体类用户文章里的图片检测等;2)敏感人脸识别:用户头像;媒体类用户文章里的图片检测;社交类用户上传的图片检测等。频率限制:单个 appId 调用上限为 1000 次/分钟,100,000 次/天 - * 详情请见: https://developers.weixin.qq.com/miniprogram/dev/api/imgSecCheck.html - *- */ - boolean imgSecCheck(File file) throws WxErrorException; - /** * 获取登录后的session信息. * @@ -186,11 +173,17 @@ public interface WxMaService { WxMaShareService getShareService(); /** - * 返回维新运动相关接口服务对象. + * 返回微信运动相关接口服务对象. * @return WxMaShareService */ WxMaRunService getRunService(); + /** + * 返回内容安全相关接口服务对象. + * @return WxMaShareService + */ + WxMaSecCheckService getSecCheckService(); + /** * 初始化http请求对象. */ diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java index 277418e752..8e7d6b170b 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImpl.java @@ -1,16 +1,17 @@ package cn.binarywang.wx.miniapp.api.impl; +import java.io.File; + import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor; import cn.binarywang.wx.miniapp.bean.WxMaQrcode; -import cn.binarywang.wx.miniapp.bean.WxMaWxcode; +import cn.binarywang.wx.miniapp.bean.WxaCode; import cn.binarywang.wx.miniapp.bean.WxaCodeUnlimit; -import cn.binarywang.wx.miniapp.util.http.QrCodeRequestExecutor; +import cn.binarywang.wx.miniapp.util.QrcodeBytesRequestExecutor; +import cn.binarywang.wx.miniapp.util.QrcodeRequestExecutor; import me.chanjar.weixin.common.error.WxErrorException; -import java.io.File; - /** * @author Binary Wang */ @@ -21,10 +22,16 @@ public WxMaQrcodeServiceImpl(WxMaService wxMaService) { this.wxMaService = wxMaService; } + @Override + public byte[] createQrcodeBytes(String path, int width) throws WxErrorException { + final QrcodeBytesRequestExecutor executor = new QrcodeBytesRequestExecutor(this.wxMaService.getRequestHttp()); + return this.wxMaService.execute(executor, CREATE_QRCODE_URL, new WxMaQrcode(path, width)); + } + @Override public File createQrcode(String path, int width) throws WxErrorException { - return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), - CREATE_QRCODE_URL, new WxMaQrcode(path, width)); + final QrcodeRequestExecutor executor = new QrcodeRequestExecutor(this.wxMaService.getRequestHttp()); + return this.wxMaService.execute(executor, CREATE_QRCODE_URL, new WxMaQrcode(path, width)); } @Override @@ -33,15 +40,29 @@ public File createQrcode(String path) throws WxErrorException { } @Override - public File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException { - WxMaWxcode wxMaWxcode = new WxMaWxcode(); - wxMaWxcode.setPath(path); - wxMaWxcode.setWidth(width); - wxMaWxcode.setAutoColor(autoColor); - wxMaWxcode.setLineColor(lineColor); - wxMaWxcode.setHyaline(isHyaline); - return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), - GET_WXACODE_URL, wxMaWxcode); + public byte[] createWxaCodeBytes(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) + throws WxErrorException { + final QrcodeBytesRequestExecutor executor = new QrcodeBytesRequestExecutor(this.wxMaService.getRequestHttp()); + return this.wxMaService.execute(executor, GET_WXACODE_URL, WxaCode.builder() + .path(path) + .width(width) + .autoColor(autoColor) + .lineColor(lineColor) + .isHyaline(isHyaline) + .build()); + } + + @Override + public File createWxaCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) + throws WxErrorException { + final QrcodeRequestExecutor executor = new QrcodeRequestExecutor(this.wxMaService.getRequestHttp()); + return this.wxMaService.execute(executor, GET_WXACODE_URL, WxaCode.builder() + .path(path) + .width(width) + .autoColor(autoColor) + .lineColor(lineColor) + .isHyaline(isHyaline) + .build()); } @Override @@ -51,12 +72,27 @@ public File createWxaCode(String path, int width) throws WxErrorException { @Override public File createWxaCode(String path) throws WxErrorException { - return this.createWxaCode(path, 430, true, null, false); + return this.createWxaCode(path, 430); } @Override - public File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, WxMaCodeLineColor lineColor, boolean isHyaline) - throws WxErrorException { + public byte[] createWxaCodeUnlimitBytes(String scene, String page, int width, boolean autoColor, + WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException { + return this.wxMaService.execute(new QrcodeBytesRequestExecutor(this.wxMaService.getRequestHttp()), + GET_WXACODE_UNLIMIT_URL, + this.buildWxaCodeUnlimit(scene, page, width, autoColor, lineColor, isHyaline)); + } + + @Override + public File createWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, + WxMaCodeLineColor lineColor, boolean isHyaline) throws WxErrorException { + return this.wxMaService.execute(new QrcodeRequestExecutor(this.wxMaService.getRequestHttp()), + GET_WXACODE_UNLIMIT_URL, + this.buildWxaCodeUnlimit(scene, page, width, autoColor, lineColor, isHyaline)); + } + + private WxaCodeUnlimit buildWxaCodeUnlimit(String scene, String page, int width, boolean autoColor, + WxMaCodeLineColor lineColor, boolean isHyaline) { WxaCodeUnlimit wxaCodeUnlimit = new WxaCodeUnlimit(); wxaCodeUnlimit.setScene(scene); wxaCodeUnlimit.setPage(page); @@ -64,8 +100,8 @@ public File createWxaCodeUnlimit(String scene, String page, int width, boolean a wxaCodeUnlimit.setAutoColor(autoColor); wxaCodeUnlimit.setLineColor(lineColor); wxaCodeUnlimit.setHyaline(isHyaline); - return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), - GET_WXACODE_UNLIMIT_URL, wxaCodeUnlimit); + + return wxaCodeUnlimit; } @Override diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImpl.java new file mode 100644 index 0000000000..1dab0a82bb --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImpl.java @@ -0,0 +1,48 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import java.io.File; + +import cn.binarywang.wx.miniapp.api.WxMaSecCheckService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import com.google.gson.JsonObject; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; + +/** + *+ * + * Created by Binary Wang on 2018/11/24. + *+ * + * @author Binary Wang + */ +public class WxMaSecCheckServiceImpl implements WxMaSecCheckService { + private WxMaService service; + + public WxMaSecCheckServiceImpl(WxMaService service) { + this.service = service; + } + + @Override + public boolean checkImage(File file) throws WxErrorException { + //这里只是借用MediaUploadRequestExecutor,并不使用其返回值WxMediaUploadResult + WxMediaUploadResult result = this.service.execute(MediaUploadRequestExecutor + .create(this.service.getRequestHttp()), IMG_SEC_CHECK_URL, file); + return result != null; + } + + @Override + public boolean checkMessage(String msgString) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("content", msgString); + try { + this.service.post(MSG_SEC_CHECK_URL, jsonObject.toString()); + } catch (WxErrorException e) { + return false; + } + + return true; + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java index 82265b9bfc..280a052e4a 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImpl.java @@ -1,6 +1,5 @@ package cn.binarywang.wx.miniapp.api.impl; -import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -12,8 +11,6 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.CloseableHttpClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import cn.binarywang.wx.miniapp.api.WxMaAnalysisService; import cn.binarywang.wx.miniapp.api.WxMaCodeService; @@ -22,6 +19,7 @@ import cn.binarywang.wx.miniapp.api.WxMaMsgService; import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; import cn.binarywang.wx.miniapp.api.WxMaRunService; +import cn.binarywang.wx.miniapp.api.WxMaSecCheckService; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.api.WxMaSettingService; import cn.binarywang.wx.miniapp.api.WxMaShareService; @@ -31,14 +29,13 @@ import cn.binarywang.wx.miniapp.config.WxMaConfig; import com.google.common.base.Joiner; import com.google.gson.Gson; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.DataUtils; import me.chanjar.weixin.common.util.crypto.SHA1; import me.chanjar.weixin.common.util.http.HttpType; -import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; @@ -51,9 +48,8 @@ /** * @author Binary Wang */ +@Slf4j public class WxMaServiceImpl implements WxMaService, RequestHttp{ - private final Logger log = LoggerFactory.getLogger(this.getClass()); - private CloseableHttpClient httpClient; private HttpHost httpProxy; private WxMaConfig wxMaConfig; @@ -69,6 +65,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp T execute(RequestExecutor executor, String uri, E data) thro return this.executeInternal(executor, uri, data); } catch (WxErrorException e) { if (retryTimes + 1 > this.maxRetryTimes) { - this.log.warn("重试达到最大次数【{}】", maxRetryTimes); + log.warn("重试达到最大次数【{}】", maxRetryTimes); //最后一次重试失败后,直接抛出异常,不再等待 throw new RuntimeException("微信服务端异常,超出重试次数"); } @@ -219,10 +209,10 @@ public T execute(RequestExecutor executor, String uri, E data) thro if (error.getErrorCode() == -1) { int sleepMillis = this.retrySleepMillis * (1 << retryTimes); try { - this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); + log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); Thread.sleep(sleepMillis); } catch (InterruptedException e1) { - throw new RuntimeException(e1); + Thread.currentThread().interrupt(); } } else { throw e; @@ -230,7 +220,7 @@ public T execute(RequestExecutor executor, String uri, E data) thro } } while (retryTimes++ < this.maxRetryTimes); - this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + log.warn("重试达到最大次数【{}】", this.maxRetryTimes); throw new RuntimeException("微信服务端异常,超出重试次数"); } @@ -246,7 +236,7 @@ private T executeInternal(RequestExecutor executor, String uri, E d try { T result = executor.execute(uriWithAccessToken, data); - this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result); + log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result); return result; } catch (WxErrorException e) { WxError error = e.getError(); @@ -264,12 +254,12 @@ private T executeInternal(RequestExecutor executor, String uri, E d } if (error.getErrorCode() != 0) { - this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error); + log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error); throw new WxErrorException(error, e); } return null; } catch (IOException e) { - this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage()); + log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage()); throw new RuntimeException(e); } } @@ -349,4 +339,9 @@ public WxMaShareService getShareService() { public WxMaRunService getRunService() { return this.runService; } + + @Override + public WxMaSecCheckService getSecCheckService() { + return this.secCheckService; + } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcode.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxaCode.java similarity index 62% rename from weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcode.java rename to weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxaCode.java index e538a1bb83..2d94f05cea 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaWxcode.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxaCode.java @@ -1,36 +1,48 @@ package cn.binarywang.wx.miniapp.bean; +import java.io.Serializable; + import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; - -import java.io.Serializable; +import lombok.NoArgsConstructor; /** + * 小程序码. * * @author Element * @date 2017/7/27 */ @Data @EqualsAndHashCode(callSuper = false) -public class WxMaWxcode extends AbstractWxMaQrcodeWrapper implements Serializable { +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxaCode extends AbstractWxMaQrcodeWrapper implements Serializable { private static final long serialVersionUID = 1287399621649210322L; private String path; + + @Builder.Default private int width = 430; @SerializedName("auto_color") + @Builder.Default private boolean autoColor = true; @SerializedName("is_hyaline") + @Builder.Default private boolean isHyaline = false; @SerializedName("line_color") + @Builder.Default private WxMaCodeLineColor lineColor = new WxMaCodeLineColor("0", "0", "0"); - public static WxMaWxcode fromJson(String json) { - return WxMaGsonBuilder.create().fromJson(json, WxMaWxcode.class); + public static WxaCode fromJson(String json) { + return WxMaGsonBuilder.create().fromJson(json, WxaCode.class); } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java index 9a26890d27..49a80cc423 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java @@ -1,10 +1,10 @@ package cn.binarywang.wx.miniapp.config; +import java.util.concurrent.locks.Lock; + import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; -import java.util.concurrent.locks.Lock; - /** * 小程序配置 * @@ -57,6 +57,9 @@ public interface WxMaConfig { */ void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); + /** + * 卡券api_ticket. + */ String getCardApiTicket(); Lock getCardApiTicketLock(); @@ -64,14 +67,14 @@ public interface WxMaConfig { boolean isCardApiTicketExpired(); /** - * 强制将卡券api ticket过期掉 + * 强制将卡券api ticket过期掉. */ void expireCardApiTicket(); /** - * 应该是线程安全的 + * 应该是线程安全的. * - * @param 卡券apiTicket 新的卡券api ticket值 + * @param apiTicket 新的卡券api ticket值 * @param expiresInSeconds 过期时间,以秒为单位 */ void updateCardApiTicket(String apiTicket, int expiresInSeconds); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeBytesRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeBytesRequestExecutor.java new file mode 100644 index 0000000000..5421aea316 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeBytesRequestExecutor.java @@ -0,0 +1,66 @@ +package cn.binarywang.wx.miniapp.util; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; + +import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; + +/** + * @author Binary Wang + */ +public class QrcodeBytesRequestExecutor implements RequestExecutor { + protected RequestHttp requestHttp; + + public QrcodeBytesRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } + + @Override + public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + + @Override + public byte[] execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + httpPost.setConfig( + RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build() + ); + } + + httpPost.setEntity(new StringEntity(qrcodeWrapper.toJson())); + + try (final CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); + final InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) { + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0 + && ContentType.APPLICATION_JSON.getMimeType() + .equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + + return IOUtils.toByteArray(inputStream); + } finally { + httpPost.releaseConnection(); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeRequestExecutor.java similarity index 71% rename from weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java rename to weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeRequestExecutor.java index cb8097db53..672f97a0b4 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/http/QrCodeRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/QrcodeRequestExecutor.java @@ -1,13 +1,10 @@ -package cn.binarywang.wx.miniapp.util.http; +package cn.binarywang.wx.miniapp.util; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; -import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper; -import me.chanjar.weixin.common.error.WxError; -import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.common.util.fs.FileUtils; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; -import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; import org.apache.http.Header; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -17,33 +14,44 @@ import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.UUID; +import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; /** * @author Binary Wang */ -public class QrCodeRequestExecutor implements RequestExecutor { +public class QrcodeRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; - public QrCodeRequestExecutor(RequestHttp requestHttp) { + public QrcodeRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } @Override - public File execute(String uri, AbstractWxMaQrcodeWrapper ticket) throws WxErrorException, IOException { + public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + + @Override + public File execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper) throws WxErrorException, IOException { HttpPost httpPost = new HttpPost(uri); if (requestHttp.getRequestHttpProxy() != null) { httpPost.setConfig( RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build() ); } - httpPost.setEntity(new StringEntity(ticket.toJson())); - try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); - InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { + httpPost.setEntity(new StringEntity(qrcodeWrapper.toJson())); + + try (final CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); + final InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) { Header[] contentTypeHeader = response.getHeaders("Content-Type"); if (contentTypeHeader != null && contentTypeHeader.length > 0 && ContentType.APPLICATION_JSON.getMimeType() diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java index ae2e8d8fed..e73fec4270 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaQrcodeServiceImplTest.java @@ -7,6 +7,9 @@ import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.test.ApiTestModule; import com.google.inject.Inject; +import me.chanjar.weixin.common.error.WxErrorException; + +import static org.assertj.core.api.Assertions.assertThat; /** * @author Binary Wang @@ -18,21 +21,38 @@ public class WxMaQrcodeServiceImplTest { private WxMaService wxService; @Test - public void testCreateQrCode() throws Exception { + public void testCreateQrcode() throws Exception { final File qrCode = this.wxService.getQrcodeService().createQrcode("111", 122); - System.out.println(qrCode); + assertThat(qrCode).isNotNull(); } @Test public void testCreateWxaCode() throws Exception { final File wxCode = this.wxService.getQrcodeService().createWxaCode("111", 122); - System.out.println(wxCode); + assertThat(wxCode).isNotNull(); } @Test public void testCreateWxaCodeUnlimit() throws Exception { final File wxCode = this.wxService.getQrcodeService().createWxaCodeUnlimit("111", null); - System.out.println(wxCode); + assertThat(wxCode).isNotNull(); } + @Test + public void testCreateQrcodeBytes() throws WxErrorException { + final byte[] qrCode = this.wxService.getQrcodeService().createQrcodeBytes("111", 122); + assertThat(qrCode).isNotNull(); + } + + @Test + public void testCreateWxaCodeBytes() throws WxErrorException { + final byte[] wxCode = this.wxService.getQrcodeService().createWxaCodeBytes("111", 122, true, null, false); + assertThat(wxCode).isNotNull(); + } + + @Test + public void testCreateWxaCodeUnlimitBytes() throws WxErrorException { + final byte[] wxCode = this.wxService.getQrcodeService().createWxaCodeUnlimitBytes("111", null, 122, true, null, false); + assertThat(wxCode).isNotNull(); + } } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImplTest.java new file mode 100644 index 0000000000..df9ccaa823 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaSecCheckServiceImplTest.java @@ -0,0 +1,51 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import java.io.File; + +import org.testng.annotations.*; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import me.chanjar.weixin.common.error.WxErrorException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.testng.Assert.*; + +/** + * + * + * Created by Binary Wang on 2018/11/24. + *+ * + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaSecCheckServiceImplTest { + @Inject + private WxMaService wxService; + + @Test + public void testCheckImage() throws WxErrorException { + boolean result = this.wxService.getSecCheckService() + .checkImage(new File(ClassLoader.getSystemResource("tmp.png").getFile())); + assertTrue(result); + } + + @DataProvider + public Object[][] secData() { + return new Object[][]{ + {"特3456书yuuo莞6543李zxcz蒜7782法fgnv级", false}, + {"完2347全dfji试3726测asad感3847知qwez到", false}, + {"hello world!", true} + }; + } + + @Test(dataProvider = "secData") + public void testCheckMessage(String msg, boolean result) { + assertThat(this.wxService.getSecCheckService() + .checkMessage(msg)) + .isEqualTo(result); + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java index dcefc68c72..1f87c7e4ee 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java @@ -33,9 +33,4 @@ public void testRefreshAccessToken() throws WxErrorException { assertTrue(StringUtils.isNotBlank(after)); } - @Test - public void testImgSecCheck() throws WxErrorException { - boolean result = this.wxService.imgSecCheck(new File(ClassLoader.getSystemResource("tmp.png").getFile())); - assertTrue(result); - } } diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index ea8bf09377..5c50e83a5b 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -6,11 +6,11 @@4.0.0 com.github.binarywang -weixin-java-parent -3.2.4.B +wx-java +3.3.1.B weixin-java-mp -Weixin Java Tools - MP +WxJava - MP 微信公众号Java SDK @@ -36,6 +36,11 @@ testng test
* 使用说明:本实现仅供参考,并不完整, * 比如为减少项目依赖,未加入redis分布式锁的实现,如有需要请自行实现。 *+ * * @author nickwong */ @SuppressWarnings("hiding") public class WxMpInRedisConfigStorage extends WxMpInMemoryConfigStorage { - - private final static String ACCESS_TOKEN_KEY = "wechat_access_token_"; - - private final static String JSAPI_TICKET_KEY = "wechat_jsapi_ticket_"; - - private final static String CARDAPI_TICKET_KEY = "wechat_cardapi_ticket_"; + private static final String ACCESS_TOKEN_KEY = "wx:access_token:"; /** - * 使用连接池保证线程安全 + * 使用连接池保证线程安全. */ protected final JedisPool jedisPool; private String accessTokenKey; - private String jsapiTicketKey; - - private String cardapiTicketKey; - public WxMpInRedisConfigStorage(JedisPool jedisPool) { this.jedisPool = jedisPool; } /** - * 每个公众号生成独有的存储key - * - * @param appId + * 每个公众号生成独有的存储key. */ @Override public void setAppId(String appId) { super.setAppId(appId); this.accessTokenKey = ACCESS_TOKEN_KEY.concat(appId); - this.jsapiTicketKey = JSAPI_TICKET_KEY.concat(appId); - this.cardapiTicketKey = CARDAPI_TICKET_KEY.concat(appId); + } + + private String getTicketRedisKey(TicketType type) { + return String.format("wx:ticket:key:%s:%s", this.appId, type.getCode()); } @Override @@ -77,58 +71,31 @@ public void expireAccessToken() { } @Override - public String getJsapiTicket() { - try (Jedis jedis = this.jedisPool.getResource()) { - return jedis.get(this.jsapiTicketKey); - } - } - - @Override - public boolean isJsapiTicketExpired() { - try (Jedis jedis = this.jedisPool.getResource()) { - return jedis.ttl(this.jsapiTicketKey) < 2; - } - } - - @Override - public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { + public String getTicket(TicketType type) { try (Jedis jedis = this.jedisPool.getResource()) { - jedis.setex(this.jsapiTicketKey, expiresInSeconds - 200, jsapiTicket); + return jedis.get(this.getTicketRedisKey(type)); } } @Override - public void expireJsapiTicket() { + public boolean isTicketExpired(TicketType type) { try (Jedis jedis = this.jedisPool.getResource()) { - jedis.expire(this.jsapiTicketKey, 0); + return jedis.ttl(this.getTicketRedisKey(type)) < 2; } } @Override - public String getCardApiTicket() { + public synchronized void updateTicket(TicketType type, String jsapiTicket, int expiresInSeconds) { try (Jedis jedis = this.jedisPool.getResource()) { - return jedis.get(this.cardapiTicketKey); + jedis.setex(this.getTicketRedisKey(type), expiresInSeconds - 200, jsapiTicket); } } @Override - public boolean isCardApiTicketExpired() { + public void expireTicket(TicketType type) { try (Jedis jedis = this.jedisPool.getResource()) { - return jedis.ttl(this.cardapiTicketKey) < 2; + jedis.expire(this.getTicketRedisKey(type), 0); } } - @Override - public synchronized void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { - try (Jedis jedis = this.jedisPool.getResource()) { - jedis.setex(this.cardapiTicketKey, expiresInSeconds - 200, cardApiTicket); - } - } - - @Override - public void expireCardApiTicket() { - try (Jedis jedis = this.jedisPool.getResource()) { - jedis.expire(this.cardapiTicketKey, 0); - } - } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java index 2bdf631bb3..b071980480 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java @@ -1,11 +1,20 @@ package me.chanjar.weixin.mp.api; import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.mp.bean.card.*; -import me.chanjar.weixin.mp.bean.membercard.*; +import me.chanjar.weixin.mp.bean.card.CardUpdateResult; +import me.chanjar.weixin.mp.bean.card.MemberCardActivateUserFormRequest; +import me.chanjar.weixin.mp.bean.card.MemberCardActivateUserFormResult; +import me.chanjar.weixin.mp.bean.card.MemberCardUpdateRequest; +import me.chanjar.weixin.mp.bean.card.WxMpCardCreateResult; +import me.chanjar.weixin.mp.bean.membercard.ActivatePluginParam; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardActivatedMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardCreateMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateMessage; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUpdateResult; +import me.chanjar.weixin.mp.bean.membercard.WxMpMemberCardUserInfoResult; /** - * 会员卡相关接口 + * 会员卡相关接口. * * @author YuJian(mgcnrx11 @ gmail.com) * @author yuanqixun @@ -18,46 +27,38 @@ public interface WxMpMemberCardService { String MEMBER_CARD_USER_INFO_GET = "https://api.weixin.qq.com/card/membercard/userinfo/get"; String MEMBER_CARD_UPDATE_USER = "https://api.weixin.qq.com/card/membercard/updateuser"; /** - * 会员卡激活之微信开卡接口(wx_activate=true情况调用) + * 会员卡激活之微信开卡接口(wx_activate=true情况调用). */ String MEMBER_CARD_ACTIVATEUSERFORM = "https://api.weixin.qq.com/card/membercard/activateuserform/set"; /** - * 获取会员卡开卡插件参数 + * 获取会员卡开卡插件参数. */ String MEMBER_CARD_ACTIVATE_URL = "https://api.weixin.qq.com/card/membercard/activate/geturl"; /** - * 会员卡信息更新 + * 会员卡信息更新. */ String MEMBER_CARD_UPDATE = "https://api.weixin.qq.com/card/update"; /** - * 得到WxMpService + * 得到WxMpService. */ WxMpService getWxMpService(); /** - * 会员卡创建接口 - * - * @param createJson - * @return - * @throws WxErrorException + * 会员卡创建接口. */ WxMpCardCreateResult createMemberCard(String createJson) throws WxErrorException; /** - * 会员卡创建接口 - * - * @param createMessageMessage - * @return WxMpCardCreateResult - * @throws WxErrorException + * 会员卡创建接口. */ WxMpCardCreateResult createMemberCard(WxMpMemberCardCreateMessage createMessageMessage) throws WxErrorException; /** - * 会员卡激活接口 + * 会员卡激活接口. * * @param activatedMessage 激活所需参数 * @return 返回json字符串 @@ -66,7 +67,7 @@ public interface WxMpMemberCardService { String activateMemberCard(WxMpMemberCardActivatedMessage activatedMessage) throws WxErrorException; /** - * 拉取会员信息接口 + * 拉取会员信息接口. * * @param cardId 会员卡的CardId,微信分配 * @param code 领取会员的会员卡Code @@ -76,10 +77,10 @@ public interface WxMpMemberCardService { WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) throws WxErrorException; /** - * 当会员持卡消费后,支持开发者调用该接口更新会员信息。会员卡交易后的每次信息变更需通过该接口通知微信,便于后续消息通知及其他扩展功能。 - *
- * 1.开发者可以同时传入add_bonus和bonus解决由于同步失败带来的幂等性问题。同时传入add_bonus和bonus时 - * add_bonus作为积分变动消息中的变量值,而bonus作为卡面上的总积分额度显示。余额变动同理。 + * 当会员持卡消费后,支持开发者调用该接口更新会员信息. + * 会员卡交易后的每次信息变更需通过该接口通知微信,便于后续消息通知及其他扩展功能。 + * 1.开发者可以同时传入add_bonus和bonus解决由于同步失败带来的幂等性问题。 + * 同时传入add_bonus和bonus时 add_bonus作为积分变动消息中的变量值,而bonus作为卡面上的总积分额度显示。余额变动同理。 * 2.开发者可以传入is_notify_bonus控制特殊的积分对账变动不发送消息,余额变动同理。 * * @param updateUserMessage 更新会员信息所需字段消息 @@ -89,29 +90,17 @@ public interface WxMpMemberCardService { WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessage updateUserMessage) throws WxErrorException; /** - * 设置会员卡激活的字段(会员卡设置:wx_activate=true 时需要) - * - * @param userFormRequest - * @return - * @throws WxErrorException + * 设置会员卡激活的字段(会员卡设置:wx_activate=true 时需要). */ MemberCardActivateUserFormResult setActivateUserForm(MemberCardActivateUserFormRequest userFormRequest) throws WxErrorException; /** - * 获取会员卡开卡插件参数(跳转型开卡组件需要参数) - * - * @param cardId - * @param outStr - * @return - * @throws WxErrorException + * 获取会员卡开卡插件参数(跳转型开卡组件需要参数). */ ActivatePluginParam getActivatePluginParam(String cardId, String outStr) throws WxErrorException; /** - * 更新会员卡信息 - * @param memberCardUpdateRequest - * @return - * @throws WxErrorException + * 更新会员卡信息. */ CardUpdateResult updateCardInfo(MemberCardUpdateRequest memberCardUpdateRequest) throws WxErrorException; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java index 8350593aa2..e85a2b65cb 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java @@ -1,5 +1,18 @@ package me.chanjar.weixin.mp.api; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import me.chanjar.weixin.common.api.WxErrorExceptionHandler; import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; @@ -10,18 +23,6 @@ import me.chanjar.weixin.common.util.LogExceptionHandler; import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; /** *
@@ -155,11 +156,12 @@ public WxMpMessageRouterRule rule() { public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage, final Mapcontext) { return route(wxMessage, context, null); } + /** * 处理微信消息 */ public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage, final Map context, WxMpService wxMpService) { - if(wxMpService == null){ + if (wxMpService == null) { wxMpService = this.wxMpService; } final WxMpService mpService = wxMpService; @@ -214,7 +216,10 @@ public void run() { WxMpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUser()); // 异步操作结束,session访问结束 sessionEndAccess(wxMessage); - } catch (InterruptedException | ExecutionException e) { + } catch (InterruptedException e) { + WxMpMessageRouter.this.log.error("Error happened when wait task finish", e); + Thread.currentThread().interrupt(); + } catch (ExecutionException e) { WxMpMessageRouter.this.log.error("Error happened when wait task finish", e); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index c4212affc2..fead289a36 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -10,76 +10,79 @@ import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult; import me.chanjar.weixin.mp.bean.result.WxMpUser; +import me.chanjar.weixin.mp.enums.TicketType; /** - * 微信API的Service + * 微信公众号API的Service. + * + * @author chanjarster */ public interface WxMpService { /** - * 获取access_token + * 获取access_token. */ String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; /** - * 获得jsapi_ticket + * 获得各种类型的ticket. */ - String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; + String GET_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type="; /** - * 长链接转短链接接口 + * 长链接转短链接接口. */ String SHORTURL_API_URL = "https://api.weixin.qq.com/cgi-bin/shorturl"; /** - * 语义查询接口 + * 语义查询接口. */ String SEMANTIC_SEMPROXY_SEARCH_URL = "https://api.weixin.qq.com/semantic/semproxy/search"; /** - * 用code换取oauth2的access token + * 用code换取oauth2的access token. */ String OAUTH2_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"; /** - * 刷新oauth2的access token + * 刷新oauth2的access token. */ String OAUTH2_REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s"; /** - * 用oauth2获取用户信息 + * 用oauth2获取用户信息. */ String OAUTH2_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s"; /** - * 验证oauth2的access token是否有效 + * 验证oauth2的access token是否有效. */ String OAUTH2_VALIDATE_TOKEN_URL = "https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s"; /** - * 获取微信服务器IP地址 + * 获取微信服务器IP地址. */ String GET_CALLBACK_IP_URL = "https://api.weixin.qq.com/cgi-bin/getcallbackip"; /** - * 第三方使用网站应用授权登录的url + * 第三方使用网站应用授权登录的url. */ String QRCONNECT_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"; /** - * oauth2授权的url连接 + * oauth2授权的url连接. */ String CONNECT_OAUTH2_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&connect_redirect=1#wechat_redirect"; /** - * 获取公众号的自动回复规则 + * 获取公众号的自动回复规则. */ String GET_CURRENT_AUTOREPLY_INFO_URL = "https://api.weixin.qq.com/cgi-bin/get_current_autoreply_info"; /** - * 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零 + * 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零. */ String CLEAR_QUOTA_URL = "https://api.weixin.qq.com/cgi-bin/clear_quota"; /** * - * 验证消息的确来自微信服务器 + * 验证消息的确来自微信服务器. * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN **/ boolean checkSignature(String timestamp, String nonce, String signature); /** - * 获取access_token, 不强制刷新access_token + * 获取access_token, 不强制刷新access_token. * * @see #getAccessToken(boolean) */ @@ -87,7 +90,7 @@ public interface WxMpService { /** *- * 获取access_token,本方法线程安全 + * 获取access_token,本方法线程安全. * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限 * * 另:本service的所有方法都会在access_token过期时调用此方法 @@ -102,7 +105,24 @@ public interface WxMpService { String getAccessToken(boolean forceRefresh) throws WxErrorException; /** - * 获得jsapi_ticket,不强制刷新jsapi_ticket + * 获得ticket,不强制刷新ticket. + * + * @see #getTicket(TicketType, boolean) + */ + String getTicket(TicketType type) throws WxErrorException; + + /** + *+ * 获得ticket. + * 获得时会检查 Token是否过期,如果过期了,那么就刷新一下,否则就什么都不干 + *+ * + * @param forceRefresh 强制刷新 + */ + String getTicket(TicketType type, boolean forceRefresh) throws WxErrorException; + + /** + * 获得jsapi_ticket,不强制刷新jsapi_ticket. * * @see #getJsapiTicket(boolean) */ @@ -110,7 +130,7 @@ public interface WxMpService { /** *- * 获得jsapi_ticket + * 获得jsapi_ticket. * 获得时会检查jsapiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干 * * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN @@ -122,7 +142,7 @@ public interface WxMpService { /** *- * 创建调用jsapi时所需要的签名 + * 创建调用jsapi时所需要的签名. * * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN *@@ -131,7 +151,7 @@ public interface WxMpService { /** *- * 长链接转短链接接口 + * 长链接转短链接接口. * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=长链接转短链接接口 **/ @@ -139,7 +159,7 @@ public interface WxMpService { /** *- * 语义查询接口 + * 语义查询接口. * 详情请见:http://mp.weixin.qq.com/wiki/index.php?title=语义理解 **/ @@ -147,7 +167,7 @@ public interface WxMpService { /** *- * 构造第三方使用网站应用授权登录的url + * 构造第三方使用网站应用授权登录的url. * 详情请见: 网站应用微信登录开发指南 * URL格式为:https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect *@@ -161,7 +181,7 @@ public interface WxMpService { /** *- * 构造oauth2授权的url连接 + * 构造oauth2授权的url连接. * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息 ** @@ -172,7 +192,7 @@ public interface WxMpService { /** *- * 用code换取oauth2的access token + * 用code换取oauth2的access token. * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息 **/ @@ -180,14 +200,14 @@ public interface WxMpService { /** *- * 刷新oauth2的access token + * 刷新oauth2的access token. **/ WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException; /** *- * 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以 + * 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以. ** * @param lang zh_CN, zh_TW, en @@ -196,7 +216,7 @@ public interface WxMpService { /** *- * 验证oauth2的access token是否有效 + * 验证oauth2的access token是否有效. **/ boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken); @@ -211,7 +231,7 @@ public interface WxMpService { /** *- * 获取公众号的自动回复规则 + * 获取公众号的自动回复规则. * http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751299&token=&lang=zh_CN * 开发者可以通过该接口,获取公众号当前使用的自动回复规则,包括关注后自动回复、消息自动回复(60分钟内触发一次)、关键词自动回复。 * 请注意: @@ -240,12 +260,12 @@ public interface WxMpService { void clearQuota(String appid) throws WxErrorException; /** - * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求. */ String get(String url, String queryParam) throws WxErrorException; /** - * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求. */ String post(String url, String postData) throws WxErrorException; @@ -260,7 +280,7 @@ public interface WxMpService { /** *- * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试 + * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试. * @param retrySleepMillis 默认:1000ms **/ @@ -268,131 +288,131 @@ public interface WxMpService { /** *- * 设置当微信系统响应系统繁忙时,最大重试次数 + * 设置当微信系统响应系统繁忙时,最大重试次数. * 默认:5次 **/ void setMaxRetryTimes(int maxRetryTimes); /** - * 获取WxMpConfigStorage 对象 + * 获取WxMpConfigStorage 对象. * * @return WxMpConfigStorage */ WxMpConfigStorage getWxMpConfigStorage(); /** - * 注入 {@link WxMpConfigStorage} 的实现 + * 注入 {@link WxMpConfigStorage} 的实现. */ void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider); /** - * 返回客服接口方法实现类,以方便调用其各个接口 + * 返回客服接口方法实现类,以方便调用其各个接口. * * @return WxMpKefuService */ WxMpKefuService getKefuService(); /** - * 返回素材相关接口方法的实现类对象,以方便调用其各个接口 + * 返回素材相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpMaterialService */ WxMpMaterialService getMaterialService(); /** - * 返回菜单相关接口方法的实现类对象,以方便调用其各个接口 + * 返回菜单相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpMenuService */ WxMpMenuService getMenuService(); /** - * 返回用户相关接口方法的实现类对象,以方便调用其各个接口 + * 返回用户相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpUserService */ WxMpUserService getUserService(); /** - * 返回用户标签相关接口方法的实现类对象,以方便调用其各个接口 + * 返回用户标签相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpUserTagService */ WxMpUserTagService getUserTagService(); /** - * 返回二维码相关接口方法的实现类对象,以方便调用其各个接口 + * 返回二维码相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpQrcodeService */ WxMpQrcodeService getQrcodeService(); /** - * 返回卡券相关接口方法的实现类对象,以方便调用其各个接口 + * 返回卡券相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpCardService */ WxMpCardService getCardService(); /** - * 返回数据分析统计相关接口方法的实现类对象,以方便调用其各个接口 + * 返回数据分析统计相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpDataCubeService */ WxMpDataCubeService getDataCubeService(); /** - * 返回用户黑名单管理相关接口方法的实现类对象,以方便调用其各个接口 + * 返回用户黑名单管理相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpUserBlacklistService */ WxMpUserBlacklistService getBlackListService(); /** - * 返回门店管理相关接口方法的实现类对象,以方便调用其各个接口 + * 返回门店管理相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpStoreService */ WxMpStoreService getStoreService(); /** - * 返回模板消息相关接口方法的实现类对象,以方便调用其各个接口 + * 返回模板消息相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpTemplateMsgService */ WxMpTemplateMsgService getTemplateMsgService(); /** - * 返回一次性订阅消息相关接口方法的实现类对象,以方便调用其各个接口 + * 返回一次性订阅消息相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpSubscribeMsgService */ WxMpSubscribeMsgService getSubscribeMsgService(); /** - * 返回硬件平台相关接口方法的实现类对象,以方便调用其各个接口 + * 返回硬件平台相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpDeviceService */ WxMpDeviceService getDeviceService(); /** - * 返回摇一摇周边相关接口方法的实现类对象,以方便调用其各个接口 + * 返回摇一摇周边相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpShakeService */ WxMpShakeService getShakeService(); /** - * 返回会员卡相关接口方法的实现类对象,以方便调用其各个接口 + * 返回会员卡相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpMemberCardService */ WxMpMemberCardService getMemberCardService(); /** - * 初始化http请求对象 + * 初始化http请求对象. */ void initHttp(); @@ -402,21 +422,21 @@ public interface WxMpService { RequestHttp getRequestHttp(); /** - * 返回群发消息相关接口方法的实现类对象,以方便调用其各个接口 + * 返回群发消息相关接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpMassMessageService */ WxMpMassMessageService getMassMessageService(); /** - * 返回AI开放接口方法的实现类对象,以方便调用其各个接口 + * 返回AI开放接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpAiOpenService */ WxMpAiOpenService getAiOpenService(); /** - * 返回WIFI接口方法的实现类对象,以方便调用其各个接口 + * 返回WIFI接口方法的实现类对象,以方便调用其各个接口. * * @return WxMpWifiService */ diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java index 7523a9f39e..71b6b17092 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java @@ -1,18 +1,24 @@ package me.chanjar.weixin.mp.api; +import java.util.List; + import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.bean.WxMpUserQuery; +import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid; import me.chanjar.weixin.mp.bean.result.WxMpUser; import me.chanjar.weixin.mp.bean.result.WxMpUserList; -import java.util.List; - /** - * 用户管理相关操作接口 + * 用户管理相关操作接口. * * @author Binary Wang */ public interface WxMpUserService { + String USER_INFO_BATCH_GET_URL = "https://api.weixin.qq.com/cgi-bin/user/info/batchget"; + String USER_GET_URL = "https://api.weixin.qq.com/cgi-bin/user/get"; + String USER_INFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info"; + String USER_INFO_UPDATE_REMARK_URL = "https://api.weixin.qq.com/cgi-bin/user/info/updateremark"; + String USER_CHANGE_OPENID_URL = "http://api.weixin.qq.com/cgi-bin/changeopenid"; /** *@@ -61,9 +67,9 @@ public interface WxMpUserService { * 接口地址:https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=ACCESS_TOKEN ** - * @param openids 用户openid列表 + * @param openidList 用户openid列表 */ - ListuserInfoList(List openids) throws WxErrorException; + List userInfoList(List openidList) throws WxErrorException; /** * @@ -90,4 +96,17 @@ public interface WxMpUserService { * @param nextOpenid 可选,第一个拉取的OPENID,null为从头开始拉取 */ WxMpUserList userList(String nextOpenid) throws WxErrorException; + + /** + *+ * 微信公众号主体变更迁移用户 openid + * 详情请见: http://kf.qq.com/faq/170221aUnmmU170221eUZJNf.html + * http请求方式: POST + * 接口地址:https://api.weixin.qq.com/cgi-bin/changeopenid?access_token=ACCESS_TOKEN + *+ * + * @param fromAppid 原公众号的 appid + * @param openidList 需要转换的openid,这些必须是旧账号目前关注的才行,否则会出错;一次最多100个 + */ + ListchangeOpenid(String fromAppid, List openidList) throws WxErrorException; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java index 09d21bacff..f720461652 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java @@ -1,5 +1,12 @@ package me.chanjar.weixin.mp.api.impl; +import java.io.IOException; +import java.util.concurrent.locks.Lock; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -12,21 +19,41 @@ import me.chanjar.weixin.common.util.DataUtils; import me.chanjar.weixin.common.util.RandomUtils; import me.chanjar.weixin.common.util.crypto.SHA1; -import me.chanjar.weixin.common.util.http.*; -import me.chanjar.weixin.mp.api.*; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; +import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; +import me.chanjar.weixin.common.util.http.URIUtil; +import me.chanjar.weixin.mp.api.WxMpAiOpenService; +import me.chanjar.weixin.mp.api.WxMpCardService; +import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.api.WxMpDataCubeService; +import me.chanjar.weixin.mp.api.WxMpDeviceService; +import me.chanjar.weixin.mp.api.WxMpKefuService; +import me.chanjar.weixin.mp.api.WxMpMassMessageService; +import me.chanjar.weixin.mp.api.WxMpMaterialService; +import me.chanjar.weixin.mp.api.WxMpMemberCardService; +import me.chanjar.weixin.mp.api.WxMpMenuService; +import me.chanjar.weixin.mp.api.WxMpQrcodeService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.WxMpShakeService; +import me.chanjar.weixin.mp.api.WxMpStoreService; +import me.chanjar.weixin.mp.api.WxMpSubscribeMsgService; +import me.chanjar.weixin.mp.api.WxMpTemplateMsgService; +import me.chanjar.weixin.mp.api.WxMpUserBlacklistService; +import me.chanjar.weixin.mp.api.WxMpUserService; +import me.chanjar.weixin.mp.api.WxMpUserTagService; +import me.chanjar.weixin.mp.api.WxMpWifiService; import me.chanjar.weixin.mp.bean.WxMpSemanticQuery; import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo; import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult; import me.chanjar.weixin.mp.bean.result.WxMpUser; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.concurrent.locks.Lock; +import me.chanjar.weixin.mp.enums.TicketType; /** + * 基础实现类. + * * @author someone */ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestHttp { @@ -71,31 +98,42 @@ public boolean checkSignature(String timestamp, String nonce, String signature) } @Override - public String getJsapiTicket() throws WxErrorException { - return getJsapiTicket(false); + public String getTicket(TicketType type) throws WxErrorException { + return this.getTicket(type, false); } @Override - public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { - Lock lock = this.getWxMpConfigStorage().getJsapiTicketLock(); + public String getTicket(TicketType type, boolean forceRefresh) throws WxErrorException { + Lock lock = this.getWxMpConfigStorage().getTicketLock(type); try { lock.lock(); if (forceRefresh) { - this.getWxMpConfigStorage().expireJsapiTicket(); + this.getWxMpConfigStorage().expireTicket(type); } - if (this.getWxMpConfigStorage().isJsapiTicketExpired()) { - String responseContent = execute(SimpleGetRequestExecutor.create(this), WxMpService.GET_JSAPI_TICKET_URL, null); - JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent); - JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + if (this.getWxMpConfigStorage().isTicketExpired(type)) { + String responseContent = execute(SimpleGetRequestExecutor.create(this), + WxMpService.GET_TICKET_URL + type.getCode(), null); + JsonObject tmpJsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.getWxMpConfigStorage().updateJsapiTicket(jsapiTicket, expiresInSeconds); + this.getWxMpConfigStorage().updateTicket(type, jsapiTicket, expiresInSeconds); } } finally { lock.unlock(); } - return this.getWxMpConfigStorage().getJsapiTicket(); + + return this.getWxMpConfigStorage().getTicket(type); + } + + @Override + public String getJsapiTicket() throws WxErrorException { + return this.getJsapiTicket(false); + } + + @Override + public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { + return this.getTicket(TicketType.JSAPI, forceRefresh); } @Override diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java index f492e4670d..b97da0a8a2 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java @@ -5,7 +5,7 @@ import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.mp.AiLangType; +import me.chanjar.weixin.mp.enums.AiLangType; import me.chanjar.weixin.mp.api.WxMpAiOpenService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.util.requestexecuter.voice.VoiceUploadRequestExecutor; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java index 51c87fdcc9..5237fd6d2a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java @@ -3,6 +3,7 @@ import java.util.Arrays; import java.util.concurrent.locks.Lock; +import me.chanjar.weixin.mp.bean.card.*; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,17 +23,16 @@ import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; import me.chanjar.weixin.mp.api.WxMpCardService; import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.bean.card.WxMpCardLandingPageCreateRequest; -import me.chanjar.weixin.mp.bean.card.WxMpCardLandingPageCreateResult; -import me.chanjar.weixin.mp.bean.card.WxMpCardQrcodeCreateResult; import me.chanjar.weixin.mp.bean.result.WxMpCardResult; +import me.chanjar.weixin.mp.enums.TicketType; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** * Created by Binary Wang on 2016/7/27. + * + * @author BinaryWang */ public class WxMpCardServiceImpl implements WxMpCardService { - private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class); private WxMpService wxMpService; @@ -49,7 +49,7 @@ public WxMpService getWxMpService() { } /** - * 获得卡券api_ticket,不强制刷新卡券api_ticket + * 获得卡券api_ticket,不强制刷新卡券api_ticket. * * @return 卡券api_ticket * @see #getCardApiTicket(boolean) @@ -61,7 +61,7 @@ public String getCardApiTicket() throws WxErrorException { /** * - * 获得卡券api_ticket + * 获得卡券api_ticket. * 获得时会检查卡券apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干 * * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD @@ -74,26 +74,28 @@ public String getCardApiTicket() throws WxErrorException { */ @Override public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { - Lock lock = getWxMpService().getWxMpConfigStorage().getCardApiTicketLock(); + final TicketType type = TicketType.WX_CARD; + Lock lock = getWxMpService().getWxMpConfigStorage().getTicketLock(type); try { lock.lock(); if (forceRefresh) { - this.getWxMpService().getWxMpConfigStorage().expireCardApiTicket(); + this.getWxMpService().getWxMpConfigStorage().expireTicket(type); } - if (this.getWxMpService().getWxMpConfigStorage().isCardApiTicketExpired()) { - String responseContent = this.wxMpService.execute(SimpleGetRequestExecutor.create(this.getWxMpService().getRequestHttp()), CARD_GET_TICKET, null); + if (this.getWxMpService().getWxMpConfigStorage().isTicketExpired(type)) { + String responseContent = this.wxMpService.execute(SimpleGetRequestExecutor + .create(this.getWxMpService().getRequestHttp()), CARD_GET_TICKET, null); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); String cardApiTicket = tmpJsonObject.get("ticket").getAsString(); int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); - this.getWxMpService().getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds); + this.getWxMpService().getWxMpConfigStorage().updateTicket(type, cardApiTicket, expiresInSeconds); } } finally { lock.unlock(); } - return this.getWxMpService().getWxMpConfigStorage().getCardApiTicket(); + return this.getWxMpService().getWxMpConfigStorage().getTicket(type); } /** @@ -147,7 +149,7 @@ public String decryptCardCode(String encryptCode) throws WxErrorException { } /** - * 卡券Code查询 + * 卡券Code查询. * * @param cardId 卡券ID代表一类卡券 * @param code 单张卡券的唯一标准 @@ -247,11 +249,11 @@ public String getCardDetail(String cardId) throws WxErrorException { } /** - * 添加测试白名单 + * 添加测试白名单. * * @param openid 用户的openid - * @return */ + @Override public String addTestWhiteList(String openid) throws WxErrorException { JsonArray array = new JsonArray(); array.add(openid); @@ -261,26 +263,29 @@ public String addTestWhiteList(String openid) throws WxErrorException { return respone; } + @Override + public WxMpCardCreateResult createCard(WxMpCardCreateMessage cardCreateMessage) throws WxErrorException { + + String response = this.wxMpService.post(CARD_CREATE, GSON.toJson(cardCreateMessage)); + return WxMpCardCreateResult.fromJson(response); + } + /** - * 创建卡券二维码 - * - * @param cardId - * @param outerStr - * @return + * 创建卡券二维码. */ + @Override public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr) throws WxErrorException { return createQrcodeCard(cardId, outerStr, 0); } /** - * 创建卡券二维码 + * 创建卡券二维码. * * @param cardId 卡券编号 * @param outerStr 二维码标识 * @param expiresIn 失效时间,单位秒,不填默认365天 - * @return - * @throws WxErrorException */ + @Override public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn) throws WxErrorException { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("action_name", "QR_CARD"); @@ -293,42 +298,35 @@ public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerSt cardJson.addProperty("outer_str", outerStr); actionInfoJson.add("card", cardJson); jsonObject.add("action_info", actionInfoJson); - String response = this.wxMpService.post(CARD_QRCODE_CREAET, GSON.toJson(jsonObject)); - return WxMpCardQrcodeCreateResult.fromJson(response); + return WxMpCardQrcodeCreateResult.fromJson(this.wxMpService.post(CARD_QRCODE_CREATE, GSON.toJson(jsonObject))); } /** - * 创建卡券货架接口 - * - * @param request - * @return - * @throws WxErrorException + * 创建卡券货架接口. */ @Override public WxMpCardLandingPageCreateResult createLandingPage(WxMpCardLandingPageCreateRequest request) throws WxErrorException { - String response = this.wxMpService.post(CARD_LANDING_PAGE_CREAET, GSON.toJson(request)); + String response = this.wxMpService.post(CARD_LANDING_PAGE_CREATE, GSON.toJson(request)); return WxMpCardLandingPageCreateResult.fromJson(response); } /** - * 将用户的卡券设置为失效状态 + * 将用户的卡券设置为失效状态. * 详见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025272&anchor=9 * * @param cardId 卡券编号 * @param code 用户会员卡号 * @param reason 设置为失效的原因 - * @return - * @throws WxErrorException */ @Override public String unavailableCardCode(String cardId, String code, String reason) throws WxErrorException { - if (StringUtils.isAnyBlank(cardId, code, reason)) + if (StringUtils.isAnyBlank(cardId, code, reason)) { throw new WxErrorException(WxError.builder().errorCode(41012).errorMsg("参数不完整").build()); + } JsonObject jsonRequest = new JsonObject(); jsonRequest.addProperty("card_id", cardId); jsonRequest.addProperty("code", code); jsonRequest.addProperty("reason", reason); - String response = this.wxMpService.post(CARD_CODE_UNAVAILABLE, GSON.toJson(jsonRequest)); - return response; + return this.wxMpService.post(CARD_CODE_UNAVAILABLE, GSON.toJson(jsonRequest)); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java index 0db3632217..9bdc11b365 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java @@ -5,20 +5,28 @@ import java.util.HashMap; import java.util.Map; -import me.chanjar.weixin.mp.bean.card.*; import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.api.WxMpMemberCardService; import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.card.AdvancedInfo; +import me.chanjar.weixin.mp.bean.card.BaseInfo; +import me.chanjar.weixin.mp.bean.card.CardUpdateResult; +import me.chanjar.weixin.mp.bean.card.DateInfo; +import me.chanjar.weixin.mp.bean.card.MemberCard; +import me.chanjar.weixin.mp.bean.card.MemberCardActivateUserFormRequest; +import me.chanjar.weixin.mp.bean.card.MemberCardActivateUserFormResult; +import me.chanjar.weixin.mp.bean.card.MemberCardCreateRequest; +import me.chanjar.weixin.mp.bean.card.MemberCardUpdateRequest; +import me.chanjar.weixin.mp.bean.card.WxMpCardCreateResult; import me.chanjar.weixin.mp.bean.card.enums.BusinessServiceType; import me.chanjar.weixin.mp.bean.card.enums.CardColor; import me.chanjar.weixin.mp.bean.card.enums.DateInfoType; @@ -37,10 +45,8 @@ * @author YuJian(mgcnrx11 @ gmail.com) * @version 2017/7/8 */ +@Slf4j public class WxMpMemberCardServiceImpl implements WxMpMemberCardService { - - private final Logger log = LoggerFactory.getLogger(WxMpMemberCardServiceImpl.class); - private WxMpService wxMpService; private static final Gson GSON = WxMpGsonBuilder.create(); @@ -49,50 +55,37 @@ public class WxMpMemberCardServiceImpl implements WxMpMemberCardService { this.wxMpService = wxMpService; } - /** - * 得到WxMpService - */ @Override public WxMpService getWxMpService() { return this.wxMpService; } - /** - * 会员卡创建接口 - * - * @param createJson 创建json - * @return 调用返回的JSON字符串。 - * @throws WxErrorException 接口调用失败抛出的异常 - */ @Override public WxMpCardCreateResult createMemberCard(String createJson) throws WxErrorException { - WxMpMemberCardCreateMessage createMessage = WxGsonBuilder.create().fromJson(createJson, WxMpMemberCardCreateMessage.class); + WxMpMemberCardCreateMessage createMessage = WxGsonBuilder.create() + .fromJson(createJson, WxMpMemberCardCreateMessage.class); return createMemberCard(createMessage); } - /** - * 会员卡创建接口 - * - * @param createMessageMessage 创建所需参数 - * @return WxMpCardCreateResult。 - * @throws WxErrorException 接口调用失败抛出的异常 - */ @Override - public WxMpCardCreateResult createMemberCard(WxMpMemberCardCreateMessage createMessageMessage) throws WxErrorException { + public WxMpCardCreateResult createMemberCard(WxMpMemberCardCreateMessage createMessageMessage) + throws WxErrorException { //校验请求对象合法性 WxMpCardCreateResult validResult = validCheck(createMessageMessage); - if (!validResult.isSuccess()) + if (!validResult.isSuccess()) { return validResult; + } + String response = this.wxMpService.post(MEMBER_CARD_CREAET, GSON.toJson(createMessageMessage)); return WxMpCardCreateResult.fromJson(response); } - private WxMpCardCreateResult validCheck(WxMpMemberCardCreateMessage createMessageMessage) throws WxErrorException { + private WxMpCardCreateResult validCheck(WxMpMemberCardCreateMessage createMessageMessage) { if (createMessageMessage == null) { return WxMpCardCreateResult.failure("对象不能为空"); } MemberCardCreateRequest cardCreateRequest = createMessageMessage.getCardCreateRequest(); - if (createMessageMessage == null) { + if (cardCreateRequest == null) { return WxMpCardCreateResult.failure("会员卡对象不能为空"); } String cardType = cardCreateRequest.getCardType(); @@ -105,17 +98,11 @@ private WxMpCardCreateResult validCheck(WxMpMemberCardCreateMessage createMessag return WxMpCardCreateResult.failure("会员卡特权说明不能为空:prerogative"); } //卡片激活规则 - if (!memberCard.isAutoActivate() && !memberCard.isWxActivate() && StringUtils.isEmpty(memberCard.getActivateUrl())) { + if (!memberCard.isAutoActivate() && !memberCard.isWxActivate() + && StringUtils.isEmpty(memberCard.getActivateUrl())) { return WxMpCardCreateResult.failure("会员卡激活方式为接口激活,activate_url不能为空"); } - //积分支持 -// if(memberCard.isSupplyBonus() && StringUtils.isEmpty(memberCard.getBonusUrl())){ -// return WxMpCardCreateResult.failure("会员卡支持积分,bonus_url不能为空"); -// } -// if(memberCard.isSupplyBonus() && memberCard.getBonusRule() == null){ -// return WxMpCardCreateResult.failure("会员卡支持积分,bonus_rule不能为空"); -// } BaseInfo baseInfo = memberCard.getBaseInfo(); if (baseInfo == null) { return WxMpCardCreateResult.failure("会员卡基本信息对象base_info不能为空"); @@ -188,16 +175,24 @@ private WxMpCardCreateResult validCheck(WxMpMemberCardCreateMessage createMessag } //固定时长 - if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TERM && (dateInfo.getFixedTerm() == null || dateInfo.getFixedBeginTerm() == null)) { - return WxMpCardCreateResult.failure("会员卡基本信息的使用日期为:" + dateInfoType.getDescription() + ",fixedTerm和fixedBeginTerm不能为空"); + if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TERM + && (dateInfo.getFixedTerm() == null || dateInfo.getFixedBeginTerm() == null)) { + return WxMpCardCreateResult.failure(String.format("会员卡基本信息的使用日期为:%s,fixedTerm和fixedBeginTerm不能为空", + dateInfoType.getDescription())); } //固定期限 - if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TIME_RANGE && (dateInfo.getBeginTimestamp() == null || dateInfo.getEndTimestamp() == null)) { - return WxMpCardCreateResult.failure("会员卡基本信息的使用日期为:" + dateInfoType.getDescription() + ",beginTimestamp 和 endTimestamp 不能为空"); + if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TIME_RANGE + && (dateInfo.getBeginTimestamp() == null || dateInfo.getEndTimestamp() == null)) { + return WxMpCardCreateResult.failure(String.format("会员卡基本信息的使用日期为:%s,beginTimestamp 和 endTimestamp 不能为空", + dateInfoType.getDescription())); } - if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TIME_RANGE && (dateInfo.getBeginTimestamp() < System.currentTimeMillis() || dateInfo.getEndTimestamp() < System.currentTimeMillis() || dateInfo.getBeginTimestamp() > dateInfo.getEndTimestamp())) { - return WxMpCardCreateResult.failure("会员卡基本信息的使用日期为:" + dateInfoType.getDescription() + ",beginTimestamp和endTimestamp的值不合法,请检查"); + if (dateInfoType == DateInfoType.DATE_TYPE_FIX_TIME_RANGE + && (dateInfo.getBeginTimestamp() * 1000 < System.currentTimeMillis() + || dateInfo.getEndTimestamp() * 1000 < System.currentTimeMillis() + || dateInfo.getBeginTimestamp() > dateInfo.getEndTimestamp())) { + return WxMpCardCreateResult.failure(String.format("会员卡基本信息的使用日期为:%s,beginTimestamp和endTimestamp的值不合法,请检查", + dateInfoType.getDescription())); } if (!baseInfo.isUseAllLocations() && StringUtils.isBlank(baseInfo.getLocationIdList())) { @@ -209,9 +204,8 @@ private WxMpCardCreateResult validCheck(WxMpMemberCardCreateMessage createMessag if (advancedInfo != null) { if (advancedInfo.getBusinessServiceList() != null) { for (String bs : advancedInfo.getBusinessServiceList()) { - BusinessServiceType businessServiceType = null; try { - businessServiceType = BusinessServiceType.valueOf(bs); + BusinessServiceType.valueOf(bs); } catch (IllegalArgumentException ex) { return WxMpCardCreateResult.failure("会员卡高级信息的商户服务:" + bs + " 不合法"); } @@ -222,26 +216,11 @@ private WxMpCardCreateResult validCheck(WxMpMemberCardCreateMessage createMessag return WxMpCardCreateResult.success(); } - /** - * 会员卡激活接口 - * - * @param activatedMessage 激活所需参数 - * @return WxMpCardCreateResult。 - * @throws WxErrorException 接口调用失败抛出的异常 - */ @Override public String activateMemberCard(WxMpMemberCardActivatedMessage activatedMessage) throws WxErrorException { return this.wxMpService.post(MEMBER_CARD_ACTIVATE, GSON.toJson(activatedMessage)); } - /** - * 拉取会员信息接口 - * - * @param cardId 会员卡的CardId,微信分配 - * @param code 领取会员的会员卡Code - * @return 会员信息的结果对象 - * @throws WxErrorException 接口调用失败抛出的异常 - */ @Override public WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) throws WxErrorException { JsonObject jsonObject = new JsonObject(); @@ -256,17 +235,6 @@ public WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) thro }.getType()); } - /** - * 当会员持卡消费后,支持开发者调用该接口更新会员信息。会员卡交易后的每次信息变更需通过该接口通知微信,便于后续消息通知及其他扩展功能。 - *- * 1.开发者可以同时传入add_bonus和bonus解决由于同步失败带来的幂等性问题。同时传入add_bonus和bonus时 - * add_bonus作为积分变动消息中的变量值,而bonus作为卡面上的总积分额度显示。余额变动同理。 - * 2.开发者可以传入is_notify_bonus控制特殊的积分对账变动不发送消息,余额变动同理。 - * - * @param updateUserMessage 更新会员信息所需字段消息 - * @return 调用返回的JSON字符串。 - * @throws WxErrorException 接口调用失败抛出的异常 - */ @Override public WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessage updateUserMessage) throws WxErrorException { @@ -279,26 +247,13 @@ public WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessa }.getType()); } - /** - * 设置会员卡激活的字段(会员卡设置:wx_activate=true 时需要) - * - * @param userFormRequest - * @return - * @throws WxErrorException - */ @Override public MemberCardActivateUserFormResult setActivateUserForm(MemberCardActivateUserFormRequest userFormRequest) throws WxErrorException { String responseContent = this.getWxMpService().post(MEMBER_CARD_ACTIVATEUSERFORM, GSON.toJson(userFormRequest)); return MemberCardActivateUserFormResult.fromJson(responseContent); } - /** - * 获取会员卡开卡插件参数(跳转型开卡组件需要参数) - * - * @param outStr - * @return - * @throws WxErrorException - */ + @Override public ActivatePluginParam getActivatePluginParam(String cardId, String outStr) throws WxErrorException { JsonObject params = new JsonObject(); params.addProperty("card_id", cardId); @@ -313,7 +268,7 @@ public ActivatePluginParam getActivatePluginParam(String cardId, String outStr) ActivatePluginParam activatePluginParam = new ActivatePluginParam(); activatePluginParam.setEncryptCardId(resultMap.get("encrypt_card_id")); activatePluginParam.setOuterStr(resultMap.get("outer_str")); - activatePluginParam.setBiz(resultMap.get("biz")+"=="); + activatePluginParam.setBiz(resultMap.get("biz") + "=="); return activatePluginParam; } catch (UnsupportedEncodingException e) { e.printStackTrace(); @@ -322,13 +277,6 @@ public ActivatePluginParam getActivatePluginParam(String cardId, String outStr) return null; } - /** - * 更新会员卡信息 - * - * @param memberCardUpdateRequest - * @return - * @throws WxErrorException - */ @Override public CardUpdateResult updateCardInfo(MemberCardUpdateRequest memberCardUpdateRequest) throws WxErrorException { String response = this.wxMpService.post(MEMBER_CARD_UPDATE, GSON.toJson(memberCardUpdateRequest)); @@ -336,15 +284,9 @@ public CardUpdateResult updateCardInfo(MemberCardUpdateRequest memberCardUpdateR return result; } - /** - * 去掉url中的路径,留下请求参数部分 - * - * @param strURL url地址 - * @return url请求参数部分 - */ private static String truncateUrlPage(String strURL) { String strAllParam = null; - String[] arrSplit = null; + String[] arrSplit; arrSplit = strURL.split("[?]"); if (strURL.length() > 1) { if (arrSplit.length > 1) { @@ -357,25 +299,18 @@ private static String truncateUrlPage(String strURL) { return strAllParam; } - /** - * 解析出url参数中的键值对 - * 如 "index.jsp?Action=del&id=123",解析出Action:del,id:123存入map中 - * - * @param URL url地址 - * @return url请求参数部分 - */ - public static Map
parseRequestUrl(String URL) { - Map mapRequest = new HashMap (); + public static Map parseRequestUrl(String url) { + Map mapRequest = new HashMap<>(16); - String[] arrSplit = null; + String[] arrSplit; - String strUrlParam = truncateUrlPage(URL); + String strUrlParam = truncateUrlPage(url); if (strUrlParam == null) { return mapRequest; } arrSplit = strUrlParam.split("[&]"); for (String strSplit : arrSplit) { - String[] arrSplitEqual = null; + String[] arrSplitEqual; arrSplitEqual = strSplit.split("[=]"); //解析出键值 @@ -384,7 +319,7 @@ public static Map parseRequestUrl(String URL) { mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]); } else { - if (arrSplitEqual[0] != "") { + if (!"".equals(arrSplitEqual[0])) { //只有参数没有值,不加入 mapRequest.put(arrSplitEqual[0], ""); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java index def801e4e9..d8c8943d36 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java @@ -1,20 +1,26 @@ package me.chanjar.weixin.mp.api.impl; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.gson.JsonArray; import com.google.gson.JsonObject; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpUserService; import me.chanjar.weixin.mp.bean.WxMpUserQuery; +import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid; import me.chanjar.weixin.mp.bean.result.WxMpUser; import me.chanjar.weixin.mp.bean.result.WxMpUserList; - -import java.util.List; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** * Created by Binary Wang on 2016/7/21. + * + * @author BinaryWang */ public class WxMpUserServiceImpl implements WxMpUserService { - private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/user"; private WxMpService wxMpService; public WxMpUserServiceImpl(WxMpService wxMpService) { @@ -23,11 +29,10 @@ public WxMpUserServiceImpl(WxMpService wxMpService) { @Override public void userUpdateRemark(String openid, String remark) throws WxErrorException { - String url = API_URL_PREFIX + "/info/updateremark"; JsonObject json = new JsonObject(); json.addProperty("openid", openid); json.addProperty("remark", remark); - this.wxMpService.post(url, json.toString()); + this.wxMpService.post(USER_INFO_UPDATE_REMARK_URL, json.toString()); } @Override @@ -37,32 +42,38 @@ public WxMpUser userInfo(String openid) throws WxErrorException { @Override public WxMpUser userInfo(String openid, String lang) throws WxErrorException { - String url = API_URL_PREFIX + "/info"; lang = lang == null ? "zh_CN" : lang; - String responseContent = this.wxMpService.get(url, + String responseContent = this.wxMpService.get(USER_INFO_URL, "openid=" + openid + "&lang=" + lang); return WxMpUser.fromJson(responseContent); } @Override - public WxMpUserList userList(String next_openid) throws WxErrorException { - String url = API_URL_PREFIX + "/get"; - String responseContent = this.wxMpService.get(url, - next_openid == null ? null : "next_openid=" + next_openid); + public WxMpUserList userList(String nextOpenid) throws WxErrorException { + String responseContent = this.wxMpService.get(USER_GET_URL, + nextOpenid == null ? null : "next_openid=" + nextOpenid); return WxMpUserList.fromJson(responseContent); } @Override - public List userInfoList(List openids) + public List changeOpenid(String fromAppid, List openidList) throws WxErrorException { + Map map = new HashMap<>(); + map.put("from_appid", fromAppid); + map.put("openid_list", openidList); + String responseContent = this.wxMpService.post(USER_CHANGE_OPENID_URL, WxMpGsonBuilder.create().toJson(map)); + + return WxMpChangeOpenid.fromJsonList(responseContent); + } + + @Override + public List userInfoList(List openidList) throws WxErrorException { - return this.userInfoList(new WxMpUserQuery(openids)); + return this.userInfoList(new WxMpUserQuery(openidList)); } @Override public List userInfoList(WxMpUserQuery userQuery) throws WxErrorException { - String url = API_URL_PREFIX + "/info/batchget"; - String responseContent = this.wxMpService.post(url, - userQuery.toJsonString()); + String responseContent = this.wxMpService.post(USER_INFO_BATCH_GET_URL, userQuery.toJsonString()); return WxMpUser.fromJsonList(responseContent); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Card.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Card.java new file mode 100644 index 0000000000..c97f88f2fc --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Card.java @@ -0,0 +1,31 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * . + * @author leeis + * @Date 2018/12/29 + */ +@Data +public class Card implements Serializable { + + private static final long serialVersionUID = -3697110761983756780L; + + /** + * 基本信息. + */ + @SerializedName("base_info") + private BaseInfo baseInfo; + + /** + * 创建优惠券特有的高级字段. + */ + @SerializedName("advanced_info") + private AdvancedInfo advancedInfo; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CardCreateRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CardCreateRequest.java new file mode 100644 index 0000000000..8cb16bc7b2 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CardCreateRequest.java @@ -0,0 +1,13 @@ +package me.chanjar.weixin.mp.bean.card; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @Author leeis + * @Date 2018/12/29 + */ +@Data +public class CardCreateRequest implements Serializable { +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CashCard.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CashCard.java new file mode 100644 index 0000000000..3d4de40c0b --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CashCard.java @@ -0,0 +1,39 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * . + * @author leeis + * @Date 2018/12/29 + */ +@Data +public final class CashCard extends Card implements Serializable { + + private static final long serialVersionUID = 6965491956462769745L; + + /** + * 代金券专用,表示起用金额(单位为分),如果无起用门槛则填0 + */ + @SerializedName("least_cost") + private int leastCost; + + /** + * 代金券专用,表示减免金额。(单位为分) + */ + @SerializedName("reduce_cost") + private int reduceCost; + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } + + public static CashCard fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, CashCard.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CashCardCreateRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CashCardCreateRequest.java new file mode 100644 index 0000000000..dcefab0e29 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/CashCardCreateRequest.java @@ -0,0 +1,25 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * . + * @author leeis + * @Date 2018/12/29 + */ +@Data +public class CashCardCreateRequest extends CardCreateRequest implements Serializable { + @SerializedName("card_type") + private String cardType = "CASH"; + + private CashCard cash; + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/DiscountCard.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/DiscountCard.java new file mode 100644 index 0000000000..b2c3a13ffc --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/DiscountCard.java @@ -0,0 +1,32 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * . + * @author leeis + * @Date 2018/12/29 + */ +@Data +public final class DiscountCard extends Card implements Serializable { + + private static final long serialVersionUID = 1704610082472315077L; + + /** + * 折扣券专用,表示打折额度(百分比)。填30就是七折。 + */ + private int discount; + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } + + public static DiscountCard fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, DiscountCard.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/DiscountCardCreateRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/DiscountCardCreateRequest.java new file mode 100644 index 0000000000..869c487c92 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/DiscountCardCreateRequest.java @@ -0,0 +1,25 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * . + * @author leeis + * @Date 2018/12/29 + */ +@Data +public class DiscountCardCreateRequest extends CardCreateRequest implements Serializable { + @SerializedName("card_type") + private String cardType = "DISCOUNT"; + + private DiscountCard discount; + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GeneralCard.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GeneralCard.java new file mode 100644 index 0000000000..dcfba74da7 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GeneralCard.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * . + * @author leeis + * @Date 2018/12/29 + */ +@Data +public final class GeneralCard extends Card implements Serializable { + + private static final long serialVersionUID = -1577656733441132585L; + + /** + * 兑换券专用,填写兑换内容的名称。 + */ + @SerializedName("default_detail") + private String defaultDetail; + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } + + public static GeneralCard fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, GeneralCard.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GeneralCardCreateRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GeneralCardCreateRequest.java new file mode 100644 index 0000000000..8a9c3d1801 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GeneralCardCreateRequest.java @@ -0,0 +1,26 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * . + * @author leeis + * @Date 2018/12/29 + */ +@Data +public class GeneralCardCreateRequest extends CardCreateRequest implements Serializable { + @SerializedName("card_type") + private String cardType = "GENERAL_COUPON"; + + @SerializedName("general_coupon") + private GeneralCard generalCoupon; + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GiftCard.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GiftCard.java new file mode 100644 index 0000000000..0bfb5359ba --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GiftCard.java @@ -0,0 +1,32 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * . + * @author leeis + * @Date 2018/12/29 + */ +@Data +public final class GiftCard extends Card implements Serializable { + + private static final long serialVersionUID = -6168739707511792266L; + + /** + * 兑换券专用,填写兑换内容的名称。 + */ + private String gift; + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } + + public static GiftCard fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, GiftCard.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GiftCardCreateRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GiftCardCreateRequest.java new file mode 100644 index 0000000000..8791b70a9d --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GiftCardCreateRequest.java @@ -0,0 +1,25 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * . + * @author leeis + * @Date 2018/12/29 + */ +@Data +public class GiftCardCreateRequest extends CardCreateRequest implements Serializable { + @SerializedName("card_type") + private String cardType = "GIFT"; + + private GiftCard gift; + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GrouponCard.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GrouponCard.java new file mode 100644 index 0000000000..b0df7262bb --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GrouponCard.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * . + * @author leeis + * @Date 2018/12/29 + */ +@Data +public final class GrouponCard extends Card implements Serializable { + + private static final long serialVersionUID = 3221312561666697005L; + + /** + * 团购券专用,团购详情 + */ + @SerializedName("deal_detail") + private String dealDetail; + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } + + public static GrouponCard fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, GrouponCard.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GrouponCardCreateRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GrouponCardCreateRequest.java new file mode 100644 index 0000000000..48b1e3e7da --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/GrouponCardCreateRequest.java @@ -0,0 +1,25 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * . + * @author leeis + * @Date 2018/12/29 + */ +@Data +public class GrouponCardCreateRequest extends CardCreateRequest implements Serializable { + @SerializedName("card_type") + private String cardType = "GROUPON"; + + private GrouponCard groupon; + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardCreateMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardCreateMessage.java new file mode 100644 index 0000000000..760002cb52 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardCreateMessage.java @@ -0,0 +1,23 @@ +package me.chanjar.weixin.mp.bean.card; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +@Data +public final class WxMpCardCreateMessage implements Serializable { + + @SerializedName("card") + private CardCreateRequest cardCreateRequest; + + @Override + public String toString() { + return WxMpGsonBuilder.create().toJson(this); + } + + public static WxMpCardCreateMessage fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpCardCreateMessage.class); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java index cbd6970597..368f70e383 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.Serializable; +import java.nio.charset.StandardCharsets; import java.util.Map; import org.apache.commons.io.IOUtils; @@ -445,6 +446,8 @@ public class WxMpXmlMessage implements Serializable { /** * 审核结果,成功succ 或失败fail. + * + * 在商品审核结果推送时,verify_ok表示审核通过,verify_not_pass表示审核未通过。 */ @XStreamAlias("Result") private String result; @@ -566,6 +569,68 @@ public class WxMpXmlMessage implements Serializable { @XStreamAlias("Reason") private String reason; + /////////////////////////////////////// + // 扫一扫事件推送 + /////////////////////////////////////// + /** + * 商品编码标准 + */ + @XStreamAlias("KeyStandard") + private String keyStandard; + /** + * 商品编码内容 + */ + @XStreamAlias("KeyStr") + private String keyStr; + + /** + * 用户在微信内设置的国家 + */ + @XStreamAlias("Country") + private String country; + + /** + * 用户在微信内设置的省份 + */ + @XStreamAlias("Province") + private String province; + + /** + * 用户在微信内设置的城市 + */ + @XStreamAlias("City") + private String city; + + /** + * 用户的性别,1为男性,2为女性,0代表未知 + */ + @XStreamAlias("Sex") + private String sex; + + /** + * 打开商品主页的场景,1为扫码,2为其他打开场景(如会话、收藏或朋友圈) + */ + @XStreamAlias("Scene") + private String scene; + + /** + * 调用“获取商品二维码接口”时传入的extinfo,为标识参数 + */ + @XStreamAlias("ExtInfo") + private String extInfo; + + /** + * 用户的实时地理位置信息(目前只精确到省一级),可在国家统计局网站查到对应明细: http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/201504/t20150415_712722.html + */ + @XStreamAlias("RegionCode") + private String regionCode; + + /** + * 审核未通过的原因。 + */ + @XStreamAlias("ReasonMsg") + private String reasonMsg; + public static WxMpXmlMessage fromXml(String xml) { //修改微信变态的消息内容格式,方便解析 xml = xml.replace(" ", ""); @@ -598,7 +663,7 @@ public static WxMpXmlMessage fromEncryptedXml(String encryptedXml, WxMpConfigSto public static WxMpXmlMessage fromEncryptedXml(InputStream is, WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce, String msgSignature) { try { - return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxMpConfigStorage, timestamp, nonce, msgSignature); + return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8), wxMpConfigStorage, timestamp, nonce, msgSignature); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpChangeOpenid.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpChangeOpenid.java new file mode 100644 index 0000000000..203aa97f5b --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpChangeOpenid.java @@ -0,0 +1,34 @@ +package me.chanjar.weixin.mp.bean.result; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; +import lombok.Data; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.util.List; + +/** + * 主体变更迁移用户 openid 返回. + * + * @author 007gzs + */ +@Data +public class WxMpChangeOpenid implements Serializable { + private static final long serialVersionUID = -8132023284876534743L; + private String oriOpenid; + private String newOpenid; + private String errMsg; + public static WxMpChangeOpenid fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpChangeOpenid.class); + } + public static List fromJsonList(String json) { + Type collectionType = new TypeToken >() { + }.getType(); + Gson gson = WxMpGsonBuilder.create(); + JsonObject jsonObject = gson.fromJson(json, JsonObject.class); + return gson.fromJson(jsonObject.get("result_list"), collectionType); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java index 3923374366..f04f8c91a8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java @@ -55,6 +55,7 @@ public class WxMpTemplateMessage implements Serializable { /** * 模板数据. */ + @Builder.Default private List
data = new ArrayList<>(); public WxMpTemplateMessage addData(WxMpTemplateData datum) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/AiLangType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java similarity index 84% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/AiLangType.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java index 54b61b1e51..b37772b01a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/AiLangType.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.mp; +package me.chanjar.weixin.mp.enums; import lombok.Getter; @@ -13,11 +13,11 @@ @Getter public enum AiLangType { /** - * 中文 汉语 + * 中文 汉语. */ zh_CN("zh_CN"), /** - * 英文 英语 + * 英文 英语. */ en_US("en_US"); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/TicketType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/TicketType.java new file mode 100644 index 0000000000..02de06f6d1 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/TicketType.java @@ -0,0 +1,35 @@ +package me.chanjar.weixin.mp.enums; + +import lombok.Getter; + +/** + * + * ticket类型枚举 + * Created by Binary Wang on 2018/11/18. + *+ * + * @author Binary Wang + */ +@Getter +public enum TicketType { + /** + * jsapi + */ + JSAPI("jsapi"), + /** + * sdk + */ + SDK("2"), + /** + * 微信卡券 + */ + WX_CARD("wx_card"); + /** + * type代码 + */ + private String code; + + TicketType(String code) { + this.code = code; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpChangeOpenidGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpChangeOpenidGsonAdapter.java new file mode 100644 index 0000000000..430726ca49 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpChangeOpenidGsonAdapter.java @@ -0,0 +1,25 @@ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid; + +import java.lang.reflect.Type; + +public class WxMpChangeOpenidGsonAdapter implements JsonDeserializer{ + + @Override + public WxMpChangeOpenid deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject o = json.getAsJsonObject(); + WxMpChangeOpenid changeOpenid = new WxMpChangeOpenid(); + changeOpenid.setOriOpenid(GsonHelper.getString(o, "ori_openid")); + changeOpenid.setNewOpenid(GsonHelper.getString(o, "new_openid")); + changeOpenid.setErrMsg(GsonHelper.getString(o, "err_msg")); + return changeOpenid; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java index e34128eaf5..a4357e9117 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java @@ -25,6 +25,7 @@ public class WxMpGsonBuilder { INSTANCE.registerTypeAdapter(WxMpMassTagMessage.class, new WxMpMassTagMessageGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpMassOpenIdsMessage.class, new WxMpMassOpenIdsMessageGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpUser.class, new WxMpUserGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMpChangeOpenid.class, new WxMpChangeOpenidGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpUserList.class, new WxUserListGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpMassVideo.class, new WxMpMassVideoAdapter()); INSTANCE.registerTypeAdapter(WxMpMassSendResult.class, new WxMpMassSendResultAdapter()); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteOkhttpRequestExecutor.java index 1635793e95..2e4a37ec42 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteOkhttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteOkhttpRequestExecutor.java @@ -1,15 +1,21 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; -import okhttp3.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; +import okhttp3.FormBody; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; /** * Created by ecoolper on 2017/5/5. @@ -17,11 +23,15 @@ public class MaterialDeleteOkhttpRequestExecutor extends MaterialDeleteRequestExecutor { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public MaterialDeleteOkhttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } + @Override + public void execute(String uri, String data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + @Override public Boolean execute(String uri, String materialId) throws WxErrorException, IOException { logger.debug("MaterialDeleteOkhttpRequestExecutor is running"); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java index a185b54d75..b1fd2ca90b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java @@ -1,7 +1,11 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; +import java.io.IOException; + +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; public abstract class MaterialDeleteRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; @@ -10,6 +14,11 @@ public MaterialDeleteRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } + @Override + public void execute(String uri, String data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java index 62ef709aca..a636ed2696 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java @@ -1,7 +1,11 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; +import java.io.IOException; + +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; public abstract class MaterialNewsInfoRequestExecutor implements RequestExecutor { @@ -11,6 +15,11 @@ public MaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } + @Override + public void execute(String uri, String data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java index c279be3213..4e518669b1 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java @@ -1,7 +1,11 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; +import java.io.IOException; + +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; import me.chanjar.weixin.mp.bean.material.WxMpMaterial; import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; @@ -15,6 +19,11 @@ public MaterialUploadRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } + @Override + public void execute(String uri, WxMpMaterial data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java index b09fd75ae2..ee0575929b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java @@ -1,30 +1,37 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; - import me.chanjar.weixin.common.util.http.RequestExecutor; - import me.chanjar.weixin.common.util.http.RequestHttp; - - import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; +import java.io.IOException; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; public abstract class MaterialVideoInfoRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; public MaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { - this.requestHttp = requestHttp; - } - - public static RequestExecutor create(RequestHttp requestHttp) { - switch (requestHttp.getRequestType()) { - case APACHE_HTTP: - return new MaterialVideoInfoApacheHttpRequestExecutor(requestHttp); - case JODD_HTTP: - return new MaterialVideoInfoJoddHttpRequestExecutor(requestHttp); - case OK_HTTP: - return new MaterialVideoInfoOkhttpRequestExecutor(requestHttp); - default: - return null; - } - } - - } + this.requestHttp = requestHttp; + } + + @Override + public void execute(String uri, String data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + + public static RequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new MaterialVideoInfoApacheHttpRequestExecutor(requestHttp); + case JODD_HTTP: + return new MaterialVideoInfoJoddHttpRequestExecutor(requestHttp); + case OK_HTTP: + return new MaterialVideoInfoOkhttpRequestExecutor(requestHttp); + default: + return null; + } + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java index c11c41cce0..c00ac148e4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java @@ -1,13 +1,15 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; -import me.chanjar.weixin.common.util.http.RequestExecutor; -import me.chanjar.weixin.common.util.http.RequestHttp; - import java.io.File; +import java.io.IOException; import java.io.InputStream; -public abstract class MaterialVoiceAndImageDownloadRequestExecutor - implements RequestExecutor { +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; + +public abstract class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; protected File tmpDirFile; @@ -16,6 +18,11 @@ public MaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, Fil this.tmpDirFile = tmpDirFile; } + @Override + public void execute(String uri, String data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp, File tmpDirFile) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java index c937fbe51a..18678f87f5 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java @@ -1,11 +1,14 @@ package me.chanjar.weixin.mp.util.requestexecuter.media; +import java.io.File; +import java.io.IOException; + +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; -import java.io.File; - /** * @author miller */ @@ -16,6 +19,11 @@ public MediaImgUploadRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } + @Override + public void execute(String uri, File data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java index 7c666cd0d5..ca4f6e6d4c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java @@ -1,15 +1,17 @@ package me.chanjar.weixin.mp.util.requestexecuter.qrcode; +import java.io.File; +import java.io.IOException; + import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; -import java.io.File; - /** - * 获得QrCode图片 请求执行器 + * 获得QrCode图片 请求执行器. * * @author chanjarster */ @@ -20,6 +22,11 @@ public QrCodeRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } + @Override + public void execute(String uri, WxMpQrCodeTicket data, ResponseHandler handler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) throws WxErrorException { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java index 34c7ae2108..32bab9f60e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java @@ -1,9 +1,12 @@ package me.chanjar.weixin.mp.util.requestexecuter.voice; +import java.io.File; +import java.io.IOException; + +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; - -import java.io.File; +import me.chanjar.weixin.common.util.http.ResponseHandler; /** * @@ -19,6 +22,11 @@ public VoiceUploadRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } + @Override + public void execute(String uri, File data, ResponseHandlerhandler) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data)); + } + public static RequestExecutor create(RequestHttp requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java deleted file mode 100644 index ffcd232cf4..0000000000 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java +++ /dev/null @@ -1,38 +0,0 @@ -package me.chanjar.weixin.mp.api; - -import com.google.inject.Inject; -import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.mp.api.test.ApiTestModule; -import org.apache.commons.lang3.StringUtils; -import org.testng.*; -import org.testng.annotations.*; - -/** - * 基础API测试 - * - * @author chanjarster - */ -@Test(groups = "baseAPI") -@Guice(modules = ApiTestModule.class) -public class WxMpBaseAPITest { - - @Inject - protected WxMpService wxService; - - public void testRefreshAccessToken() throws WxErrorException { - WxMpConfigStorage configStorage = this.wxService.getWxMpConfigStorage(); - String before = configStorage.getAccessToken(); - this.wxService.getAccessToken(false); - - String after = configStorage.getAccessToken(); - Assert.assertNotEquals(before, after); - Assert.assertTrue(StringUtils.isNotBlank(after)); - } - - public void testJsapiTicket() throws WxErrorException { - String jsapiTicket = this.wxService.getJsapiTicket(false); - System.out.println(jsapiTicket); - Assert.assertNotNull(jsapiTicket); - } - -} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImplTest.java index f10f988866..1e61c1faa8 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImplTest.java @@ -2,7 +2,7 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.mp.AiLangType; +import me.chanjar.weixin.mp.enums.AiLangType; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.test.ApiTestModule; import org.testng.annotations.Guice; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java index 06945d9a08..5623299394 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java @@ -2,8 +2,10 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.bean.WxCardApiSignature; +import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.test.ApiTestModule; +import me.chanjar.weixin.mp.bean.card.*; import me.chanjar.weixin.mp.bean.result.WxMpCardResult; import org.testng.annotations.*; @@ -100,4 +102,98 @@ public void testUnavailableCardCode() throws Exception { assertNotNull(result); System.out.println(result); } + + @Test + public void testCreateGrouponCard() throws WxErrorException { + + BaseInfo base = new BaseInfo(); + base.setLogoUrl("http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFNjakmxibMLGWpXrEXB33367o7zHN0CwngnQY7zb7g/0"); + base.setBrandName("测试优惠券"); + base.setCodeType("CODE_TYPE_QRCODE"); + base.setTitle("测试标题"); + base.setColor("Color010"); + base.setNotice("测试Notice"); + base.setServicePhone("020-88888888"); + base.setDescription("不可与其他优惠同享\\n如需团购券发票,请在消费时向商户提出\\n店内均可使用,仅限堂食"); + DateInfo info = new DateInfo(); + info.setType("DATE_TYPE_FIX_TERM"); + info.setFixedBeginTerm(0); + info.setFixedTerm(30); + base.setDateInfo(info); + Sku sku = new Sku(); + sku.setQuantity(100); + base.setSku(sku); + base.setGetLimit(1); + base.setCanShare(true); + base.setCanGiveFriend(true); + base.setUseAllLocations(true); + base.setCenterTitle("顶部居中按钮"); + base.setCenterSubTitle("按钮下方的wording"); + base.setCenterUrl("www.qq.com"); + base.setCustomUrl("http://www.qq.com"); + base.setCustomUrlName("立即使用"); + base.setCustomUrlSubTitle("副标题tip"); + base.setPromotionUrlName("更多优惠"); + base.setPromotionUrl("http://www.qq.com"); + base.setLocationIdList("1234"); + + //团购券 + WxMpCardCreateMessage grouponMessage = new WxMpCardCreateMessage(); + GrouponCardCreateRequest grouponCardCreateRequest = new GrouponCardCreateRequest(); + GrouponCard grouponCard = new GrouponCard(); + grouponCard.setBaseInfo(base); + grouponCard.setDealDetail("deal detail"); + + grouponCardCreateRequest.setGroupon(grouponCard); + grouponMessage.setCardCreateRequest(grouponCardCreateRequest); + + System.out.println(this.wxService.getCardService().createCard(grouponMessage)); + + //现金券 + WxMpCardCreateMessage cashMessage = new WxMpCardCreateMessage(); + CashCardCreateRequest cashCardCreateRequest = new CashCardCreateRequest(); + CashCard cashCard = new CashCard(); + cashCard.setBaseInfo(base); + cashCard.setLeastCost(1000); + cashCard.setReduceCost(100); + + cashCardCreateRequest.setCash(cashCard); + cashMessage.setCardCreateRequest(cashCardCreateRequest); + + System.out.println(this.wxService.getCardService().createCard(cashMessage)); + + //折扣券 + WxMpCardCreateMessage discountMessage = new WxMpCardCreateMessage(); + DiscountCardCreateRequest discountCardCreateRequest = new DiscountCardCreateRequest(); + DiscountCard discountCard = new DiscountCard(); + discountCard.setBaseInfo(base); + discountCard.setDiscount(30); + + discountCardCreateRequest.setDiscount(discountCard); + discountMessage.setCardCreateRequest(discountCardCreateRequest); + + System.out.println(this.wxService.getCardService().createCard(discountMessage)); + + //兑换券 + WxMpCardCreateMessage giftMessage = new WxMpCardCreateMessage(); + GiftCardCreateRequest giftCardCreateRequest = new GiftCardCreateRequest(); + GiftCard giftCard = new GiftCard(); + giftCard.setBaseInfo(base); + giftCard.setGift("星巴克雪瑞纳咖啡大杯"); + + giftCardCreateRequest.setGift(giftCard); + giftMessage.setCardCreateRequest(giftCardCreateRequest); + System.out.println(this.wxService.getCardService().createCard(giftMessage)); + + //普通兑换券 + WxMpCardCreateMessage generalMessage = new WxMpCardCreateMessage(); + GeneralCardCreateRequest generalCardCreateRequest = new GeneralCardCreateRequest(); + GeneralCard generalCard = new GeneralCard(); + generalCard.setBaseInfo(base); + generalCard.setDefaultDetail("音乐木盒"); + + generalCardCreateRequest.setGeneralCoupon(generalCard); + generalMessage.setCardCreateRequest(generalCardCreateRequest); + System.out.println(this.wxService.getCardService().createCard(generalMessage)); + } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java index e9999f577d..7c36930b0a 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java @@ -1,14 +1,18 @@ package me.chanjar.weixin.mp.api.impl; +import org.apache.commons.lang3.StringUtils; +import org.testng.*; +import org.testng.annotations.*; + import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.test.ApiTestModule; import me.chanjar.weixin.mp.api.test.TestConfigStorage; import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo; -import org.testng.*; -import org.testng.annotations.*; +import me.chanjar.weixin.mp.enums.TicketType; import static org.testng.Assert.*; @@ -40,4 +44,19 @@ public void testBuildQrConnectUrl() { System.out.println(qrConnectUrl); } + public void testGetTicket() throws WxErrorException { + String ticket = this.wxService.getTicket(TicketType.SDK, false); + System.out.println(ticket); + Assert.assertNotNull(ticket); + } + + public void testRefreshAccessToken() throws WxErrorException { + WxMpConfigStorage configStorage = this.wxService.getWxMpConfigStorage(); + String before = configStorage.getAccessToken(); + this.wxService.getAccessToken(false); + + String after = configStorage.getAccessToken(); + Assert.assertNotEquals(before, after); + Assert.assertTrue(StringUtils.isNotBlank(after)); + } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java index 0a4cd21a17..fa73b8f4d8 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java @@ -1,5 +1,16 @@ package me.chanjar.weixin.mp.api.impl; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import me.chanjar.weixin.mp.api.WxMpUserService; +import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.testng.*; +import org.testng.annotations.*; + import com.google.inject.Inject; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; @@ -8,11 +19,9 @@ import me.chanjar.weixin.mp.bean.WxMpUserQuery; import me.chanjar.weixin.mp.bean.result.WxMpUser; import me.chanjar.weixin.mp.bean.result.WxMpUserList; -import org.testng.*; -import org.testng.annotations.*; -import java.util.ArrayList; -import java.util.List; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; /** * 测试用户相关的接口 @@ -20,7 +29,7 @@ * @author chanjarster * @author Binary Wang */ -@Test(groups = "userAPI") +@Test @Guice(modules = ApiTestModule.class) public class WxMpUserServiceImplTest { @@ -68,10 +77,56 @@ public void testUserInfoListByWxMpUserQuery() throws WxErrorException { public void testUserList() throws WxErrorException { WxMpUserList wxMpUserList = this.wxService.getUserService().userList(null); Assert.assertNotNull(wxMpUserList); - Assert.assertFalse(wxMpUserList.getCount() == -1); - Assert.assertFalse(wxMpUserList.getTotal() == -1); - Assert.assertFalse(wxMpUserList.getOpenids().size() == -1); + Assert.assertNotEquals(-1, wxMpUserList.getCount()); + Assert.assertNotEquals(-1, wxMpUserList.getTotal()); + Assert.assertNotEquals(-1, wxMpUserList.getOpenids().size()); System.out.println(wxMpUserList); } + public void testChangeOpenid() throws WxErrorException { + List openids = new ArrayList<>(); + openids.add(this.configProvider.getOpenid()); + List wxMpChangeOpenidList = this.wxService.getUserService() + .changeOpenid("原公众号appid", openids); + Assert.assertNotNull(wxMpChangeOpenidList); + Assert.assertEquals(1, wxMpChangeOpenidList.size()); + WxMpChangeOpenid wxMpChangeOpenid = wxMpChangeOpenidList.get(0); + Assert.assertNotNull(wxMpChangeOpenid); + Assert.assertEquals(this.configProvider.getOpenid(), wxMpChangeOpenid.getOriOpenid()); + System.out.println(wxMpChangeOpenid); + } + + public static class MockTest { + private WxMpService wxService = mock(WxMpService.class); + @Test + public void testMockChangeOpenid() throws WxErrorException { + List openids = new ArrayList<>(); + openids.add("oEmYbwN-n24jxvk4Sox81qedINkQ"); + openids.add("oEmYbwH9uVd4RKJk7ZZg6SzL6tTo"); + String fromAppid = "old_appid"; + Map map = new HashMap<>(); + map.put("from_appid", fromAppid); + map.put("openid_list", openids); + + String returnJson = "{\"errcode\": 0,\"errmsg\": \"ok\",\"result_list\": [{\"ori_openid\": \"oEmYbwN-n24jxvk4Sox81qedINkQ\",\"new_openid\": \"o2FwqwI9xCsVadFah_HtpPfaR-X4\",\"err_msg\": \"ok\"},{\"ori_openid\": \"oEmYbwH9uVd4RKJk7ZZg6SzL6tTo\",\"err_msg\": \"ori_openid error\"}]}"; + when(wxService.post(WxMpUserService.USER_CHANGE_OPENID_URL, WxMpGsonBuilder.create().toJson(map))).thenReturn(returnJson); + List wxMpChangeOpenidList = this.wxService.getUserService() + .changeOpenid(fromAppid, openids); + Assert.assertNotNull(wxMpChangeOpenidList); + Assert.assertEquals(2, wxMpChangeOpenidList.size()); + WxMpChangeOpenid wxMpChangeOpenid = wxMpChangeOpenidList.get(0); + Assert.assertNotNull(wxMpChangeOpenid); + Assert.assertEquals("oEmYbwN-n24jxvk4Sox81qedINkQ", wxMpChangeOpenid.getOriOpenid()); + Assert.assertEquals("o2FwqwI9xCsVadFah_HtpPfaR-X4", wxMpChangeOpenid.getNewOpenid()); + Assert.assertEquals("ok", wxMpChangeOpenid.getErrMsg()); + wxMpChangeOpenid = wxMpChangeOpenidList.get(1); + Assert.assertNotNull(wxMpChangeOpenid); + Assert.assertEquals("oEmYbwH9uVd4RKJk7ZZg6SzL6tTo", wxMpChangeOpenid.getOriOpenid()); + Assert.assertNull(wxMpChangeOpenid.getNewOpenid()); + Assert.assertEquals("ori_openid error", wxMpChangeOpenid.getErrMsg()); + System.out.println(wxMpChangeOpenid); + } + + } + } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessageTest.java index e741e93108..50bb0ac09d 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessageTest.java @@ -1,14 +1,13 @@ package me.chanjar.weixin.mp.bean.message; +import me.chanjar.weixin.common.api.WxConsts; +import org.testng.annotations.Test; + import java.util.List; import java.util.Map; -import org.testng.annotations.*; - -import me.chanjar.weixin.common.api.WxConsts; - import static org.assertj.core.api.Assertions.assertThat; -import static org.testng.Assert.*; +import static org.testng.Assert.assertEquals; @Test public class WxMpXmlMessageTest { @@ -44,7 +43,7 @@ public void testFromXml() { + " " + "" + " " - + " " + "1 \n" + + "1 " + "" + " " + "- " + "
" @@ -52,12 +51,22 @@ public void testFromXml() { + " " - + " " + + "\n" - + " \n" - + " \n" - + " \n" - + " \n" + + " " + + " " + + " " + + " " + + " " + " " + + " " + + " " + + " " + + " " + + " 1 " + + "2 " + + "" + + " " + + " " + ""; WxMpXmlMessage wxMessage = WxMpXmlMessage.fromXml(xml); assertEquals(wxMessage.getToUser(), "toUser"); @@ -92,6 +101,16 @@ public void testFromXml() { assertEquals(wxMessage.getSendLocationInfo().getScale(), "15"); assertEquals(wxMessage.getSendLocationInfo().getLabel(), " 广州市海珠区客村艺苑路 106号"); assertEquals(wxMessage.getSendLocationInfo().getPoiName(), "wo de poi"); + assertEquals(wxMessage.getKeyStandard(), "ean13"); + assertEquals(wxMessage.getKeyStr(), "6901481811083"); + assertEquals(wxMessage.getCountry(), "中国"); + assertEquals(wxMessage.getProvince(), "广东"); + assertEquals(wxMessage.getCity(), "揭阳"); + assertEquals(wxMessage.getSex(), "1"); + assertEquals(wxMessage.getScene(), "2"); + assertEquals(wxMessage.getExtInfo(), "123"); + assertEquals(wxMessage.getRegionCode(), "440105"); + assertEquals(wxMessage.getReasonMsg(), ""); } public void testFromXml2() { @@ -232,7 +251,8 @@ public void testFromXml_MASSSENDJOBFINISH() { final Map allFields = wxMessage.getAllFieldsMap(); assertThat(allFields).isNotNull(); final Map copyrightCheckResult = (Map ) allFields.get("CopyrightCheckResult"); - List