测试白名单也已设置。
请求路径:https://api.mch.weixin.qq.com/pay/unifiedorder
1、参数拼接(回车排序一下方便看):
appid=wxb5e39527f2f3eb32
&body=SourceTest
&mch_id=1271438801
&nonce_str=ns64Mu07nTYX2iPZ
¬ify_url=http://fanbingjiang.gicp.net/s/store/front/wxpay
&openid=oi18Jv38WxdxKEXF9ER-8mIyYya4
&out_trade_no=1234567891
&spbill_create_ip=58.42.242.98
&total_fee=1123
&trade_type=JSAPI
&key=36cd38f49b9afa08222c0dc9ebfe35eb
2、生成sign:54511A905603EDE7CED60F5643845EC7
3、拼接请求xml文件(顺序与第1步参数拼接一样):
globals这个类是读取配置文件的类
参考jeesite
微信支付工具类
package com.thinkgem.jeesite.common.wechat;
import com.thinkgem.jeesite.common.config.Global;
import java.text.DecimalFormat;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;
/**
* 微信支付
* Created by yuhaiming on 2016/11/18 0018.
*/
public class WeChatUtil {
/**
* 基本常量设置
*/
/**
* APPID
*/
public static String APP_ID = Global.getConfig("wechat.appid");
/**
* 微信支付商户号
*/
public static String MCH_ID= Global.getConfig("wechat.mch_id");
/**
* 请求路径
*/
public static String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
/**
* 密匙
*/
public static String API_KEY = Global.getConfig("wechat.key");
/**
* 发起支付IP
*/
public static String CREATE_IP = "112.117.94.77";
/**
* 回调url
*/
public static String NOTIFY_URL = "http%3a%2f%2fqqz33fe9841.ngrok.wendal.cn%2fapp%2fhome%2f";
/**
* 生成微信签名
* @param order_id
* 订单ID
* @param body
* 描述
* @param order_price
* 价格
* @return
*/
public static String GetWeChatXML(String order_id, String body, double order_price ){
String currTime = PayCommonUtil.getCurrTime();
String strTime = currTime.substring(8, currTime.length());
String strRandom = PayCommonUtil.buildRandom(4) + "";
//随机字符串
String nonce_str = strTime + strRandom;//UUID.randomUUID().toString();
nonce_str=nonce_str.substring(0,16);
// 获取发起电脑 ip
String spbill_create_ip = WeChatUtil.CREATE_IP;
// 回调接口
String notify_url = WeChatUtil.NOTIFY_URL;
//交易类型
String trade_type = "JSAPI";
//微信价格最小单位分 转换为整数
DecimalFormat df = new DecimalFormat("#######.##");
order_price = order_price * 100;
order_price = Math.ceil(order_price);
String price = df.format(order_price);
SortedMap
package com.thinkgem.jeesite.common.wechat;
import java.text.SimpleDateFormat;
import java.util.*;
public class PayCommonUtil {
/**
* 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
* @return boolean
*/
@SuppressWarnings("unchecked")
public static boolean isTenpaySign(String characterEncoding, SortedMap packageParams, String API_KEY) {
StringBuffer sb = new StringBuffer();
Set> es = packageParams.entrySet();
Iterator> it = es.iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String k = (String)entry.getKey();
String v = (String)entry.getValue();
if(!"sign".equals(k) && null != v && !"".equals(v)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + API_KEY);
//算出摘要
String mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();
String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();
//System.out.println(tenpaySign + " " + mysign);
return tenpaySign.equals(mysign);
}
/**
* @Description:sign签名
* @param characterEncoding
* 编码格式
* @param packageParams
* 请求参数
* @param API_KEY
* @return
*/
@SuppressWarnings("unchecked")
public static String createSign(String characterEncoding, SortedMap packageParams, String API_KEY) {
StringBuffer sb = new StringBuffer();
Set> es = packageParams.entrySet();
Iterator> it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
// if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k) && !"notify_url".equals(k)&& !"out_trade_no".equals(k)&& !"spbill_create_ip".equals(k)&& !"total_fee".equals(k)&& !"trade_type".equals(k)) {
if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k) ) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + API_KEY);
// String stringA="appid=wxc7b425229b570867&mch_id=1406330002&nonce_str=1702585759&key=ab42e0b7aa6bce35164a2d14855d7264";
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
// String sign = MD5Util.MD5Encode(stringA, characterEncoding).toUpperCase();
// System.out.println(sign);
// System.out.println(MD5Util.MD5Encode("appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA&key=192006250b4c09247ec02edce69f6a2d", characterEncoding).toUpperCase());
// System.out.println(sign);
return sign;
}
/**
* @author
* @date 2016-4-22
* @Description:将请求参数转换为xml格式的string
* @param parameters
* 请求参数
* @return
*/
@SuppressWarnings("unchecked")
public static String getRequestXml(SortedMap parameters) {
StringBuffer sb = new StringBuffer();
sb.append("");
Set> es = parameters.entrySet();
Iterator> it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
sb.append("<" + k + ">" + "" + k + ">");
} else {
sb.append("<" + k + ">" + v + "" + k + ">");
}
}
sb.append(" ");
return sb.toString();
}
/**
* 取出一个指定长度大小的随机正整数.
*
* @param length
* int 设定所取出随机数的长度。length小于11
* @return int 返回生成的随机数。
*/
public static int buildRandom(int length) {
int num = 1;
double random = Math.random();
if (random < 0.1) {
random = random + 0.1;
}
for (int i = 0; i < length; i++) {
num = num * 10;
}
return (int) ((random * num));
}
/**
* 获取当前时间 yyyyMMddHHmmss
*
* @return String
*/
public static String getCurrTime() {
Date now = new Date();
SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String s = outFormat.format(now);
return s;
}
}
package com.thinkgem.jeesite.common.wechat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
public class HttpUtil {
// private static final Log logger = Logs.get();
private final static int CONNECT_TIMEOUT = 5000; // in milliseconds
private final static String DEFAULT_ENCODING = "UTF-8";
public static String postData(String urlStr, String data){
return postData(urlStr, data, null);
}
public static String postData(String urlStr, String data, String contentType){
BufferedReader reader = null;
try {
URL url = new URL(urlStr);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
conn.setConnectTimeout(CONNECT_TIMEOUT);
conn.setReadTimeout(CONNECT_TIMEOUT);
if(contentType != null)
conn.setRequestProperty("content-type", contentType);
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);
if(data == null)
data = "";
writer.write(data);
writer.flush();
writer.close();
reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line);
sb.append("\r\n");
}
return sb.toString();
} catch (IOException e) {
// logger.logError("Error connecting to " + urlStr + ": " + e.getMessage());
} finally {
try {
if (reader != null)
reader.close();
} catch (IOException e) {
}
}
return null;
}
}
String order_id="e3177146e5";
String body="彼得潘";
Double order =0.01;
Map xmlMap = new HashMap<>();
Map resMap = new HashMap<>();
//生成签名
String xml = WeChatUtil.GetWeChatXML(order_id,body,order);
xmlMap = XMLUtil.doXMLParse(xml);
//统一下单
String SubmitResult = HttpUtil.postData(WeChatUtil.UFDODER_URL,xml);
SortedMap SubmitMap = new TreeMap();
//解析XML
resMap = XMLUtil.doXMLParse(SubmitResult);
String result_code = resMap.get("result_code");
if("SUCCESS".equals(result_code)) {
//appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式为Sign=WXPay
SubmitMap.put("appid", WeChatUtil.APP_ID);
SubmitMap.put("partnerid", WeChatUtil.MCH_ID);
SubmitMap.put("prepayid", resMap.get("prepay_id"));
SubmitMap.put("noncestr", resMap.get("nonce_str"));
Long time = (System.currentTimeMillis() / 1000);
SubmitMap.put("timestamp", time.toString());
SubmitMap.put("package", "Sign=WXPay");
//第二次生成签名
String sign = PayCommonUtil.createSign("UTF-8", SubmitMap, WeChatUtil.API_KEY);
SubmitMap.put("sign", sign);
}
在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。
最后 提醒各位 注意一下几点
1.支付签名是需要签名两次
2.检查key设置是否正确
尝试很多种方法都是签名错误 最后怀疑是不是KEY的问题 没想到真是
key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置