官方文档 :https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=23_1

微信支付PC二维码支付:https://www.cnblogs.com/pxblog/p/10542917.html

公众号支付:https://www.cnblogs.com/pxblog/p/12815705.html

在做沙箱测试的时候,微信支付里面的金额固定的,其他金额是无效的。需要按照文档来输入。金额必须是(1.01)

<xml>
<return_code><![CDATA[FAIL]]></return_code>
<return_msg><![CDATA[沙箱支付金额(1)无效,请检查需要验收的case]]></return_msg>
</xml>

这里需要用到沙箱秘钥来替换签名中的key,同样验签的时候也是同样用沙箱秘钥获取签名,沙箱秘钥的获取方法

微信支付仿真测试系统(后简称仿真系统)的简化原理图。仿真系统的API协议与正式API完全相同(API接口文档)。商户开发者只需将正式API的调用URL增加一层sandboxnew路径,即可对接到仿真系统。

例如,付款码支付URL:https://api.mch.weixin.qq.com/pay/micropay

变更为:https://api.mch.weixin.qq.com/sandboxnew/pay/micropay。

仿真系统与生产环境完全独立,包括存储层。商户在仿真系统所做的所有交易(如下单、支付、查询)均为无资金流的假数据,即:用户无需真实扣款,商户也不会有资金入账。代金券同理,沙箱环境中无需商户真实制券与发券,亦不会出现真实扣券情况。验收仿真测试系统的API验签密钥需从API获取:

支付的接口地址改为:

https://api2.mch.weixin.qq.com/sandboxnew/pay/unifiedorder
<xml>
<return_code><![CDATA[FAIL]]></return_code>
<return_msg><![CDATA[沙箱验证签名失败,请确认沙箱签名key是否正确(通过getsignkey调用生成)]]></return_msg>
</xml>

需要引入

commons-lang-2.4.jar、jdom-1.1.3.jar

getSignKeyUtils.java 工具类

package com.jetcms.weixinpay;

