原创

微信支付

微信支付相关签名,以及踩过的坑,以及退款接口,签名各项请查看微信开放平台说明。

public static Map<String, Object> jspay(String videoTitlel,String openid,String orderID,String totalFee, String weixinAppid,
String weixinAppsecret, String weixinSpnumber ,String userIP,String notify_url) throws XmlPullParserException, IOException, DocumentException {
String attach = "测试统一下单";
String nonceStr = WxSignUtils.getNonceStr();
SortedMap<String, String> param = new TreeMap<String, String>();
param.put("appid", weixinAppid);
param.put("mch_id", weixinSpnumber);
param.put("nonce_str", nonceStr);
param.put("body", videoTitlel);
param.put("attach", attach);
param.put("out_trade_no", orderID);
BigDecimal bigDecimal = new BigDecimal(totalFee);
BigDecimal multiply = bigDecimal.multiply(new BigDecimal(100));
System.out.println("转换后的钱数======"+multiply.intValue()+"");
param.put("total_fee", multiply.intValue()+"");
param.put("spbill_create_ip", userIP);
param.put("openid", openid);
param.put("notify_url", notify_url);
param.put("trade_type", "JSAPI");
String sign = WxSignUtils.createSign("UTF-8",param,weixinAppsecret);
param.put("sign", sign);
String xml = ArrayToXml(param);
String xmlStr = WxSignUtils.httpsRequest(PayCommon.wx_unifiedorder, "POST", xml);
System.out.println(xmlStr);
// 预付商品id
String prepay_id = "";
if (xmlStr.indexOf("SUCCESS") != -1) {
Map<String, String> map = XmlUtils.parseXmlStr(xmlStr);
prepay_id = (String) map.get("prepay_id");
}
String create_timestamp = WxSignUtils.create_timestamp();
SortedMap<String, String> payMap = new TreeMap<String, String>();
payMap.put("appId", weixinAppid);
payMap.put("timeStamp", create_timestamp);
payMap.put("nonceStr", nonceStr);
payMap.put("signType", "MD5");
payMap.put("package", "prepay_id=" + prepay_id);
String paySign = WxSignUtils.createSign("UTF-8",payMap,weixinAppsecret);
payMap.put("pg", prepay_id);
payMap.put("paySign", paySign);
Map<String, Object> resultMap = new HashMap<String, Object>();
resultMap.put("appid", weixinAppid);
resultMap.put("timestamp", create_timestamp);
resultMap.put("noncestr",nonceStr);
resultMap.put("signType","MD5");
resultMap.put("package","prepay_id=" + prepay_id);
resultMap.put("pg", prepay_id);
resultMap.put("paySign", paySign);
System.out.println(resultMap);
System.out.println(prepay_id);
return resultMap;
}
public class WxSignUtils {
//定义签名,微信根据参数字段的ASCII码值进行排序 加密签名,故使用SortMap进行参数排序
public static String createSign(String characterEncoding,SortedMap<String,String> parameters,String PARTNER_KEY){
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();
Iterator it = es.iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String k = (String)entry.getKey();
Object v = entry.getValue();
if(null != v && !"".equals(v)
&& !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + PARTNER_KEY);//最后加密时添加商户密钥,由于key值放在最后,所以不用添加到SortMap里面去,单独处理,编码方式采用UTF-8
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}

/**
* @Title: getNonceStr
* @Description: 获取随机字符串
* @author pj
* @date 2019年8月11日 下午5:38:22
* @return
*/
public static String getNonceStr() {
Random random = new Random();
return MD5Util.MD5Encode(String.valueOf(random.nextInt(10000)), "UTF-8");
}
public static String getTimeStamp() {
return String.valueOf(System.currentTimeMillis() / 1000);
}
public static String getSign(Map<String, String> params, String paternerKey )
throws UnsupportedEncodingException {
String string1 = createSign(params, false);
String stringSignTemp = string1 + "&key=" + paternerKey;
String signValue = DigestUtils.md5Hex(stringSignTemp).toUpperCase();
return signValue;
}
public static String createSign(Map<String, String> params, boolean encode) throws UnsupportedEncodingException {
Set<String> keysSet = params.keySet();
Object[] keys = keysSet.toArray();
Arrays.sort(keys);
StringBuffer temp = new StringBuffer();
boolean first = true;
for (Object key : keys) {
if (first) {
first = false;
} else {
temp.append("&");
}
temp.append(key).append("=");
Object value = params.get(key);
String valueString = "";
if (null != value) {
valueString = value.toString();
}
if (encode) {
temp.append(URLEncoder.encode(valueString, "UTF-8"));
} else {
temp.append(valueString);
}
}
return temp.toString();
}

/**
* 解析XML
* */
public static String getRequestXml(Map<String, String> packageParams){
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
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 ("attach".equalsIgnoreCase(k)||"body".equalsIgnoreCase(k)||"sign".equalsIgnoreCase(k)) {
sb.append("<"+k+">"+"<![CDATA["+v+"]]></"+k+">");
}else {
sb.append("<"+k+">"+v+"</"+k+">");
}
}
sb.append("</xml>");
return sb.toString();
}
/**
* map转成xml
*
* @param arr
* @return
*/
public static String ArrayToXml(Map<String, String> arr) {
String xml = "<xml>";

Iterator<Entry<String, String>> iter = arr.entrySet().iterator();
while (iter.hasNext()) {
Entry<String, String> entry = iter.next();
String key = entry.getKey();
String val = entry.getValue();
xml += "<" + key + ">" + val + "</" + key + ">";
}

xml += "</xml>";
return xml;
}
/**
* 发送https请求
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return 返回微信服务器响应的信息
*/
public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
MyX509TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream=null;
try {
inputStream = conn.getInputStream();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
return buffer.toString();
} catch (ConnectException ce) {
//log.error("连接超时:{}", ce);
} catch (Exception e) {
//log.error("https请求异常:{}", e);
}
return null;
}
public static Map<String, String> doXMLParse(String xml)
throws XmlPullParserException, IOException {
InputStream inputStream = new ByteArrayInputStream(xml.getBytes());
Map<String, String> map = null;
XmlPullParser pullParser = XmlPullParserFactory.newInstance()
.newPullParser();
pullParser.setInput(inputStream, "UTF-8"); // 为xml设置要解析的xml数据
int eventType = pullParser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_DOCUMENT:
map = new HashMap<String, String>();
break;
case XmlPullParser.START_TAG:
String key = pullParser.getName();
if (key.equals("xml"))
break;
String value = pullParser.nextText();
map.put(key, value);
break;
case XmlPullParser.END_TAG:
break;
}
eventType = pullParser.next();
}
return map;
}
public static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
/**
* @Title: getSha1
* @Description: 创建Sha1签名
* @author pj
* @date 2019年8月11日 下午5:38:54
* @param str
* @return
*/
public static String getSha1(String str) {
if (str == null || str.length() == 0) {
return null;
}
char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };

