1. 程式人生 > >JAVA 微信支付 native方式

JAVA 微信支付 native方式

     最近做了一個微信native方式支付的demo,整理一下。

    首先到微信公眾號官網閱讀開發文件,雖然文件對於java沒有例子,但是也可以作參考。https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1

    我的demo是使用者在商家系統H5頁面發起付款申請,商家系統通過H5頁面收集相關引數,呼叫java方法生成支付字串返回給H5頁面,H5頁面將支付字串生成二維碼,使用者掃描即可支付。我這是最簡單的例子。先看頁面吧,JSP頁面中javascript指令碼如下:

<script src="qrcode.js"></script>   

<script>
//這個地址是Demo.java生成的code_url,這個就是java生成的支付字串,javascript把這個字串變成二維碼顯示在頁面上,使用者即可掃碼支付
var url="weixin://wxpay/bizpayurl?pr=30XrslD";
//引數1表示影象大小,取值範圍1-10;引數2表示質量,取值範圍'L','M','Q','H'
var qr = qrcode(10, 'M');
qr.addData(url);
qr.make();
var dom=document.createElement('DIV');
dom.innerHTML = qr.createImgTag();
var element=document.getElementById("qrcode");
element.appendChild(dom);
</script>

    看過了jsp頁面如何使用支付字串,那麼就來看看最關鍵的如何用java生成這個支付二維碼連結字串。

    1、 首先看java類中需要的變數有哪些

  //微信支付商戶開通後 微信會提供appid和appsecret和商戶號partner
  private static String appid = ".......";
  private static String appsecret = ".........";
  //商戶號,公眾號支付申請通過後發給申請人的郵件中有該資訊,需要用商戶號登入商戶平臺檢視使用者已付款訂單等等支付資訊
  private static String partner = ".......";
  //這個引數partnerkey是在商戶後臺配置的一個32位的key,微信商戶平臺-賬戶設定-安全設定-api安全。是自己設定的,設定後自己記住。我在商戶平臺沒有發現能檢視的地方
  private static String partnerkey = "........";
  //微信支付成功後通知地址 必須要求80埠並且地址不能帶引數
  private static String notifyurl = "http://localhost:8080/weChatpay/page/back.jsp";

  2、定義一個支付pojo

public class WxPayDto {

private String orderId;//訂單號
private String totalFee;//金額
private String spbillCreateIp;//訂單生成的機器 IP
private String notifyUrl;//這裡notify_url是 支付完成後微信發給該連結資訊,可以判斷會員是否支付成功,改變訂單狀態等
private String body;// 商品描述根據情況修改
private String openId;//微信使用者對一個公眾號唯一

//getter、setter等方法

}

  3、設定支付所需引數

WxPayDto tpWxPay1 = new WxPayDto();
tpWxPay1.setBody("商品資訊");
tpWxPay1.setOrderId(getNonceStr());//這個是訂單號,可以根據自己系統實際需要設定,我這裡其實設定的是時間戳字串
tpWxPay1.setSpbillCreateIp("127.0.0.1");
tpWxPay1.setTotalFee("0.01");//使用者需要支付的金額,單位是元
String codeurl= getCodeurl(tpWxPay1);//這個codeurl就是需要傳給H5頁面的支付引數了,大概是這樣滴:weixin://wxpay/bizpayurl?pr=30XrslD

 4、生成支付二維碼連結字串方法

