增加新的统一下单接口,并添加对接口格式的单元测试,并未对实际功能进行测试

This commit is contained in:
BinaryWang
2016-09-26 12:34:37 +08:00
parent c4838295e5
commit 839ecadaa7
10 changed files with 1090 additions and 367 deletions

View File

@@ -35,6 +35,12 @@ public class SimplePostRequestExecutor implements RequestExecutor<String, String
try (CloseableHttpResponse response = httpclient.execute(httpPost)) { try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
if (responseContent.isEmpty()) {
throw new WxErrorException(
WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容")
.build());
}
if (responseContent.startsWith("<xml>")) { if (responseContent.startsWith("<xml>")) {
//xml格式输出直接返回 //xml格式输出直接返回
return responseContent; return responseContent;

View File

@@ -6,10 +6,11 @@ import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.pay.WxMpPayCallback; import me.chanjar.weixin.mp.bean.pay.WxMpPayCallback;
import me.chanjar.weixin.mp.bean.pay.WxMpPayRefundResult; import me.chanjar.weixin.mp.bean.pay.WxMpPayRefundResult;
import me.chanjar.weixin.mp.bean.pay.WxMpPayResult; import me.chanjar.weixin.mp.bean.pay.WxMpPayResult;
import me.chanjar.weixin.mp.bean.pay.WxMpPrepayIdResult;
import me.chanjar.weixin.mp.bean.pay.WxRedpackResult; import me.chanjar.weixin.mp.bean.pay.WxRedpackResult;
import me.chanjar.weixin.mp.bean.pay.WxSendRedpackRequest; import me.chanjar.weixin.mp.bean.pay.WxSendRedpackRequest;
import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderRequest; import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderRequest;
import me.chanjar.weixin.mp.bean.result.WxMpPrepayIdResult; import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderResult;
/** /**
* 微信支付相关接口 * 微信支付相关接口
@@ -48,9 +49,11 @@ public interface WxMpPayService {
* 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
* 接口地址https://api.mch.weixin.qq.com/pay/unifiedorder * 接口地址https://api.mch.weixin.qq.com/pay/unifiedorder
* @throws WxErrorException
* *
*/ */
WxMpPrepayIdResult unifiedOrder(WxUnifiedOrderRequest request); WxUnifiedOrderResult unifiedOrder(WxUnifiedOrderRequest request)
throws WxErrorException;
/** /**
* 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数 * 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数

View File

@@ -3,6 +3,7 @@ package me.chanjar.weixin.mp.api.impl;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.SortedMap; import java.util.SortedMap;
@@ -20,10 +21,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.slf4j.helpers.MessageFormatter; import org.slf4j.helpers.MessageFormatter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import me.chanjar.weixin.common.annotation.Required;
import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; import me.chanjar.weixin.common.util.http.Utf8ResponseHandler;
@@ -32,9 +35,11 @@ import me.chanjar.weixin.mp.api.WxMpPayService;
import me.chanjar.weixin.mp.bean.pay.WxMpPayCallback; import me.chanjar.weixin.mp.bean.pay.WxMpPayCallback;
import me.chanjar.weixin.mp.bean.pay.WxMpPayRefundResult; import me.chanjar.weixin.mp.bean.pay.WxMpPayRefundResult;
import me.chanjar.weixin.mp.bean.pay.WxMpPayResult; import me.chanjar.weixin.mp.bean.pay.WxMpPayResult;
import me.chanjar.weixin.mp.bean.pay.WxMpPrepayIdResult;
import me.chanjar.weixin.mp.bean.pay.WxRedpackResult; import me.chanjar.weixin.mp.bean.pay.WxRedpackResult;
import me.chanjar.weixin.mp.bean.pay.WxSendRedpackRequest; import me.chanjar.weixin.mp.bean.pay.WxSendRedpackRequest;
import me.chanjar.weixin.mp.bean.result.WxMpPrepayIdResult; import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderRequest;
import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderResult;
/** /**
* Created by Binary Wang on 2016/7/28. * Created by Binary Wang on 2016/7/28.
@@ -43,10 +48,12 @@ import me.chanjar.weixin.mp.bean.result.WxMpPrepayIdResult;
*/ */
public class WxMpPayServiceImpl implements WxMpPayService { public class WxMpPayServiceImpl implements WxMpPayService {
private static final List<String> TRADE_TYPES = Lists.newArrayList("JSAPI",
"NATIVE", "APP");
private final Logger log = LoggerFactory.getLogger(WxMpPayServiceImpl.class); private final Logger log = LoggerFactory.getLogger(WxMpPayServiceImpl.class);
private final String[] REQUIRED_ORDER_PARAMETERS = new String[]{"appid", private final String[] REQUIRED_ORDER_PARAMETERS = new String[] { "appid",
"mch_id", "body", "out_trade_no", "total_fee", "spbill_create_ip", "mch_id", "body", "out_trade_no", "total_fee", "spbill_create_ip",
"notify_url", "trade_type"}; "notify_url", "trade_type" };
private HttpHost httpProxy; private HttpHost httpProxy;
private WxMpServiceImpl wxMpService; private WxMpServiceImpl wxMpService;
@@ -58,13 +65,13 @@ public class WxMpPayServiceImpl implements WxMpPayService {
@Override @Override
@Deprecated @Deprecated
public WxMpPrepayIdResult getPrepayId(String openId, String outTradeNo, public WxMpPrepayIdResult getPrepayId(String openId, String outTradeNo,
double amt, String body, String tradeType, String ip, double amt, String body, String tradeType, String ip,
String callbackUrl) { String callbackUrl) {
Map<String, String> packageParams = new HashMap<>(); Map<String, String> packageParams = new HashMap<>();
packageParams.put("appid", packageParams.put("appid",
this.wxMpService.getWxMpConfigStorage().getAppId()); this.wxMpService.getWxMpConfigStorage().getAppId());
packageParams.put("mch_id", packageParams.put("mch_id",
this.wxMpService.getWxMpConfigStorage().getPartnerId()); this.wxMpService.getWxMpConfigStorage().getPartnerId());
packageParams.put("body", body); packageParams.put("body", body);
packageParams.put("out_trade_no", outTradeNo); packageParams.put("out_trade_no", outTradeNo);
packageParams.put("total_fee", (int) (amt * 100) + ""); packageParams.put("total_fee", (int) (amt * 100) + "");
@@ -77,47 +84,48 @@ public class WxMpPayServiceImpl implements WxMpPayService {
} }
@Override @Override
@Deprecated
public WxMpPrepayIdResult getPrepayId(final Map<String, String> parameters) { public WxMpPrepayIdResult getPrepayId(final Map<String, String> parameters) {
final SortedMap<String, String> packageParams = new TreeMap<>(parameters); final SortedMap<String, String> packageParams = new TreeMap<>(parameters);
packageParams.put("appid", packageParams.put("appid",
this.wxMpService.getWxMpConfigStorage().getAppId()); this.wxMpService.getWxMpConfigStorage().getAppId());
packageParams.put("mch_id", packageParams.put("mch_id",
this.wxMpService.getWxMpConfigStorage().getPartnerId()); this.wxMpService.getWxMpConfigStorage().getPartnerId());
packageParams.put("nonce_str", System.currentTimeMillis() + ""); packageParams.put("nonce_str", System.currentTimeMillis() + "");
checkParameters(packageParams); checkParameters(packageParams);
String sign = this.createSign(packageParams, String sign = this.createSign(packageParams,
this.wxMpService.getWxMpConfigStorage().getPartnerKey()); this.wxMpService.getWxMpConfigStorage().getPartnerKey());
packageParams.put("sign", sign); packageParams.put("sign", sign);
StringBuilder request = new StringBuilder("<xml>"); StringBuilder request = new StringBuilder("<xml>");
for (Map.Entry<String, String> para : packageParams.entrySet()) { for (Map.Entry<String, String> para : packageParams.entrySet()) {
request.append(String.format("<%s>%s</%s>", para.getKey(), request.append(String.format("<%s>%s</%s>", para.getKey(),
para.getValue(), para.getKey())); para.getValue(), para.getKey()));
} }
request.append("</xml>"); request.append("</xml>");
HttpPost httpPost = new HttpPost( HttpPost httpPost = new HttpPost(
"https://api.mch.weixin.qq.com/pay/unifiedorder"); "https://api.mch.weixin.qq.com/pay/unifiedorder");
if (this.httpProxy != null) { if (this.httpProxy != null) {
RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy) RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy)
.build(); .build();
httpPost.setConfig(config); httpPost.setConfig(config);
} }
StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8);
httpPost.setEntity(entity); httpPost.setEntity(entity);
try (CloseableHttpResponse response = this.wxMpService.getHttpclient() try (CloseableHttpResponse response = this.wxMpService.getHttpclient()
.execute(httpPost)) { .execute(httpPost)) {
String responseContent = Utf8ResponseHandler.INSTANCE String responseContent = Utf8ResponseHandler.INSTANCE
.handleResponse(response); .handleResponse(response);
XStream xstream = XStreamInitializer.getInstance(); XStream xstream = XStreamInitializer.getInstance();
xstream.alias("xml", WxMpPrepayIdResult.class); xstream.alias("xml", WxMpPrepayIdResult.class);
return (WxMpPrepayIdResult) xstream.fromXML(responseContent); return (WxMpPrepayIdResult) xstream.fromXML(responseContent);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Failed to get prepay id due to IO exception.", throw new RuntimeException("Failed to get prepay id due to IO exception.",
e); e);
} finally { } finally {
httpPost.releaseConnection(); httpPost.releaseConnection();
} }
@@ -127,33 +135,33 @@ public class WxMpPayServiceImpl implements WxMpPayService {
for (String para : this.REQUIRED_ORDER_PARAMETERS) { for (String para : this.REQUIRED_ORDER_PARAMETERS) {
if (!parameters.containsKey(para)) { if (!parameters.containsKey(para)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Reqiured argument '" + para + "' is missing."); "Reqiured argument '" + para + "' is missing.");
} }
} }
if ("JSAPI".equals(parameters.get("trade_type")) if ("JSAPI".equals(parameters.get("trade_type"))
&& !parameters.containsKey("openid")) { && !parameters.containsKey("openid")) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Reqiured argument 'openid' is missing when trade_type is 'JSAPI'."); "Reqiured argument 'openid' is missing when trade_type is 'JSAPI'.");
} }
if ("NATIVE".equals(parameters.get("trade_type")) if ("NATIVE".equals(parameters.get("trade_type"))
&& !parameters.containsKey("product_id")) { && !parameters.containsKey("product_id")) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Reqiured argument 'product_id' is missing when trade_type is 'NATIVE'."); "Reqiured argument 'product_id' is missing when trade_type is 'NATIVE'.");
} }
} }
@Override @Override
@Deprecated @Deprecated
public Map<String, String> getJsapiPayInfo(String openId, String outTradeNo, public Map<String, String> getJsapiPayInfo(String openId, String outTradeNo,
double amt, String body, String ip, String callbackUrl) double amt, String body, String ip, String callbackUrl)
throws WxErrorException { throws WxErrorException {
Map<String, String> packageParams = new HashMap<>(); Map<String, String> packageParams = new HashMap<>();
packageParams.put("appid", packageParams.put("appid",
this.wxMpService.getWxMpConfigStorage().getAppId()); this.wxMpService.getWxMpConfigStorage().getAppId());
packageParams.put("mch_id", packageParams.put("mch_id",
this.wxMpService.getWxMpConfigStorage().getPartnerId()); this.wxMpService.getWxMpConfigStorage().getPartnerId());
packageParams.put("body", body); packageParams.put("body", body);
packageParams.put("out_trade_no", outTradeNo); packageParams.put("out_trade_no", outTradeNo);
packageParams.put("total_fee", (int) (amt * 100) + ""); packageParams.put("total_fee", (int) (amt * 100) + "");
@@ -168,13 +176,13 @@ public class WxMpPayServiceImpl implements WxMpPayService {
@Override @Override
@Deprecated @Deprecated
public Map<String, String> getNativePayInfo(String productId, public Map<String, String> getNativePayInfo(String productId,
String outTradeNo, double amt, String body, String ip, String callbackUrl) String outTradeNo, double amt, String body, String ip, String callbackUrl)
throws WxErrorException { throws WxErrorException {
Map<String, String> packageParams = new HashMap<>(); Map<String, String> packageParams = new HashMap<>();
packageParams.put("appid", packageParams.put("appid",
this.wxMpService.getWxMpConfigStorage().getAppId()); this.wxMpService.getWxMpConfigStorage().getAppId());
packageParams.put("mch_id", packageParams.put("mch_id",
this.wxMpService.getWxMpConfigStorage().getPartnerId()); this.wxMpService.getWxMpConfigStorage().getPartnerId());
packageParams.put("body", body); packageParams.put("body", body);
packageParams.put("out_trade_no", outTradeNo); packageParams.put("out_trade_no", outTradeNo);
packageParams.put("total_fee", (int) (amt * 100) + ""); packageParams.put("total_fee", (int) (amt * 100) + "");
@@ -188,27 +196,27 @@ public class WxMpPayServiceImpl implements WxMpPayService {
@Override @Override
public Map<String, String> getPayInfo(Map<String, String> parameters) public Map<String, String> getPayInfo(Map<String, String> parameters)
throws WxErrorException { throws WxErrorException {
WxMpPrepayIdResult wxMpPrepayIdResult = getPrepayId(parameters); WxMpPrepayIdResult wxMpPrepayIdResult = getPrepayId(parameters);
if (!"SUCCESS".equalsIgnoreCase(wxMpPrepayIdResult.getReturn_code()) if (!"SUCCESS".equalsIgnoreCase(wxMpPrepayIdResult.getReturn_code())
|| !"SUCCESS".equalsIgnoreCase(wxMpPrepayIdResult.getResult_code())) { || !"SUCCESS".equalsIgnoreCase(wxMpPrepayIdResult.getResult_code())) {
WxError error = new WxError(); WxError error = new WxError();
error.setErrorCode(-1); error.setErrorCode(-1);
error.setErrorMsg("return_code:" + wxMpPrepayIdResult.getReturn_code() error.setErrorMsg("return_code:" + wxMpPrepayIdResult.getReturn_code()
+ ";return_msg:" + wxMpPrepayIdResult.getReturn_msg() + ";return_msg:" + wxMpPrepayIdResult.getReturn_msg()
+ ";result_code:" + wxMpPrepayIdResult.getResult_code() + ";err_code" + ";result_code:" + wxMpPrepayIdResult.getResult_code() + ";err_code"
+ wxMpPrepayIdResult.getErr_code() + ";err_code_des" + wxMpPrepayIdResult.getErr_code() + ";err_code_des"
+ wxMpPrepayIdResult.getErr_code_des()); + wxMpPrepayIdResult.getErr_code_des());
throw new WxErrorException(error); throw new WxErrorException(error);
} }
String prepayId = wxMpPrepayIdResult.getPrepay_id(); String prepayId = wxMpPrepayIdResult.getPrepay_id();
if (prepayId == null || prepayId.equals("")) { if (prepayId == null || prepayId.equals("")) {
throw new RuntimeException( throw new RuntimeException(
String.format("Failed to get prepay id due to error code '%s'(%s).", String.format("Failed to get prepay id due to error code '%s'(%s).",
wxMpPrepayIdResult.getErr_code(), wxMpPrepayIdResult.getErr_code(),
wxMpPrepayIdResult.getErr_code_des())); wxMpPrepayIdResult.getErr_code_des()));
} }
Map<String, String> payInfo = new HashMap<>(); Map<String, String> payInfo = new HashMap<>();
@@ -223,21 +231,21 @@ public class WxMpPayServiceImpl implements WxMpPayService {
} }
String finalSign = this.createSign(payInfo, String finalSign = this.createSign(payInfo,
this.wxMpService.getWxMpConfigStorage().getPartnerKey()); this.wxMpService.getWxMpConfigStorage().getPartnerKey());
payInfo.put("paySign", finalSign); payInfo.put("paySign", finalSign);
return payInfo; return payInfo;
} }
@Override @Override
public WxMpPayResult getJSSDKPayResult(String transactionId, public WxMpPayResult getJSSDKPayResult(String transactionId,
String outTradeNo) { String outTradeNo) {
String nonce_str = System.currentTimeMillis() + ""; String nonce_str = System.currentTimeMillis() + "";
SortedMap<String, String> packageParams = new TreeMap<>(); SortedMap<String, String> packageParams = new TreeMap<>();
packageParams.put("appid", packageParams.put("appid",
this.wxMpService.getWxMpConfigStorage().getAppId()); this.wxMpService.getWxMpConfigStorage().getAppId());
packageParams.put("mch_id", packageParams.put("mch_id",
this.wxMpService.getWxMpConfigStorage().getPartnerId()); this.wxMpService.getWxMpConfigStorage().getPartnerId());
if (transactionId != null && !"".equals(transactionId.trim())) { if (transactionId != null && !"".equals(transactionId.trim())) {
packageParams.put("transaction_id", transactionId); packageParams.put("transaction_id", transactionId);
@@ -245,40 +253,40 @@ public class WxMpPayServiceImpl implements WxMpPayService {
packageParams.put("out_trade_no", outTradeNo); packageParams.put("out_trade_no", outTradeNo);
} else { } else {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Either 'transactionId' or 'outTradeNo' must be given."); "Either 'transactionId' or 'outTradeNo' must be given.");
} }
packageParams.put("nonce_str", nonce_str); packageParams.put("nonce_str", nonce_str);
packageParams.put("sign", this.createSign(packageParams, packageParams.put("sign", this.createSign(packageParams,
this.wxMpService.getWxMpConfigStorage().getPartnerKey())); this.wxMpService.getWxMpConfigStorage().getPartnerKey()));
StringBuilder request = new StringBuilder("<xml>"); StringBuilder request = new StringBuilder("<xml>");
for (Map.Entry<String, String> para : packageParams.entrySet()) { for (Map.Entry<String, String> para : packageParams.entrySet()) {
request.append(String.format("<%s>%s</%s>", para.getKey(), request.append(String.format("<%s>%s</%s>", para.getKey(),
para.getValue(), para.getKey())); para.getValue(), para.getKey()));
} }
request.append("</xml>"); request.append("</xml>");
HttpPost httpPost = new HttpPost( HttpPost httpPost = new HttpPost(
"https://api.mch.weixin.qq.com/pay/orderquery"); "https://api.mch.weixin.qq.com/pay/orderquery");
if (this.httpProxy != null) { if (this.httpProxy != null) {
RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy) RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy)
.build(); .build();
httpPost.setConfig(config); httpPost.setConfig(config);
} }
StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8);
httpPost.setEntity(entity); httpPost.setEntity(entity);
try (CloseableHttpResponse response = this.wxMpService.getHttpclient() try (CloseableHttpResponse response = this.wxMpService.getHttpclient()
.execute(httpPost)) { .execute(httpPost)) {
String responseContent = Utf8ResponseHandler.INSTANCE String responseContent = Utf8ResponseHandler.INSTANCE
.handleResponse(response); .handleResponse(response);
XStream xstream = XStreamInitializer.getInstance(); XStream xstream = XStreamInitializer.getInstance();
xstream.alias("xml", WxMpPayResult.class); xstream.alias("xml", WxMpPayResult.class);
return (WxMpPayResult) xstream.fromXML(responseContent); return (WxMpPayResult) xstream.fromXML(responseContent);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Failed to query order due to IO exception.", throw new RuntimeException("Failed to query order due to IO exception.",
e); e);
} }
} }
@@ -297,66 +305,66 @@ public class WxMpPayServiceImpl implements WxMpPayService {
@Override @Override
public WxMpPayRefundResult refundPay(Map<String, String> parameters) public WxMpPayRefundResult refundPay(Map<String, String> parameters)
throws WxErrorException { throws WxErrorException {
SortedMap<String, String> refundParams = new TreeMap<>(parameters); SortedMap<String, String> refundParams = new TreeMap<>(parameters);
refundParams.put("appid", refundParams.put("appid",
this.wxMpService.getWxMpConfigStorage().getAppId()); this.wxMpService.getWxMpConfigStorage().getAppId());
refundParams.put("mch_id", refundParams.put("mch_id",
this.wxMpService.getWxMpConfigStorage().getPartnerId()); this.wxMpService.getWxMpConfigStorage().getPartnerId());
refundParams.put("nonce_str", System.currentTimeMillis() + ""); refundParams.put("nonce_str", System.currentTimeMillis() + "");
refundParams.put("op_user_id", refundParams.put("op_user_id",
this.wxMpService.getWxMpConfigStorage().getPartnerId()); this.wxMpService.getWxMpConfigStorage().getPartnerId());
String sign = this.createSign(refundParams, String sign = this.createSign(refundParams,
this.wxMpService.getWxMpConfigStorage().getPartnerKey()); this.wxMpService.getWxMpConfigStorage().getPartnerKey());
refundParams.put("sign", sign); refundParams.put("sign", sign);
StringBuilder request = new StringBuilder("<xml>"); StringBuilder request = new StringBuilder("<xml>");
for (Map.Entry<String, String> para : refundParams.entrySet()) { for (Map.Entry<String, String> para : refundParams.entrySet()) {
request.append(String.format("<%s>%s</%s>", para.getKey(), request.append(String.format("<%s>%s</%s>", para.getKey(),
para.getValue(), para.getKey())); para.getValue(), para.getKey()));
} }
request.append("</xml>"); request.append("</xml>");
HttpPost httpPost = new HttpPost( HttpPost httpPost = new HttpPost(
"https://api.mch.weixin.qq.com/secapi/pay/refund"); "https://api.mch.weixin.qq.com/secapi/pay/refund");
if (this.httpProxy != null) { if (this.httpProxy != null) {
RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy) RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy)
.build(); .build();
httpPost.setConfig(config); httpPost.setConfig(config);
} }
StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8);
httpPost.setEntity(entity); httpPost.setEntity(entity);
try (CloseableHttpResponse response = this.wxMpService.getHttpclient() try (CloseableHttpResponse response = this.wxMpService.getHttpclient()
.execute(httpPost)) { .execute(httpPost)) {
String responseContent = Utf8ResponseHandler.INSTANCE String responseContent = Utf8ResponseHandler.INSTANCE
.handleResponse(response); .handleResponse(response);
XStream xstream = XStreamInitializer.getInstance(); XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxMpPayRefundResult.class); xstream.processAnnotations(WxMpPayRefundResult.class);
WxMpPayRefundResult wxMpPayRefundResult = (WxMpPayRefundResult) xstream WxMpPayRefundResult wxMpPayRefundResult = (WxMpPayRefundResult) xstream
.fromXML(responseContent); .fromXML(responseContent);
if (!"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getResultCode()) if (!"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getResultCode())
|| !"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getReturnCode())) { || !"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getReturnCode())) {
WxError error = new WxError(); WxError error = new WxError();
error.setErrorCode(-1); error.setErrorCode(-1);
error.setErrorMsg("return_code:" + wxMpPayRefundResult.getReturnCode() error.setErrorMsg("return_code:" + wxMpPayRefundResult.getReturnCode()
+ ";return_msg:" + wxMpPayRefundResult.getReturnMsg() + ";return_msg:" + wxMpPayRefundResult.getReturnMsg()
+ ";result_code:" + wxMpPayRefundResult.getResultCode() + ";result_code:" + wxMpPayRefundResult.getResultCode()
+ ";err_code" + wxMpPayRefundResult.getErrCode() + ";err_code_des" + ";err_code" + wxMpPayRefundResult.getErrCode() + ";err_code_des"
+ wxMpPayRefundResult.getErrCodeDes()); + wxMpPayRefundResult.getErrCodeDes());
throw new WxErrorException(error); throw new WxErrorException(error);
} }
return wxMpPayRefundResult; return wxMpPayRefundResult;
} catch (IOException e) { } catch (IOException e) {
String message = MessageFormatter String message = MessageFormatter
.format("Exception happened when sending refund '{}'.", .format("Exception happened when sending refund '{}'.",
request.toString()) request.toString())
.getMessage(); .getMessage();
this.log.error(message, e); this.log.error(message, e);
throw new WxErrorException( throw new WxErrorException(
WxError.newBuilder().setErrorMsg(message).build()); WxError.newBuilder().setErrorMsg(message).build());
} finally { } finally {
httpPost.releaseConnection(); httpPost.releaseConnection();
} }
@@ -364,65 +372,67 @@ public class WxMpPayServiceImpl implements WxMpPayService {
@Override @Override
public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm,
String signature) { String signature) {
return signature.equals(this.createSign(kvm, return signature.equals(this.createSign(kvm,
this.wxMpService.getWxMpConfigStorage().getPartnerKey())); this.wxMpService.getWxMpConfigStorage().getPartnerKey()));
} }
@Override @Override
@Deprecated @Deprecated
public WxRedpackResult sendRedpack(Map<String, String> parameters) public WxRedpackResult sendRedpack(Map<String, String> parameters)
throws WxErrorException { throws WxErrorException {
SortedMap<String, String> packageParams = new TreeMap<>(parameters); SortedMap<String, String> packageParams = new TreeMap<>(parameters);
packageParams.put("wxappid", packageParams.put("wxappid",
this.wxMpService.getWxMpConfigStorage().getAppId()); this.wxMpService.getWxMpConfigStorage().getAppId());
packageParams.put("mch_id", packageParams.put("mch_id",
this.wxMpService.getWxMpConfigStorage().getPartnerId()); this.wxMpService.getWxMpConfigStorage().getPartnerId());
packageParams.put("nonce_str", System.currentTimeMillis() + ""); packageParams.put("nonce_str", System.currentTimeMillis() + "");
String sign = this.createSign(packageParams, String sign = this.createSign(packageParams,
this.wxMpService.getWxMpConfigStorage().getPartnerKey()); this.wxMpService.getWxMpConfigStorage().getPartnerKey());
packageParams.put("sign", sign); packageParams.put("sign", sign);
StringBuilder request = new StringBuilder("<xml>"); StringBuilder request = new StringBuilder("<xml>");
for (Map.Entry<String, String> para : packageParams.entrySet()) { for (Map.Entry<String, String> para : packageParams.entrySet()) {
request.append(String.format("<%s>%s</%s>", para.getKey(), request.append(String.format("<%s>%s</%s>", para.getKey(),
para.getValue(), para.getKey())); para.getValue(), para.getKey()));
} }
request.append("</xml>"); request.append("</xml>");
HttpPost httpPost = new HttpPost( HttpPost httpPost = new HttpPost(
"https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack"); "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack");
if (this.httpProxy != null) { if (this.httpProxy != null) {
RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy) RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy)
.build(); .build();
httpPost.setConfig(config); httpPost.setConfig(config);
} }
StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8);
httpPost.setEntity(entity); httpPost.setEntity(entity);
try (CloseableHttpResponse response = this.wxMpService.getHttpclient() try (CloseableHttpResponse response = this.wxMpService.getHttpclient()
.execute(httpPost)) { .execute(httpPost)) {
String responseContent = Utf8ResponseHandler.INSTANCE String responseContent = Utf8ResponseHandler.INSTANCE
.handleResponse(response); .handleResponse(response);
XStream xstream = XStreamInitializer.getInstance(); XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxRedpackResult.class); xstream.processAnnotations(WxRedpackResult.class);
return (WxRedpackResult) xstream.fromXML(responseContent); return (WxRedpackResult) xstream.fromXML(responseContent);
} catch (IOException e) { } catch (IOException e) {
String message = MessageFormatter String message = MessageFormatter
.format("Exception occured when sending redpack '{}'.", .format("Exception occured when sending redpack '{}'.",
request.toString()) request.toString())
.getMessage(); .getMessage();
this.log.error(message, e); this.log.error(message, e);
throw new WxErrorException(WxError.newBuilder().setErrorMsg(message).build()); throw new WxErrorException(
WxError.newBuilder().setErrorMsg(message).build());
} finally { } finally {
httpPost.releaseConnection(); httpPost.releaseConnection();
} }
} }
@Override @Override
public WxRedpackResult sendRedpack(WxSendRedpackRequest request) throws WxErrorException { public WxRedpackResult sendRedpack(WxSendRedpackRequest request)
throws WxErrorException {
XStream xstream = XStreamInitializer.getInstance(); XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxSendRedpackRequest.class); xstream.processAnnotations(WxSendRedpackRequest.class);
xstream.processAnnotations(WxRedpackResult.class); xstream.processAnnotations(WxRedpackResult.class);
@@ -442,10 +452,13 @@ public class WxMpPayServiceImpl implements WxMpPayService {
} }
String responseContent = this.wxMpService.post(url, xstream.toXML(request)); String responseContent = this.wxMpService.post(url, xstream.toXML(request));
WxRedpackResult redpackResult = (WxRedpackResult) xstream.fromXML(responseContent); WxRedpackResult redpackResult = (WxRedpackResult) xstream
if("FAIL".equals(redpackResult.getResultCode())){ .fromXML(responseContent);
throw new WxErrorException( if ("FAIL".equals(redpackResult.getResultCode())) {
WxError.newBuilder().setErrorMsg(redpackResult.getErrCode() + ":" + redpackResult.getErrCodeDes()).build()); throw new WxErrorException(WxError.newBuilder()
.setErrorMsg(
redpackResult.getErrCode() + ":" + redpackResult.getErrCodeDes())
.build());
} }
return redpackResult; return redpackResult;
@@ -460,9 +473,10 @@ public class WxMpPayServiceImpl implements WxMpPayService {
} }
try { try {
Field field = WxSendRedpackRequest.class.getDeclaredField(entry.getKey()); Field field = bean.getClass().getDeclaredField(entry.getKey());
if (field.isAnnotationPresent(XStreamAlias.class)) { if (field.isAnnotationPresent(XStreamAlias.class)) {
result.put(field.getAnnotation(XStreamAlias.class).value(), reflect.get().toString()); result.put(field.getAnnotation(XStreamAlias.class).value(),
reflect.get().toString());
} }
} catch (NoSuchFieldException | SecurityException e) { } catch (NoSuchFieldException | SecurityException e) {
e.printStackTrace(); e.printStackTrace();
@@ -485,7 +499,8 @@ public class WxMpPayServiceImpl implements WxMpPayService {
StringBuffer toSign = new StringBuffer(); StringBuffer toSign = new StringBuffer();
for (String key : sortedMap.keySet()) { for (String key : sortedMap.keySet()) {
String value = packageParams.get(key); String value = packageParams.get(key);
if (null != value && !"".equals(value) && !"sign".equals(key) && !"key".equals(key)) { if (null != value && !"".equals(value) && !"sign".equals(key)
&& !"key".equals(key)) {
toSign.append(key + "=" + value + "&"); toSign.append(key + "=" + value + "&");
} }
} }
@@ -495,4 +510,73 @@ public class WxMpPayServiceImpl implements WxMpPayService {
return DigestUtils.md5Hex(toSign.toString()).toUpperCase(); return DigestUtils.md5Hex(toSign.toString()).toUpperCase();
} }
@Override
public WxUnifiedOrderResult unifiedOrder(WxUnifiedOrderRequest request)
throws WxErrorException {
checkParameters(request);
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxUnifiedOrderRequest.class);
xstream.processAnnotations(WxUnifiedOrderResult.class);
request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId());
request.setNonceStr(System.currentTimeMillis() + "");
String sign = this.createSign(xmlBean2Map(request),
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
String responseContent = this.wxMpService.post(url, xstream.toXML(request));
WxUnifiedOrderResult result = (WxUnifiedOrderResult) xstream
.fromXML(responseContent);
if ("FAIL".equals(result.getResultCode())) {
throw new WxErrorException(WxError.newBuilder()
.setErrorMsg(result.getErrCode() + ":" + result.getErrCodeDes())
.build());
}
return result;
}
private void checkParameters(WxUnifiedOrderRequest request) {
List<String> nullFields = com.google.common.collect.Lists.newArrayList();
for (Entry<String, Reflect> entry : Reflect.on(request).fields()
.entrySet()) {
Reflect reflect = entry.getValue();
try {
Field field = request.getClass().getDeclaredField(entry.getKey());
if (field.isAnnotationPresent(Required.class)
&& reflect.get() == null) {
nullFields.add(entry.getKey());
}
} catch (NoSuchFieldException | SecurityException e) {
e.printStackTrace();
}
}
if (!nullFields.isEmpty()) {
throw new IllegalArgumentException("必填字段[" + nullFields + "]必须提供值");
}
if (!TRADE_TYPES.contains(request.getTradeType())) {
throw new IllegalArgumentException(
"trade_type目前必须为" + TRADE_TYPES + "其中之一");
}
if ("JSAPI".equals(request.getTradeType()) && request.getOpenid() == null) {
throw new IllegalArgumentException("当 trade_type是'JSAPI'时未指定openid");
}
if ("NATIVE".equals(request.getTradeType())
&& request.getProductId() == null) {
throw new IllegalArgumentException("当 trade_type是'NATIVE'时未指定product_id");
}
}
} }

