@@ -1,73 +1,79 @@ | |||
<?xml version="1.0"?> | |||
<project | |||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" | |||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | |||
<modelVersion>4.0.0</modelVersion> | |||
<parent> | |||
<groupId>com.github.binarywang</groupId> | |||
<artifactId>weixin-java-parent</artifactId> | |||
<version>2.4.6.BETA</version> | |||
</parent> | |||
<artifactId>weixin-java-mp</artifactId> | |||
<name>WeiXin Java Tools - MP</name> | |||
<description>微信公众号Java SDK</description> | |||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"> | |||
<modelVersion>4.0.0</modelVersion> | |||
<parent> | |||
<groupId>com.github.binarywang</groupId> | |||
<artifactId>weixin-java-parent</artifactId> | |||
<version>2.4.6.BETA</version> | |||
</parent> | |||
<artifactId>weixin-java-mp</artifactId> | |||
<name>WeiXin Java Tools - MP</name> | |||
<description>微信公众号Java SDK</description> | |||
<dependencies> | |||
<dependency> | |||
<groupId>com.github.binarywang</groupId> | |||
<artifactId>weixin-java-common</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>junit</groupId> | |||
<artifactId>junit</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.testng</groupId> | |||
<artifactId>testng</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.mockito</groupId> | |||
<artifactId>mockito-all</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.google.inject</groupId> | |||
<artifactId>guice</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.eclipse.jetty</groupId> | |||
<artifactId>jetty-server</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.eclipse.jetty</groupId> | |||
<artifactId>jetty-servlet</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>joda-time</groupId> | |||
<artifactId>joda-time</artifactId> | |||
<version>2.9.4</version> | |||
<scope>test</scope> | |||
</dependency> | |||
</dependencies> | |||
<dependencies> | |||
<dependency> | |||
<groupId>com.github.binarywang</groupId> | |||
<artifactId>weixin-java-common</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>junit</groupId> | |||
<artifactId>junit</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.testng</groupId> | |||
<artifactId>testng</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.mockito</groupId> | |||
<artifactId>mockito-all</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.google.inject</groupId> | |||
<artifactId>guice</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.eclipse.jetty</groupId> | |||
<artifactId>jetty-server</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.eclipse.jetty</groupId> | |||
<artifactId>jetty-servlet</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>joda-time</groupId> | |||
<artifactId>joda-time</artifactId> | |||
<version>2.9.4</version> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>io.rest-assured</groupId> | |||
<artifactId>xml-path</artifactId> | |||
<version>3.0.1</version> | |||
</dependency> | |||
<build> | |||
<plugins> | |||
<plugin> | |||
<groupId>org.apache.maven.plugins</groupId> | |||
<artifactId>maven-surefire-plugin</artifactId> | |||
<configuration> | |||
<suiteXmlFiles> | |||
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile> | |||
</suiteXmlFiles> | |||
</configuration> | |||
</plugin> | |||
</plugins> | |||
</build> | |||
</dependencies> | |||
<build> | |||
<plugins> | |||
<plugin> | |||
<groupId>org.apache.maven.plugins</groupId> | |||
<artifactId>maven-surefire-plugin</artifactId> | |||
<configuration> | |||
<suiteXmlFiles> | |||
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile> | |||
</suiteXmlFiles> | |||
</configuration> | |||
</plugin> | |||
</plugins> | |||
</build> | |||
</project> |
@@ -310,20 +310,25 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
} | |||
@Override | |||
public void setSslContextFilePath(String filePath) throws Exception { | |||
public void setSslContextFilePath(String filePath) { | |||
if (null == partnerId) { | |||
throw new Exception("请先将partnerId进行赋值"); | |||
throw new IllegalArgumentException("请设置partnerId的值"); | |||
} | |||
File file = new File(filePath); | |||
if (!file.exists()) { | |||
throw new RuntimeException(file.getPath() + ":文件不存在!在设置SSLContext的时候"); | |||
throw new RuntimeException("证书文件:【" + file.getPath() + "】不存在!"); | |||
} | |||
try { | |||
FileInputStream inputStream = new FileInputStream(file); | |||
KeyStore keystore = KeyStore.getInstance("PKCS12"); | |||
char[] partnerId2charArray = partnerId.toCharArray(); | |||
keystore.load(inputStream, partnerId2charArray); | |||
this.sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build(); | |||
} catch (Exception e) { | |||
throw new RuntimeException("证书文件有问题,请核实!", e); | |||
} | |||
FileInputStream inputStream = new FileInputStream(file); | |||
KeyStore keystore = KeyStore.getInstance("PKCS12"); | |||
char[] partnerId2charArray = partnerId.toCharArray(); | |||
keystore.load(inputStream, partnerId2charArray); | |||
this.sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build(); | |||
} | |||
@Override | |||
@@ -1,14 +1,11 @@ | |||
package me.chanjar.weixin.mp.api.impl; | |||
import com.thoughtworks.xstream.XStream; | |||
import me.chanjar.weixin.common.bean.result.WxError; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.common.util.BeanUtils; | |||
import me.chanjar.weixin.common.util.xml.XStreamInitializer; | |||
import me.chanjar.weixin.mp.api.WxMpConfigStorage; | |||
import me.chanjar.weixin.mp.api.WxMpPayService; | |||
import me.chanjar.weixin.mp.api.WxMpService; | |||
import me.chanjar.weixin.mp.bean.pay.WxPayOrderNotifyResultConverter; | |||
import me.chanjar.weixin.mp.bean.pay.request.*; | |||
import me.chanjar.weixin.mp.bean.pay.result.*; | |||
import org.apache.commons.codec.digest.DigestUtils; | |||
@@ -54,20 +51,16 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
@Override | |||
public WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorException { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPayRefundRequest.class); | |||
xstream.processAnnotations(WxPayRefundResult.class); | |||
initRequest(request); | |||
this.initRequest(request); | |||
if (StringUtils.isBlank(request.getOpUserId())) { | |||
request.setOpUserId(getConfig().getPartnerId()); | |||
request.setOpUserId(this.getConfig().getPartnerId()); | |||
} | |||
checkParameters(request); | |||
this.checkParameters(request); | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/secapi/pay/refund"; | |||
String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request)); | |||
WxPayRefundResult result = (WxPayRefundResult) xstream.fromXML(responseContent); | |||
String responseContent = this.executeWithKey(url, request.toXML()); | |||
WxPayRefundResult result = WxPayRefundResult.fromXML(responseContent, WxPayRefundResult.class); | |||
this.checkResult(result); | |||
return result; | |||
} | |||
@@ -79,12 +72,8 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
throw new IllegalArgumentException("transaction_id , out_trade_no,out_refund_no, refund_id 必须四选一"); | |||
} | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPayRefundQueryRequest.class); | |||
xstream.processAnnotations(WxPayRefundQueryResult.class); | |||
WxPayRefundQueryRequest request = new WxPayRefundQueryRequest(); | |||
initRequest(request); | |||
this.initRequest(request); | |||
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); | |||
request.setTransactionId(StringUtils.trimToNull(transactionId)); | |||
request.setOutRefundNo(StringUtils.trimToNull(outRefundNo)); | |||
@@ -92,8 +81,8 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/pay/refundquery"; | |||
String responseContent = this.executeRequest(url, xstream.toXML(request)); | |||
WxPayRefundQueryResult result = (WxPayRefundQueryResult) xstream.fromXML(responseContent); | |||
String responseContent = this.executeRequest(url, request.toXML()); | |||
WxPayRefundQueryResult result = WxPayRefundQueryResult.fromXML(responseContent, WxPayRefundQueryResult.class); | |||
result.composeRefundRecords(responseContent); | |||
this.checkResult(result); | |||
return result; | |||
@@ -102,8 +91,9 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
private void checkResult(WxPayBaseResult result) throws WxErrorException { | |||
//校验返回结果签名 | |||
if (!checkSign(result.toMap())) { | |||
log.debug("校验结果签名失败,参数:{}", result.toMap()); | |||
Map<String, String> map = result.toMap(); | |||
if (!this.checkSign(map)) { | |||
log.debug("校验结果签名失败,参数:{}", map); | |||
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("参数格式校验错误!").build()); | |||
} | |||
@@ -115,7 +105,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
+ result.getReturnMsg() + ", 结果代码: " + result.getResultCode() + ", 错误代码: " | |||
+ result.getErrCode() + ", 错误详情: " + result.getErrCodeDes()) | |||
.build(); | |||
log.error("结果业务代码异常,参数:{},详细:{}", result.toMap(), error); | |||
log.error("结果业务代码异常,参数:{},详细:{}", map, error); | |||
throw new WxErrorException(error); | |||
} | |||
} | |||
@@ -138,10 +128,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxErrorException { | |||
try { | |||
log.trace("微信支付回调参数详细:{}", xmlData); | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPayOrderNotifyResult.class); | |||
xstream.registerConverter(new WxPayOrderNotifyResultConverter(xstream.getMapper(), xstream.getReflectionProvider())); | |||
WxPayOrderNotifyResult result = (WxPayOrderNotifyResult) xstream.fromXML(xmlData); | |||
WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData); | |||
log.debug("微信支付回调结果对象:{}", result); | |||
this.checkResult(result); | |||
return result; | |||
@@ -157,11 +144,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
@Override | |||
public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) | |||
throws WxErrorException { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPaySendRedpackRequest.class); | |||
xstream.processAnnotations(WxPaySendRedpackResult.class); | |||
initRequest(request); | |||
this.initRequest(request); | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/mmpaymkttransfers/sendredpack"; | |||
@@ -169,18 +152,14 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
//裂变红包 | |||
url = PAY_BASE_URL + "/mmpaymkttransfers/sendgroupredpack"; | |||
} | |||
String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request)); | |||
WxPaySendRedpackResult result = (WxPaySendRedpackResult) xstream.fromXML(responseContent); | |||
String responseContent = this.executeWithKey(url, request.toXML()); | |||
WxPaySendRedpackResult result = WxPaySendRedpackResult.fromXML(responseContent, WxPaySendRedpackResult.class); | |||
this.checkResult(result); | |||
return result; | |||
} | |||
@Override | |||
public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPayRedpackQueryRequest.class); | |||
xstream.processAnnotations(WxPayRedpackQueryResult.class); | |||
WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest(); | |||
request.setMchBillNo(mchBillNo); | |||
request.setBillType("MCHT"); | |||
@@ -188,8 +167,8 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/mmpaymkttransfers/gethbinfo"; | |||
String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request)); | |||
WxPayRedpackQueryResult result = (WxPayRedpackQueryResult) xstream.fromXML(responseContent); | |||
String responseContent = this.executeWithKey(url, request.toXML()); | |||
WxPayRedpackQueryResult result = WxPayRedpackQueryResult.fromXML(responseContent, WxPayRedpackQueryResult.class); | |||
this.checkResult(result); | |||
return result; | |||
} | |||
@@ -201,10 +180,6 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
throw new IllegalArgumentException("transaction_id 和 out_trade_no 不能同时存在或同时为空,必须二选一"); | |||
} | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPayOrderQueryRequest.class); | |||
xstream.processAnnotations(WxPayOrderQueryResult.class); | |||
WxPayOrderQueryRequest request = new WxPayOrderQueryRequest(); | |||
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); | |||
request.setTransactionId(StringUtils.trimToNull(transactionId)); | |||
@@ -212,8 +187,8 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/pay/orderquery"; | |||
String responseContent = this.executeRequest(url, xstream.toXML(request)); | |||
WxPayOrderQueryResult result = (WxPayOrderQueryResult) xstream.fromXML(responseContent); | |||
String responseContent = this.executeRequest(url, request.toXML()); | |||
WxPayOrderQueryResult result = WxPayOrderQueryResult.fromXML(responseContent, WxPayOrderQueryResult.class); | |||
result.composeCoupons(responseContent); | |||
this.checkResult(result); | |||
return result; | |||
@@ -225,18 +200,14 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
throw new IllegalArgumentException("out_trade_no 不能为空"); | |||
} | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPayOrderCloseRequest.class); | |||
xstream.processAnnotations(WxPayOrderCloseResult.class); | |||
WxPayOrderCloseRequest request = new WxPayOrderCloseRequest(); | |||
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); | |||
initRequest(request); | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/pay/closeorder"; | |||
String responseContent = this.executeRequest(url, xstream.toXML(request)); | |||
WxPayOrderCloseResult result = (WxPayOrderCloseResult) xstream.fromXML(responseContent); | |||
String responseContent = this.executeRequest(url, request.toXML()); | |||
WxPayOrderCloseResult result = WxPayOrderCloseResult.fromXML(responseContent, WxPayOrderCloseResult.class); | |||
this.checkResult(result); | |||
return result; | |||
@@ -246,11 +217,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) | |||
throws WxErrorException { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPayUnifiedOrderRequest.class); | |||
xstream.processAnnotations(WxPayUnifiedOrderResult.class); | |||
initRequest(request); | |||
this.initRequest(request); | |||
if (StringUtils.isBlank(request.getNotifyURL())) { | |||
request.setNotifyURL(getConfig().getNotifyURL()); | |||
} | |||
@@ -261,12 +228,12 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/pay/unifiedorder"; | |||
String xmlParam = xstream.toXML(request); | |||
String xmlParam = request.toXML(); | |||
log.debug("微信统一下单接口,URL:{},参数:{}", url, xmlParam); | |||
String responseContent = this.executeRequest(url, xmlParam); | |||
log.debug("微信统一下单接口,URL:{},结果:{}", url, responseContent); | |||
WxPayUnifiedOrderResult result = (WxPayUnifiedOrderResult) xstream.fromXML(responseContent); | |||
WxPayUnifiedOrderResult result = WxPayUnifiedOrderResult.fromXML(responseContent, WxPayUnifiedOrderResult.class); | |||
this.checkResult(result); | |||
return result; | |||
} | |||
@@ -324,35 +291,27 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
@Override | |||
public WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxEntPayRequest.class); | |||
xstream.processAnnotations(WxEntPayResult.class); | |||
initRequest(request); | |||
this.initRequest(request); | |||
BeanUtils.checkRequiredFields(request); | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/mmpaymkttransfers/promotion/transfers"; | |||
String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request)); | |||
WxEntPayResult result = (WxEntPayResult) xstream.fromXML(responseContent); | |||
String responseContent = this.executeWithKey(url, request.toXML()); | |||
WxEntPayResult result = WxEntPayResult.fromXML(responseContent, WxEntPayResult.class); | |||
this.checkResult(result); | |||
return result; | |||
} | |||
@Override | |||
public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxEntPayQueryRequest.class); | |||
xstream.processAnnotations(WxEntPayQueryResult.class); | |||
WxEntPayQueryRequest request = new WxEntPayQueryRequest(); | |||
initRequest(request); | |||
this.initRequest(request); | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/mmpaymkttransfers/gettransferinfo"; | |||
String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request)); | |||
WxEntPayQueryResult result = (WxEntPayQueryResult) xstream.fromXML(responseContent); | |||
String responseContent = this.executeWithKey(url, request.toXML()); | |||
WxEntPayQueryResult result = WxEntPayQueryResult.fromXML(responseContent, WxEntPayQueryResult.class); | |||
this.checkResult(result); | |||
return result; | |||
} | |||
@@ -379,11 +338,11 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
} | |||
} | |||
private String executeRequestWithKeyFile(String url, String requestStr) throws WxErrorException { | |||
private String executeWithKey(String url, String requestStr) throws WxErrorException { | |||
try { | |||
SSLContext sslContext = getConfig().getSslContext(); | |||
if (null == sslContext) { | |||
throw new Exception("请将配置类(即WxMpConfigStorage的实现类)中的SSLContext初始化"); | |||
throw new IllegalArgumentException("请先初始化配置类(即WxMpConfigStorage的实现类)中的SSLContext!"); | |||
} | |||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1"}, null, | |||
@@ -412,17 +371,17 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
@Override | |||
public String createSign(Object xmlBean) { | |||
return createSign(BeanUtils.xmlBean2Map(xmlBean), getConfig().getPartnerKey()); | |||
return this.createSign(BeanUtils.xmlBean2Map(xmlBean), getConfig().getPartnerKey()); | |||
} | |||
@Override | |||
public String createSign(Object xmlBean, String signKey) { | |||
return createSign(BeanUtils.xmlBean2Map(xmlBean), signKey); | |||
return this.createSign(BeanUtils.xmlBean2Map(xmlBean), signKey); | |||
} | |||
@Override | |||
public String createSign(Map<String, String> params) { | |||
return createSign(params, getConfig().getPartnerKey()); | |||
return this.createSign(params, this.getConfig().getPartnerKey()); | |||
} | |||
@Override | |||
@@ -443,17 +402,17 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
@Override | |||
public boolean checkSign(Object xmlBean) { | |||
return checkSign(BeanUtils.xmlBean2Map(xmlBean), getConfig().getPartnerKey()); | |||
return this.checkSign(BeanUtils.xmlBean2Map(xmlBean), getConfig().getPartnerKey()); | |||
} | |||
@Override | |||
public boolean checkSign(Object xmlBean, String signKey) { | |||
return checkSign(BeanUtils.xmlBean2Map(xmlBean), signKey); | |||
return this.checkSign(BeanUtils.xmlBean2Map(xmlBean), signKey); | |||
} | |||
@Override | |||
public boolean checkSign(Map<String, String> params) { | |||
return checkSign(params, getConfig().getPartnerKey()); | |||
return this.checkSign(params, getConfig().getPartnerKey()); | |||
} | |||
@Override | |||
@@ -1,7 +1,9 @@ | |||
package me.chanjar.weixin.mp.bean.pay.request; | |||
import com.thoughtworks.xstream.XStream; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import me.chanjar.weixin.common.util.xml.XStreamInitializer; | |||
import java.math.BigDecimal; | |||
@@ -17,6 +19,7 @@ import java.math.BigDecimal; | |||
* <li>示例值 | |||
* <li>描述 | |||
* </pre> | |||
* | |||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||
*/ | |||
public abstract class WxPayBaseRequest { | |||
@@ -69,12 +72,22 @@ public abstract class WxPayBaseRequest { | |||
@XStreamAlias("sign") | |||
protected String sign; | |||
/** | |||
* 将单位为元转换为单位为分 | |||
* | |||
* @param yuan 将要转换的元的数值字符串 | |||
*/ | |||
public static Integer yuanToFee(String yuan) { | |||
return new BigDecimal(yuan).setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue(); | |||
} | |||
public String getAppid() { | |||
return this.appid; | |||
} | |||
/** | |||
* 如果配置中已经设置,可以不设置值 | |||
* | |||
* @param appid 微信公众号appid | |||
*/ | |||
public void setAppid(String appid) { | |||
@@ -87,6 +100,7 @@ public abstract class WxPayBaseRequest { | |||
/** | |||
* 如果配置中已经设置,可以不设置值 | |||
* | |||
* @param mchId 微信商户号 | |||
*/ | |||
public void setMchId(String mchId) { | |||
@@ -99,6 +113,7 @@ public abstract class WxPayBaseRequest { | |||
/** | |||
* 默认采用时间戳为随机字符串,可以不设置 | |||
* | |||
* @param nonceStr 随机字符串 | |||
*/ | |||
public void setNonceStr(String nonceStr) { | |||
@@ -113,17 +128,14 @@ public abstract class WxPayBaseRequest { | |||
this.sign = sign; | |||
} | |||
/** | |||
* 将单位为元转换为单位为分 | |||
* | |||
* @param yuan 将要转换的元的数值字符串 | |||
*/ | |||
public static Integer yuanToFee(String yuan) { | |||
return new BigDecimal(yuan).setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue(); | |||
} | |||
@Override | |||
public String toString() { | |||
return ToStringUtils.toSimpleString(this); | |||
} | |||
public String toXML() { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(this.getClass()); | |||
return xstream.toXML(this); | |||
} | |||
} |
@@ -1,7 +1,6 @@ | |||
package me.chanjar.weixin.mp.bean.pay.request; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import me.chanjar.weixin.common.annotation.Required; | |||
/** | |||
@@ -144,8 +143,6 @@ public class WxPayRefundRequest extends WxPayBaseRequest { | |||
@XStreamAlias("refund_account") | |||
private String refundAccount; | |||
public String getDeviceInfo() { | |||
return this.deviceInfo; | |||
} | |||
@@ -217,4 +214,5 @@ public class WxPayRefundRequest extends WxPayBaseRequest { | |||
public void setRefundAccount(String refundAccount) { | |||
this.refundAccount = refundAccount; | |||
} | |||
} |
@@ -1,10 +1,19 @@ | |||
package me.chanjar.weixin.mp.bean.pay.result; | |||
import com.google.common.collect.Maps; | |||
import com.thoughtworks.xstream.XStream; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import me.chanjar.weixin.common.util.BeanUtils; | |||
import io.restassured.internal.path.xml.NodeChildrenImpl; | |||
import io.restassured.path.xml.XmlPath; | |||
import io.restassured.path.xml.element.Node; | |||
import io.restassured.path.xml.element.NodeChildren; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import me.chanjar.weixin.common.util.xml.XStreamInitializer; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import java.math.BigDecimal; | |||
import java.util.Iterator; | |||
import java.util.Map; | |||
/** | |||
@@ -15,65 +24,90 @@ import java.util.Map; | |||
* </pre> | |||
*/ | |||
public abstract class WxPayBaseResult { | |||
@Override | |||
public String toString() { | |||
return ToStringUtils.toSimpleString(this); | |||
} | |||
/** | |||
* 返回状态码 | |||
*/ | |||
@XStreamAlias("return_code") | |||
protected String returnCode; | |||
/** | |||
* 返回信息 | |||
*/ | |||
@XStreamAlias("return_msg") | |||
protected String returnMsg; | |||
private String xmlString; | |||
/** | |||
* 业务结果 | |||
*/ | |||
@XStreamAlias("result_code") | |||
private String resultCode; | |||
/** | |||
* 错误代码 | |||
*/ | |||
@XStreamAlias("err_code") | |||
private String errCode; | |||
/** | |||
* 错误代码描述 | |||
*/ | |||
@XStreamAlias("err_code_des") | |||
private String errCodeDes; | |||
/** | |||
* 公众账号ID | |||
*/ | |||
@XStreamAlias("appid") | |||
private String appid; | |||
/** | |||
* 商户号 | |||
*/ | |||
@XStreamAlias("mch_id") | |||
private String mchId; | |||
/** | |||
* 随机字符串 | |||
*/ | |||
@XStreamAlias("nonce_str") | |||
private String nonceStr; | |||
/** | |||
* 签名 | |||
*/ | |||
@XStreamAlias("sign") | |||
private String sign; | |||
/** | |||
* 将单位分转换成单位圆 | |||
* | |||
* @param fee 将要被转换为元的分的数值 | |||
*/ | |||
public static String feeToYuan(Integer fee) { | |||
return new BigDecimal(Double.valueOf(fee) / 100).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(); | |||
} | |||
/** | |||
* 从xml字符串创建bean对象 | |||
*/ | |||
public static <T extends WxPayBaseResult> T fromXML(String xmlString, Class<T> clz) { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(clz); | |||
T result = (T) xstream.fromXML(xmlString); | |||
result.setXmlString(xmlString); | |||
return result; | |||
} | |||
public String getXmlString() { | |||
return this.xmlString; | |||
} | |||
public void setXmlString(String xmlString) { | |||
this.xmlString = xmlString; | |||
} | |||
protected Logger getLogger() { | |||
return LoggerFactory.getLogger(this.getClass()); | |||
} | |||
@Override | |||
public String toString() { | |||
return ToStringUtils.toSimpleString(this); | |||
} | |||
public String getReturnCode() { | |||
return this.returnCode; | |||
} | |||
@@ -147,14 +181,43 @@ public abstract class WxPayBaseResult { | |||
} | |||
/** | |||
* 将单位分转换成单位圆 | |||
* @param fee 将要被转换为元的分的数值 | |||
* 将bean通过保存的xml字符串转换成map | |||
*/ | |||
public static String feeToYuan(Integer fee) { | |||
return new BigDecimal(Double.valueOf(fee) / 100).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(); | |||
} | |||
public Map<String,String> toMap(){ | |||
return BeanUtils.xmlBean2Map(this); | |||
public Map<String, String> toMap() { | |||
Map<String, String> result = Maps.newHashMap(); | |||
XmlPath xmlPath = new XmlPath(this.xmlString); | |||
NodeChildren nodeChildren = xmlPath.getNodeChildren("xml"); | |||
Iterator<Node> iterator = nodeChildren.nodeIterator(); | |||
while (iterator.hasNext()) { | |||
Node node = iterator.next(); | |||
result.put(node.name(), node.value()); | |||
} | |||
return result; | |||
} | |||
private String getXmlValueIfExists(XmlPath xmlPath, String path) { | |||
if (xmlPath.get(path) instanceof NodeChildrenImpl) { | |||
if (((NodeChildrenImpl) xmlPath.get(path)).size() == 0) { | |||
return null; | |||
} | |||
} | |||
return xmlPath.getString(path); | |||
} | |||
protected <T> T getXmlValueIfExists(XmlPath xmlPath, String path, Class<T> clz) { | |||
String value = this.getXmlValueIfExists(xmlPath, path); | |||
if (value == null) { | |||
return null; | |||
} | |||
switch (clz.getSimpleName()) { | |||
case "String": | |||
return (T) value; | |||
case "Integer": | |||
return (T) Integer.valueOf(value); | |||
} | |||
throw new UnsupportedOperationException("暂时不支持此种类型的数据"); | |||
} | |||
} |
@@ -1,10 +1,12 @@ | |||
package me.chanjar.weixin.mp.bean.pay.result; | |||
import com.thoughtworks.xstream.XStream; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import me.chanjar.weixin.common.util.BeanUtils; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import me.chanjar.weixin.common.util.xml.XStreamInitializer; | |||
import me.chanjar.weixin.mp.bean.pay.WxPayOrderNotifyCoupon; | |||
import org.apache.commons.lang3.builder.ToStringBuilder; | |||
import org.apache.commons.lang3.builder.ToStringStyle; | |||
import me.chanjar.weixin.mp.bean.pay.WxPayOrderNotifyResultConverter; | |||
import java.io.Serializable; | |||
import java.util.List; | |||
@@ -376,6 +378,15 @@ public class WxPayOrderNotifyResult extends WxPayBaseResult implements Serializ | |||
@Override | |||
public String toString() { | |||
return ToStringBuilder.reflectionToString(this,ToStringStyle.MULTI_LINE_STYLE); | |||
return ToStringUtils.toSimpleString(this); | |||
} | |||
public static WxPayOrderNotifyResult fromXML(String xmlString) { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPayOrderNotifyResult.class); | |||
xstream.registerConverter(new WxPayOrderNotifyResultConverter(xstream.getMapper(), xstream.getReflectionProvider())); | |||
WxPayOrderNotifyResult result = (WxPayOrderNotifyResult) xstream.fromXML(xmlString); | |||
result.setXmlString(xmlString); | |||
return result; | |||
} | |||
} |
@@ -2,6 +2,7 @@ package me.chanjar.weixin.mp.bean.pay.result; | |||
import com.google.common.collect.Lists; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import io.restassured.path.xml.XmlPath; | |||
import java.util.List; | |||
@@ -186,7 +187,38 @@ public class WxPayRefundQueryResult extends WxPayBaseResult { | |||
public void composeRefundRecords(String xmlString) { | |||
if (this.refundCount != null && this.refundCount > 0) { | |||
this.refundRecords = Lists.newArrayList(); | |||
//TODO 暂时待实现 | |||
XmlPath xmlPath = new XmlPath(xmlString); | |||
for (int i = 0; i < this.refundCount; i++) { | |||
RefundRecord refundRecord = new RefundRecord(); | |||
this.refundRecords.add(refundRecord); | |||
refundRecord.setOutRefundNo(this.getXmlValueIfExists(xmlPath, "xml.out_refund_no_" + i, String.class)); | |||
refundRecord.setRefundId(this.getXmlValueIfExists(xmlPath, "xml.refund_id_" + i, String.class)); | |||
refundRecord.setRefundChannel(this.getXmlValueIfExists(xmlPath, "xml.refund_channel_" + i, String.class)); | |||
refundRecord.setRefundFee(this.getXmlValueIfExists(xmlPath, "xml.refund_fee_" + i, Integer.class)); | |||
refundRecord.setSettlementRefundFee(this.getXmlValueIfExists(xmlPath, "xml.settlement_refund_fee_" + i, Integer.class)); | |||
refundRecord.setCouponType(this.getXmlValueIfExists(xmlPath, "xml.coupon_type_" + i, String.class)); | |||
refundRecord.setCouponRefundFee(this.getXmlValueIfExists(xmlPath, "xml.coupon_refund_fee_" + i, Integer.class)); | |||
refundRecord.setCouponRefundCount(this.getXmlValueIfExists(xmlPath, "xml.coupon_refund_count_" + i, Integer.class)); | |||
refundRecord.setRefundStatus(this.getXmlValueIfExists(xmlPath, "xml.refund_status_" + i, String.class)); | |||
refundRecord.setRefundRecvAccout(this.getXmlValueIfExists(xmlPath, "xml.refund_recv_accout_" + i, String.class)); | |||
if (refundRecord.getCouponRefundCount() == null || refundRecord.getCouponRefundCount() == 0) { | |||
continue; | |||
} | |||
List<RefundRecord.RefundCoupon> coupons = Lists.newArrayList(); | |||
for (int j = 0; j < refundRecord.getCouponRefundCount(); j++) { | |||
coupons.add( | |||
new RefundRecord.RefundCoupon( | |||
this.getXmlValueIfExists(xmlPath, "xml.coupon_refund_id_" + i + "_" + j, String.class), | |||
this.getXmlValueIfExists(xmlPath, "xml.coupon_refund_fee_" + i + "_" + j, Integer.class) | |||
) | |||
); | |||
} | |||
} | |||
} | |||
} | |||
@@ -241,7 +273,7 @@ public class WxPayRefundQueryResult extends WxPayBaseResult { | |||
* </pre> | |||
*/ | |||
@XStreamAlias("refund_fee") | |||
private String refundFee; | |||
private Integer refundFee; | |||
/** | |||
* <pre> | |||
@@ -254,7 +286,7 @@ public class WxPayRefundQueryResult extends WxPayBaseResult { | |||
* </pre> | |||
*/ | |||
@XStreamAlias("settlement_refund_fee") | |||
private String settlementRefundFee; | |||
private Integer settlementRefundFee; | |||
/** | |||
* <pre> | |||
@@ -293,7 +325,7 @@ public class WxPayRefundQueryResult extends WxPayBaseResult { | |||
* </pre> | |||
*/ | |||
@XStreamAlias("coupon_refund_fee") | |||
private String couponRefundFee; | |||
private Integer couponRefundFee; | |||
/** | |||
* <pre> | |||
@@ -306,7 +338,7 @@ public class WxPayRefundQueryResult extends WxPayBaseResult { | |||
* </pre> | |||
*/ | |||
@XStreamAlias("coupon_refund_count") | |||
private String couponRefundCount; | |||
private Integer couponRefundCount; | |||
private List<RefundCoupon> refundCoupons; | |||
@@ -364,19 +396,19 @@ public class WxPayRefundQueryResult extends WxPayBaseResult { | |||
this.refundChannel = refundChannel; | |||
} | |||
public String getRefundFee() { | |||
public Integer getRefundFee() { | |||
return refundFee; | |||
} | |||
public void setRefundFee(String refundFee) { | |||
public void setRefundFee(Integer refundFee) { | |||
this.refundFee = refundFee; | |||
} | |||
public String getSettlementRefundFee() { | |||
public Integer getSettlementRefundFee() { | |||
return settlementRefundFee; | |||
} | |||
public void setSettlementRefundFee(String settlementRefundFee) { | |||
public void setSettlementRefundFee(Integer settlementRefundFee) { | |||
this.settlementRefundFee = settlementRefundFee; | |||
} | |||
@@ -396,19 +428,19 @@ public class WxPayRefundQueryResult extends WxPayBaseResult { | |||
this.couponType = couponType; | |||
} | |||
public String getCouponRefundFee() { | |||
public Integer getCouponRefundFee() { | |||
return couponRefundFee; | |||
} | |||
public void setCouponRefundFee(String couponRefundFee) { | |||
public void setCouponRefundFee(Integer couponRefundFee) { | |||
this.couponRefundFee = couponRefundFee; | |||
} | |||
public String getCouponRefundCount() { | |||
public Integer getCouponRefundCount() { | |||
return couponRefundCount; | |||
} | |||
public void setCouponRefundCount(String couponRefundCount) { | |||
public void setCouponRefundCount(Integer couponRefundCount) { | |||
this.couponRefundCount = couponRefundCount; | |||
} | |||
@@ -446,6 +478,8 @@ public class WxPayRefundQueryResult extends WxPayBaseResult { | |||
* 100 | |||
* 退款代金券批次ID ,$n为下标,$m为下标,从0开始编号 | |||
* </pre> | |||
* | |||
* @deprecated 貌似是被去掉了,但不知是何时! | |||
*/ | |||
@XStreamAlias("coupon_refund_batch_id") | |||
private String couponRefundBatchId; | |||
@@ -474,9 +508,15 @@ public class WxPayRefundQueryResult extends WxPayBaseResult { | |||
* </pre> | |||
*/ | |||
@XStreamAlias("coupon_refund_fee") | |||
private String couponRefundFee; | |||
private Integer couponRefundFee; | |||
public RefundCoupon(String couponRefundBatchId, String couponRefundId, String couponRefundFee) { | |||
public RefundCoupon(String couponRefundId, Integer couponRefundFee) { | |||
this.couponRefundId = couponRefundId; | |||
this.couponRefundFee = couponRefundFee; | |||
} | |||
@Deprecated | |||
public RefundCoupon(String couponRefundBatchId, String couponRefundId, Integer couponRefundFee) { | |||
this.couponRefundBatchId = couponRefundBatchId; | |||
this.couponRefundId = couponRefundId; | |||
this.couponRefundFee = couponRefundFee; | |||
@@ -484,5 +524,6 @@ public class WxPayRefundQueryResult extends WxPayBaseResult { | |||
} | |||
} | |||
} | |||
@@ -13,8 +13,6 @@ import me.chanjar.weixin.mp.bean.pay.result.*; | |||
import org.testng.annotations.Guice; | |||
import org.testng.annotations.Test; | |||
import java.io.File; | |||
/** | |||
* 测试支付相关接口 | |||
* Created by Binary Wang on 2016/7/28. | |||
@@ -90,7 +88,6 @@ public class WxMpPayServiceImplTest { | |||
*/ | |||
@Test | |||
public void testQueryRedpack() throws Exception { | |||
File keyFile = new File("E:\\dlt.p12"); | |||
WxPayRedpackQueryResult redpackResult = this.wxService.getPayService().queryRedpack("aaaa"); | |||
System.err.println(redpackResult); | |||
} | |||
@@ -0,0 +1,49 @@ | |||
package me.chanjar.weixin.mp.bean.pay.result; | |||
import org.testng.Assert; | |||
import org.testng.annotations.Test; | |||
/** | |||
* <pre> | |||
* Created by Binary Wang on 2016-12-29. | |||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||
* </pre> | |||
*/ | |||
public class WxPayRefundQueryResultTest { | |||
@Test | |||
public void composeRefundRecords() throws Exception { | |||
/* | |||
该xml字符串来自于官方文档示例 | |||
*/ | |||
String xmlString = "<xml>\n" + | |||
" <appid><![CDATA[wx2421b1c4370ec43b]]></appid>\n" + | |||
" <mch_id><![CDATA[10000100]]></mch_id>\n" + | |||
" <nonce_str><![CDATA[TeqClE3i0mvn3DrK]]></nonce_str>\n" + | |||
" <out_refund_no_0><![CDATA[1415701182]]></out_refund_no_0>\n" + | |||
" <out_trade_no><![CDATA[1415757673]]></out_trade_no>\n" + | |||
" <refund_count>1</refund_count>\n" + | |||
" <refund_fee_0>1</refund_fee_0>\n" + | |||
" <refund_id_0><![CDATA[2008450740201411110000174436]]></refund_id_0>\n" + | |||
" <refund_status_0><![CDATA[PROCESSING]]></refund_status_0>\n" + | |||
" <result_code><![CDATA[SUCCESS]]></result_code>\n" + | |||
" <return_code><![CDATA[SUCCESS]]></return_code>\n" + | |||
" <return_msg><![CDATA[OK]]></return_msg>\n" + | |||
" <sign><![CDATA[1F2841558E233C33ABA71A961D27561C]]></sign>\n" + | |||
" <transaction_id><![CDATA[1008450740201411110005820873]]></transaction_id>\n" + | |||
"</xml>"; | |||
WxPayRefundQueryResult result = new WxPayRefundQueryResult(); | |||
result.setRefundCount(1); | |||
result.composeRefundRecords(xmlString); | |||
Assert.assertNotNull(result.getRefundRecords()); | |||
Assert.assertEquals(result.getRefundRecords().size(), 1); | |||
Assert.assertEquals(result.getRefundRecords().get(0).getRefundId(), "2008450740201411110000174436"); | |||
Assert.assertEquals(result.getRefundRecords().get(0).getRefundFee().intValue(), 1); | |||
Assert.assertEquals(result.getRefundRecords().get(0).getOutRefundNo(), "1415701182"); | |||
Assert.assertEquals(result.getRefundRecords().get(0).getRefundStatus(), "PROCESSING"); | |||
} | |||
} |