| @@ -1,4 +1,4 @@ | |||||
| package me.chanjar.weixin.common.util; | |||||
| package me.chanjar.weixin.common.api; | |||||
| import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| @@ -1,4 +1,4 @@ | |||||
| package me.chanjar.weixin.common.util; | |||||
| package me.chanjar.weixin.common.api; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| @@ -1,4 +1,4 @@ | |||||
| package me.chanjar.weixin.common.util; | |||||
| package me.chanjar.weixin.common.api; | |||||
| import java.util.Map; | import java.util.Map; | ||||
| import java.util.concurrent.ConcurrentHashMap; | import java.util.concurrent.ConcurrentHashMap; | ||||
| @@ -1,9 +1,9 @@ | |||||
| package me.chanjar.weixin.mp.bean.result; | |||||
| package me.chanjar.weixin.common.bean; | |||||
| /** | /** | ||||
| * jspai signature | * jspai signature | ||||
| */ | */ | ||||
| public class WxMpJsapiSignature { | |||||
| public class WxJsapiSignature { | |||||
| private String noncestr; | private String noncestr; | ||||
| @@ -1,5 +1,6 @@ | |||||
| package me.chanjar.weixin.common.util; | package me.chanjar.weixin.common.util; | ||||
| import me.chanjar.weixin.common.api.WxErrorExceptionHandler; | |||||
| import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
| @@ -0,0 +1,17 @@ | |||||
| package me.chanjar.weixin.common.util; | |||||
| public class RandomUtils { | |||||
| private static final String RANDOM_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | |||||
| private static final java.util.Random RANDOM = new java.util.Random(); | |||||
| public static String getRandomStr() { | |||||
| StringBuilder sb = new StringBuilder(); | |||||
| for (int i = 0; i < 16; i++) { | |||||
| sb.append(RANDOM_STR.charAt(RANDOM.nextInt(RANDOM_STR.length()))); | |||||
| } | |||||
| return sb.toString(); | |||||
| } | |||||
| } | |||||
| @@ -1,5 +1,6 @@ | |||||
| package me.chanjar.weixin.common.util; | package me.chanjar.weixin.common.util; | ||||
| import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; | |||||
| import org.testng.Assert; | import org.testng.Assert; | ||||
| import org.testng.annotations.Test; | import org.testng.annotations.Test; | ||||
| @@ -22,6 +22,20 @@ public interface WxCpConfigStorage { | |||||
| public void updateAccessToken(String accessToken, int expiresIn); | public void updateAccessToken(String accessToken, int expiresIn); | ||||
| public String getJsapiTicket(); | |||||
| public boolean isJsapiTicketExpired(); | |||||
| /** | |||||
| * 强制将jsapi ticket过期掉 | |||||
| */ | |||||
| public void expireJsapiTicket(); | |||||
| /** | |||||
| * 应该是线程安全的 | |||||
| * @param jsapiTicket | |||||
| */ | |||||
| public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); | |||||
| public String getCorpId(); | public String getCorpId(); | ||||
| @@ -25,6 +25,9 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { | |||||
| protected volatile String http_proxy_username; | protected volatile String http_proxy_username; | ||||
| protected volatile String http_proxy_password; | protected volatile String http_proxy_password; | ||||
| protected volatile String jsapiTicket; | |||||
| protected volatile long jsapiTicketExpiresTime; | |||||
| public String getAccessToken() { | public String getAccessToken() { | ||||
| return this.accessToken; | return this.accessToken; | ||||
| } | } | ||||
| @@ -46,6 +49,37 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { | |||||
| this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; | this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; | ||||
| } | } | ||||
| @Override | |||||
| public String getJsapiTicket() { | |||||
| return jsapiTicket; | |||||
| } | |||||
| public void setJsapiTicket(String jsapiTicket) { | |||||
| this.jsapiTicket = jsapiTicket; | |||||
| } | |||||
| public long getJsapiTicketExpiresTime() { | |||||
| return jsapiTicketExpiresTime; | |||||
| } | |||||
| public void setJsapiTicketExpiresTime(long jsapiTicketExpiresTime) { | |||||
| this.jsapiTicketExpiresTime = jsapiTicketExpiresTime; | |||||
| } | |||||
| public boolean isJsapiTicketExpired() { | |||||
| return System.currentTimeMillis() > this.jsapiTicketExpiresTime; | |||||
| } | |||||
| public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { | |||||
| this.jsapiTicket = jsapiTicket; | |||||
| // 预留200秒的时间 | |||||
| this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; | |||||
| } | |||||
| public void expireJsapiTicket() { | |||||
| this.jsapiTicketExpiresTime = 0; | |||||
| } | |||||
| public String getCorpId() { | public String getCorpId() { | ||||
| return this.corpId; | return this.corpId; | ||||
| } | } | ||||
| @@ -153,6 +187,8 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { | |||||
| ", http_proxy_port=" + http_proxy_port + | ", http_proxy_port=" + http_proxy_port + | ||||
| ", http_proxy_username='" + http_proxy_username + '\'' + | ", http_proxy_username='" + http_proxy_username + '\'' + | ||||
| ", http_proxy_password='" + http_proxy_password + '\'' + | ", http_proxy_password='" + http_proxy_password + '\'' + | ||||
| ", jsapiTicket='" + jsapiTicket + '\'' + | |||||
| ", jsapiTicketExpiresTime='" + jsapiTicketExpiresTime + '\'' + | |||||
| '}'; | '}'; | ||||
| } | } | ||||
| @@ -5,9 +5,9 @@ import me.chanjar.weixin.common.session.InternalSessionManager; | |||||
| import me.chanjar.weixin.common.session.StandardSessionManager; | import me.chanjar.weixin.common.session.StandardSessionManager; | ||||
| import me.chanjar.weixin.common.session.WxSessionManager; | import me.chanjar.weixin.common.session.WxSessionManager; | ||||
| import me.chanjar.weixin.common.util.LogExceptionHandler; | import me.chanjar.weixin.common.util.LogExceptionHandler; | ||||
| import me.chanjar.weixin.common.util.WxErrorExceptionHandler; | |||||
| import me.chanjar.weixin.common.util.WxMessageDuplicateChecker; | |||||
| import me.chanjar.weixin.common.util.WxMessageInMemoryDuplicateChecker; | |||||
| 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.cp.bean.WxCpXmlMessage; | import me.chanjar.weixin.cp.bean.WxCpXmlMessage; | ||||
| import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; | import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; | ||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
| @@ -87,8 +87,8 @@ public class WxCpMessageRouter { | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 设置自定义的 {@link me.chanjar.weixin.common.util.WxMessageDuplicateChecker} | |||||
| * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.WxMessageInMemoryDuplicateChecker} | |||||
| * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker} | |||||
| * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker} | |||||
| * </pre> | * </pre> | ||||
| * @param messageDuplicateChecker | * @param messageDuplicateChecker | ||||
| */ | */ | ||||
| @@ -109,7 +109,7 @@ public class WxCpMessageRouter { | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 设置自定义的{@link me.chanjar.weixin.common.util.WxErrorExceptionHandler} | |||||
| * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler} | |||||
| * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler} | * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler} | ||||
| * </pre> | * </pre> | ||||
| * @param exceptionHandler | * @param exceptionHandler | ||||
| @@ -2,7 +2,7 @@ package me.chanjar.weixin.cp.api; | |||||
| import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import me.chanjar.weixin.common.session.WxSessionManager; | import me.chanjar.weixin.common.session.WxSessionManager; | ||||
| import me.chanjar.weixin.common.util.WxErrorExceptionHandler; | |||||
| import me.chanjar.weixin.common.api.WxErrorExceptionHandler; | |||||
| import me.chanjar.weixin.cp.bean.WxCpXmlMessage; | import me.chanjar.weixin.cp.bean.WxCpXmlMessage; | ||||
| import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; | import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; | ||||
| @@ -8,6 +8,7 @@ import com.google.gson.internal.Streams; | |||||
| import com.google.gson.reflect.TypeToken; | import com.google.gson.reflect.TypeToken; | ||||
| import com.google.gson.stream.JsonReader; | import com.google.gson.stream.JsonReader; | ||||
| import me.chanjar.weixin.common.bean.WxAccessToken; | import me.chanjar.weixin.common.bean.WxAccessToken; | ||||
| import me.chanjar.weixin.common.bean.WxJsapiSignature; | |||||
| import me.chanjar.weixin.common.bean.WxMenu; | import me.chanjar.weixin.common.bean.WxMenu; | ||||
| import me.chanjar.weixin.common.bean.result.WxError; | import me.chanjar.weixin.common.bean.result.WxError; | ||||
| import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | ||||
| @@ -15,6 +16,7 @@ import me.chanjar.weixin.common.exception.WxErrorException; | |||||
| import me.chanjar.weixin.common.session.StandardSessionManager; | import me.chanjar.weixin.common.session.StandardSessionManager; | ||||
| import me.chanjar.weixin.common.session.WxSession; | import me.chanjar.weixin.common.session.WxSession; | ||||
| import me.chanjar.weixin.common.session.WxSessionManager; | import me.chanjar.weixin.common.session.WxSessionManager; | ||||
| import me.chanjar.weixin.common.util.RandomUtils; | |||||
| import me.chanjar.weixin.common.util.StringUtils; | import me.chanjar.weixin.common.util.StringUtils; | ||||
| import me.chanjar.weixin.common.util.crypto.SHA1; | import me.chanjar.weixin.common.util.crypto.SHA1; | ||||
| import me.chanjar.weixin.common.util.fs.FileUtils; | import me.chanjar.weixin.common.util.fs.FileUtils; | ||||
| @@ -44,6 +46,7 @@ import java.io.File; | |||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.io.InputStream; | import java.io.InputStream; | ||||
| import java.io.StringReader; | import java.io.StringReader; | ||||
| import java.security.NoSuchAlgorithmException; | |||||
| import java.util.List; | import java.util.List; | ||||
| import java.util.UUID; | import java.util.UUID; | ||||
| @@ -54,7 +57,12 @@ public class WxCpServiceImpl implements WxCpService { | |||||
| /** | /** | ||||
| * 全局的是否正在刷新access token的锁 | * 全局的是否正在刷新access token的锁 | ||||
| */ | */ | ||||
| protected static final Object GLOBAL_ACCESS_TOKEN_REFRESH_LOCK = new Object(); | |||||
| protected final Object globalAccessTokenRefreshLock = new Object(); | |||||
| /** | |||||
| * 全局的是否正在刷新jsapi_ticket的锁 | |||||
| */ | |||||
| protected final Object globalJsapiTicketRefreshLock = new Object(); | |||||
| protected WxCpConfigStorage wxCpConfigStorage; | protected WxCpConfigStorage wxCpConfigStorage; | ||||
| @@ -90,7 +98,7 @@ public class WxCpServiceImpl implements WxCpService { | |||||
| wxCpConfigStorage.expireAccessToken(); | wxCpConfigStorage.expireAccessToken(); | ||||
| } | } | ||||
| if (wxCpConfigStorage.isAccessTokenExpired()) { | if (wxCpConfigStorage.isAccessTokenExpired()) { | ||||
| synchronized (GLOBAL_ACCESS_TOKEN_REFRESH_LOCK) { | |||||
| synchronized (globalAccessTokenRefreshLock) { | |||||
| if (wxCpConfigStorage.isAccessTokenExpired()) { | if (wxCpConfigStorage.isAccessTokenExpired()) { | ||||
| String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" | String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" | ||||
| + "&corpid=" + wxCpConfigStorage.getCorpId() | + "&corpid=" + wxCpConfigStorage.getCorpId() | ||||
| @@ -121,6 +129,52 @@ public class WxCpServiceImpl implements WxCpService { | |||||
| return wxCpConfigStorage.getAccessToken(); | return wxCpConfigStorage.getAccessToken(); | ||||
| } | } | ||||
| public String getJsapiTicket() throws WxErrorException { | |||||
| return getJsapiTicket(false); | |||||
| } | |||||
| public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { | |||||
| if (forceRefresh) { | |||||
| wxCpConfigStorage.expireJsapiTicket(); | |||||
| } | |||||
| if (wxCpConfigStorage.isJsapiTicketExpired()) { | |||||
| synchronized (globalJsapiTicketRefreshLock) { | |||||
| if (wxCpConfigStorage.isJsapiTicketExpired()) { | |||||
| String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; | |||||
| String responseContent = execute(new SimpleGetRequestExecutor(), url, null); | |||||
| JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); | |||||
| JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); | |||||
| String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); | |||||
| int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); | |||||
| wxCpConfigStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds); | |||||
| } | |||||
| } | |||||
| } | |||||
| return wxCpConfigStorage.getJsapiTicket(); | |||||
| } | |||||
| public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { | |||||
| long timestamp = System.currentTimeMillis() / 1000; | |||||
| String noncestr = RandomUtils.getRandomStr(); | |||||
| String jsapiTicket = getJsapiTicket(false); | |||||
| try { | |||||
| String signature = SHA1.genWithAmple( | |||||
| "jsapi_ticket=" + jsapiTicket, | |||||
| "noncestr=" + noncestr, | |||||
| "timestamp=" + timestamp, | |||||
| "url=" + url | |||||
| ); | |||||
| WxJsapiSignature jsapiSignature = new WxJsapiSignature(); | |||||
| jsapiSignature.setTimestamp(timestamp); | |||||
| jsapiSignature.setNoncestr(noncestr); | |||||
| jsapiSignature.setUrl(url); | |||||
| jsapiSignature.setSignature(signature); | |||||
| return jsapiSignature; | |||||
| } catch (NoSuchAlgorithmException e) { | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| public void messageSend(WxCpMessage message) throws WxErrorException { | public void messageSend(WxCpMessage message) throws WxErrorException { | ||||
| String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send"; | String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send"; | ||||
| post(url, message.toJson()); | post(url, message.toJson()); | ||||
| @@ -477,7 +531,7 @@ public class WxCpServiceImpl implements WxCpService { | |||||
| * 42001 access_token超时 | * 42001 access_token超时 | ||||
| */ | */ | ||||
| if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { | if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { | ||||
| // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token | |||||
| // 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token | |||||
| wxCpConfigStorage.expireAccessToken(); | wxCpConfigStorage.expireAccessToken(); | ||||
| return execute(executor, uri, data); | return execute(executor, uri, data); | ||||
| } | } | ||||
| @@ -0,0 +1,68 @@ | |||||
| /** | |||||
| * Created by qianjia on 15/1/25. | |||||
| */ | |||||
| public class TestNonAtomicLongAssignment { | |||||
| private static final long HI = 1l << 32; | |||||
| private static final long LO = 1l; | |||||
| private static final long TEST_NUMBER = HI | LO; | |||||
| private static long assignee = 0l; | |||||
| public static void main(String[] args) { | |||||
| Thread writer = new Thread(new Runnable() { | |||||
| @Override | |||||
| public void run() { | |||||
| while (true) { | |||||
| assignee = TEST_NUMBER; | |||||
| } | |||||
| } | |||||
| }); | |||||
| writer.setDaemon(true); | |||||
| Thread reader = new Thread(new Runnable() { | |||||
| @Override | |||||
| public void run() { | |||||
| long i = 0; | |||||
| while (true) { | |||||
| i++; | |||||
| long test = assignee; | |||||
| if (test != TEST_NUMBER) { | |||||
| System.out.print(i + " times:" + toBin(test)); | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| }); | |||||
| // Thread worker = new Thread(new Runnable() { | |||||
| // @Override | |||||
| // public void run() { | |||||
| // double d = 89009808877238948224343435452333323113131313133434434341212323232424243434335354232390490189190420928348910913094983.323334401928d; | |||||
| // while(true) { | |||||
| // Math.cbrt(d); | |||||
| // d = d - 1l; | |||||
| // } | |||||
| // } | |||||
| // }); | |||||
| // worker.setDaemon(true); | |||||
| // worker.start(); | |||||
| writer.start(); | |||||
| reader.start(); | |||||
| } | |||||
| public static String toBin(long n) { | |||||
| StringBuilder sb = new StringBuilder(Long.toBinaryString(n)); | |||||
| int padding = 64 - sb.length(); | |||||
| while (padding > 0) { | |||||
| sb.insert(0, '0'); | |||||
| padding--; | |||||
| } | |||||
| return sb.toString(); | |||||
| } | |||||
| } | |||||
| @@ -51,6 +51,18 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||||
| return jsapiTicket; | return jsapiTicket; | ||||
| } | } | ||||
| public void setJsapiTicket(String jsapiTicket) { | |||||
| this.jsapiTicket = jsapiTicket; | |||||
| } | |||||
| public long getJsapiTicketExpiresTime() { | |||||
| return jsapiTicketExpiresTime; | |||||
| } | |||||
| public void setJsapiTicketExpiresTime(long jsapiTicketExpiresTime) { | |||||
| this.jsapiTicketExpiresTime = jsapiTicketExpiresTime; | |||||
| } | |||||
| public boolean isJsapiTicketExpired() { | public boolean isJsapiTicketExpired() { | ||||
| return System.currentTimeMillis() > this.jsapiTicketExpiresTime; | return System.currentTimeMillis() > this.jsapiTicketExpiresTime; | ||||
| } | } | ||||
| @@ -167,5 +179,4 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||||
| ", jsapiTicketExpiresTime='" + jsapiTicketExpiresTime + '\'' + | ", jsapiTicketExpiresTime='" + jsapiTicketExpiresTime + '\'' + | ||||
| '}'; | '}'; | ||||
| } | } | ||||
| } | } | ||||
| @@ -5,9 +5,9 @@ import me.chanjar.weixin.common.session.InternalSessionManager; | |||||
| import me.chanjar.weixin.common.session.StandardSessionManager; | import me.chanjar.weixin.common.session.StandardSessionManager; | ||||
| import me.chanjar.weixin.common.session.WxSessionManager; | import me.chanjar.weixin.common.session.WxSessionManager; | ||||
| import me.chanjar.weixin.common.util.LogExceptionHandler; | import me.chanjar.weixin.common.util.LogExceptionHandler; | ||||
| import me.chanjar.weixin.common.util.WxErrorExceptionHandler; | |||||
| import me.chanjar.weixin.common.util.WxMessageDuplicateChecker; | |||||
| import me.chanjar.weixin.common.util.WxMessageInMemoryDuplicateChecker; | |||||
| 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.WxMpXmlMessage; | ||||
| import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; | import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; | ||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
| @@ -87,8 +87,8 @@ public class WxMpMessageRouter { | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 设置自定义的 {@link me.chanjar.weixin.common.util.WxMessageDuplicateChecker} | |||||
| * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.WxMessageInMemoryDuplicateChecker} | |||||
| * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker} | |||||
| * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker} | |||||
| * </pre> | * </pre> | ||||
| * @param messageDuplicateChecker | * @param messageDuplicateChecker | ||||
| */ | */ | ||||
| @@ -109,7 +109,7 @@ public class WxMpMessageRouter { | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 设置自定义的{@link me.chanjar.weixin.common.util.WxErrorExceptionHandler} | |||||
| * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler} | |||||
| * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler} | * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler} | ||||
| * </pre> | * </pre> | ||||
| * @param exceptionHandler | * @param exceptionHandler | ||||
| @@ -2,7 +2,7 @@ package me.chanjar.weixin.mp.api; | |||||
| import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import me.chanjar.weixin.common.session.WxSessionManager; | import me.chanjar.weixin.common.session.WxSessionManager; | ||||
| import me.chanjar.weixin.common.util.WxErrorExceptionHandler; | |||||
| import me.chanjar.weixin.common.api.WxErrorExceptionHandler; | |||||
| import me.chanjar.weixin.mp.bean.WxMpXmlMessage; | import me.chanjar.weixin.mp.bean.WxMpXmlMessage; | ||||
| import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; | import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; | ||||
| @@ -1,10 +1,9 @@ | |||||
| package me.chanjar.weixin.mp.api; | package me.chanjar.weixin.mp.api; | ||||
| import me.chanjar.weixin.common.bean.WxMenu; | import me.chanjar.weixin.common.bean.WxMenu; | ||||
| import me.chanjar.weixin.common.bean.WxJsapiSignature; | |||||
| import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | ||||
| import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import me.chanjar.weixin.common.session.WxSession; | |||||
| import me.chanjar.weixin.common.session.WxSessionManager; | |||||
| import me.chanjar.weixin.common.util.http.RequestExecutor; | import me.chanjar.weixin.common.util.http.RequestExecutor; | ||||
| import me.chanjar.weixin.mp.bean.*; | import me.chanjar.weixin.mp.bean.*; | ||||
| import me.chanjar.weixin.mp.bean.result.*; | import me.chanjar.weixin.mp.bean.result.*; | ||||
| @@ -86,7 +85,7 @@ public interface WxMpService { | |||||
| * @param url url | * @param url url | ||||
| * @return | * @return | ||||
| */ | */ | ||||
| public WxMpJsapiSignature createJsapiSignature(String url) throws WxErrorException; | |||||
| public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| @@ -7,11 +7,13 @@ import com.google.gson.reflect.TypeToken; | |||||
| import com.google.gson.stream.JsonReader; | import com.google.gson.stream.JsonReader; | ||||
| import me.chanjar.weixin.common.bean.WxAccessToken; | import me.chanjar.weixin.common.bean.WxAccessToken; | ||||
| import me.chanjar.weixin.common.bean.WxMenu; | import me.chanjar.weixin.common.bean.WxMenu; | ||||
| import me.chanjar.weixin.common.bean.WxJsapiSignature; | |||||
| import me.chanjar.weixin.common.bean.result.WxError; | import me.chanjar.weixin.common.bean.result.WxError; | ||||
| import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | ||||
| import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import me.chanjar.weixin.common.session.StandardSessionManager; | import me.chanjar.weixin.common.session.StandardSessionManager; | ||||
| import me.chanjar.weixin.common.session.WxSessionManager; | import me.chanjar.weixin.common.session.WxSessionManager; | ||||
| import me.chanjar.weixin.common.util.RandomUtils; | |||||
| import me.chanjar.weixin.common.util.StringUtils; | import me.chanjar.weixin.common.util.StringUtils; | ||||
| import me.chanjar.weixin.common.util.crypto.SHA1; | import me.chanjar.weixin.common.util.crypto.SHA1; | ||||
| import me.chanjar.weixin.common.util.fs.FileUtils; | import me.chanjar.weixin.common.util.fs.FileUtils; | ||||
| @@ -42,15 +44,10 @@ import java.io.InputStream; | |||||
| import java.io.StringReader; | import java.io.StringReader; | ||||
| import java.security.NoSuchAlgorithmException; | import java.security.NoSuchAlgorithmException; | ||||
| import java.util.List; | import java.util.List; | ||||
| import java.util.Random; | |||||
| import java.util.UUID; | import java.util.UUID; | ||||
| public class WxMpServiceImpl implements WxMpService { | public class WxMpServiceImpl implements WxMpService { | ||||
| protected final String RANDOM_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | |||||
| protected final Random RANDOM = new Random(); | |||||
| protected final Logger log = LoggerFactory.getLogger(WxMpServiceImpl.class); | protected final Logger log = LoggerFactory.getLogger(WxMpServiceImpl.class); | ||||
| /** | /** | ||||
| @@ -148,9 +145,9 @@ public class WxMpServiceImpl implements WxMpService { | |||||
| return wxMpConfigStorage.getJsapiTicket(); | return wxMpConfigStorage.getJsapiTicket(); | ||||
| } | } | ||||
| public WxMpJsapiSignature createJsapiSignature(String url) throws WxErrorException { | |||||
| public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { | |||||
| long timestamp = System.currentTimeMillis() / 1000; | long timestamp = System.currentTimeMillis() / 1000; | ||||
| String noncestr = getRandomStr(); | |||||
| String noncestr = RandomUtils.getRandomStr(); | |||||
| String jsapiTicket = getJsapiTicket(false); | String jsapiTicket = getJsapiTicket(false); | ||||
| try { | try { | ||||
| String signature = SHA1.genWithAmple( | String signature = SHA1.genWithAmple( | ||||
| @@ -159,7 +156,7 @@ public class WxMpServiceImpl implements WxMpService { | |||||
| "timestamp=" + timestamp, | "timestamp=" + timestamp, | ||||
| "url=" + url | "url=" + url | ||||
| ); | ); | ||||
| WxMpJsapiSignature jsapiSignature = new WxMpJsapiSignature(); | |||||
| WxJsapiSignature jsapiSignature = new WxJsapiSignature(); | |||||
| jsapiSignature.setTimestamp(timestamp); | jsapiSignature.setTimestamp(timestamp); | ||||
| jsapiSignature.setNoncestr(noncestr); | jsapiSignature.setNoncestr(noncestr); | ||||
| jsapiSignature.setUrl(url); | jsapiSignature.setUrl(url); | ||||
| @@ -170,14 +167,6 @@ public class WxMpServiceImpl implements WxMpService { | |||||
| } | } | ||||
| } | } | ||||
| protected String getRandomStr() { | |||||
| StringBuilder sb = new StringBuilder(); | |||||
| for (int i = 0; i < 16; i++) { | |||||
| sb.append(RANDOM_STR.charAt(RANDOM.nextInt(RANDOM_STR.length()))); | |||||
| } | |||||
| return sb.toString(); | |||||
| } | |||||
| public void customMessageSend(WxMpCustomMessage message) throws WxErrorException { | public void customMessageSend(WxMpCustomMessage message) throws WxErrorException { | ||||
| String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send"; | String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send"; | ||||
| execute(new SimplePostRequestExecutor(), url, message.toJson()); | execute(new SimplePostRequestExecutor(), url, message.toJson()); | ||||