import org.apache.commons.lang.StringUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder; import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.util.*; public class getSignKeyUtils { /**
* 获取微信支付沙箱API验签密钥 (调用该方法生成)
* @param nonce_str 随机字符串 生成方法:RandomStringUtils.random(10, N62_CHARS);
* @param mchId 正式的商户号
* @param apiKey 正式的密钥
* @return
*/
public static String getSignKey(String nonce_str,String mchId,String apiKey) {
Map<String, String> param = new HashMap<String, String>();
param.put("mch_id", mchId);//需要真实商户号
param.put("nonce_str", nonce_str);//随机字符
String sign = createSign(param, apiKey);//通过SDK生成签名其中API_KEY为商户对应的真实密钥
param.put("sign", sign);
String xml = assembParamToXml(param);//将map转换为xml格式
String url = "https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey";//沙箱密钥获取api
Map<String, String> param1 = new HashMap<String, String>();
String resXml = post(url, xml);
try {
if (StringUtils.isNotBlank(resXml)) {
param1 = parseXMLToMap(resXml);
}
} catch (Exception e) {
e.printStackTrace();
}
String key = param1.get("sandbox_signkey");
return key;
} /**
* 微信支付签名sign
* @param param
* @param key
* @return
*/
@SuppressWarnings("unchecked")
public static String createSign(Map<String, String> param,String key){
//签名步骤一:按字典排序参数
List list=new ArrayList(param.keySet());
Object[] ary =list.toArray();
Arrays.sort(ary);
list=Arrays.asList(ary);
String str="";
for(int i=0;i<list.size();i++){
str+=list.get(i)+"="+param.get(list.get(i)+"")+"&";
}
//签名步骤二:加上key
str+="key="+key;
//步骤三:加密并大写
str= MD5Encode(str,"utf-8").toUpperCase();
return str;
} /**
* 将需要传递给微信的参数转成xml格式
* @param parameters
* @return
*/
public static String assembParamToXml(Map<String,String> parameters){
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Set<String> es = parameters.keySet();
List<Object> list=new ArrayList<Object>(es);
Object[] ary =list.toArray();
Arrays.sort(ary);
list=Arrays.asList(ary);
Iterator<Object> it = list.iterator();
while(it.hasNext()) {
String key = (String) it.next();
String val=(String) parameters.get(key);
if ("attach".equalsIgnoreCase(key)||"body".equalsIgnoreCase(key)||"sign".equalsIgnoreCase(key)) {
sb.append("<"+key+">"+"<![CDATA["+val+"]]></"+key+">");
}else {
sb.append("<"+key+">"+val+"</"+key+">");
}
}
sb.append("</xml>");
return sb.toString();
} public static String post(String urlStr,String xmlInfo) {
String line1 = "";
try {
URL url = new URL(urlStr);
URLConnection con = url.openConnection();
con.setDoOutput(true);
con.setRequestProperty("Cache-Control", "no-cache");
con.setRequestProperty("Content-Type", "text/xml"); OutputStreamWriter out = new OutputStreamWriter(con
.getOutputStream());
out.write(new String(xmlInfo.getBytes("utf-8")));
out.flush();
out.close();
BufferedReader br = new BufferedReader(new InputStreamReader(con
.getInputStream()));
String line = "";
for (line = br.readLine(); line != null; line = br.readLine()) {
line1+=line;
}
return new String(line1.getBytes(),"utf-8");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
} /**
* 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
* @param strxml
* @return
* @throws JDOMException
* @throws IOException
*/
public static Map parseXMLToMap(String strxml) throws JDOMException, IOException {
strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
if(null == strxml || "".equals(strxml)) {
return null;
}
Map m = new HashMap();
InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
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;
} /**
* 62个字母和数字,含大小写
*/
public static final char[] N62_CHARS = {'0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z'}; public static String MD5Encode(String origin,String charsetName){
String resultString=null;
try{
resultString=new String(origin);
MessageDigest md=MessageDigest.getInstance("MD5");
if(StringUtils.isBlank(charsetName)){
resultString=byteArrayToHexString(md.digest(resultString.getBytes()));
}else{
resultString=byteArrayToHexString(md.digest(resultString.getBytes(charsetName)));
}
}catch(Exception e){ }
return resultString;
} public static String byteArrayToHexString(byte b[]){
StringBuffer resultSb=new StringBuffer();
for(int i=0;i<b.length;i++){
resultSb.append(byteToHexString(b[i]));
}
return resultSb.toString();
} /**
* 获取子结点的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 String byteToHexString(byte b){
int n=b;
if(n<0){
n+=256;
}
int d1=n/16;
int d2=n%16;
return hexDigits[d1]+hexDigits[d2];
} public static final String hexDigits[]={ "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}

这个在进入支付操作页面的时候就会进行支付回调,所以不用进行扫码支付操作!!!

最新文章

  1. Eclipse导出插件工程
  2. WPFTookit Chart 入门
  3. Pywinauto在Windows Twain Driver自动化测试中的应用研究
  4. uva12169 Disgruntled Judge
  5. Java [leetcode 23]Merge k Sorted Lists
  6. 批量执行插入的sql和自动补零
  7. 【劳动节江南白衣Calvin 】我的后端开发书架2015
  8. 注解在android中的使用
  9. (转)cin、cin.get()、cin.getline()、getline()、gets()等函数的用法
  10. STL中map用法
  11. 解决xtrabackup command not found no mysqld group 问题
  12. nginx 高可用
  13. 移动端HTML5性能优化
  14. 以太坊挖矿源码:ethash算法
  15. 计蒜客NOIP模拟赛6 D1T1Diamond-square
  16. 安卓——Activity生命周期
  17. 一学期积累下来的SQL语句写法的学习
  18. [转载]ArcGIS SERVER 9.3如何清除REST缓存
  19. 一个例子来看C#泛型是如何登场的
  20. 2018.09.16 spoj104Highways (矩阵树定理)

热门文章

  1. UOJ #129 / BZOJ 4197 / 洛谷 P2150 - [NOI2015]寿司晚宴 (状压dp+数论+容斥)
  2. 【豆科基因组】大豆适应性位点GWAS分析 [转载]
  3. MetaboAnalyst的多组学分析
  4. python13各种器
  5. WPS表格数据透视表的美化和布局
  6. c#页面查询、数据显示
  7. .NET Core基础篇之:集成Swagger文档与自定义Swagger UI
  8. 基于 Golang 构建高可扩展的云原生 PaaS(附 PPT 下载)
  9. Hive(二)【数据类型、类型转换】
  10. 2021广东工业大学十月月赛 F-hnjhd爱序列