diff --git a/README.md b/README.md
index a519eaeb..9691368a 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ weixin-java-tools
me.chanjar
weixin-java-mp
- 1.3.0
+ 1.3.1
```
@@ -27,7 +27,7 @@ weixin-java-tools
me.chanjar
weixin-java-cp
- 1.3.0
+ 1.3.1
```
diff --git a/pom.xml b/pom.xml
index 40e2f2f2..01b42407 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
4.0.0
me.chanjar
weixin-java-parent
- 1.3.0
+ 1.3.1
pom
WeiXin Java Tools - Parent
微信公众号、企业号上级POM
diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml
index a8d1da30..a8366c7a 100644
--- a/weixin-java-common/pom.xml
+++ b/weixin-java-common/pom.xml
@@ -6,7 +6,7 @@
me.chanjar
weixin-java-parent
- 1.3.0
+ 1.3.1
weixin-java-common
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java
index c44ceea7..ce1cca01 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java
@@ -11,6 +11,7 @@ import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
+import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import me.chanjar.weixin.common.bean.result.WxError;
@@ -35,6 +36,7 @@ public class MediaUploadRequestExecutor implements RequestExecutor
me.chanjar
weixin-java-parent
- 1.3.0
+ 1.3.1
weixin-java-cp
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
index 7b95c32c..3b9e8fe7 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
@@ -555,7 +555,7 @@ public class WxCpServiceImpl implements WxCpService {
throw new RuntimeException("微信服务端异常,超出重试次数");
}
- protected T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException {
+ protected synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException {
if (uri.indexOf("access_token=") != -1) {
throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri);
}
diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml
index 48999b06..e4695436 100644
--- a/weixin-java-mp/pom.xml
+++ b/weixin-java-mp/pom.xml
@@ -6,7 +6,7 @@
me.chanjar
weixin-java-parent
- 1.3.0
+ 1.3.1
weixin-java-mp
WeiXin Java Tools - MP
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
index 5c15e89b..b583798e 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
@@ -671,33 +671,57 @@ public interface WxMpService {
*/
void setMaxRetryTimes(int maxRetryTimes);
- /**
- * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
- * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
- * @param openId 支付人openId
- * @param outTradeNo 商户端对应订单号
- * @param amt 金额(单位元)
- * @param body 商品描述
- * @param tradeType 交易类型 JSAPI,NATIVE,APP,WAP
- * @param ip 发起支付的客户端IP
- * @param notifyUrl 通知地址
- * @return
- */
- WxMpPrepayIdResult getPrepayId(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String notifyUrl);
+ /**
+ * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
+ * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
+ * @param openId 支付人openId
+ * @param outTradeNo 商户端对应订单号
+ * @param amt 金额(单位元)
+ * @param body 商品描述
+ * @param tradeType 交易类型 JSAPI,NATIVE,APP,WAP
+ * @param ip 发起支付的客户端IP
+ * @param notifyUrl 通知地址
+ * @return
+ * @deprecated Use me.chanjar.weixin.mp.api.WxMpService.getPrepayId(Map) instead
+ */
+ @Deprecated
+ WxMpPrepayIdResult getPrepayId(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String notifyUrl);
- /**
- * 该接口调用“统一下单”接口,并拼装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
- * @param openId 支付人openId
- * @param outTradeNo 商户端对应订单号
- * @param amt 金额(单位元)
- * @param body 商品描述
- * @param tradeType 交易类型 JSAPI,NATIVE,APP,WAP
- * @param ip 发起支付的客户端IP
- * @param notifyUrl 通知地址
- * @return
- */
- Map getJSSDKPayInfo(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String notifyUrl);
+ /**
+ * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
+ * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
+ *
+ * @param parameters
+ * All required/optional parameters for weixin payment
+ * @return
+ * @throws IllegalArgumentException
+ */
+ WxMpPrepayIdResult getPrepayId(Map parameters);
+
+ /**
+ * 该接口调用“统一下单”接口,并拼装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
+ * @param parameters
+ * the required or optional parameters
+ * @return
+ */
+ Map getJSSDKPayInfo(Map parameters);
+
+ /**
+ * 该接口调用“统一下单”接口,并拼装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
+ * @param openId 支付人openId
+ * @param outTradeNo 商户端对应订单号
+ * @param amt 金额(单位元)
+ * @param body 商品描述
+ * @param tradeType 交易类型 JSAPI,NATIVE,APP,WAP
+ * @param ip 发起支付的客户端IP
+ * @param notifyUrl 通知地址
+ * @return
+ * @deprecated Use me.chanjar.weixin.mp.api.WxMpService.getJSSDKPayInfo(Map) instead
+ */
+ @Deprecated
+ Map getJSSDKPayInfo(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String notifyUrl);
/**
* 该接口提供所有微信支付订单的查询,当支付通知处理异常戒丢失的情冴,商户可以通过该接口查询订单支付状态。
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java
index 6e616284..da4252fd 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java
@@ -11,6 +11,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;
@@ -634,8 +635,9 @@ public class WxMpServiceImpl implements WxMpService {
param.addProperty("end_date", SIMPLE_DATE_FORMAT.format(endDate));
String responseContent = post(url, param.toString());
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
- return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"), new TypeToken>() {
- }.getType());
+ return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"),
+ new TypeToken>() {
+ }.getType());
}
@Override
@@ -695,7 +697,7 @@ public class WxMpServiceImpl implements WxMpService {
throw new RuntimeException("微信服务端异常,超出重试次数");
}
- protected T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException {
+ protected synchronized T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException {
if (uri.indexOf("access_token=") != -1) {
throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri);
}
@@ -776,35 +778,37 @@ public class WxMpServiceImpl implements WxMpService {
@Override
public WxMpPrepayIdResult getPrepayId(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String callbackUrl) {
- String nonce_str = System.currentTimeMillis() + "";
-
- SortedMap packageParams = new TreeMap();
+ Map packageParams = new HashMap();
packageParams.put("appid", wxMpConfigStorage.getAppId());
packageParams.put("mch_id", wxMpConfigStorage.getPartnerId());
- packageParams.put("nonce_str", nonce_str);
packageParams.put("body", body);
packageParams.put("out_trade_no", outTradeNo);
-
packageParams.put("total_fee", (int) (amt * 100) + "");
packageParams.put("spbill_create_ip", ip);
packageParams.put("notify_url", callbackUrl);
packageParams.put("trade_type", tradeType);
packageParams.put("openid", openId);
+ return getPrepayId(packageParams);
+ }
+
+ public WxMpPrepayIdResult getPrepayId(final Map parameters) {
+ String nonce_str = System.currentTimeMillis() + "";
+
+ final SortedMap packageParams = new TreeMap(parameters);
+ packageParams.put("appid", wxMpConfigStorage.getAppId());
+ packageParams.put("mch_id", wxMpConfigStorage.getPartnerId());
+ packageParams.put("nonce_str", nonce_str);
+ checkParameters(packageParams);
+
String sign = WxCryptUtil.createSign(packageParams, wxMpConfigStorage.getPartnerKey());
- String xml = "" +
- "" + wxMpConfigStorage.getAppId() + "" +
- "" + wxMpConfigStorage.getPartnerId() + "" +
- "" + nonce_str + "" +
- "" + sign + "" +
- "" +
- "" + outTradeNo + "" +
- "" + packageParams.get("total_fee") + "" +
- "" + ip + "" +
- "" + callbackUrl + "" +
- "" + tradeType + "" +
- "" + openId + "" +
- "";
+ packageParams.put("sign", sign);
+
+ StringBuilder request = new StringBuilder("");
+ for (Entry para : packageParams.entrySet()) {
+ request.append(String.format("<%s>%s%s>", para.getKey(), para.getValue(), para.getKey()));
+ }
+ request.append("");
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder");
if (httpProxy != null) {
@@ -812,7 +816,7 @@ public class WxMpServiceImpl implements WxMpService {
httpPost.setConfig(config);
}
- StringEntity entity = new StringEntity(xml, Consts.UTF_8);
+ StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8);
httpPost.setEntity(entity);
try {
CloseableHttpResponse response = getHttpclient().execute(httpPost);
@@ -827,9 +831,39 @@ public class WxMpServiceImpl implements WxMpService {
return new WxMpPrepayIdResult();
}
+ final String[] REQUIRED_ORDER_PARAMETERS = new String[] { "appid", "mch_id", "body", "out_trade_no", "total_fee", "spbill_create_ip", "notify_url",
+ "trade_type", };
+
+ private void checkParameters(Map parameters) {
+ for (String para : REQUIRED_ORDER_PARAMETERS) {
+ if (!parameters.containsKey(para))
+ throw new IllegalArgumentException("Reqiured argument '" + para + "' is missing.");
+ }
+ if ("JSAPI".equals(parameters.get("trade_type")) && !parameters.containsKey("openid"))
+ throw new IllegalArgumentException("Reqiured argument 'openid' is missing when trade_type is 'JSAPI'.");
+ if ("NATIVE".equals(parameters.get("trade_type")) && !parameters.containsKey("product_id"))
+ throw new IllegalArgumentException("Reqiured argument 'product_id' is missing when trade_type is 'NATIVE'.");
+ }
+
@Override
public Map getJSSDKPayInfo(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String callbackUrl) {
- WxMpPrepayIdResult wxMpPrepayIdResult = getPrepayId(openId, outTradeNo, amt, body, tradeType, ip, callbackUrl);
+ Map packageParams = new HashMap();
+ packageParams.put("appid", wxMpConfigStorage.getAppId());
+ packageParams.put("mch_id", wxMpConfigStorage.getPartnerId());
+ packageParams.put("body", body);
+ packageParams.put("out_trade_no", outTradeNo);
+ packageParams.put("total_fee", (int) (amt * 100) + "");
+ packageParams.put("spbill_create_ip", ip);
+ packageParams.put("notify_url", callbackUrl);
+ packageParams.put("trade_type", tradeType);
+ packageParams.put("openid", openId);
+
+ return getJSSDKPayInfo(packageParams);
+ }
+
+ @Override
+ public Map getJSSDKPayInfo(Map parameters) {
+ WxMpPrepayIdResult wxMpPrepayIdResult = getPrepayId(parameters);
String prepayId = wxMpPrepayIdResult.getPrepay_id();
if (prepayId == null || prepayId.equals("")) {
throw new RuntimeException("get prepayid error");
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpPrepayIdResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpPrepayIdResult.java
index aa42299a..b5c09b21 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpPrepayIdResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpPrepayIdResult.java
@@ -22,6 +22,9 @@ public class WxMpPrepayIdResult implements Serializable {
private String result_code;
private String prepay_id;
private String trade_type;
+ private String err_code;
+ private String err_code_des;
+ private String code_url;
public String getReturn_code() {
return return_code;
@@ -94,4 +97,28 @@ public class WxMpPrepayIdResult implements Serializable {
public void setTrade_type(String trade_type) {
this.trade_type = trade_type;
}
+
+ public String getErr_code() {
+ return err_code;
+ }
+
+ public void setErr_code(String err_code) {
+ this.err_code = err_code;
+ }
+
+ public String getErr_code_des() {
+ return err_code_des;
+ }
+
+ public void setErr_code_des(String err_code_des) {
+ this.err_code_des = err_code_des;
+ }
+
+ public String getCode_url() {
+ return code_url;
+ }
+
+ public void setCode_url(String code_url) {
+ this.code_url = code_url;
+ }
}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java
index 63d92523..41ee9883 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/http/MaterialUploadRequestExecutor.java
@@ -13,6 +13,7 @@ import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
+import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.impl.client.CloseableHttpClient;
@@ -36,7 +37,9 @@ public class MaterialUploadRequestExecutor implements RequestExecutor form = material.getForm();
if (material.getForm() != null) {
multipartEntityBuilder.addTextBody("description", WxGsonBuilder.create().toJson(form));
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserGsonAdapter.java
index 9ffb41a0..0b80e90a 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserGsonAdapter.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserGsonAdapter.java
@@ -19,7 +19,10 @@ public class WxMpUserGsonAdapter implements JsonDeserializer {
public WxMpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject o = json.getAsJsonObject();
WxMpUser wxMpUser = new WxMpUser();
- wxMpUser.setSubscribe(new Integer(0).equals(GsonHelper.getInteger(o, "subscribe")) ? false : true);
+ Integer subscribe = GsonHelper.getInteger(o, "subscribe");
+ if (subscribe != null) {
+ wxMpUser.setSubscribe(new Integer(0).equals(subscribe) ? false : true);
+ }
wxMpUser.setCity(GsonHelper.getString(o, "city"));
wxMpUser.setCountry(GsonHelper.getString(o, "country"));
wxMpUser.setHeadImgUrl(GsonHelper.getString(o, "headimgurl"));