/**
* 獲取微信掃碼支付二維碼連線
*/
public static String getCodeurl(WxPayDto tpWxPayDto){

// 1 引數
// 訂單號
String orderId = tpWxPayDto.getOrderId();
// 附加資料 原樣返回
String attach = "";
// 總金額以分為單位,不帶小數點
String totalFee =tpWxPayDto.getTotalFee()*100;

// 訂單生成的機器 IP
String spbill_create_ip = tpWxPayDto.getSpbillCreateIp();
// 這裡notify_url是 支付完成後微信發給該連結資訊,可以判斷會員是否支付成功,改變訂單狀態等。
String notify_url = notifyurl;
String trade_type = "NATIVE";

// 商戶號
String mch_id = partner;
// 隨機字串
String nonce_str = getNonceStr();//我設定的是時間戳字串

// 商品描述根據自己系統情況修改
String body = tpWxPayDto.getBody();

// 商戶訂單號
String out_trade_no = orderId;

SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("appid", appid);
packageParams.put("mch_id", mch_id);
packageParams.put("nonce_str", nonce_str);
packageParams.put("body", body);
packageParams.put("attach", attach);
packageParams.put("out_trade_no", out_trade_no);

// 這裡寫的金額為1 分,根據自己系統實際需要到時修改
packageParams.put("total_fee", totalFee);
packageParams.put("spbill_create_ip", spbill_create_ip);
packageParams.put("notify_url", notify_url);

packageParams.put("trade_type", trade_type);

RequestHandler reqHandler = new RequestHandler(null, null);
reqHandler.init(appid, appsecret, partnerkey);

String sign = reqHandler.createSign(packageParams);
String xml = "<xml>" + "<appid>" + appid + "</appid>" + "<mch_id>"
+ mch_id + "</mch_id>" + "<nonce_str>" + nonce_str
+ "</nonce_str>" + "<sign>" + sign + "</sign>"
+ "<body><![CDATA[" + body + "]]></body>" 
+ "<out_trade_no>" + out_trade_no
+ "</out_trade_no>" + "<attach>" + attach + "</attach>"
+ "<total_fee>" + totalFee + "</total_fee>"
+ "<spbill_create_ip>" + spbill_create_ip
+ "</spbill_create_ip>" + "<notify_url>" + notify_url
+ "</notify_url>" + "<trade_type>" + trade_type
+ "</trade_type>" + "</xml>";
String code_url = "";
//統一支付介面
String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
code_url = new GetWxOrderno().getCodeUrl(createOrderURL, xml);
return code_url;//支付二維碼連結字串
}

   這就是最簡單的java版本微信公眾號掃碼native支付方式demo,歡迎你交流經驗問題。

  ps:這是GetWxOrderno類的全部程式碼

package com.utils;


import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import com.utils.http.HttpClientConnectionManager;

public class GetWxOrderno
{
public static DefaultHttpClient httpclient;

static
{
httpclient = new DefaultHttpClient();
httpclient = (DefaultHttpClient)HttpClientConnectionManager.getSSLInstance(httpclient);
}


/**
*description:獲取預支付id
*@param url
*@param xmlParam
*@return
* @author ex_yangxiaoyi
* @see
*/
public static String getPayNo(String url,String xmlParam){
DefaultHttpClient client = new DefaultHttpClient();
client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
HttpPost httpost= HttpClientConnectionManager.getPostMethod(url);
String prepay_id = "";
try {
httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));
HttpResponse response = httpclient.execute(httpost);
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
if(jsonStr.indexOf("FAIL")!=-1){
return prepay_id;
}
Map map = doXMLParse(jsonStr);
prepay_id = (String) map.get("prepay_id");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return prepay_id;
}

/**
*description:獲取掃碼支付連線
*@param url
*@param xmlParam
*@return
* @author ex_yangxiaoyi
* @see
*/
public static String getCodeUrl(String url,String xmlParam){
DefaultHttpClient client = new DefaultHttpClient();
client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
HttpPost httpost= HttpClientConnectionManager.getPostMethod(url);
String code_url = "";
try {
httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));
HttpResponse response = httpclient.execute(httpost);
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
if(jsonStr.indexOf("FAIL")!=-1){
return code_url;
}
Map map = doXMLParse(jsonStr);
code_url = (String) map.get("code_url");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return code_url;
}


/**
* 解析xml,返回第一級元素鍵值對。如果第一級元素有子節點,則此節點的值是子節點的xml資料。
* @param strxml
* @return
* @throws JDOMException
* @throws IOException
*/
public static Map doXMLParse(String strxml) throws Exception {
if(null == strxml || "".equals(strxml)) {
return null;
}

Map m = new HashMap();
InputStream in = String2Inputstream(strxml);
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while(it.hasNext()) {
Element e = (Element) it.next();
String k = e.getName();
String v = "";
List children = e.getChildren();
if(children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = getChildrenText(children);
}

m.put(k, v);
}

//關閉流
in.close();

return m;
}
/**
* 獲取子結點的xml
* @param children
* @return String
*/
public static String getChildrenText(List children) {
StringBuffer sb = new StringBuffer();
if(!children.isEmpty()) {
Iterator it = children.iterator();
while(it.hasNext()) {
Element e = (Element) it.next();
String name = e.getName();
String value = e.getTextNormalize();
List list = e.getChildren();
sb.append("<" + name + ">");
if(!list.isEmpty()) {
sb.append(getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
}

return sb.toString();
}
public static InputStream String2Inputstream(String str) {
return new ByteArrayInputStream(str.getBytes());
}

}