try {
MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
mdTemp.update(str.getBytes("GBK"));

byte[] md = mdTemp.digest();
int j = md.length;
char buf[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
buf[k++] = hexDigits[byte0 & 0xf];
}
return new String(buf);
} catch (Exception e) {
return null;
}
}
}

以上是微信统一下单接口签名。话不多说直接上退款接口实例代码。

public static Map<String, String> jspayRefund(String AppID,String mchId,String orderNum,
String outTradeNo,String weixinAppsecret, int totalFee ,int refundFee) throws Exception {
Map<String, String> packageParams = new HashMap<String, String>();
packageParams.put("appid", AppID);
packageParams.put("mch_id", mchId);
packageParams.put("nonce_str",WxSignUtils.getNonceStr());
packageParams.put("out_refund_no",outTradeNo);
packageParams.put("out_trade_no",orderNum);
packageParams.put("refund_fee",totalFee+"");
packageParams.put("total_fee", refundFee+"");
String sign = WxSignUtils.getSign(packageParams, weixinAppsecret);
packageParams.put("sign", sign);
String reuqestXml = WxSignUtils.getRequestXml(packageParams);
String xmlStr = ClientCustomSSL.doRefund(PayCommon.wx_refund, reuqestXml);;
Map<String, String> params = new HashMap<String, String>();
if(xmlStr!=null){
Map<String, String> map = XmlUtils.parseXmlStr(xmlStr);
if("SUCCESS".equals(map.get("result_code"))){
params.put("msg", "0");
System.out.println("退款成功");
}else{
System.out.println("退款失败");
params.put("msg", "1");
}
}
return params;
}


正文到此结束