diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java index 19424e0b..fead486e 100755 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java @@ -19,14 +19,8 @@ package me.chanjar.weixin.common.util.crypto; import java.io.StringReader; import java.nio.charset.Charset; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; import java.util.Random; -import java.util.SortedMap; -import java.util.TreeMap; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; @@ -36,7 +30,6 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.digest.DigestUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.InputSource; @@ -79,32 +72,6 @@ public class WxCryptUtil { this.aesKey = Base64.decodeBase64(encodingAesKey + "="); } - /** - * 微信公众号支付签名算法(详见:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3) - * @param packageParams 原始参数 - * @param signKey 加密Key(即 商户Key) - * @return 签名字符串 - */ - public static String createSignForPay(Map packageParams, String signKey) { - SortedMap sortedMap = new TreeMap<>(); - sortedMap.putAll(packageParams); - - List keys = new ArrayList<>(packageParams.keySet()); - Collections.sort(keys); - - StringBuffer toSign = new StringBuffer(); - for (String key : keys) { - String value = packageParams.get(key); - if (null != value && !"".equals(value) && !"sign".equals(key) - && !"key".equals(key)) { - toSign.append(key + "=" + value + "&"); - } - } - toSign.append("key=" + signKey); - String sign = DigestUtils.md5Hex(toSign.toString()).toUpperCase(); - return sign; - } - static String extractEncryptPart(String xml) { try { DocumentBuilder db = builderLocal.get(); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java index ad67bd51..3a137849 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.common.util.http; -import me.chanjar.weixin.common.bean.result.WxError; -import me.chanjar.weixin.common.exception.WxErrorException; +import java.io.IOException; + import org.apache.http.Consts; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -10,7 +10,8 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; -import java.io.IOException; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; /** * 简单的POST请求执行器,请求的参数是String, 返回的结果也是String @@ -34,6 +35,11 @@ public class SimplePostRequestExecutor implements RequestExecutor")) { + //xml格式输出直接返回 + return responseContent; + } + WxError error = WxError.fromJson(responseContent); if (error.getErrorCode() != 0) { throw new WxErrorException(error); diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java index d885327a..ba49528a 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamInitializer.java @@ -1,5 +1,7 @@ package me.chanjar.weixin.common.util.xml; +import java.io.Writer; + import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.core.util.QuickWriter; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; @@ -8,8 +10,6 @@ import com.thoughtworks.xstream.io.xml.XppDriver; import com.thoughtworks.xstream.security.NullPermission; import com.thoughtworks.xstream.security.PrimitiveTypePermission; -import java.io.Writer; - public class XStreamInitializer { public static XStream getInstance() { @@ -34,6 +34,11 @@ public class XStreamInitializer { } } + + @Override + public String encodeNode(String name) { + return name;//防止将_转换成__ + } }; } }); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java index f331a143..979f4a23 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java @@ -8,6 +8,7 @@ import java.util.Map.Entry; import java.util.SortedMap; import java.util.TreeMap; +import org.apache.commons.codec.digest.DigestUtils; import org.apache.http.Consts; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -25,7 +26,6 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.util.crypto.WxCryptUtil; import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.mp.api.WxMpPayService; @@ -85,7 +85,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { packageParams.put("nonce_str", System.currentTimeMillis() + ""); checkParameters(packageParams); - String sign = WxCryptUtil.createSignForPay(packageParams, + String sign = this.createSign(packageParams, this.wxMpService.getWxMpConfigStorage().getPartnerKey()); packageParams.put("sign", sign); @@ -219,7 +219,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { payInfo.put("codeUrl", wxMpPrepayIdResult.getCode_url()); } - String finalSign = WxCryptUtil.createSignForPay(payInfo, + String finalSign = this.createSign(payInfo, this.wxMpService.getWxMpConfigStorage().getPartnerKey()); payInfo.put("paySign", finalSign); return payInfo; @@ -246,7 +246,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { } packageParams.put("nonce_str", nonce_str); - packageParams.put("sign", WxCryptUtil.createSignForPay(packageParams, + packageParams.put("sign", this.createSign(packageParams, this.wxMpService.getWxMpConfigStorage().getPartnerKey())); StringBuilder request = new StringBuilder(""); @@ -303,7 +303,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { refundParams.put("nonce_str", System.currentTimeMillis() + ""); refundParams.put("op_user_id", this.wxMpService.getWxMpConfigStorage().getPartnerId()); - String sign = WxCryptUtil.createSignForPay(refundParams, + String sign = this.createSign(refundParams, this.wxMpService.getWxMpConfigStorage().getPartnerKey()); refundParams.put("sign", sign); @@ -362,7 +362,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { @Override public boolean checkJSSDKCallbackDataSignature(Map kvm, String signature) { - return signature.equals(WxCryptUtil.createSignForPay(kvm, + return signature.equals(this.createSign(kvm, this.wxMpService.getWxMpConfigStorage().getPartnerKey())); } @@ -377,7 +377,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { this.wxMpService.getWxMpConfigStorage().getPartnerId()); packageParams.put("nonce_str", System.currentTimeMillis() + ""); - String sign = WxCryptUtil.createSignForPay(packageParams, + String sign = this.createSign(packageParams, this.wxMpService.getWxMpConfigStorage().getPartnerKey()); packageParams.put("sign", sign); @@ -428,7 +428,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId()); request.setNonceStr(System.currentTimeMillis() + ""); - String sign = WxCryptUtil.createSignForPay(xmlBean2Map(request), + String sign = this.createSign(xmlBean2Map(request), this.wxMpService.getWxMpConfigStorage().getPartnerKey()); request.setSign(sign); @@ -453,7 +453,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { try { Field field = WxSendRedpackRequest.class.getDeclaredField(entry.getKey()); if (field.isAnnotationPresent(XStreamAlias.class)) { - result.put(reflect.get().toString(), field.getAnnotation(XStreamAlias.class).value()); + result.put(field.getAnnotation(XStreamAlias.class).value(), reflect.get().toString()); } } catch (NoSuchFieldException | SecurityException e) { e.printStackTrace(); @@ -464,4 +464,26 @@ public class WxMpPayServiceImpl implements WxMpPayService { return result; } + /** + * 微信公众号支付签名算法(详见:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3) + * @param packageParams 原始参数 + * @param signKey 加密Key(即 商户Key) + * @return 签名字符串 + */ + private String createSign(Map packageParams, String signKey) { + SortedMap sortedMap = new TreeMap<>(packageParams); + + StringBuffer toSign = new StringBuffer(); + for (String key : sortedMap.keySet()) { + String value = packageParams.get(key); + if (null != value && !"".equals(value) && !"sign".equals(key) && !"key".equals(key)) { + toSign.append(key + "=" + value + "&"); + } + } + + toSign.append("key=" + signKey); + + return DigestUtils.md5Hex(toSign.toString()).toUpperCase(); + } + } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java index 79a5a631..b17d1206 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java @@ -1,12 +1,26 @@ package me.chanjar.weixin.mp.api.impl; +import org.testng.annotations.Guice; import org.testng.annotations.Test; +import com.google.inject.Inject; + +import me.chanjar.weixin.mp.api.ApiTestModule; +import me.chanjar.weixin.mp.bean.pay.WxRedpackResult; +import me.chanjar.weixin.mp.bean.pay.WxSendRedpackRequest; + /** + * 测试支付相关接口 * Created by Binary Wang on 2016/7/28. * @author binarywang (https://github.com/binarywang) */ +@Test +@Guice(modules = ApiTestModule.class) public class WxMpPayServiceImplTest { + + @Inject + protected WxMpServiceImpl wxService; + @Test public void testGetPrepayId() throws Exception { @@ -54,7 +68,14 @@ public class WxMpPayServiceImplTest { @Test public void testSendRedpack() throws Exception { - + WxSendRedpackRequest request = new WxSendRedpackRequest(); + request.setActName("abc"); + request.setClientIp("aaa"); + request.setMchBillno("aaaa"); + request + .setReOpenid(((ApiTestModule.WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage()).getOpenid()); + WxRedpackResult redpackResult = this.wxService.getPayService().sendRedpack(request); + System.err.println(redpackResult); } } \ No newline at end of file diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/pay/WxSendRedpackRequestTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/pay/WxSendRedpackRequestTest.java new file mode 100644 index 00000000..feb50c5a --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/pay/WxSendRedpackRequestTest.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.mp.bean.pay; + +import java.lang.reflect.Field; +import java.util.Map.Entry; + +import org.joor.Reflect; +import org.testng.annotations.Test; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@Test +public class WxSendRedpackRequestTest { + + public void test() throws NoSuchFieldException, SecurityException { + + WxSendRedpackRequest request = new WxSendRedpackRequest(); + request.setMchBillno("123"); + request.setActName("ab"); + for (Entry entry : Reflect.on(request).fields().entrySet()) { + Reflect reflect = entry.getValue(); + if (reflect.get() == null) { + continue; + } + + Field field = WxSendRedpackRequest.class.getDeclaredField(entry.getKey()); + if (field.isAnnotationPresent(XStreamAlias.class)) { + System.err.println(reflect.get() + " = " + field.getAnnotation(XStreamAlias.class).value()); + } + } + + } + +}