@@ -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()); | ||||