| @@ -69,9 +69,9 @@ public interface WxMpConfigStorage { | |||||
| public String getSecret(); | public String getSecret(); | ||||
| public String getPartnerId(); | |||||
| public String getPartnerKey(); | |||||
| public String getPartnerId(); | |||||
| public String getPartnerKey(); | |||||
| public String getToken(); | public String getToken(); | ||||
| @@ -1,232 +1,232 @@ | |||||
| package me.chanjar.weixin.mp.api; | |||||
| import me.chanjar.weixin.common.session.InternalSession; | |||||
| import me.chanjar.weixin.common.session.InternalSessionManager; | |||||
| import me.chanjar.weixin.common.session.StandardSessionManager; | |||||
| import me.chanjar.weixin.common.session.WxSessionManager; | |||||
| import me.chanjar.weixin.common.util.LogExceptionHandler; | |||||
| import me.chanjar.weixin.common.api.WxErrorExceptionHandler; | |||||
| import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; | |||||
| import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; | |||||
| import me.chanjar.weixin.mp.bean.WxMpXmlMessage; | |||||
| import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; | |||||
| import org.slf4j.Logger; | |||||
| import org.slf4j.LoggerFactory; | |||||
| import java.util.ArrayList; | |||||
| import java.util.List; | |||||
| import java.util.concurrent.ExecutionException; | |||||
| import java.util.concurrent.ExecutorService; | |||||
| import java.util.concurrent.Executors; | |||||
| import java.util.concurrent.Future; | |||||
| /** | |||||
| * <pre> | |||||
| * 微信消息路由器,通过代码化的配置,把来自微信的消息交给handler处理 | |||||
| * | |||||
| * 说明: | |||||
| * 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理 | |||||
| * 2. 默认情况下消息只会被处理一次,除非使用 {@link WxMpMessageRouterRule#next()} | |||||
| * 3. 规则的结束必须用{@link WxMpMessageRouterRule#end()}或者{@link WxMpMessageRouterRule#next()},否则不会生效 | |||||
| * | |||||
| * 使用方法: | |||||
| * WxMpMessageRouter router = new WxMpMessageRouter(); | |||||
| * router | |||||
| * .rule() | |||||
| * .msgType("MSG_TYPE").event("EVENT").eventKey("EVENT_KEY").content("CONTENT") | |||||
| * .interceptor(interceptor, ...).handler(handler, ...) | |||||
| * .end() | |||||
| * .rule() | |||||
| * // 另外一个匹配规则 | |||||
| * .end() | |||||
| * ; | |||||
| * | |||||
| * // 将WxXmlMessage交给消息路由器 | |||||
| * router.route(message); | |||||
| * | |||||
| * </pre> | |||||
| * @author Daniel Qian | |||||
| * | |||||
| */ | |||||
| public class WxMpMessageRouter { | |||||
| protected final Logger log = LoggerFactory.getLogger(WxMpMessageRouter.class); | |||||
| private static final int DEFAULT_THREAD_POOL_SIZE = 100; | |||||
| private final List<WxMpMessageRouterRule> rules = new ArrayList<WxMpMessageRouterRule>(); | |||||
| private final WxMpService wxMpService; | |||||
| private ExecutorService executorService; | |||||
| private WxMessageDuplicateChecker messageDuplicateChecker; | |||||
| private WxSessionManager sessionManager; | |||||
| private WxErrorExceptionHandler exceptionHandler; | |||||
| public WxMpMessageRouter(WxMpService wxMpService) { | |||||
| this.wxMpService = wxMpService; | |||||
| this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE); | |||||
| this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker(); | |||||
| this.sessionManager = new StandardSessionManager(); | |||||
| this.exceptionHandler = new LogExceptionHandler(); | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 设置自定义的 {@link ExecutorService} | |||||
| * 如果不调用该方法,默认使用 Executors.newFixedThreadPool(100) | |||||
| * </pre> | |||||
| * @param executorService | |||||
| */ | |||||
| public void setExecutorService(ExecutorService executorService) { | |||||
| this.executorService = executorService; | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker} | |||||
| * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker} | |||||
| * </pre> | |||||
| * @param messageDuplicateChecker | |||||
| */ | |||||
| public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) { | |||||
| this.messageDuplicateChecker = messageDuplicateChecker; | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager} | |||||
| * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.session.StandardSessionManager} | |||||
| * </pre> | |||||
| * @param sessionManager | |||||
| */ | |||||
| public void setSessionManager(WxSessionManager sessionManager) { | |||||
| this.sessionManager = sessionManager; | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler} | |||||
| * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler} | |||||
| * </pre> | |||||
| * @param exceptionHandler | |||||
| */ | |||||
| public void setExceptionHandler(WxErrorExceptionHandler exceptionHandler) { | |||||
| this.exceptionHandler = exceptionHandler; | |||||
| } | |||||
| List<WxMpMessageRouterRule> getRules() { | |||||
| return this.rules; | |||||
| } | |||||
| /** | |||||
| * 开始一个新的Route规则 | |||||
| * @return | |||||
| */ | |||||
| public WxMpMessageRouterRule rule() { | |||||
| return new WxMpMessageRouterRule(this); | |||||
| } | |||||
| /** | |||||
| * 处理微信消息 | |||||
| * @param wxMessage | |||||
| */ | |||||
| public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage) { | |||||
| if (isDuplicateMessage(wxMessage)) { | |||||
| // 如果是重复消息,那么就不做处理 | |||||
| return null; | |||||
| } | |||||
| final List<WxMpMessageRouterRule> matchRules = new ArrayList<WxMpMessageRouterRule>(); | |||||
| // 收集匹配的规则 | |||||
| for (final WxMpMessageRouterRule rule : rules) { | |||||
| if (rule.test(wxMessage)) { | |||||
| matchRules.add(rule); | |||||
| if(!rule.isReEnter()) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (matchRules.size() == 0) { | |||||
| return null; | |||||
| } | |||||
| WxMpXmlOutMessage res = null; | |||||
| final List<Future> futures = new ArrayList<Future>(); | |||||
| for (final WxMpMessageRouterRule rule : matchRules) { | |||||
| // 返回最后一个非异步的rule的执行结果 | |||||
| if(rule.isAsync()) { | |||||
| futures.add( | |||||
| executorService.submit(new Runnable() { | |||||
| public void run() { | |||||
| rule.service(wxMessage, wxMpService, sessionManager, exceptionHandler); | |||||
| } | |||||
| }) | |||||
| ); | |||||
| } else { | |||||
| res = rule.service(wxMessage, wxMpService, sessionManager, exceptionHandler); | |||||
| // 在同步操作结束,session访问结束 | |||||
| log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUserName()); | |||||
| sessionEndAccess(wxMessage); | |||||
| } | |||||
| } | |||||
| if (futures.size() > 0) { | |||||
| executorService.submit(new Runnable() { | |||||
| @Override | |||||
| public void run() { | |||||
| for (Future future : futures) { | |||||
| try { | |||||
| future.get(); | |||||
| log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUserName()); | |||||
| // 异步操作结束,session访问结束 | |||||
| sessionEndAccess(wxMessage); | |||||
| } catch (InterruptedException e) { | |||||
| log.error("Error happened when wait task finish", e); | |||||
| } catch (ExecutionException e) { | |||||
| log.error("Error happened when wait task finish", e); | |||||
| } | |||||
| } | |||||
| } | |||||
| }); | |||||
| } | |||||
| return res; | |||||
| } | |||||
| protected boolean isDuplicateMessage(WxMpXmlMessage wxMessage) { | |||||
| String messageId = ""; | |||||
| if (wxMessage.getMsgId() == null) { | |||||
| messageId = String.valueOf(wxMessage.getCreateTime()) | |||||
| + "-" + wxMessage.getFromUserName() | |||||
| + "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey()) | |||||
| + "-" + String.valueOf(wxMessage.getEvent() == null ? "" : wxMessage.getEvent()) | |||||
| ; | |||||
| } else { | |||||
| messageId = String.valueOf(wxMessage.getMsgId()); | |||||
| } | |||||
| if (messageDuplicateChecker.isDuplicate(messageId)) { | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /** | |||||
| * 对session的访问结束 | |||||
| * @param wxMessage | |||||
| */ | |||||
| protected void sessionEndAccess(WxMpXmlMessage wxMessage) { | |||||
| InternalSession session = ((InternalSessionManager)sessionManager).findSession(wxMessage.getFromUserName()); | |||||
| if (session != null) { | |||||
| session.endAccess(); | |||||
| } | |||||
| } | |||||
| } | |||||
| package me.chanjar.weixin.mp.api; | |||||
| import me.chanjar.weixin.common.session.InternalSession; | |||||
| import me.chanjar.weixin.common.session.InternalSessionManager; | |||||
| import me.chanjar.weixin.common.session.StandardSessionManager; | |||||
| import me.chanjar.weixin.common.session.WxSessionManager; | |||||
| import me.chanjar.weixin.common.util.LogExceptionHandler; | |||||
| import me.chanjar.weixin.common.api.WxErrorExceptionHandler; | |||||
| import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; | |||||
| import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; | |||||
| import me.chanjar.weixin.mp.bean.WxMpXmlMessage; | |||||
| import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; | |||||
| import org.slf4j.Logger; | |||||
| import org.slf4j.LoggerFactory; | |||||
| import java.util.ArrayList; | |||||
| import java.util.List; | |||||
| import java.util.concurrent.ExecutionException; | |||||
| import java.util.concurrent.ExecutorService; | |||||
| import java.util.concurrent.Executors; | |||||
| import java.util.concurrent.Future; | |||||
| /** | |||||
| * <pre> | |||||
| * 微信消息路由器,通过代码化的配置,把来自微信的消息交给handler处理 | |||||
| * | |||||
| * 说明: | |||||
| * 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理 | |||||
| * 2. 默认情况下消息只会被处理一次,除非使用 {@link WxMpMessageRouterRule#next()} | |||||
| * 3. 规则的结束必须用{@link WxMpMessageRouterRule#end()}或者{@link WxMpMessageRouterRule#next()},否则不会生效 | |||||
| * | |||||
| * 使用方法: | |||||
| * WxMpMessageRouter router = new WxMpMessageRouter(); | |||||
| * router | |||||
| * .rule() | |||||
| * .msgType("MSG_TYPE").event("EVENT").eventKey("EVENT_KEY").content("CONTENT") | |||||
| * .interceptor(interceptor, ...).handler(handler, ...) | |||||
| * .end() | |||||
| * .rule() | |||||
| * // 另外一个匹配规则 | |||||
| * .end() | |||||
| * ; | |||||
| * | |||||
| * // 将WxXmlMessage交给消息路由器 | |||||
| * router.route(message); | |||||
| * | |||||
| * </pre> | |||||
| * @author Daniel Qian | |||||
| * | |||||
| */ | |||||
| public class WxMpMessageRouter { | |||||
| protected final Logger log = LoggerFactory.getLogger(WxMpMessageRouter.class); | |||||
| private static final int DEFAULT_THREAD_POOL_SIZE = 100; | |||||
| private final List<WxMpMessageRouterRule> rules = new ArrayList<WxMpMessageRouterRule>(); | |||||
| private final WxMpService wxMpService; | |||||
| private ExecutorService executorService; | |||||
| private WxMessageDuplicateChecker messageDuplicateChecker; | |||||
| private WxSessionManager sessionManager; | |||||
| private WxErrorExceptionHandler exceptionHandler; | |||||
| public WxMpMessageRouter(WxMpService wxMpService) { | |||||
| this.wxMpService = wxMpService; | |||||
| this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE); | |||||
| this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker(); | |||||
| this.sessionManager = new StandardSessionManager(); | |||||
| this.exceptionHandler = new LogExceptionHandler(); | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 设置自定义的 {@link ExecutorService} | |||||
| * 如果不调用该方法,默认使用 Executors.newFixedThreadPool(100) | |||||
| * </pre> | |||||
| * @param executorService | |||||
| */ | |||||
| public void setExecutorService(ExecutorService executorService) { | |||||
| this.executorService = executorService; | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker} | |||||
| * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker} | |||||
| * </pre> | |||||
| * @param messageDuplicateChecker | |||||
| */ | |||||
| public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) { | |||||
| this.messageDuplicateChecker = messageDuplicateChecker; | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager} | |||||
| * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.session.StandardSessionManager} | |||||
| * </pre> | |||||
| * @param sessionManager | |||||
| */ | |||||
| public void setSessionManager(WxSessionManager sessionManager) { | |||||
| this.sessionManager = sessionManager; | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler} | |||||
| * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler} | |||||
| * </pre> | |||||
| * @param exceptionHandler | |||||
| */ | |||||
| public void setExceptionHandler(WxErrorExceptionHandler exceptionHandler) { | |||||
| this.exceptionHandler = exceptionHandler; | |||||
| } | |||||
| List<WxMpMessageRouterRule> getRules() { | |||||
| return this.rules; | |||||
| } | |||||
| /** | |||||
| * 开始一个新的Route规则 | |||||
| * @return | |||||
| */ | |||||
| public WxMpMessageRouterRule rule() { | |||||
| return new WxMpMessageRouterRule(this); | |||||
| } | |||||
| /** | |||||
| * 处理微信消息 | |||||
| * @param wxMessage | |||||
| */ | |||||
| public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage) { | |||||
| if (isDuplicateMessage(wxMessage)) { | |||||
| // 如果是重复消息,那么就不做处理 | |||||
| return null; | |||||
| } | |||||
| final List<WxMpMessageRouterRule> matchRules = new ArrayList<WxMpMessageRouterRule>(); | |||||
| // 收集匹配的规则 | |||||
| for (final WxMpMessageRouterRule rule : rules) { | |||||
| if (rule.test(wxMessage)) { | |||||
| matchRules.add(rule); | |||||
| if(!rule.isReEnter()) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (matchRules.size() == 0) { | |||||
| return null; | |||||
| } | |||||
| WxMpXmlOutMessage res = null; | |||||
| final List<Future> futures = new ArrayList<Future>(); | |||||
| for (final WxMpMessageRouterRule rule : matchRules) { | |||||
| // 返回最后一个非异步的rule的执行结果 | |||||
| if(rule.isAsync()) { | |||||
| futures.add( | |||||
| executorService.submit(new Runnable() { | |||||
| public void run() { | |||||
| rule.service(wxMessage, wxMpService, sessionManager, exceptionHandler); | |||||
| } | |||||
| }) | |||||
| ); | |||||
| } else { | |||||
| res = rule.service(wxMessage, wxMpService, sessionManager, exceptionHandler); | |||||
| // 在同步操作结束,session访问结束 | |||||
| log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUserName()); | |||||
| sessionEndAccess(wxMessage); | |||||
| } | |||||
| } | |||||
| if (futures.size() > 0) { | |||||
| executorService.submit(new Runnable() { | |||||
| @Override | |||||
| public void run() { | |||||
| for (Future future : futures) { | |||||
| try { | |||||
| future.get(); | |||||
| log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUserName()); | |||||
| // 异步操作结束,session访问结束 | |||||
| sessionEndAccess(wxMessage); | |||||
| } catch (InterruptedException e) { | |||||
| log.error("Error happened when wait task finish", e); | |||||
| } catch (ExecutionException e) { | |||||
| log.error("Error happened when wait task finish", e); | |||||
| } | |||||
| } | |||||
| } | |||||
| }); | |||||
| } | |||||
| return res; | |||||
| } | |||||
| protected boolean isDuplicateMessage(WxMpXmlMessage wxMessage) { | |||||
| StringBuffer messageId = new StringBuffer(); | |||||
| if (wxMessage.getMsgId() == null) { | |||||
| messageId.append(wxMessage.getCreateTime()) | |||||
| .append("-").append(wxMessage.getFromUserName()) | |||||
| .append("-").append(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey()) | |||||
| .append("-").append(wxMessage.getEvent() == null ? "" : wxMessage.getEvent()) | |||||
| ; | |||||
| } else { | |||||
| messageId.append(wxMessage.getMsgId()); | |||||
| } | |||||
| if (messageDuplicateChecker.isDuplicate(messageId.toString())) { | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /** | |||||
| * 对session的访问结束 | |||||
| * @param wxMessage | |||||
| */ | |||||
| protected void sessionEndAccess(WxMpXmlMessage wxMessage) { | |||||
| InternalSession session = ((InternalSessionManager)sessionManager).findSession(wxMessage.getFromUserName()); | |||||
| if (session != null) { | |||||
| session.endAccess(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -728,8 +728,8 @@ public interface WxMpService { | |||||
| * @return | * @return | ||||
| * @throws WxErrorException | * @throws WxErrorException | ||||
| */ | */ | ||||
| Map<String, String> getJSSDKPayInfo(Map<String, String> parameters) throws WxErrorException; | |||||
| Map<String, String> getJSSDKPayInfo(Map<String, String> parameters) throws WxErrorException; | |||||
| /** | /** | ||||
| * 该接口调用“统一下单”接口,并拼装JSSDK发起支付请求需要的参数 | * 该接口调用“统一下单”接口,并拼装JSSDK发起支付请求需要的参数 | ||||
| * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 | * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 | ||||
| @@ -100,9 +100,10 @@ public class WxMpServiceImpl implements WxMpService { | |||||
| if (wxMpConfigStorage.isAccessTokenExpired()) { | if (wxMpConfigStorage.isAccessTokenExpired()) { | ||||
| synchronized (globalAccessTokenRefreshLock) { | synchronized (globalAccessTokenRefreshLock) { | ||||
| if (wxMpConfigStorage.isAccessTokenExpired()) { | if (wxMpConfigStorage.isAccessTokenExpired()) { | ||||
| String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" | |||||
| + "&appid=" + wxMpConfigStorage.getAppId() | |||||
| + "&secret=" + wxMpConfigStorage.getSecret(); | |||||
| String url = new StringBuffer() | |||||
| .append("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential") | |||||
| .append("&appid=").append(wxMpConfigStorage.getAppId()) | |||||
| .append("&secret=").append(wxMpConfigStorage.getSecret()).toString(); | |||||
| try { | try { | ||||
| HttpGet httpGet = new HttpGet(url); | HttpGet httpGet = new HttpGet(url); | ||||
| if (httpProxy != null) { | if (httpProxy != null) { | ||||
| @@ -505,29 +506,31 @@ public class WxMpServiceImpl implements WxMpService { | |||||
| @Override | @Override | ||||
| public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { | public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { | ||||
| String url = "https://open.weixin.qq.com/connect/oauth2/authorize?"; | |||||
| url += "appid=" + wxMpConfigStorage.getAppId(); | |||||
| url += "&redirect_uri=" + URIUtil.encodeURIComponent(redirectURI); | |||||
| url += "&response_type=code"; | |||||
| url += "&scope=" + scope; | |||||
| StringBuffer url = new StringBuffer(); | |||||
| url.append("https://open.weixin.qq.com/connect/oauth2/authorize?"); | |||||
| url.append("appid=").append(wxMpConfigStorage.getAppId()); | |||||
| url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectURI)); | |||||
| url.append("&response_type=code"); | |||||
| url.append("&scope=").append(scope); | |||||
| if (state != null) { | if (state != null) { | ||||
| url += "&state=" + state; | |||||
| url.append("&state=").append(state); | |||||
| } | } | ||||
| url += "#wechat_redirect"; | |||||
| return url; | |||||
| url.append("#wechat_redirect"); | |||||
| return url.toString(); | |||||
| } | } | ||||
| @Override | @Override | ||||
| public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { | public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { | ||||
| String url = "https://api.weixin.qq.com/sns/oauth2/access_token?"; | |||||
| url += "appid=" + wxMpConfigStorage.getAppId(); | |||||
| url += "&secret=" + wxMpConfigStorage.getSecret(); | |||||
| url += "&code=" + code; | |||||
| url += "&grant_type=authorization_code"; | |||||
| StringBuffer url = new StringBuffer(); | |||||
| url.append("https://api.weixin.qq.com/sns/oauth2/access_token?"); | |||||
| url.append("appid=").append(wxMpConfigStorage.getAppId()); | |||||
| url.append("&secret=").append(wxMpConfigStorage.getSecret()); | |||||
| url.append("&code=").append(code); | |||||
| url.append("&grant_type=authorization_code"); | |||||
| try { | try { | ||||
| RequestExecutor<String, String> executor = new SimpleGetRequestExecutor(); | RequestExecutor<String, String> executor = new SimpleGetRequestExecutor(); | ||||
| String responseText = executor.execute(getHttpclient(), httpProxy, url, null); | |||||
| String responseText = executor.execute(getHttpclient(), httpProxy, url.toString(), null); | |||||
| return WxMpOAuth2AccessToken.fromJson(responseText); | return WxMpOAuth2AccessToken.fromJson(responseText); | ||||
| } catch (ClientProtocolException e) { | } catch (ClientProtocolException e) { | ||||
| throw new RuntimeException(e); | throw new RuntimeException(e); | ||||
| @@ -538,14 +541,15 @@ public class WxMpServiceImpl implements WxMpService { | |||||
| @Override | @Override | ||||
| public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { | public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { | ||||
| String url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?"; | |||||
| url += "appid=" + wxMpConfigStorage.getAppId(); | |||||
| url += "&grant_type=refresh_token"; | |||||
| url += "&refresh_token=" + refreshToken; | |||||
| StringBuffer url = new StringBuffer(); | |||||
| url.append("https://api.weixin.qq.com/sns/oauth2/refresh_token?"); | |||||
| url.append("appid=").append(wxMpConfigStorage.getAppId()); | |||||
| url.append("&grant_type=refresh_token"); | |||||
| url.append("&refresh_token=").append(refreshToken); | |||||
| try { | try { | ||||
| RequestExecutor<String, String> executor = new SimpleGetRequestExecutor(); | RequestExecutor<String, String> executor = new SimpleGetRequestExecutor(); | ||||
| String responseText = executor.execute(getHttpclient(), httpProxy, url, null); | |||||
| String responseText = executor.execute(getHttpclient(), httpProxy, url.toString(), null); | |||||
| return WxMpOAuth2AccessToken.fromJson(responseText); | return WxMpOAuth2AccessToken.fromJson(responseText); | ||||
| } catch (ClientProtocolException e) { | } catch (ClientProtocolException e) { | ||||
| throw new RuntimeException(e); | throw new RuntimeException(e); | ||||
| @@ -556,18 +560,19 @@ public class WxMpServiceImpl implements WxMpService { | |||||
| @Override | @Override | ||||
| public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException { | public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException { | ||||
| String url = "https://api.weixin.qq.com/sns/userinfo?"; | |||||
| url += "access_token=" + oAuth2AccessToken.getAccessToken(); | |||||
| url += "&openid=" + oAuth2AccessToken.getOpenId(); | |||||
| StringBuffer url = new StringBuffer(); | |||||
| url.append("https://api.weixin.qq.com/sns/userinfo?"); | |||||
| url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); | |||||
| url.append("&openid=").append(oAuth2AccessToken.getOpenId()); | |||||
| if (lang == null) { | if (lang == null) { | ||||
| url += "&lang=zh_CN"; | |||||
| url.append("&lang=zh_CN"); | |||||
| } else { | } else { | ||||
| url += "&lang=" + lang; | |||||
| url.append("&lang=").append(lang); | |||||
| } | } | ||||
| try { | try { | ||||
| RequestExecutor<String, String> executor = new SimpleGetRequestExecutor(); | RequestExecutor<String, String> executor = new SimpleGetRequestExecutor(); | ||||
| String responseText = executor.execute(getHttpclient(), httpProxy, url, null); | |||||
| String responseText = executor.execute(getHttpclient(), httpProxy, url.toString(), null); | |||||
| return WxMpUser.fromJson(responseText); | return WxMpUser.fromJson(responseText); | ||||
| } catch (ClientProtocolException e) { | } catch (ClientProtocolException e) { | ||||
| throw new RuntimeException(e); | throw new RuntimeException(e); | ||||
| @@ -578,13 +583,14 @@ public class WxMpServiceImpl implements WxMpService { | |||||
| @Override | @Override | ||||
| public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) { | public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) { | ||||
| String url = "https://api.weixin.qq.com/sns/auth?"; | |||||
| url += "access_token=" + oAuth2AccessToken.getAccessToken(); | |||||
| url += "&openid=" + oAuth2AccessToken.getOpenId(); | |||||
| StringBuffer url = new StringBuffer(); | |||||
| url.append("https://api.weixin.qq.com/sns/auth?"); | |||||
| url.append("access_token=").append(oAuth2AccessToken.getAccessToken()); | |||||
| url.append("&openid=").append(oAuth2AccessToken.getOpenId()); | |||||
| try { | try { | ||||
| RequestExecutor<String, String> executor = new SimpleGetRequestExecutor(); | RequestExecutor<String, String> executor = new SimpleGetRequestExecutor(); | ||||
| executor.execute(getHttpclient(), httpProxy, url, null); | |||||
| executor.execute(getHttpclient(), httpProxy, url.toString(), null); | |||||
| } catch (ClientProtocolException e) { | } catch (ClientProtocolException e) { | ||||
| throw new RuntimeException(e); | throw new RuntimeException(e); | ||||
| } catch (IOException e) { | } catch (IOException e) { | ||||
| @@ -984,7 +990,7 @@ public class WxMpServiceImpl implements WxMpService { | |||||
| @Override | @Override | ||||
| public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature) { | public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature) { | ||||
| return signature.equals(WxCryptUtil.createSign(kvm, wxMpConfigStorage.getPartnerKey())); | |||||
| return signature.equals(WxCryptUtil.createSign(kvm, wxMpConfigStorage.getPartnerKey())); | |||||
| } | } | ||||
| @Override | @Override | ||||
| @@ -30,15 +30,15 @@ import java.util.UUID; | |||||
| public class QrCodeRequestExecutor implements RequestExecutor<File, WxMpQrCodeTicket> { | public class QrCodeRequestExecutor implements RequestExecutor<File, WxMpQrCodeTicket> { | ||||
| @Override | @Override | ||||
| public File execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, WxMpQrCodeTicket ticket) throws WxErrorException, ClientProtocolException, IOException { | |||||
| public File execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, | |||||
| WxMpQrCodeTicket ticket) throws WxErrorException, ClientProtocolException, IOException { | |||||
| if (ticket != null) { | if (ticket != null) { | ||||
| if (uri.indexOf('?') == -1) { | if (uri.indexOf('?') == -1) { | ||||
| uri += '?'; | uri += '?'; | ||||
| } | } | ||||
| uri += uri.endsWith("?") ? | |||||
| "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") | |||||
| : | |||||
| "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); | |||||
| uri += uri.endsWith("?") | |||||
| ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") | |||||
| : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); | |||||
| } | } | ||||
| HttpGet httpGet = new HttpGet(uri); | HttpGet httpGet = new HttpGet(uri); | ||||
| @@ -59,7 +59,7 @@ public class QrCodeRequestExecutor implements RequestExecutor<File, WxMpQrCodeTi | |||||
| InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response); | InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response); | ||||
| return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); | return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); | ||||
| }finally { | |||||
| } finally { | |||||
| httpGet.releaseConnection(); | httpGet.releaseConnection(); | ||||
| } | } | ||||
| @@ -1,18 +1,15 @@ | |||||
| package me.chanjar.weixin.mp.util.json; | package me.chanjar.weixin.mp.util.json; | ||||
| import java.lang.reflect.Type; | |||||
| import com.google.gson.JsonDeserializationContext; | import com.google.gson.JsonDeserializationContext; | ||||
| import com.google.gson.JsonDeserializer; | import com.google.gson.JsonDeserializer; | ||||
| import com.google.gson.JsonElement; | import com.google.gson.JsonElement; | ||||
| import com.google.gson.JsonObject; | import com.google.gson.JsonObject; | ||||
| import com.google.gson.JsonParseException; | import com.google.gson.JsonParseException; | ||||
| import com.google.gson.reflect.TypeToken; | |||||
| import me.chanjar.weixin.common.util.json.GsonHelper; | import me.chanjar.weixin.common.util.json.GsonHelper; | ||||
| import me.chanjar.weixin.mp.bean.WxMpCard; | import me.chanjar.weixin.mp.bean.WxMpCard; | ||||
| import org.slf4j.Logger; | |||||
| import org.slf4j.LoggerFactory; | |||||
| import java.lang.reflect.Type; | |||||
| import java.util.List; | |||||
| /** | /** | ||||
| * Created by YuJian on 15/11/11. | * Created by YuJian on 15/11/11. | ||||
| @@ -1,20 +1,17 @@ | |||||
| package me.chanjar.weixin.mp.util.json; | package me.chanjar.weixin.mp.util.json; | ||||
| import java.lang.reflect.Type; | |||||
| import com.google.gson.JsonDeserializationContext; | import com.google.gson.JsonDeserializationContext; | ||||
| import com.google.gson.JsonDeserializer; | import com.google.gson.JsonDeserializer; | ||||
| import com.google.gson.JsonElement; | import com.google.gson.JsonElement; | ||||
| import com.google.gson.JsonObject; | import com.google.gson.JsonObject; | ||||
| import com.google.gson.JsonParseException; | import com.google.gson.JsonParseException; | ||||
| import com.google.gson.reflect.TypeToken; | import com.google.gson.reflect.TypeToken; | ||||
| import me.chanjar.weixin.common.util.json.GsonHelper; | import me.chanjar.weixin.common.util.json.GsonHelper; | ||||
| import me.chanjar.weixin.mp.bean.WxMpCard; | import me.chanjar.weixin.mp.bean.WxMpCard; | ||||
| import me.chanjar.weixin.mp.bean.result.WxMpCardResult; | import me.chanjar.weixin.mp.bean.result.WxMpCardResult; | ||||
| import org.slf4j.Logger; | |||||
| import org.slf4j.LoggerFactory; | |||||
| import java.lang.reflect.Type; | |||||
| import java.text.ParseException; | |||||
| import java.util.List; | |||||
| /** | /** | ||||
| * Created by YuJian on 15/11/11. | * Created by YuJian on 15/11/11. | ||||