| @@ -4,6 +4,7 @@ import cn.binarywang.wx.miniapp.api.WxMaMsgService; | |||||
| import cn.binarywang.wx.miniapp.api.WxMaService; | import cn.binarywang.wx.miniapp.api.WxMaService; | ||||
| import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | ||||
| import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; | import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; | ||||
| import cn.binarywang.wx.miniapp.constant.WxMaConstants; | |||||
| import com.google.gson.JsonObject; | import com.google.gson.JsonObject; | ||||
| import com.google.gson.JsonParser; | import com.google.gson.JsonParser; | ||||
| import me.chanjar.weixin.common.bean.result.WxError; | import me.chanjar.weixin.common.bean.result.WxError; | ||||
| @@ -30,7 +31,7 @@ public class WxMaMsgServiceImpl implements WxMaMsgService { | |||||
| public void sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException { | public void sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException { | ||||
| String responseContent = this.wxMaService.post(TEMPLATE_MSG_SEND_URL, templateMessage.toJson()); | String responseContent = this.wxMaService.post(TEMPLATE_MSG_SEND_URL, templateMessage.toJson()); | ||||
| JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); | JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); | ||||
| if (jsonObject.get("errcode").getAsInt() != 0) { | |||||
| if (jsonObject.get(WxMaConstants.ERRCODE).getAsInt() != 0) { | |||||
| throw new WxErrorException(WxError.fromJson(responseContent)); | throw new WxErrorException(WxError.fromJson(responseContent)); | ||||
| } | } | ||||
| } | } | ||||
| @@ -2,6 +2,7 @@ package cn.binarywang.wx.miniapp.api.impl; | |||||
| import cn.binarywang.wx.miniapp.api.*; | import cn.binarywang.wx.miniapp.api.*; | ||||
| import cn.binarywang.wx.miniapp.config.WxMaConfig; | import cn.binarywang.wx.miniapp.config.WxMaConfig; | ||||
| import cn.binarywang.wx.miniapp.constant.WxMaConstants; | |||||
| import com.google.gson.JsonParser; | import com.google.gson.JsonParser; | ||||
| import me.chanjar.weixin.common.bean.WxAccessToken; | import me.chanjar.weixin.common.bean.WxAccessToken; | ||||
| import me.chanjar.weixin.common.bean.result.WxError; | import me.chanjar.weixin.common.bean.result.WxError; | ||||
| @@ -147,6 +148,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
| /** | /** | ||||
| * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 | * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 | ||||
| */ | */ | ||||
| @Override | |||||
| public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException { | public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException { | ||||
| int retryTimes = 0; | int retryTimes = 0; | ||||
| do { | do { | ||||
| @@ -195,11 +197,10 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
| WxError error = e.getError(); | WxError error = e.getError(); | ||||
| /* | /* | ||||
| * 发生以下情况时尝试刷新access_token | * 发生以下情况时尝试刷新access_token | ||||
| * 40001 获取access_token时AppSecret错误,或者access_token无效 | |||||
| * 42001 access_token超时 | |||||
| * 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期) | |||||
| */ | */ | ||||
| if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001 || error.getErrorCode() == 40014) { | |||||
| if (error.getErrorCode() == WxMaConstants.ErrorCode.ERR_40001 | |||||
| || error.getErrorCode() == WxMaConstants.ErrorCode.ERR_42001 | |||||
| || error.getErrorCode() == WxMaConstants.ErrorCode.ERR_40014) { | |||||
| // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token | // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token | ||||
| this.getWxMaConfig().expireAccessToken(); | this.getWxMaConfig().expireAccessToken(); | ||||
| if (this.getWxMaConfig().autoRefreshToken()) { | if (this.getWxMaConfig().autoRefreshToken()) { | ||||
| @@ -19,14 +19,14 @@ import java.util.Map; | |||||
| public class WxMaUserServiceImpl implements WxMaUserService { | public class WxMaUserServiceImpl implements WxMaUserService { | ||||
| private WxMaService service; | private WxMaService service; | ||||
| WxMaUserServiceImpl(WxMaService service) { | |||||
| public WxMaUserServiceImpl(WxMaService service) { | |||||
| this.service = service; | this.service = service; | ||||
| } | } | ||||
| @Override | @Override | ||||
| public WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException { | public WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException { | ||||
| final WxMaConfig config = service.getWxMaConfig(); | final WxMaConfig config = service.getWxMaConfig(); | ||||
| Map<String, String> params = new HashMap<>(); | |||||
| Map<String, String> params = new HashMap<>(8); | |||||
| params.put("appid", config.getAppid()); | params.put("appid", config.getAppid()); | ||||
| params.put("secret", config.getSecret()); | params.put("secret", config.getSecret()); | ||||
| params.put("js_code", jsCode); | params.put("js_code", jsCode); | ||||
| @@ -4,9 +4,10 @@ import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||||
| /** | /** | ||||
| * 微信二维码(小程序码)包装器 | * 微信二维码(小程序码)包装器 | ||||
| * Created by Element on 2017/7/27. | |||||
| * | |||||
| * @author Element | |||||
| */ | */ | ||||
| public abstract class WxMaQrcodeWrapper { | |||||
| public abstract class AbstractWxMaQrcodeWrapper { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| @@ -6,6 +6,7 @@ package cn.binarywang.wx.miniapp.bean; | |||||
| * 用于描述二维码(小程序码)颜色(RGB参数值), | * 用于描述二维码(小程序码)颜色(RGB参数值), | ||||
| * 详情请查看文档 https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html | * 详情请查看文档 https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html | ||||
| * </pre> | * </pre> | ||||
| * @author Element | |||||
| */ | */ | ||||
| public class WxMaCodeLineColor { | public class WxMaCodeLineColor { | ||||
| private String r = "0", g = "0", b = "0"; | private String r = "0", g = "0", b = "0"; | ||||
| @@ -25,14 +25,14 @@ public class WxMaKefuMessage implements Serializable { | |||||
| /** | /** | ||||
| * 获得文本消息builder | * 获得文本消息builder | ||||
| */ | */ | ||||
| public static TextBuilder TEXT() { | |||||
| public static TextBuilder newTextBuilder() { | |||||
| return new TextBuilder(); | return new TextBuilder(); | ||||
| } | } | ||||
| /** | /** | ||||
| * 获得图片消息builder | * 获得图片消息builder | ||||
| */ | */ | ||||
| public static ImageBuilder IMAGE() { | |||||
| public static ImageBuilder newImageBuilder() { | |||||
| return new ImageBuilder(); | return new ImageBuilder(); | ||||
| } | } | ||||
| @@ -7,7 +7,7 @@ import java.io.Serializable; | |||||
| /** | /** | ||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| */ | */ | ||||
| public class WxMaQrcode extends WxMaQrcodeWrapper implements Serializable { | |||||
| public class WxMaQrcode extends AbstractWxMaQrcodeWrapper implements Serializable { | |||||
| private static final long serialVersionUID = 5777119669111011584L; | private static final long serialVersionUID = 5777119669111011584L; | ||||
| private String path; | private String path; | ||||
| private int width = 430; | private int width = 430; | ||||
| @@ -6,9 +6,11 @@ import com.google.gson.annotations.SerializedName; | |||||
| import java.io.Serializable; | import java.io.Serializable; | ||||
| /** | /** | ||||
| * Created by Element on 2017/7/27. | |||||
| * | |||||
| * @author Element | |||||
| * @date 2017/7/27 | |||||
| */ | */ | ||||
| public class WxMaWxcode extends WxMaQrcodeWrapper implements Serializable { | |||||
| public class WxMaWxcode extends AbstractWxMaQrcodeWrapper implements Serializable { | |||||
| private static final long serialVersionUID = 1287399621649210322L; | private static final long serialVersionUID = 1287399621649210322L; | ||||
| private String path; | private String path; | ||||
| @@ -6,9 +6,11 @@ import com.google.gson.annotations.SerializedName; | |||||
| import java.io.Serializable; | import java.io.Serializable; | ||||
| /** | /** | ||||
| * Created by Element on 2017/7/27. | |||||
| * | |||||
| * @author Element | |||||
| * @date 2017/7/27 | |||||
| */ | */ | ||||
| public class WxMaWxcodeLimit extends WxMaQrcodeWrapper implements Serializable { | |||||
| public class WxMaWxcodeLimit extends AbstractWxMaQrcodeWrapper implements Serializable { | |||||
| private static final long serialVersionUID = 4782193774524960401L; | private static final long serialVersionUID = 4782193774524960401L; | ||||
| private String scene; | private String scene; | ||||
| private String page; | private String page; | ||||
| @@ -13,8 +13,8 @@ public final class ImageBuilder extends BaseBuilder<ImageBuilder> { | |||||
| this.msgType = WxMaConstants.KefuMsgType.IMAGE; | this.msgType = WxMaConstants.KefuMsgType.IMAGE; | ||||
| } | } | ||||
| public ImageBuilder mediaId(String media_id) { | |||||
| this.mediaId = media_id; | |||||
| public ImageBuilder mediaId(String mediaId) { | |||||
| this.mediaId = mediaId; | |||||
| return this; | return this; | ||||
| } | } | ||||
| @@ -175,6 +175,7 @@ public class WxMaInMemoryConfig implements WxMaConfig { | |||||
| return true; | return true; | ||||
| } | } | ||||
| @Override | |||||
| public String getAppid() { | public String getAppid() { | ||||
| return appid; | return appid; | ||||
| } | } | ||||
| @@ -8,11 +8,19 @@ package cn.binarywang.wx.miniapp.constant; | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| */ | */ | ||||
| public class WxMaConstants { | public class WxMaConstants { | ||||
| /** | |||||
| * 微信接口返回的参数errcode | |||||
| */ | |||||
| public static final String ERRCODE = "errcode"; | |||||
| /** | /** | ||||
| * 素材类型 | * 素材类型 | ||||
| */ | */ | ||||
| public static class MediaType { | public static class MediaType { | ||||
| public static final String IMAGE = "image";//图片 | |||||
| /** | |||||
| * 图片 | |||||
| */ | |||||
| public static final String IMAGE = "image"; | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -27,7 +35,30 @@ public class WxMaConstants { | |||||
| * 客服消息的消息类型 | * 客服消息的消息类型 | ||||
| */ | */ | ||||
| public static class KefuMsgType { | public static class KefuMsgType { | ||||
| public static final String TEXT = "text";//文本消息 | |||||
| public static final String IMAGE = "image";//图片消息 | |||||
| /** | |||||
| * 文本消息 | |||||
| */ | |||||
| public static final String TEXT = "text"; | |||||
| /** | |||||
| * 图片消息 | |||||
| */ | |||||
| public static final String IMAGE = "image"; | |||||
| } | |||||
| public static final class ErrorCode { | |||||
| /** | |||||
| * 40001 获取access_token时AppSecret错误,或者access_token无效 | |||||
| */ | |||||
| public static final int ERR_40001 = 40001; | |||||
| /** | |||||
| * 42001 access_token超时 | |||||
| */ | |||||
| public static final int ERR_42001 = 42001; | |||||
| /** | |||||
| * 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期) | |||||
| */ | |||||
| public static final int ERR_40014 = 40014; | |||||
| } | } | ||||
| } | } | ||||
| @@ -2,6 +2,7 @@ package cn.binarywang.wx.miniapp.message; | |||||
| import cn.binarywang.wx.miniapp.api.WxMaService; | import cn.binarywang.wx.miniapp.api.WxMaService; | ||||
| import cn.binarywang.wx.miniapp.bean.WxMaMessage; | import cn.binarywang.wx.miniapp.bean.WxMaMessage; | ||||
| import com.google.common.util.concurrent.ThreadFactoryBuilder; | |||||
| import me.chanjar.weixin.common.api.WxErrorExceptionHandler; | import me.chanjar.weixin.common.api.WxErrorExceptionHandler; | ||||
| import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; | import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; | ||||
| import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; | import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; | ||||
| @@ -17,10 +18,7 @@ import java.util.ArrayList; | |||||
| import java.util.HashMap; | import java.util.HashMap; | ||||
| import java.util.List; | import java.util.List; | ||||
| import java.util.Map; | 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 java.util.concurrent.*; | |||||
| /** | /** | ||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| @@ -42,7 +40,9 @@ public class WxMaMessageRouter { | |||||
| public WxMaMessageRouter(WxMaService wxMaService) { | public WxMaMessageRouter(WxMaService wxMaService) { | ||||
| this.wxMaService = wxMaService; | this.wxMaService = wxMaService; | ||||
| this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE); | |||||
| ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("WxMaMessageRouter-pool-%d").build(); | |||||
| this.executorService = new ThreadPoolExecutor(DEFAULT_THREAD_POOL_SIZE, DEFAULT_THREAD_POOL_SIZE, | |||||
| 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), namedThreadFactory); | |||||
| this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker(); | this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker(); | ||||
| this.sessionManager = new StandardSessionManager(); | this.sessionManager = new StandardSessionManager(); | ||||
| this.exceptionHandler = new LogExceptionHandler(); | this.exceptionHandler = new LogExceptionHandler(); | ||||
| @@ -159,7 +159,7 @@ public class WxMaMessageRouter { | |||||
| } | } | ||||
| public void route(final WxMaMessage wxMessage) { | public void route(final WxMaMessage wxMessage) { | ||||
| this.route(wxMessage, new HashMap<String, Object>()); | |||||
| this.route(wxMessage, new HashMap<String, Object>(2)); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -196,7 +196,7 @@ public class WxMaMessageRouterRule { | |||||
| WxSessionManager sessionManager, | WxSessionManager sessionManager, | ||||
| WxErrorExceptionHandler exceptionHandler) { | WxErrorExceptionHandler exceptionHandler) { | ||||
| if (context == null) { | if (context == null) { | ||||
| context = new HashMap<>(); | |||||
| context = new HashMap<>(16); | |||||
| } | } | ||||
| try { | try { | ||||
| @@ -1,6 +1,6 @@ | |||||
| package cn.binarywang.wx.miniapp.util.http; | package cn.binarywang.wx.miniapp.util.http; | ||||
| import cn.binarywang.wx.miniapp.bean.WxMaQrcodeWrapper; | |||||
| import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper; | |||||
| import me.chanjar.weixin.common.bean.result.WxError; | import me.chanjar.weixin.common.bean.result.WxError; | ||||
| import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import me.chanjar.weixin.common.util.fs.FileUtils; | import me.chanjar.weixin.common.util.fs.FileUtils; | ||||
| @@ -25,7 +25,7 @@ import java.util.UUID; | |||||
| /** | /** | ||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| */ | */ | ||||
| public class QrCodeRequestExecutor implements RequestExecutor<File, WxMaQrcodeWrapper> { | |||||
| public class QrCodeRequestExecutor implements RequestExecutor<File, AbstractWxMaQrcodeWrapper> { | |||||
| protected RequestHttp<CloseableHttpClient, HttpHost> requestHttp; | protected RequestHttp<CloseableHttpClient, HttpHost> requestHttp; | ||||
| public QrCodeRequestExecutor(RequestHttp requestHttp) { | public QrCodeRequestExecutor(RequestHttp requestHttp) { | ||||
| @@ -33,7 +33,7 @@ public class QrCodeRequestExecutor implements RequestExecutor<File, WxMaQrcodeWr | |||||
| } | } | ||||
| @Override | @Override | ||||
| public File execute(String uri, WxMaQrcodeWrapper ticket) throws WxErrorException, IOException { | |||||
| public File execute(String uri, AbstractWxMaQrcodeWrapper ticket) throws WxErrorException, IOException { | |||||
| HttpPost httpPost = new HttpPost(uri); | HttpPost httpPost = new HttpPost(uri); | ||||
| if (requestHttp.getRequestHttpProxy() != null) { | if (requestHttp.getRequestHttpProxy() != null) { | ||||
| httpPost | httpPost | ||||
| @@ -19,7 +19,7 @@ public class WxMaKefuMessageTest { | |||||
| } | } | ||||
| public void testTextBuild() { | public void testTextBuild() { | ||||
| WxMaKefuMessage reply = WxMaKefuMessage.TEXT().toUser("OPENID").content("sfsfdsdf").build(); | |||||
| WxMaKefuMessage reply = WxMaKefuMessage.newTextBuilder().toUser("OPENID").content("sfsfdsdf").build(); | |||||
| Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); | Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); | ||||
| } | } | ||||
| @@ -32,7 +32,7 @@ public class WxMaKefuMessageTest { | |||||
| } | } | ||||
| public void testImageBuild() { | public void testImageBuild() { | ||||
| WxMaKefuMessage reply = WxMaKefuMessage.IMAGE().toUser("OPENID").mediaId("MEDIA_ID").build(); | |||||
| WxMaKefuMessage reply = WxMaKefuMessage.newImageBuilder().toUser("OPENID").mediaId("MEDIA_ID").build(); | |||||
| Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); | Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); | ||||
| } | } | ||||
| @@ -34,7 +34,7 @@ public class WxMaDemoServer { | |||||
| public void handle(WxMaMessage wxMessage, Map<String, Object> context, | public void handle(WxMaMessage wxMessage, Map<String, Object> context, | ||||
| WxMaService service, WxSessionManager sessionManager) throws WxErrorException { | WxMaService service, WxSessionManager sessionManager) throws WxErrorException { | ||||
| System.out.println("收到消息:" + wxMessage.toString()); | System.out.println("收到消息:" + wxMessage.toString()); | ||||
| service.getMsgService().sendKefuMsg(WxMaKefuMessage.TEXT().content("收到信息为:" + wxMessage.toJson()) | |||||
| service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson()) | |||||
| .toUser(wxMessage.getFromUser()).build()); | .toUser(wxMessage.getFromUser()).build()); | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -44,7 +44,7 @@ public class WxMaDemoServer { | |||||
| public void handle(WxMaMessage wxMessage, Map<String, Object> context, | public void handle(WxMaMessage wxMessage, Map<String, Object> context, | ||||
| WxMaService service, WxSessionManager sessionManager) | WxMaService service, WxSessionManager sessionManager) | ||||
| throws WxErrorException { | throws WxErrorException { | ||||
| service.getMsgService().sendKefuMsg(WxMaKefuMessage.TEXT().content("回复文本消息") | |||||
| service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息") | |||||
| .toUser(wxMessage.getFromUser()).build()); | .toUser(wxMessage.getFromUser()).build()); | ||||
| } | } | ||||
| @@ -60,7 +60,7 @@ public class WxMaDemoServer { | |||||
| ClassLoader.getSystemResourceAsStream("tmp.png")); | ClassLoader.getSystemResourceAsStream("tmp.png")); | ||||
| service.getMsgService().sendKefuMsg( | service.getMsgService().sendKefuMsg( | ||||
| WxMaKefuMessage | WxMaKefuMessage | ||||
| .IMAGE() | |||||
| .newImageBuilder() | |||||
| .mediaId(uploadResult.getMediaId()) | .mediaId(uploadResult.getMediaId()) | ||||
| .toUser(wxMessage.getFromUser()) | .toUser(wxMessage.getFromUser()) | ||||
| .build()); | .build()); | ||||
| @@ -79,7 +79,7 @@ public class WxMaDemoServer { | |||||
| WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia(WxMaConstants.MediaType.IMAGE, file); | WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia(WxMaConstants.MediaType.IMAGE, file); | ||||
| service.getMsgService().sendKefuMsg( | service.getMsgService().sendKefuMsg( | ||||
| WxMaKefuMessage | WxMaKefuMessage | ||||
| .IMAGE() | |||||
| .newImageBuilder() | |||||
| .mediaId(uploadResult.getMediaId()) | .mediaId(uploadResult.getMediaId()) | ||||
| .toUser(wxMessage.getFromUser()) | .toUser(wxMessage.getFromUser()) | ||||
| .build()); | .build()); | ||||