| @@ -31,6 +31,11 @@ | |||
| <artifactId>weixin-java-mp</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.github.binarywang</groupId> | |||
| <artifactId>weixin-java-miniapp</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.jodd</groupId> | |||
| @@ -1,6 +1,7 @@ | |||
| package me.chanjar.weixin.open.api; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import cn.binarywang.wx.miniapp.api.WxMaService; | |||
| import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.mp.api.WxMpService; | |||
| import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; | |||
| @@ -35,8 +36,10 @@ public interface WxOpenComponentService { | |||
| */ | |||
| String OAUTH2_REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/component/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s&component_appid=%s"; | |||
| WxMpService getWxMpServiceByAppid(String appid); | |||
| String MINIAPP_JSCODE_2_SESSION = "https://api.weixin.qq.com/sns/component/jscode2session?appid=%s&js_code=%s&grant_type=authorization_code&component_appid=%s"; | |||
| WxMpService getWxMpServiceByAppid(String appid); | |||
| WxMaService getWxMaServiceByAppid(String appid); | |||
| WxOpenConfigStorage getWxOpenConfigStorage(); | |||
| boolean checkSignature(String timestamp, String nonce, String signature); | |||
| @@ -49,7 +52,6 @@ public interface WxOpenComponentService { | |||
| String getPreAuthUrl(String redirectURI) throws WxErrorException; | |||
| String route(WxOpenXmlMessage wxMessage) throws WxErrorException; | |||
| /** | |||
| * 使用授权码换取公众号或小程序的接口调用凭据和授权信息 | |||
| */ | |||
| @@ -68,7 +70,7 @@ public interface WxOpenComponentService { | |||
| /** | |||
| * 设置授权方的选项信息 | |||
| */ | |||
| WxError setAuthorizerOption(String authorizerAppid, String optionName, String optionValue) throws WxErrorException; | |||
| void setAuthorizerOption(String authorizerAppid, String optionName, String optionValue) throws WxErrorException; | |||
| String getAuthorizerAccessToken(String appid, boolean forceRefresh) throws WxErrorException; | |||
| @@ -79,5 +81,6 @@ public interface WxOpenComponentService { | |||
| WxMpOAuth2AccessToken oauth2refreshAccessToken(String appid, String refreshToken) throws WxErrorException; | |||
| String oauth2buildAuthorizationUrl(String appid, String redirectURI, String scope, String state); | |||
| WxMaJscode2SessionResult miniappJscode2Session(String appid, String jsCode, String appId) throws WxErrorException; | |||
| } | |||
| @@ -1,5 +1,6 @@ | |||
| package me.chanjar.weixin.open.api; | |||
| import cn.binarywang.wx.miniapp.config.WxMaConfig; | |||
| import me.chanjar.weixin.mp.api.WxMpConfigStorage; | |||
| import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; | |||
| import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; | |||
| @@ -36,6 +37,7 @@ public interface WxOpenConfigStorage { | |||
| void updateComponentAccessTokent(WxOpenComponentAccessToken componentAccessToken); | |||
| WxMpConfigStorage getWxMpConfigStorage(String appId); | |||
| WxMaConfig getWxMaConfig(String appId); | |||
| /** | |||
| * 应该是线程安全的 | |||
| @@ -1,7 +1,8 @@ | |||
| package me.chanjar.weixin.open.api.impl; | |||
| import cn.binarywang.wx.miniapp.api.WxMaService; | |||
| import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; | |||
| import com.google.gson.JsonObject; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.common.util.crypto.SHA1; | |||
| import me.chanjar.weixin.common.util.http.URIUtil; | |||
| @@ -30,7 +31,10 @@ import java.util.Map; | |||
| * @author <a href="https://github.com/007gzs">007</a> | |||
| */ | |||
| public class WxOpenComponentServiceImpl implements WxOpenComponentService { | |||
| private static final Map<String, WxMaService> WX_OPEN_MA_SERVICE_MAP = new Hashtable<>(); | |||
| private static final Map<String, WxMpService> WX_OPEN_MP_SERVICE_MAP = new Hashtable<>(); | |||
| protected final Logger log = LoggerFactory.getLogger(this.getClass()); | |||
| private WxOpenService wxOpenService; | |||
| @@ -54,6 +58,20 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService { | |||
| return wxMpService; | |||
| } | |||
| @Override | |||
| public WxMaService getWxMaServiceByAppid(String appId) { | |||
| WxMaService wxMaService = WX_OPEN_MA_SERVICE_MAP.get(appId); | |||
| if (wxMaService == null) { | |||
| synchronized (WX_OPEN_MA_SERVICE_MAP) { | |||
| wxMaService = WX_OPEN_MA_SERVICE_MAP.get(appId); | |||
| if (wxMaService == null) { | |||
| wxMaService = new WxOpenMaServiceImpl(this, appId, getWxOpenConfigStorage().getWxMaConfig(appId)); | |||
| WX_OPEN_MA_SERVICE_MAP.put(appId, wxMaService); | |||
| } | |||
| } | |||
| } | |||
| return wxMaService; | |||
| } | |||
| public WxOpenService getWxOpenService() { | |||
| return wxOpenService; | |||
| } | |||
| @@ -137,7 +155,7 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService { | |||
| } | |||
| return "success"; | |||
| } | |||
| return null; | |||
| return ""; | |||
| } | |||
| @Override | |||
| @@ -169,14 +187,13 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService { | |||
| } | |||
| @Override | |||
| public WxError setAuthorizerOption(String authorizerAppid, String optionName, String optionValue) throws WxErrorException { | |||
| public void setAuthorizerOption(String authorizerAppid, String optionName, String optionValue) throws WxErrorException { | |||
| JsonObject jsonObject = new JsonObject(); | |||
| jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId()); | |||
| jsonObject.addProperty("authorizer_appid", authorizerAppid); | |||
| jsonObject.addProperty("option_name", optionName); | |||
| jsonObject.addProperty("option_value", optionValue); | |||
| String responseContent = post(API_SET_AUTHORIZER_OPTION_URL, jsonObject.toString()); | |||
| return WxGsonBuilder.create().fromJson(responseContent, WxError.class); | |||
| post(API_SET_AUTHORIZER_OPTION_URL, jsonObject.toString()); | |||
| } | |||
| @Override | |||
| @@ -220,4 +237,11 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService { | |||
| appId, URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state), getWxOpenConfigStorage().getComponentAppId()); | |||
| } | |||
| @Override | |||
| public WxMaJscode2SessionResult miniappJscode2Session(String appid, String jsCode, String appId) throws WxErrorException { | |||
| String url = String.format(MINIAPP_JSCODE_2_SESSION, appId, jsCode, getWxOpenConfigStorage().getComponentAppId()); | |||
| String responseContent = get(url); | |||
| return WxMaJscode2SessionResult.fromJson(responseContent); | |||
| } | |||
| } | |||
| @@ -1,6 +1,7 @@ | |||
| package me.chanjar.weixin.open.api.impl; | |||
| import cn.binarywang.wx.miniapp.config.WxMaConfig; | |||
| import me.chanjar.weixin.common.bean.WxAccessToken; | |||
| import me.chanjar.weixin.common.util.ToStringUtils; | |||
| import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; | |||
| @@ -101,7 +102,12 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { | |||
| @Override | |||
| public WxMpConfigStorage getWxMpConfigStorage(String appId) { | |||
| return new WxOpenMpConfigStorage(this, appId); | |||
| return new WxOpenInnerConfigStorage(this, appId); | |||
| } | |||
| @Override | |||
| public WxMaConfig getWxMaConfig(String appId) { | |||
| return new WxOpenInnerConfigStorage(this, appId); | |||
| } | |||
| @Override | |||
| @@ -222,14 +228,13 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { | |||
| private String token; | |||
| private Long expiresTime; | |||
| } | |||
| private static class WxOpenMpConfigStorage implements WxMpConfigStorage { | |||
| private static class WxOpenInnerConfigStorage implements WxMpConfigStorage, WxMaConfig { | |||
| private WxOpenConfigStorage wxOpenConfigStorage; | |||
| private String appId; | |||
| private Lock accessTokenLock = new ReentrantLock(); | |||
| private Lock jsapiTicketLock = new ReentrantLock(); | |||
| private Lock cardApiTicketLock = new ReentrantLock(); | |||
| private WxOpenMpConfigStorage(WxOpenConfigStorage wxOpenConfigStorage, String appId) { | |||
| private WxOpenInnerConfigStorage(WxOpenConfigStorage wxOpenConfigStorage, String appId) { | |||
| this.wxOpenConfigStorage = wxOpenConfigStorage; | |||
| this.appId = appId; | |||
| } | |||
| @@ -259,6 +264,11 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { | |||
| wxOpenConfigStorage.updateAuthorizerAccessToken(appId, accessToken, expiresInSeconds); | |||
| } | |||
| @Override | |||
| public String getAppid() { | |||
| return this.appId; | |||
| } | |||
| @Override | |||
| public void expireAccessToken() { | |||
| wxOpenConfigStorage.expireAuthorizerAccessToken(appId); | |||
| @@ -343,6 +353,11 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { | |||
| return wxOpenConfigStorage.getComponentAesKey(); | |||
| } | |||
| @Override | |||
| public String getMsgDataFormat() { | |||
| return null; | |||
| } | |||
| @Override | |||
| public String getOauth2redirectUri() { | |||
| return null; | |||
| @@ -0,0 +1,36 @@ | |||
| package me.chanjar.weixin.open.api.impl; | |||
| import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; | |||
| import cn.binarywang.wx.miniapp.config.WxMaConfig; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.mp.api.WxMpConfigStorage; | |||
| import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; | |||
| import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; | |||
| import me.chanjar.weixin.open.api.WxOpenComponentService; | |||
| /** | |||
| * @author <a href="https://github.com/007gzs">007</a> | |||
| */ | |||
| /* package */ class WxOpenMaServiceImpl extends WxMaServiceImpl { | |||
| private WxOpenComponentService wxOpenComponentService; | |||
| private WxMaConfig wxMaConfig; | |||
| private String appId; | |||
| public WxOpenMaServiceImpl(WxOpenComponentService wxOpenComponentService, String appId, WxMaConfig wxMaConfig) { | |||
| this.wxOpenComponentService = wxOpenComponentService; | |||
| this.appId = appId; | |||
| this.wxMaConfig = wxMaConfig; | |||
| initHttp(); | |||
| } | |||
| @Override | |||
| public WxMaConfig getWxMaConfig() { | |||
| return wxMaConfig; | |||
| } | |||
| @Override | |||
| public String getAccessToken(boolean forceRefresh) throws WxErrorException { | |||
| return wxOpenComponentService.getAuthorizerAccessToken(appId, forceRefresh); | |||
| } | |||
| } | |||
| @@ -23,7 +23,6 @@ public class WxOpenAuthorizerInfo implements Serializable { | |||
| private Map<String, Integer> businessInfo; | |||
| private String alias; | |||
| private String qrcodeUrl; | |||
| /** | |||
| * 账号介绍 | |||
| */ | |||
| @@ -0,0 +1,14 @@ | |||
| package me.chanjar.weixin.open.bean.auth; | |||
| import lombok.Data; | |||
| import org.apache.commons.lang3.tuple.Pair; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| @Data | |||
| public class WxOpenMiniProgramInfo { | |||
| private Map<String, List<String>> network; | |||
| private List<Pair<String, String>> categories; | |||
| private Integer visitStatus; | |||
| } | |||
| @@ -15,4 +15,7 @@ public class WxOpenAuthorizerInfoResult implements Serializable { | |||
| private WxOpenAuthorizationInfo authorizationInfo; | |||
| private WxOpenAuthorizerInfo authorizerInfo; | |||
| public boolean isMiniProgram(){ | |||
| return authorizerInfo != null && authorizerInfo.getMiniProgramInfo() != null; | |||
| } | |||
| } | |||
| @@ -23,6 +23,8 @@ public class WxOpenAuthorizerInfoGsonAdapter implements JsonDeserializer<WxOpenA | |||
| authorizationInfo.setPrincipalName(GsonHelper.getString(jsonObject, "principal_name")); | |||
| authorizationInfo.setAlias(GsonHelper.getString(jsonObject, "alias")); | |||
| authorizationInfo.setQrcodeUrl(GsonHelper.getString(jsonObject, "qrcode_url")); | |||
| authorizationInfo.setSignature(GsonHelper.getString(jsonObject, "signature")); | |||
| if (jsonObject.has("service_type_info")) { | |||
| authorizationInfo.setServiceTypeInfo(GsonHelper.getInteger(jsonObject.getAsJsonObject("service_type_info"), "id")); | |||
| } | |||
| @@ -33,11 +35,12 @@ public class WxOpenAuthorizerInfoGsonAdapter implements JsonDeserializer<WxOpenA | |||
| new TypeToken<Map<String, Integer>>() { | |||
| }.getType()); | |||
| authorizationInfo.setBusinessInfo(businessInfo); | |||
| WxOpenAuthorizerInfo.MiniProgramInfo miniProgramInfo = WxOpenGsonBuilder.create().fromJson(jsonObject.get("MiniProgramInfo"), | |||
| new TypeToken<WxOpenAuthorizerInfo.MiniProgramInfo>() { | |||
| }.getType()); | |||
| authorizationInfo.setMiniProgramInfo(miniProgramInfo); | |||
| if (jsonObject.has("MiniProgramInfo")) { | |||
| WxOpenAuthorizerInfo.MiniProgramInfo miniProgramInfo = WxOpenGsonBuilder.create().fromJson(jsonObject.get("MiniProgramInfo"), | |||
| new TypeToken<WxOpenAuthorizerInfo.MiniProgramInfo>() { | |||
| }.getType()); | |||
| authorizationInfo.setMiniProgramInfo(miniProgramInfo); | |||
| } | |||
| return authorizationInfo; | |||
| } | |||
| } | |||