View File

@@ -0,0 +1,124 @@
package me.chanjar.weixin.mp.bean.pay;
import java.io.Serializable;
/**
* <pre>
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"返回的结果
* 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
* </pre>
*
* @author chanjarster
*/
@Deprecated
public class WxMpPrepayIdResult implements Serializable {
private static final long serialVersionUID = -8970574397788396143L;
private String return_code;
private String return_msg;
private String appid;
private String mch_id;
private String nonce_str;
private String sign;
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 this.return_code;
}
public void setReturn_code(String return_code) {
this.return_code = return_code;
}
public String getReturn_msg() {
return this.return_msg;
}
public void setReturn_msg(String return_msg) {
this.return_msg = return_msg;
}
public String getAppid() {
return this.appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getMch_id() {
return this.mch_id;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
public String getNonce_str() {
return this.nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
public String getSign() {
return this.sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getResult_code() {
return this.result_code;
}
public void setResult_code(String result_code) {
this.result_code = result_code;
}
public String getPrepay_id() {
return this.prepay_id;
}
public void setPrepay_id(String prepay_id) {
this.prepay_id = prepay_id;
}
public String getTrade_type() {
return this.trade_type;
}
public void setTrade_type(String trade_type) {
this.trade_type = trade_type;
}
public String getErr_code() {
return this.err_code;
}
public void setErr_code(String err_code) {
this.err_code = err_code;
}
public String getErr_code_des() {
return this.err_code_des;
}
public void setErr_code_des(String err_code_des) {
this.err_code_des = err_code_des;
}
public String getCode_url() {
return this.code_url;
}
public void setCode_url(String code_url) {
this.code_url = code_url;
}
}

View File

@@ -19,32 +19,32 @@ public class WxRedpackResult implements Serializable {
private static final long serialVersionUID = -4837415036337132073L; private static final long serialVersionUID = -4837415036337132073L;
@XStreamAlias("return_code") @XStreamAlias("return_code")
String returnCode; private String returnCode;
@XStreamAlias("return_msg") @XStreamAlias("return_msg")
String returnMsg; private String returnMsg;
@XStreamAlias("sign") @XStreamAlias("sign")
String sign; private String sign;
@XStreamAlias("result_code") @XStreamAlias("result_code")
String resultCode; private String resultCode;
@XStreamAlias("err_code") @XStreamAlias("err_code")
String errCode; private String errCode;
@XStreamAlias("err_code_des") @XStreamAlias("err_code_des")
String errCodeDes; private String errCodeDes;
@XStreamAlias("mch_billno") @XStreamAlias("mch_billno")
String mchBillno; private String mchBillno;
@XStreamAlias("mch_id") @XStreamAlias("mch_id")
String mchId; private String mchId;
@XStreamAlias("wxappid") @XStreamAlias("wxappid")
String wxappid; private String wxappid;
@XStreamAlias("re_openid") @XStreamAlias("re_openid")
String reOpenid; private String reOpenid;
@XStreamAlias("total_amount") @XStreamAlias("total_amount")
int totalAmount; private int totalAmount;
@XStreamAlias("send_time") @XStreamAlias("send_time")
String sendTime; private String sendTime;
@XStreamAlias("send_listid") @XStreamAlias("send_listid")
String sendListid; private String sendListid;
public String getErrCode() { public String getErrCode() {
return this.errCode; return this.errCode;

View File

@@ -158,7 +158,7 @@ public class WxSendRedpackRequest {
private String consumeMchId; private String consumeMchId;
public String getMchBillno() { public String getMchBillno() {
return mchBillno; return this.mchBillno;
} }
public void setMchBillno(String mchBillno) { public void setMchBillno(String mchBillno) {
@@ -166,7 +166,7 @@ public class WxSendRedpackRequest {
} }
public String getSendName() { public String getSendName() {
return sendName; return this.sendName;
} }
public void setSendName(String sendName) { public void setSendName(String sendName) {
@@ -174,7 +174,7 @@ public class WxSendRedpackRequest {
} }
public String getReOpenid() { public String getReOpenid() {
return reOpenid; return this.reOpenid;
} }
public void setReOpenid(String reOpenid) { public void setReOpenid(String reOpenid) {
@@ -182,7 +182,7 @@ public class WxSendRedpackRequest {
} }
public Integer getTotalAmount() { public Integer getTotalAmount() {
return totalAmount; return this.totalAmount;
} }
public void setTotalAmount(Integer totalAmount) { public void setTotalAmount(Integer totalAmount) {
@@ -190,7 +190,7 @@ public class WxSendRedpackRequest {
} }
public Integer getTotalNum() { public Integer getTotalNum() {
return totalNum; return this.totalNum;
} }
public void setTotalNum(Integer totalNum) { public void setTotalNum(Integer totalNum) {
@@ -198,7 +198,7 @@ public class WxSendRedpackRequest {
} }
public String getAmtType() { public String getAmtType() {
return amtType; return this.amtType;
} }
public void setAmtType(String amtType) { public void setAmtType(String amtType) {
@@ -206,7 +206,7 @@ public class WxSendRedpackRequest {
} }
public String getWishing() { public String getWishing() {
return wishing; return this.wishing;
} }
public void setWishing(String wishing) { public void setWishing(String wishing) {
@@ -214,7 +214,7 @@ public class WxSendRedpackRequest {
} }
public String getClientIp() { public String getClientIp() {
return clientIp; return this.clientIp;
} }
public void setClientIp(String clientIp) { public void setClientIp(String clientIp) {
@@ -222,7 +222,7 @@ public class WxSendRedpackRequest {
} }
public String getActName() { public String getActName() {
return actName; return this.actName;
} }
public void setActName(String actName) { public void setActName(String actName) {
@@ -230,7 +230,7 @@ public class WxSendRedpackRequest {
} }
public String getRemark() { public String getRemark() {
return remark; return this.remark;
} }
public void setRemark(String remark) { public void setRemark(String remark) {
@@ -238,7 +238,7 @@ public class WxSendRedpackRequest {
} }
public String getWxAppid() { public String getWxAppid() {
return wxAppid; return this.wxAppid;
} }
public void setWxAppid(String wxAppid) { public void setWxAppid(String wxAppid) {
@@ -246,7 +246,7 @@ public class WxSendRedpackRequest {
} }
public String getMchId() { public String getMchId() {
return mchId; return this.mchId;
} }
public void setMchId(String mchId) { public void setMchId(String mchId) {
@@ -254,7 +254,7 @@ public class WxSendRedpackRequest {
} }
public String getNonceStr() { public String getNonceStr() {
return nonceStr; return this.nonceStr;
} }
public void setNonceStr(String nonceStr) { public void setNonceStr(String nonceStr) {
@@ -262,7 +262,7 @@ public class WxSendRedpackRequest {
} }
public String getSign() { public String getSign() {
return sign; return this.sign;
} }
public void setSign(String sign) { public void setSign(String sign) {
@@ -270,7 +270,7 @@ public class WxSendRedpackRequest {
} }
public String getSceneId() { public String getSceneId() {
return sceneId; return this.sceneId;
} }
public void setSceneId(String sceneId) { public void setSceneId(String sceneId) {
@@ -278,7 +278,7 @@ public class WxSendRedpackRequest {
} }
public String getRiskInfo() { public String getRiskInfo() {
return riskInfo; return this.riskInfo;
} }
public void setRiskInfo(String riskInfo) { public void setRiskInfo(String riskInfo) {
@@ -286,7 +286,7 @@ public class WxSendRedpackRequest {
} }
public String getConsumeMchId() { public String getConsumeMchId() {
return consumeMchId; return this.consumeMchId;
} }
public void setConsumeMchId(String consumeMchId) { public void setConsumeMchId(String consumeMchId) {

View File

@@ -1,14 +1,30 @@
package me.chanjar.weixin.mp.bean.pay; package me.chanjar.weixin.mp.bean.pay;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import me.chanjar.weixin.common.annotation.Required;
/** /**
* 统一下单请求参数对象 * <pre>
* Created by Binary Wang on 2016/9/25. * 统一下单请求参数对象
* 参考文档https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
* 每个字段描述对应如下:
* <li>字段名
* <li>变量名
* <li>是否必填
* <li>类型
* <li>示例值
* <li>描述
* </pre>
* Created by Binary Wang on 2016/9/25.
* @author binarywang (https://github.com/binarywang) * @author binarywang (https://github.com/binarywang)
*/ */
@XStreamAlias("xml") @XStreamAlias("xml")
public class WxUnifiedOrderRequest { public class WxUnifiedOrderRequest {
/** /**
* <pre> * <pre>
* 公众账号ID * 公众账号ID
@@ -19,6 +35,9 @@ public class WxUnifiedOrderRequest {
* 微信分配的公众账号ID企业号corpid即为此appId * 微信分配的公众账号ID企业号corpid即为此appId
* </pre> * </pre>
*/ */
@XStreamAlias("appid")
private String appid;
/** /**
* <pre> * <pre>
* 商户号 * 商户号
@@ -29,6 +48,9 @@ public class WxUnifiedOrderRequest {
* 微信支付分配的商户号 * 微信支付分配的商户号
* </pre> * </pre>
*/ */
@XStreamAlias("mch_id")
private String mchId;
/** /**
* <pre> * <pre>
* 设备号 * 设备号
@@ -36,9 +58,12 @@ public class WxUnifiedOrderRequest {
* 否 * 否
* String(32) * String(32)
* 013467007045764 * 013467007045764
* 终端设备号(门店号或收银设备ID)注意PC网页或公众号内支付请传"WEB" * 终端设备号(门店号或收银设备Id)注意PC网页或公众号内支付请传"WEB"
* </pre> * </pre>
*/ */
@XStreamAlias("device_info")
private String deviceInfo;
/** /**
* <pre> * <pre>
* 随机字符串 * 随机字符串
@@ -49,16 +74,22 @@ public class WxUnifiedOrderRequest {
* 随机字符串不长于32位。推荐随机数生成算法 * 随机字符串不长于32位。推荐随机数生成算法
* </pre> * </pre>
*/ */
@XStreamAlias("nonce_str")
private String nonceStr;
/** /**
* <pre> * <pre>
* 签名 * 签名
* sign * sign
* 是 * 是
* String(32) * String(32)
* C380BEC2BFD727A4B6845133519F3AD6 * C380BEC2BFD727A4B6845133519F3AD6
* 签名,详见签名生成算法 * 签名,详见签名生成算法
* </pre> * </pre>
*/ */
@XStreamAlias("sign")
private String sign;
/** /**
* <pre> * <pre>
* 商品描述 * 商品描述
@@ -69,6 +100,10 @@ public class WxUnifiedOrderRequest {
* 商品简单描述,该字段须严格按照规范传递,具体请见参数规定 * 商品简单描述,该字段须严格按照规范传递,具体请见参数规定
* </pre> * </pre>
*/ */
@Required
@XStreamAlias("body")
private String body;
/** /**
* <pre> * <pre>
* 商品详情 * 商品详情
@@ -76,37 +111,40 @@ public class WxUnifiedOrderRequest {
* 否 * 否
* String(6000) * String(6000)
* { "goods_detail":[ * { "goods_detail":[
{ {
"goods_id":"iphone6s_16G", "goods_id":"iphone6s_16G",
"wxpay_goods_id":"1001", "wxpay_goods_id":"1001",
"goods_name":"iPhone6s 16G", "goods_name":"iPhone6s 16G",
"goods_num":1, "goods_num":1,
"price":528800, "price":528800,
"goods_category":"123456", "goods_category":"123456",
"body":"苹果手机" "body":"苹果手机"
}, },
{ {
"goods_id":"iphone6s_32G", "goods_id":"iphone6s_32G",
"wxpay_goods_id":"1002", "wxpay_goods_id":"1002",
"goods_name":"iPhone6s 32G", "goods_name":"iPhone6s 32G",
"quantity":1, "quantity":1,
"price":608800, "price":608800,
"goods_category":"123789", "goods_category":"123789",
"body":"苹果手机" "body":"苹果手机"
} }
] ]
} }
商品详细列表使用Json格式传输签名前请务必使用CDATA标签将JSON文本串保护起来。 商品详细列表使用Json格式传输签名前请务必使用CDATA标签将JSON文本串保护起来。
goods_detail [] goods_detail []
└ goods_id String 必填 32 商品的编号 └ goods_id String 必填 32 商品的编号
└ wxpay_goods_id String 可选 32 微信支付定义的统一商品编号 └ wxpay_goods_id String 可选 32 微信支付定义的统一商品编号
└ goods_name String 必填 256 商品名称 └ goods_name String 必填 256 商品名称
└ goods_num Int 必填 商品数量 └ goods_num Int 必填 商品数量
└ price Int 必填 商品单价,单位为分 └ price Int 必填 商品单价,单位为分
└ goods_category String 可选 32 商品类目ID └ goods_category String 可选 32 商品类目Id
└ body String 可选 1000 商品描述信息 └ body String 可选 1000 商品描述信息
* </pre> * </pre>
*/ */
@XStreamAlias("detail")
private String detail;
/** /**
* <pre> * <pre>
* 附加数据 * 附加数据
@@ -117,6 +155,9 @@ public class WxUnifiedOrderRequest {
* 附加数据在查询API和支付通知中原样返回该字段主要用于商户携带订单的自定义数据 * 附加数据在查询API和支付通知中原样返回该字段主要用于商户携带订单的自定义数据
* </pre> * </pre>
*/ */
@XStreamAlias("attach")
private String attach;
/** /**
* <pre> * <pre>
* 商户订单号 * 商户订单号
@@ -127,6 +168,10 @@ public class WxUnifiedOrderRequest {
* 商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号 * 商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
* </pre> * </pre>
*/ */
@Required
@XStreamAlias("out_trade_no")
private String outTradeNo;
/** /**
* <pre> * <pre>
* 货币类型 * 货币类型
@@ -137,6 +182,9 @@ public class WxUnifiedOrderRequest {
* 符合ISO 4217标准的三位字母代码默认人民币CNY其他值列表详见货币类型 * 符合ISO 4217标准的三位字母代码默认人民币CNY其他值列表详见货币类型
* </pre> * </pre>
*/ */
@XStreamAlias("fee_type")
private String feeType;
/** /**
* <pre> * <pre>
* 总金额 * 总金额
@@ -147,6 +195,10 @@ public class WxUnifiedOrderRequest {
* 订单总金额,单位为分,详见支付金额 * 订单总金额,单位为分,详见支付金额
* </pre> * </pre>
*/ */
@Required
@XStreamAlias("total_fee")
private Integer totalFee;
/** /**
* <pre> * <pre>
* 终端IP * 终端IP
@@ -157,41 +209,458 @@ public class WxUnifiedOrderRequest {
* APP和网页支付提交用户端ipNative支付填调用微信支付API的机器IP。 * APP和网页支付提交用户端ipNative支付填调用微信支付API的机器IP。
* </pre> * </pre>
*/ */
@Required
@XStreamAlias("spbill_create_ip")
private String spbillCreateIp;
/** /**
* <pre> 交易起始时间 time_start 否 String(14) 20091225091010 订单生成时间格式为yyyyMMddHHmmss如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则 * <pre>
* 交易起始时间
* time_start
* 否
* String(14)
* 20091225091010
* 订单生成时间格式为yyyyMMddHHmmss如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
* </pre> * </pre>
*/ */
@XStreamAlias("time_start")
private String timeStart;
/** /**
* <pre> 交易结束时间 time_expire 否 String(14) 20091227091010 * <pre>
* </pre> * 交易结束时间
*/ * time_expire
/** *
* <pre> 订单失效时间格式为yyyyMMddHHmmss如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则 * String(14)
* 20091227091010
* 订单失效时间格式为yyyyMMddHHmmss如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则
* 注意最短失效时间间隔必须大于5分钟 * 注意最短失效时间间隔必须大于5分钟
* </pre> * </pre>
*/ */
@XStreamAlias("time_expire")
private String timeExpire;
/** /**
* <pre> 商品标记 goods_tag 否 String(32) WXG 商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠 * <pre>
* 商品标记
* goods_tag
* 否
* String(32)
* WXG
* 商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠
* </pre> * </pre>
*/ */
@XStreamAlias("goods_tag")
private String goodsTag;
/** /**
* <pre> 通知地址 notify_url 是 String(256) http://www.weixin.qq.com/wxpay/pay.php 接收微信支付异步通知回调地址通知url必须为直接可访问的url不能携带参数。 * <pre>
* 通知地址
* notify_url
* 是
* String(256)
* http://www.weixin.qq.com/wxpay/pay.php
* 接收微信支付异步通知回调地址通知url必须为直接可访问的url不能携带参数。
* </pre> * </pre>
*/ */
@Required
@XStreamAlias("notify_url")
private String notifyURL;
/** /**
* <pre> 交易类型 trade_type 是 String(16) JSAPI 取值如下JSAPINATIVEAPP详细说明见参数规定 * <pre>
* 交易类型
* trade_type
* 是
* String(16)
* JSAPI
* 取值如下JSAPINATIVEAPP详细说明见参数规定:
* JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付统一下单接口trade_type的传参可参考这里
* </pre> * </pre>
*/ */
@Required
@XStreamAlias("trade_type")
private String tradeType;
/** /**
* <pre> 商品ID product_id 否 String(32) 12235413214070356458058 trade_type=NATIVE此参数必传。此id为二维码中包含的商品ID商户自行定义。 * <pre>
* 商品Id
* product_id
* 否
* String(32)
* 12235413214070356458058
* trade_type=NATIVE此参数必传。此id为二维码中包含的商品Id商户自行定义。
* </pre> * </pre>
*/ */
@XStreamAlias("product_id")
private String productId;
/** /**
* <pre> 指定支付方式 limit_pay 否 String(32) no_credit no_credit--指定不能使用信用卡支付 * <pre>
* 指定支付方式
* limit_pay
* 否
* String(32)
* no_credit no_credit--指定不能使用信用卡支付
* </pre> * </pre>
*/ */
@XStreamAlias("limit_pay")
private String limitPay;
/** /**
* <pre> 用户标识 openid 否 String(128) oUpF8uMuAJO_M2pxb1Q9zNjWeS6o trade_type=JSAPI此参数必传用户在商户appid下的唯一标识。openid如何获取可参考【获取openid】。企业号请使用【企业号OAuth2.0接口】获取企业号内成员userid再调用【企业号userid转openid接口】进行转换 * <pre>
* 用户标识
* openid
* 否
* String(128)
* oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
* trade_type=JSAPI此参数必传用户在商户appid下的唯一标识。
* openid如何获取可参考【获取openid】。
* 企业号请使用【企业号OAuth2.0接口】获取企业号内成员userid再调用【企业号userid转openid接口】进行转换
* </pre> * </pre>
*/ */
@XStreamAlias("openid")
private String openid;
public String getAppid() {
return this.appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getMchId() {
return this.mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
public String getDeviceInfo() {
return this.deviceInfo;
}
public void setDeviceInfo(String deviceInfo) {
this.deviceInfo = deviceInfo;
}
public String getNonceStr() {
return this.nonceStr;
}
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
public String getSign() {
return this.sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getBody() {
return this.body;
}
public void setBody(String body) {
this.body = body;
}
public String getDetail() {
return this.detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getAttach() {
return this.attach;
}
public void setAttach(String attach) {
this.attach = attach;
}
public String getOutTradeNo() {
return this.outTradeNo;
}
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
public String getFeeType() {
return this.feeType;
}
public void setFeeType(String feeType) {
this.feeType = feeType;
}
public Integer getTotalFee() {
return this.totalFee;
}
public void setTotalFee(Integer totalFee) {
this.totalFee = totalFee;
}
public String getSpbillCreateIp() {
return this.spbillCreateIp;
}
public void setSpbillCreateIp(String spbillCreateIp) {
this.spbillCreateIp = spbillCreateIp;
}
public String getTimeStart() {
return this.timeStart;
}
public void setTimeStart(String timeStart) {
this.timeStart = timeStart;
}
public String getTimeExpire() {
return this.timeExpire;
}
public void setTimeExpire(String timeExpire) {
this.timeExpire = timeExpire;
}
public String getGoodsTag() {
return this.goodsTag;
}
public void setGoodsTag(String goodsTag) {
this.goodsTag = goodsTag;
}
public String getNotifyURL() {
return this.notifyURL;
}
public void setNotifyURL(String notifyURL) {
this.notifyURL = notifyURL;
}
public String getTradeType() {
return this.tradeType;
}
public void setTradeType(String tradeType) {
this.tradeType = tradeType;
}
public String getProductId() {
return this.productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getLimitPay() {
return this.limitPay;
}
public void setLimitPay(String limitPay) {
this.limitPay = limitPay;
}
public String getOpenid() {
return this.openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
public static WxUnifiedOrderRequestBuilder builder() {
return new WxUnifiedOrderRequestBuilder();
}
public static class WxUnifiedOrderRequestBuilder {
private String appid;
private String mchId;
private String deviceInfo;
private String nonceStr;
private String sign;
private String body;
private String detail;
private String attach;
private String outTradeNo;
private String feeType;
private Integer totalFee;
private String spbillCreateIp;
private String timeStart;
private String timeExpire;
private String goodsTag;
private String notifyURL;
private String tradeType;
private String productId;
private String limitPay;
private String openid;
public WxUnifiedOrderRequestBuilder appid(String appid) {
this.appid = appid;
return this;
}
public WxUnifiedOrderRequestBuilder mchId(String mchId) {
this.mchId = mchId;
return this;
}
public WxUnifiedOrderRequestBuilder deviceInfo(String deviceInfo) {
this.deviceInfo = deviceInfo;
return this;
}
public WxUnifiedOrderRequestBuilder nonceStr(String nonceStr) {
this.nonceStr = nonceStr;
return this;
}
public WxUnifiedOrderRequestBuilder sign(String sign) {
this.sign = sign;
return this;
}
public WxUnifiedOrderRequestBuilder body(String body) {
this.body = body;
return this;
}
public WxUnifiedOrderRequestBuilder detail(String detail) {
this.detail = detail;
return this;
}
public WxUnifiedOrderRequestBuilder attach(String attach) {
this.attach = attach;
return this;
}
public WxUnifiedOrderRequestBuilder outTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
return this;
}
public WxUnifiedOrderRequestBuilder feeType(String feeType) {
this.feeType = feeType;
return this;
}
public WxUnifiedOrderRequestBuilder totalFee(Integer totalFee) {
this.totalFee = totalFee;
return this;
}
public WxUnifiedOrderRequestBuilder spbillCreateIp(String spbillCreateIp) {
this.spbillCreateIp = spbillCreateIp;
return this;
}
public WxUnifiedOrderRequestBuilder timeStart(String timeStart) {
this.timeStart = timeStart;
return this;
}
public WxUnifiedOrderRequestBuilder timeExpire(String timeExpire) {
this.timeExpire = timeExpire;
return this;
}
public WxUnifiedOrderRequestBuilder goodsTag(String goodsTag) {
this.goodsTag = goodsTag;
return this;
}
public WxUnifiedOrderRequestBuilder notifyURL(String notifyURL) {
this.notifyURL = notifyURL;
return this;
}
public WxUnifiedOrderRequestBuilder tradeType(String tradeType) {
this.tradeType = tradeType;
return this;
}
public WxUnifiedOrderRequestBuilder productId(String productId) {
this.productId = productId;
return this;
}
public WxUnifiedOrderRequestBuilder limitPay(String limitPay) {
this.limitPay = limitPay;
return this;
}
public WxUnifiedOrderRequestBuilder openid(String openid) {
this.openid = openid;
return this;
}
public WxUnifiedOrderRequestBuilder from(WxUnifiedOrderRequest origin) {
this.appid(origin.appid);
this.mchId(origin.mchId);
this.deviceInfo(origin.deviceInfo);
this.nonceStr(origin.nonceStr);
this.sign(origin.sign);
this.body(origin.body);
this.detail(origin.detail);
this.attach(origin.attach);
this.outTradeNo(origin.outTradeNo);
this.feeType(origin.feeType);
this.totalFee(origin.totalFee);
this.spbillCreateIp(origin.spbillCreateIp);
this.timeStart(origin.timeStart);
this.timeExpire(origin.timeExpire);
this.goodsTag(origin.goodsTag);
this.notifyURL(origin.notifyURL);
this.tradeType(origin.tradeType);
this.productId(origin.productId);
this.limitPay(origin.limitPay);
this.openid(origin.openid);
return this;
}
public WxUnifiedOrderRequest build() {
WxUnifiedOrderRequest m = new WxUnifiedOrderRequest();
m.appid = this.appid;
m.mchId = this.mchId;
m.deviceInfo = this.deviceInfo;
m.nonceStr = this.nonceStr;
m.sign = this.sign;
m.body = this.body;
m.detail = this.detail;
m.attach = this.attach;
m.outTradeNo = this.outTradeNo;
m.feeType = this.feeType;
m.totalFee = this.totalFee;
m.spbillCreateIp = this.spbillCreateIp;
m.timeStart = this.timeStart;
m.timeExpire = this.timeExpire;
m.goodsTag = this.goodsTag;
m.notifyURL = this.notifyURL;
m.tradeType = this.tradeType;
m.productId = this.productId;
m.limitPay = this.limitPay;
m.openid = this.openid;
return m;
}
}
} }

View File

@@ -0,0 +1,155 @@
package me.chanjar.weixin.mp.bean.pay;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* <pre>
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"返回的结果
* 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
* </pre>
*
* @author chanjarster
*/
@XStreamAlias("xml")
public class WxUnifiedOrderResult {
@XStreamAlias("return_code")
private String returnCode;
@XStreamAlias("return_msg")
private String returnMsg;
@XStreamAlias("appid")
private String appid;
@XStreamAlias("mch_id")
private String mchId;
@XStreamAlias("nonce_str")
private String nonceStr;
@XStreamAlias("sign")
private String sign;
@XStreamAlias("result_code")
private String resultCode;
@XStreamAlias("prepay_id")
private String prepayId;
@XStreamAlias("trade_type")
private String tradeType;
@XStreamAlias("err_code")
private String errCode;
@XStreamAlias("err_code_des")
private String errCodeDes;
@XStreamAlias("code_url")
private String codeURL;
public String getReturnCode() {
return this.returnCode;
}
public void setReturnCode(String returnCode) {
this.returnCode = returnCode;
}
public String getReturnMsg() {
return this.returnMsg;
}
public void setReturnMsg(String returnMsg) {
this.returnMsg = returnMsg;
}
public String getAppid() {
return this.appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getMchId() {
return this.mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
public String getNonceStr() {
return this.nonceStr;
}
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
public String getSign() {
return this.sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getResultCode() {
return this.resultCode;
}
public void setResultCode(String resultCode) {
this.resultCode = resultCode;
}
public String getPrepayId() {
return this.prepayId;
}
public void setPrepayId(String prepayId) {
this.prepayId = prepayId;
}
public String getTradeType() {
return this.tradeType;
}
public void setTradeType(String tradeType) {
this.tradeType = tradeType;
}
public String getErrCode() {
return this.errCode;
}
public void setErrCode(String errCode) {
this.errCode = errCode;
}
public String getErrCodeDes() {
return this.errCodeDes;
}
public void setErrCodeDes(String errCodeDes) {
this.errCodeDes = errCodeDes;
}
public String getCodeURL() {
return this.codeURL;
}
public void setCodeURL(String codeURL) {
this.codeURL = codeURL;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
}

View File

@@ -1,128 +0,0 @@
package me.chanjar.weixin.mp.bean.result;
import java.io.Serializable;
/**
* <pre>
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"返回的结果
*
* 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
*
* </pre>
*
* @author chanjarster
*/
public class WxMpPrepayIdResult implements Serializable {
/**
*
*/
private static final long serialVersionUID = -8970574397788396143L;
private String return_code;
private String return_msg;
private String appid;
private String mch_id;
private String nonce_str;
private String sign;
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 this.return_code;
}
public void setReturn_code(String return_code) {
this.return_code = return_code;
}
public String getReturn_msg() {
return this.return_msg;
}
public void setReturn_msg(String return_msg) {
this.return_msg = return_msg;
}
public String getAppid() {
return this.appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getMch_id() {
return this.mch_id;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
public String getNonce_str() {
return this.nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
public String getSign() {
return this.sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getResult_code() {
return this.result_code;
}
public void setResult_code(String result_code) {
this.result_code = result_code;
}
public String getPrepay_id() {
return this.prepay_id;
}
public void setPrepay_id(String prepay_id) {
this.prepay_id = prepay_id;
}
public String getTrade_type() {
return this.trade_type;
}
public void setTrade_type(String trade_type) {
this.trade_type = trade_type;
}
public String getErr_code() {
return this.err_code;
}
public void setErr_code(String err_code) {
this.err_code = err_code;
}
public String getErr_code_des() {
return this.err_code_des;
}
public void setErr_code_des(String err_code_des) {
this.err_code_des = err_code_des;
}
public String getCode_url() {
return this.code_url;
}
public void setCode_url(String code_url) {
this.code_url = code_url;
}
}

View File

@@ -5,9 +5,12 @@ import org.testng.annotations.Test;
import com.google.inject.Inject; import com.google.inject.Inject;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.ApiTestModule; import me.chanjar.weixin.mp.api.ApiTestModule;
import me.chanjar.weixin.mp.bean.pay.WxRedpackResult; import me.chanjar.weixin.mp.bean.pay.WxRedpackResult;
import me.chanjar.weixin.mp.bean.pay.WxSendRedpackRequest; import me.chanjar.weixin.mp.bean.pay.WxSendRedpackRequest;
import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderRequest;
import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderResult;
/** /**
* 测试支付相关接口 * 测试支付相关接口
@@ -26,11 +29,6 @@ public class WxMpPayServiceImplTest {
} }
@Test
public void testGetPrepayId1() throws Exception {
}
@Test @Test
public void testGetJsapiPayInfo() throws Exception { public void testGetJsapiPayInfo() throws Exception {
@@ -78,4 +76,16 @@ public class WxMpPayServiceImplTest {
System.err.println(redpackResult); System.err.println(redpackResult);
} }
/**
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#unifiedOrder(me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderRequest)}.
* @throws WxErrorException
*/
@Test
public void testUnifiedOrder() throws WxErrorException {
WxUnifiedOrderResult result = this.wxService.getPayService()
.unifiedOrder(WxUnifiedOrderRequest.builder().body("1111111")
.totalFee(1).spbillCreateIp("111111").notifyURL("111111")
.tradeType("JSAPI1").openid("122").outTradeNo("111111").build());
System.err.println(result);
}
} }