PC網站NATIVE支付爲例
直接上代碼代碼片
主方法
@RequestMapping("WeiXinPay")
@ResponseBody
public ResponseEntity WeiXinPay (String orderNum, String payInfo) {
ResponseEntity entity = new ResponseEntity();
entity.setFlag(false);
HashMap<String, Object> maps = new HashMap<String, Object>();
maps.put("orderNum",orderNum);
Order order = orderService.selectByPrimaryKey(maps);
if (order == null) {
entity.setMessage("訂單編號錯誤");
return entity;
}
String appid = "wxd00000000000";
String mch_id = "00000000000000000000000"; //商戶號
String Key = "000000000000000000";// API 密鑰
String notify_url = "http://00000000:0000000/notify";//測試環境使用IP地址
// String SIGNKEY = "你的商戶密鑰";
String spbill_create_ip = "10000000000";//ip地址
System.out.println("spbill_create_ip="+spbill_create_ip);
//String spbill_create_ip = "";//測試地址,也就是本地真是ip,用於本地測試用
// String scene_info = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"這裏寫在h5支付配置的那個域名\",\"wap_name\": \"信息認證\"}}";//我這裏是網頁入口,app入口參考文檔的安卓和ios寫法
String tradeType = "NATIVE";//NATIVE支付標記
String MD5 = "MD5";//雖然官方文檔不是必須參數,但是不送有時候會驗籤失敗
String subject = "0000000-"+payInfo;//前端上送的支付描述
String total_amount =String.valueOf(order.getPrice());//支付金額
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
//金額轉化爲分爲單位 微信支付以分爲單
String finalmoney = WeiXinUtils.getMoney(total_amount);
int randomNum = (int) (Math.random() * 1999+5000);
//String out_trade_no = DataUtil.getSysTime("yyyyMMddHHmmss") + randomNum;
String out_trade_no = orderNum;
//隨機數
String nonce_str= WeiXinUtils.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());
//簽名數據
Map<String, String> reqData = new HashMap();
reqData.put("appid", appid);
reqData.put("mch_id",mch_id);
reqData.put("nonce_str",nonce_str);
reqData.put("sign_type",MD5);
reqData.put("body",subject);
reqData.put("out_trade_no",out_trade_no );
reqData.put("total_fee",finalmoney );
reqData.put("spbill_create_ip",spbill_create_ip );
reqData.put("notify_url",notify_url);
reqData.put("trade_type",tradeType );
reqData.put("product_id",orderNum);
//簽名MD5加密
String sign = null;
try {
logger.info("簽名數據:"+reqData);
System.out.println("reqData="+reqData);
sign = WeiXinUtils.generateSignature(reqData,Key, MD5);
} catch (Exception e) {
logger.error("微信簽名數據:"+e);
entity.setMessage("微信簽名數據");
return entity;
}
logger.info("簽名數據:"+sign);
//封裝xml報文
String xml="<xml>"+
"<appid>"+ appid+"</appid>"+
"<mch_id>"+ mch_id+"</mch_id>"+
"<nonce_str>"+nonce_str+"</nonce_str>"+
"<sign>"+sign+"</sign>"+
"<sign_type>MD5</sign_type>"+
"<body>"+subject+"</body>"+
"<out_trade_no>"+out_trade_no+"</out_trade_no>"+
"<total_fee>"+finalmoney+"</total_fee>"+
"<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+
"<notify_url>"+notify_url+"</notify_url>"+
"<trade_type>"+tradeType+"</trade_type>"+
// "<scene_info>"+scene_info+"</scene_info>"+
"<product_id>"+orderNum+"</product_id>"+
"</xml>";
String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信統一下單接口
String code_url = "";
Map map = new HashMap();
try {
//預下單 獲取接口地址
map = WeiXinUtils.getMwebUrl(createOrderURL, xml);
String return_code = (String) map.get("return_code");
String return_msg = (String) map.get("return_msg");
if("SUCCESS".equals(return_code) && "OK".equals(return_msg)){
code_url = (String) map.get("code_url");//調微信支付接口地址
logger.info("map="+map);
entity.setFlag(true);
entity.setObject(code_url);
entity.setMessage("success");
}else{
logger.error("統一支付接口獲取預支付訂單出錯"+map);
entity.setMessage("支付錯誤");
return entity;
}
} catch (Exception e) {
logger.error("統一支付接口獲取預支付訂單出錯" + e);
entity.setMessage("支付錯誤");
return entity;
}
return entity;
}
返回值例子:
<xml><return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[000000]]></appid>
<mch_id><![CDATA[000000000]]></mch_id>
<nonce_str><![CDATA[0000000]]></nonce_str>
<sign><![CDATA[0000000]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<prepay_id><![CDATA[0000000000]]></prepay_id>
<trade_type><![CDATA[NATIVE]]></trade_type>
<code_url><![CDATA[weixin://wxpay/bizpayurl?pr=0000000000]]></code_url>
</xml>
工具類
package com.zd.exam.Unitl;
import com.zd.exam.Entity.WXPayConstants;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.springframework.stereotype.Component;
import org.xml.sax.InputSource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedInputStream;
import java.io.StringReader;
import java.security.MessageDigest;
import java.util.*;
@Component
public class WeiXinUtils {
public static Map getMwebUrl(String url, String xmlParam){
String jsonStr = null;
HttpClient httpClient = new HttpClient();
Map map = new HashMap();
try {
PostMethod method = null;
RequestEntity reqEntity = new StringRequestEntity(xmlParam,"text/json","UTF-8");
method = new PostMethod(url);
method.setRequestEntity(reqEntity);
method.addRequestHeader("Content-Type","application/json;charset=utf-8");
httpClient.executeMethod(method);
StringBuffer resBodyBuf = new StringBuffer();
byte[] responseBody = new byte[1024];
int readCount = 0;
BufferedInputStream is = new BufferedInputStream(method.getResponseBodyAsStream());
while((readCount = is.read(responseBody,0,responseBody.length))!=-1){
resBodyBuf.append(new String(responseBody,0,readCount,"utf-8"));
}
jsonStr = resBodyBuf.toString();
System.out.println(jsonStr);
map = parseXmlToList(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
/**
* description: 解析微信通知xml
*
* @param xml
* @return
* @author ex_yangxiaoyi
* @see
*/
@SuppressWarnings({ "unused", "rawtypes", "unchecked" })
public static Map parseXmlToList(String xml) {
Map retMap = new HashMap();
try {
StringReader read = new StringReader(xml);
// 創建新的輸入源SAX 解析器將使用 InputSource 對象來確定如何讀取 XML 輸入
InputSource source = new InputSource(read);
// 創建一個新的SAXBuilder
SAXBuilder sb = new SAXBuilder();
// 通過輸入源構造一個Document
Document doc = (Document) sb.build(source);
Element root = doc.getRootElement();// 指向根節點
List<Element> es = root.getChildren();
if (es != null && es.size() != 0) {
for (Element element : es) {
retMap.put(element.getName(), element.getValue());
}
}
} catch (Exception e) {
e.printStackTrace();
}
return retMap;
}
/**
* 元轉換成分
* @param amount
* @return
*/
public static String getMoney(String amount) {
if(amount==null){
return "";
}
// 金額轉化爲分爲單位
String currency = amount.replaceAll("\\$|\\¥|\\,", ""); //處理包含, ¥ 或者$的金額
int index = currency.indexOf(".");
int length = currency.length();
Long amLong = 0l;
if(index == -1){
amLong = Long.valueOf(currency+"00");
}else if(length - index >= 3){
amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));
}else if(length - index == 2){
amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);
}else{
amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");
}
return amLong.toString();
}
public final static String getMessageDigest(byte[] buffer) {
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(buffer);
byte[] md = mdTemp.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
/**
* 生成簽名. 注意,若含有sign_type字段,必須和signType參數保持一致。
*
* @param data 待簽名數據
* @param key API密鑰
* @param signType 簽名方式
* @return 簽名
*/
public static String generateSignature(final Map<String, String> data, String key, String signType) throws Exception {
Set<String> keySet = data.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()]);
Arrays.sort(keyArray);
StringBuilder sb = new StringBuilder();
for (String k : keyArray) {
if (k.equals(WXPayConstants.FIELD_SIGN)) {
continue;
}
if (data.get(k).trim().length() > 0) // 參數值爲空,則不參與簽名
sb.append(k).append("=").append(data.get(k).trim()).append("&");
}
sb.append("key=").append(key);
if (WXPayConstants.MD5.equals(signType)) {
return MD5(sb.toString()).toUpperCase();
}
else if (WXPayConstants.HMACSHA256.equals(signType)) {
return HMACSHA256(sb.toString(), key);
}
else {
throw new Exception(String.format("Invalid sign_type: %s", signType));
}
}
/**
* 生成 MD5
*
* @param data 待處理數據
* @return MD5結果
*/
public static String MD5(String data) throws Exception {
java.security.MessageDigest md = MessageDigest.getInstance("MD5");
byte[] array = md.digest(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toUpperCase();
}
/**
* 生成 HMACSHA256
* @param data 待處理數據
* @param key 密鑰
* @return 加密結果
* @throws Exception
*/
public static String HMACSHA256(String data, String key) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toUpperCase();
}
}
回調方法
@RequestMapping(value = "/notify")
public void weixinPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
BufferedReader reader = request.getReader();
String line = "";
Map map = new HashMap();
String xml = "<xml><return_code><![CDATA[FAIL]]></xml>";
;
JSONObject dataInfo = new JSONObject();
StringBuffer inputString = new StringBuffer();
while ((line = reader.readLine()) != null) {
inputString.append(line);
}
request.getReader().close();
logger.info("----接收到的報文---" + inputString.toString());
if (inputString.toString().length() > 0) {
map = WeiXinUtils.parseXmlToList(inputString.toString());
} else {
logger.info("接受微信報文爲空");
}
logger.info("map=" + map);
if (map != null && "SUCCESS".equals(map.get("result_code"))) {
//成功的業務。。。
xml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
} else {
//失敗的業務。。。
}
//告訴微信端已經確認支付成功
response.getWriter().write(xml);
}
生成二維碼路徑需要 QRCode.js 生成二維碼 具體使用方法