首先插入微信支付的时序图
统一下单时候的请求对象,需要把这个转为xml 文件格式所以需要在pom.xml 文件中导入 、和微信支付的sdk
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<deendency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.10</version>
</dependency>
微信统一下单接口需要的所有参数可以微信官方查看 微信官方统一下单接口
@XmlRootElement(name = "xml")
public class UnifiedOrderRequest {
private java.lang.String appid;//微信分配的小程序IDwxd678efh567hg6787,NotNull
private java.lang.String mch_id;//微信支付分配的商户号1230000109,NotNull
private java.lang.String device_info;//自定义参数,可以为终端设备号(门店号或收银设备ID),PC网页或公众号内支付可以传"WEB"
private java.lang.String nonce_str;//随机字符串,必须,NotNull
private java.lang.String sign;//签名,必须,,
private java.lang.String sign_type;//"HMAC-SHA256"或者"MD5",非必须,默认MD5
private java.lang.String body;//商品简单描述,必须
private java.lang.String detail;//商品详细列表,使用json格式
private java.lang.String attach;//附加数据,如"贵阳分店",非必须(1,代表采购订单 2,代表租凭酒机订单)
private java.lang.String out_trade_no;//商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一
private java.lang.String fee_type;//默认人民币:CNY,非必须
private Integer total_fee;//订单金额,单位分,必须
private java.lang.String spbill_create_ip;//支付提交客户端IP,如“123.123.123.123”,必须
private java.lang.String time_start;//订单生成时间,格式为yyyyMMddHHmmss,如20170324094700,非必须
private java.lang.String time_expire;//订单结束时间,格式同上,非必须
private java.lang.String goods_tag;//订单优惠标记,代金券或立减优惠功能的参数,非必须
private java.lang.String notify_url;//接收微信支付异步通知回调地址,不能携带参数,必须
private java.lang.String trade_type;//交易类型,小程序写"JSAPI",必须
private java.lang.String product_id;//商品ID trade_type=NATIVE时(即扫码支付),此参数必传。此参数为二维码中包含的商品ID,商户自行定义。
private java.lang.String limit_pay;//限制某种支付方式,非必须
private java.lang.String openid;//微信用户唯一标识,必须
private String scene_info;//h5支付必须 (场景信息)
public UnifiedOrderRequest(java.lang.String openid, java.lang.String appid, java.lang.String mchId, java.lang.String deviceId,
java.lang.String nonceStr, java.lang.String body, java.lang.String outTradeNo, Integer totalFee,
java.lang.String spbillCreateIp, java.lang.String notifyUrl, java.lang.String tradeType, java.lang.String productId) {
this.openid = openid;
this.appid = appid;
this.mch_id = mchId;
this.device_info = deviceId;
this.nonce_str = nonceStr;
this.body = body;
this.out_trade_no = outTradeNo;
this.total_fee = totalFee;
this.spbill_create_ip = spbillCreateIp;
this.notify_url = notifyUrl;
this.trade_type = tradeType;
this.product_id = productId;
}
public UnifiedOrderRequest(java.lang.String appid, java.lang.String machid, java.lang.String nonceStr, java.lang.String body, java.lang.String outTradeNo, Integer totalFee, java.lang.String spbillCreateIp, java.lang.String notifyUrl, java.lang.String trade_type, String string) {
this.appid = appid;
this.mch_id = machid;
this.nonce_str = nonceStr;
this.body = body;
this.out_trade_no = outTradeNo;
this.total_fee = totalFee;
this.spbill_create_ip = spbillCreateIp;
this.notify_url = notifyUrl;
this.trade_type = trade_type;
this.scene_info = string;
}
public String getScene_info() {
return scene_info;
}
public void setScene_info(String scene_info) {
this.scene_info = scene_info;
}
public java.lang.String getAppid() {
return appid;
}
public void setAppid(java.lang.String appid) {
this.appid = appid;
}
public java.lang.String getMch_id() {
return mch_id;
}
public void setMch_id(java.lang.String mch_id) {
this.mch_id = mch_id;
}
public java.lang.String getDevice_info() {
return device_info;
}
public void setDevice_info(java.lang.String device_info) {
this.device_info = device_info;
}
public java.lang.String getNonce_str() {
return nonce_str;
}
public void setNonce_str(java.lang.String nonce_str) {
this.nonce_str = nonce_str;
}
public java.lang.String getSign() {
return sign;
}
public void setSign(java.lang.String sign) {
this.sign = sign;
}
public java.lang.String getSign_type() {
return sign_type;
}
public void setSign_type(java.lang.String sign_type) {
this.sign_type = sign_type;
}
public java.lang.String getBody() {
return body;
}
public void setBody(java.lang.String body) {
this.body = body;
}
public java.lang.String getDetail() {
return detail;
}
public void setDetail(java.lang.String detail) {
this.detail = detail;
}
public java.lang.String getAttach() {
return attach;
}
public void setAttach(java.lang.String attach) {
this.attach = attach;
}
public java.lang.String getOut_trade_no() {
return out_trade_no;
}
public void setOut_trade_no(java.lang.String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public java.lang.String getFee_type() {
return fee_type;
}
public void setFee_type(java.lang.String fee_type) {
this.fee_type = fee_type;
}
public Integer getTotal_fee() {
return total_fee;
}
public void setTotal_fee(Integer total_fee) {
this.total_fee = total_fee;
}
public java.lang.String getSpbill_create_ip() {
return spbill_create_ip;
}
public void setSpbill_create_ip(java.lang.String spbill_create_ip) {
this.spbill_create_ip = spbill_create_ip;
}
public java.lang.String getTime_start() {
return time_start;
}
public void setTime_start(java.lang.String time_start) {
this.time_start = time_start;
}
public java.lang.String getTime_expire() {
return time_expire;
}
public void setTime_expire(java.lang.String time_expire) {
this.time_expire = time_expire;
}
public java.lang.String getGoods_tag() {
return goods_tag;
}
public void setGoods_tag(java.lang.String goods_tag) {
this.goods_tag = goods_tag;
}
public java.lang.String getNotify_url() {
return notify_url;
}
public void setNotify_url(java.lang.String notify_url) {
this.notify_url = notify_url;
}
public java.lang.String getTrade_type() {
return trade_type;
}
public void setTrade_type(java.lang.String trade_type) {
this.trade_type = trade_type;
}
public java.lang.String getProduct_id() {
return product_id;
}
public void setProduct_id(java.lang.String product_id) {
this.product_id = product_id;
}
public java.lang.String getLimit_pay() {
return limit_pay;
}
public void setLimit_pay(java.lang.String limit_pay) {
this.limit_pay = limit_pay;
}
public java.lang.String getOpenid() {
return openid;
}
public void setOpenid(java.lang.String openid) {
this.openid = openid;
}
public UnifiedOrderRequest() {
}
public UnifiedOrderRequest(java.lang.String appid, java.lang.String mch_id, java.lang.String device_info, java.lang.String nonce_str, java.lang.String sign, java.lang.String sign_type, java.lang.String body, java.lang.String detail, java.lang.String attach, java.lang.String out_trade_no, java.lang.String fee_type, Integer total_fee, java.lang.String spbill_create_ip, java.lang.String time_start, java.lang.String time_expire, java.lang.String goods_tag, java.lang.String notify_url, java.lang.String trade_type, java.lang.String product_id, java.lang.String limit_pay, java.lang.String openid) {
this.appid = appid;
this.mch_id = mch_id;
this.device_info = device_info;
this.nonce_str = nonce_str;
this.sign = sign;
this.sign_type = sign_type;
this.body = body;
this.detail = detail;
this.attach = attach;
this.out_trade_no = out_trade_no;
this.fee_type = fee_type;
this.total_fee = total_fee;
this.spbill_create_ip = spbill_create_ip;
this.time_start = time_start;
this.time_expire = time_expire;
this.goods_tag = goods_tag;
this.notify_url = notify_url;
this.trade_type = trade_type;
this.product_id = product_id;
this.limit_pay = limit_pay;
this.openid = openid;
}
@Override
public java.lang.String toString() {
return "UnifiedOrderRequest{" +
"appid='" + appid + '\'' +
", mch_id='" + mch_id + '\'' +
", device_info='" + device_info + '\'' +
", nonce_str='" + nonce_str + '\'' +
", sign='" + sign + '\'' +
", sign_type='" + sign_type + '\'' +
", body='" + body + '\'' +
", detail='" + detail + '\'' +
", attach='" + attach + '\'' +
", out_trade_no='" + out_trade_no + '\'' +
", fee_type='" + fee_type + '\'' +
", total_fee=" + total_fee +
", spbill_create_ip='" + spbill_create_ip + '\'' +
", time_start='" + time_start + '\'' +
", time_expire='" + time_expire + '\'' +
", goods_tag='" + goods_tag + '\'' +
", notify_url='" + notify_url + '\'' +
", trade_type='" + trade_type + '\'' +
", product_id='" + product_id + '\'' +
", limit_pay='" + limit_pay + '\'' +
", openid='" + openid + '\'' +
'}';
}
}
微信支付统一下单的响应字段 可以通过 微信官方统一下单接口
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "xml")
public class UnifiedOrderResponse {
private String return_code;//返回状态码
private String return_msg;//返回信息
private String appid;//小程序ID
private String mch_id;//商户号
private String device_info;//设备号
private String nonce_str;//随机字符串
private String sign;//签名
private String result_code;//业务结果
private String err_code;//错误代码
private String err_code_des;//错错误代码描述
private String trade_type;//交易类型
private String prepay_id;//预支付交易会话标识
private String code_url;//二维码链接
private String mweb_url;//支付跳转链接 (h5支付返回)
public String getMweb_url() {
return mweb_url;
}
public void setMweb_url(String mweb_url) {
this.mweb_url = mweb_url;
}
public String getReturn_code() {
return return_code;
}
public void setReturn_code(String return_code) {
this.return_code = return_code;
}
public String getReturn_msg() {
return return_msg;
}
public void setReturn_msg(String return_msg) {
this.return_msg = return_msg;
}
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getMch_id() {
return mch_id;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
public String getDevice_info() {
return device_info;
}
public void setDevice_info(String device_info) {
this.device_info = device_info;
}
public String getNonce_str() {
return nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getResult_code() {
return result_code;
}
public void setResult_code(String result_code) {
this.result_code = result_code;
}
public String getErr_code_des() {
return err_code_des;
}
public void setErr_code_des(String err_code_des) {
this.err_code_des = err_code_des;
}
public String getTrade_type() {
return trade_type;
}
public void setTrade_type(String trade_type) {
this.trade_type = trade_type;
}
public String getPrepay_id() {
return prepay_id;
}
public void setPrepay_id(String prepay_id) {
this.prepay_id = prepay_id;
}
public String getCode_url() {
return code_url;
}
public void setCode_url(String code_url) {
this.code_url = code_url;
}
public String getErr_code() {
return err_code;
}
public void setErr_code(String err_code) {
this.err_code = err_code;
}
public UnifiedOrderResponse() {
}
public UnifiedOrderResponse(String return_code, String return_msg, String appid, String mch_id, String device_info, String nonce_str, String sign, String result_code, String err_code_des, String trade_type, String prepay_id, String code_url) {
this.return_code = return_code;
this.return_msg = return_msg;
this.appid = appid;
this.mch_id = mch_id;
this.device_info = device_info;
this.nonce_str = nonce_str;
this.sign = sign;
this.result_code = result_code;
this.err_code_des = err_code_des;
this.trade_type = trade_type;
this.prepay_id = prepay_id;
this.code_url = code_url;
}
@Override
public String toString() {
return "UnifiedOrderResponse{" +
"return_code='" + return_code + '\'' +
", return_msg='" + return_msg + '\'' +
", appid='" + appid + '\'' +
", mch_id='" + mch_id + '\'' +
", device_info='" + device_info + '\'' +
", nonce_str='" + nonce_str + '\'' +
", sign='" + sign + '\'' +
", result_code='" + result_code + '\'' +
", err_code='" + err_code + '\'' +
", err_code_des='" + err_code_des + '\'' +
", trade_type='" + trade_type + '\'' +
", prepay_id='" + prepay_id + '\'' +
", code_url='" + code_url + '\'' +
'}';
}
}
新建一个微信支付的service
public interface WechatPayService {
//统一下单
UnifiedOrderResponse unifiedOrder(UnifiedOrderRequest request, String key) throws UnsupportedEncodingException;
}
接口类的实现
public class WechatPayServiceImpl implements WechatPayService {
private static final Logger logger = LoggerFactory.getLogger(WechatPayServiceImpl.class);
/**
request 接口请求对象
*/
@Override
public UnifiedOrderResponse unifiedOrder(UnifiedOrderRequest request, String key) {
logger.info("WechatPayServiceImpl, unifiedOrder(), 返回值类型:UnifiedOrderResponse, request:{}", request);
//String tmp = request.getBody();
/** 获取签名 这里我的签名方式是MD5 WxConst.PAYKEY为你的密钥 */
request.setSign(WxUtil.getSign(request,WxConst.PAYKEY));
//request.setBody(tmp);
String unifiedOrderRequestStr = XMLUtil.convertToXml(request);
logger.info(unifiedOrderRequestStr);
/** 设置https 请求*/
HttpClient client = createSSLClientDefault();
/** post请求*/
HttpPost post = new HttpPost(WxConst.WXUNIFIEDORDERURL);
/** 设置请求头*/
post.setHeader("Content-Type", "application/xml");
/** 转换实体参数*/
StringEntity stringEntity = new StringEntity(unifiedOrderRequestStr, "UTF-8");
/*stringEntity.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,
"application/xml"));*/
post.setEntity(stringEntity);
try {
HttpResponse httpResponse = client.execute(post);
String resp = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
UnifiedOrderResponse unifiedOrderResponse = (UnifiedOrderResponse) XMLUtil.convertXmlStrToObject(UnifiedOrderResponse.class, resp);
logger.info(unifiedOrderResponse.toString());
//成功
if ("SUCCESS".equals(unifiedOrderResponse.getReturn_code()) && "SUCCESS".equals(unifiedOrderResponse.getResult_code())) {
logger.info(unifiedOrderResponse.toString());
}
return unifiedOrderResponse;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
!!!!微信支付签名的MD5加密的 方式通过参数拼接这里可以参考微信官方的参考文档 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3, 这个地方拼接的参数有个坑 (在做APP 调用支付的时候 我一直以为请求参数的商务id 是mch_id 其实 partnerid,要不然在 APP端调用支付会失败,但是自己在后端请求查询没问题。所以在app 调用支付的时候签名如果是后端返回的商务端id 字段是 partnerid )
public class WxUtil {
public static String getSign(Object request,String key) {
//logger.info("WechatPayServiceImpl, getSign(), 返回值类型:String, request:{}", request);
String sign = "";
Field[] fields = request.getClass().getDeclaredFields();
int index = 0;
int fieldNum = 0;
String[] signArray = new String[fields.length - 1];
for (int i = 0; i < fields.length; i++) {
try {
/** 这里通过反射获得到请求的参数,通过参数拼接这里可以参考微信官方 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3
*/
fields[i].setAccessible(true);
if ("Sign".equals(fields[i].getName()) || fields[i].get(request) == null ||
"".equals(String.valueOf(fields[i].get(request)))) {
continue;
}
if (fields[i].getName().equals("packAge")) {
signArray[index] = String.format("%s=%s", "package", String.valueOf(fields[i].get(request)));
} else {
signArray[index] = String.format("%s=%s", fields[i].getName(), String.valueOf(fields[i].get(request)));
}
index++;
fieldNum++;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
if (fieldNum < signArray.length) {
signArray = Arrays.copyOf(signArray, fieldNum);
}
Arrays.sort(signArray);
//logger.info(toString(signArray) + String.format("&%s=%s", "key", WxConst.PAYKEY));
sign = MD5Util.md5(toString(signArray) + String.format("&%s=%s", "key", key)).toUpperCase();
return sign;
}
private static String toString(String[] a) {
if (a == null)
return "null";
int iMax = a.length - 1;
if (iMax == -1)
return "";
StringBuilder b = new StringBuilder();
for (int i = 0; ; i++) {
b.append(a[i]);
if (i == iMax)
return b.toString();
b.append("&");
}
}
}
- 测试调用
public class Test1{
public void test (){
/** 给予统一支付下单 对象赋值*/
/**
* 小程序支付必须传参为
* @Param [user.getOpenId() 用户标识] [WxConst.APPID3小程序ID] [WxConst.MACHID3 商户号] [nonceStr 随机字符串] [MD5 表示加密的方式] ,["原材料采购" 表示采购的名称]
* @Param [body 商品描述 依照微信小程序规范上传] [purchaseOrder.getOrderNumber() 自己生成的订单号 ] [totalFee 订单总金额 单位为分]
* @Param [spbillCreateIp 调用微信支付API的机器IP 终端IP ] [notify_url 回调地址] [trade_type 交易类型 APP 表示APP 支付] [product_id 商品id 商品ID trade_type=NATIVE时(即扫码支付),此参数必传。此参数为二维码中包含的商品ID,商户自行定义。]
*/
UnifiedOrderRequest unifiedOrderRequest = new UnifiedOrderRequest(WxConstMobile.APPID3, WxConstMobile.MACHID3,
null, nonceStr, null, "MD5", "原材料采购", null, "1",
purchaseOrder.getOrderNumber(), null, totalFee, spbillCreateIp, null, null,
null, WxConstMobile.WXNOTIFYURL, "APP", null, null, null);
try {
/** 调用统一下单接口*/
UnifiedOrderResponse unifiedOrderResponse = wechatPayService.unifiedOrder(unifiedOrderRequest, WxConstMobile.PAYKEY3);
/** 可以查看统一下单接口里面的参如果是成功 */
if (!unifiedOrderResponse.getReturn_code().equals("SUCCESS")) {
return new BaseResponse<>(ErrorCode.ERROR_CUSTOM.getValue(), unifiedOrderResponse.getReturn_msg());
}
WechatUnifiedOrder wechatUnifiedOrder = new WechatUnifiedOrder(unifiedOrderResponse);
/** 对于返回的参数二次签名返回给APP 参数为上图所示的请求参数 */
appPayResponse = new AppPayResponse(purchaseOrder.getWechatUnifiedOrder());
appPayResponse.setSign(WxUtil.getSign(appPayResponse, WxConstMobile.PAYKEY3));
} catch (Exception e) {
e.printStackTrace();
}
}
}