• 相比支付宝的接口,微信的接口与实现都很简单其实,官方文档都有很详细的讲解。 官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4 步骤: 1.下载 安全证书!!【关键】 2.按官方...

    相比支付宝的接口,微信的接口与实现都很简单其实,官方文档都有很详细的讲解。

    官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4


    步骤:

    1.下载 安全证书!!【关键】

    2.按官方文档组织参数,生成URL

    3.CURL等同步访问URL,获取XML返回值

    4.自己系统的回调验证,完成自己系统退款的后续操作



    一.证书的配置与下载

    路径下载:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->证书下载 。证书文件有四个,全部下载即可。






    二.配置参数

    array(
    		'appid'=>'your_appid',//应用ID,固定
    		'mch_id'=>'your_mch_id',//商户号,固定
    		'nonce_str'=>'123456',//随机字符串
    		'op_user_id'=>'646131',//操作员
    		'out_refund_no'=>'201608142308',//商户内部唯一退款单号
    		'out_trade_no'=>'860524080535541654',//商户订单号,pay_sn码 1.1二选一,微信生成的订单号,在支付通知中有返回
    		// 'transaction_id'=>'1',//微信订单号 1.2二选一,商户侧传给微信的订单号
    		'refund_fee'=>'3',//退款金额
    		'total_fee'=>'3',//总金额
    		'sign'=>$ref//签名
    	);



    三.注意事项

    常见问题:

    1. 本接口是需要证书的,下载放上见上边

    2. 微信的接口里,所有对金额的描述,都是以分为单位的

    3.交易时间超过一年的订单无法提交退款;

    4.微信支付退款支持单笔交易分多次退款,多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。一笔退款失败后重新提交,要采用原来的退款单号。总退款金额不能超过用户实际支付金额。

    5.在用下边demo做测试的时候,请先真实支付一次,获取相应的ID与参数,然后直接运行调试即可,仅供参考

    6.注意下签名规则




    7.CURL 返回值为58
        答: 证书路径问题,证书路径应该为物理全路径getcwd().'/apiclient_cert.pem'这种写法 或者自己函数获取

    8.CURL 返回值为77
        答:证书问题,重新下载证书,按照配置对应放在生产路径,同上一条,用全的物理路径


    <err_code><![CDATA[TRADE_STATE_ERROR]]></err_code>

    <err_code_des><![CDATA[订单状态错误]]></err_code_des>

    原因:out_trade_no错误【out_trade_no为自己系统生产的支付码】


    <err_code><![CDATA[ORDERNOTEXIST]]></err_code>

    <err_code_des><![CDATA[订单不存在]]></err_code_des>

    原因:out_trade_no不存在,也是就说没有这笔支付号


    demo源码

    <?php
    /*
    请确保您的libcurl版本是否支持双向认证,版本高于7.20.1
    */
    
    function Home_index(){
       $ref= strtoupper(md5("appid=your_appid&mch_id=your_mch_id&nonce_str=123456&op_user_id=646131"
          . "&out_refund_no=201608142308&out_trade_no=860524080535541654&refund_fee=3&total_fee=3"
          . "&key=suiji123"));//sign加密MD5
    
       $refund=array(
          'appid'=>'your_appid',//应用ID,固定
          'mch_id'=>'your_mch_id',//商户号,固定
          'nonce_str'=>'123456',//随机字符串
          'op_user_id'=>'646131',//操作员
          'out_refund_no'=>'201608142308',//商户内部唯一退款单号
          'out_trade_no'=>'860524080535541654',//商户订单号,pay_sn码 1.1二选一,微信生成的订单号,在支付通知中有返回
          // 'transaction_id'=>'1',//微信订单号 1.2二选一,商户侧传给微信的订单号
          'refund_fee'=>'3',//退款金额
          'total_fee'=>'3',//总金额
          'sign'=>$ref//签名
       );
    
       $url="https://api.mch.weixin.qq.com/secapi/pay/refund";;//微信退款地址,post请求
       $xml=arrayToXml($refund);
    
       $ch=curl_init();
       curl_setopt($ch,CURLOPT_URL,$url);
       curl_setopt($ch,CURLOPT_HEADER,1);
       curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
       curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,1);//证书检查
       curl_setopt($ch,CURLOPT_SSLCERTTYPE,'pem');
       curl_setopt($ch,CURLOPT_SSLCERT,dirname(__FILE__).'/cert/apiclient_cert.pem');
       curl_setopt($ch,CURLOPT_SSLCERTTYPE,'pem');
       curl_setopt($ch,CURLOPT_SSLKEY,dirname(__FILE__).'/cert/apiclient_key.pem');
       curl_setopt($ch,CURLOPT_SSLCERTTYPE,'pem');
       curl_setopt($ch,CURLOPT_CAINFO,dirname(__FILE__).'/cert/rootca.pem');
       curl_setopt($ch,CURLOPT_POST,1);
       curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
    
       $data=curl_exec($ch);
       if($data){ //返回来的是xml格式需要转换成数组再提取值,用来做更新
          curl_close($ch);
          var_dump($data);
       }else{
          $error=curl_errno($ch);
          echo "curl出错,错误代码:$error"."<br/>";
          echo "<a href='http://curl.haxx.se/libcurl/c/libcurs.html'>;错误原因查询</a><br/>";
          curl_close($ch);
          echo false;
       }
    }
    function arrayToXml($arr){
       $xml = "<root>";
       foreach ($arr as $key=>$val){
          if(is_array($val)){
             $xml.="<".$key.">".arrayToXml($val)."</".$key.">";
          }else{
             $xml.="<".$key.">".$val."</".$key.">";
          }
       }
       $xml.="</root>";
       return $xml ;
    }
    Home_index();



    四.退款查询接口

    如果上述退款调通了的话,那这个接口更简单了,只要把上述demo的参数换成退款查询的参数即可,这里就不赘述了

    官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5


    $url = https://api.mch.weixin.qq.com/pay/refundquery


    请求参数

    字段名 变量名 必填 类型 示例值 描述
    公众账号ID appid String(32) wx8888888888888888 微信分配的公众账号ID(企业号corpid即为此appId)
    商户号 mch_id String(32) 1900000109 微信支付分配的商户号
    设备号 device_info String(32) 013467007045764 商户自定义的终端设备号,如门店编号、设备的ID等
    随机字符串 nonce_str String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,不长于32位。推荐随机数生成算法
    签名 sign String(32) C380BEC2BFD727A4B6845133519F3AD6 签名,详见签名生成算法
    微信订单号 transaction_id 四选一 String(32) 1217752501201407033233368018 微信订单号
    商户订单号 out_trade_no String(32) 1217752501201407033233368018 商户系统内部的订单号
    商户退款单号 out_refund_no String(32) 1217752501201407033233368018 商户侧传给微信的退款单号
    微信退款单号 refund_id String(28) 1217752501201407033233368018

    微信生成的退款单号,在申请退款接口有返回

    举例如下:

    <xml>
       <appid>wx2421b1c4370ec43b</appid>
       <mch_id>10000100</mch_id>
       <nonce_str>0b9f35f484df17a732e537c37708d1d0</nonce_str>
       <out_refund_no></out_refund_no>
       <out_trade_no>1415757673</out_trade_no>
       <refund_id></refund_id>
       <transaction_id></transaction_id>
       <sign>66FFB727015F450D167EF38CCC549521</sign>
    </xml>



    展开全文
  • 1、商户号(或同主体其他非服务商商户号)已入驻90日 2、截止今日回推30天,商户号(或同主体其他非服务商商户号)连续不间断保持有交易 3、登录微信支付商户平台-产品中心,开通企业付款。 需要去商户平台配置 ...

    使用条件

     1、商户号(或同主体其他非服务商商户号)已入驻90日

      2、截止今日回推30天,商户号(或同主体其他非服务商商户号)连续不间断保持有交易

      3、 登录微信支付商户平台-产品中心,开通企业付款。

    需要去商户平台配置

      1,企业付款到零钱需要证书,需要下载证书

      2,需要设置支付白名单,放开一下ip地址,ip地址是要外网ip,域名不行,只能是ip地址,配置的方法是:账户中心》api安全,把你的外网ip写进去就ok了。

    下面直接上代码了。

    企业付款到零钱支付常量类,这里需要注意的是证书,证书的位置可以放在,如图所示,这个位置,这样就可以读取到了

     

    支付常类,企业付款到零钱没有回调地址,可以不写。支付要用到,这里的配置这样写不太好,正确的写发是放在配置文件里面,然后去读配置文件,这里就先这样写了

    package com.util;
    /**
     * 支付常量类
     */
    
    public class WXPayConstant {
    	
    	/**
    	 * 小程序 appId
    	 */
    	public static final String APP_ID = "";
    	/**
    	 * 商户id
    	 */
    	public static final String MCH_ID = "";
    	/**
    	 * 支付密钥
    	 */
    	public static final String PAY_APP_SECRET = "";
    
    	/**
    	 * 支付回调地址
    	 */
    	public static final String PAY_NOTIFY_URL = "";
    	
    	/**
    	 * 统一下单API接口链接
    	 */
    	public static final String PAY_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    	/**
    	 * 证书名字
    	 */
    	public static final String CLIENT_CERT_NAME = "cart/apiclient_cert.p12";
    
    	/**
    	 * 微信退款接口
    	 */
    	public static final String WEIXIN_REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
    
    }
    

     

     

    业务处理类,退款需要2个参数,一个是appendid(openid),一个是money

    
    	
    	@Autowired
    	private RedisTemplate<String, String> redisTemplate;
    	
    	public Object Presentation(String appendid, String money) {
    		String key = WXPayConstant.PAY_APP_SECRET;
     
    		// 1.0 拼凑企业支付需要的参数
    		String appid = WXPayConstant.APP_ID; // 微信公众号的appid
    		String mch_id = WXPayConstant.MCH_ID; // 商户号
    		//String nonce_str = CreateRandomUtil.getRandom(20);// 随机字符串
    		String nonce_str =CreateRandomUtil.getRandom(20);// 随机字符串
    		String partner_trade_no="";
    		synchronized (this) {
    			 partner_trade_no = orderNo("T");// 商户订单号
    		}
    		String openid = appendid; // 支付给用户openid
    		String check_name = "NO_CHECK"; // 是否验证真实姓名呢
    		String re_user_name = "KOLO"; // 收款用户姓名(非必须)
    		
    		BigDecimal tmoney=new BigDecimal("100");
    		BigDecimal newtmoney=new BigDecimal(money);
    		money=newtmoney.multiply(tmoney).toString();
    		
    		Integer aaaaaaa= newtmoney.multiply(tmoney).intValue();
    		String amount = aaaaaaa.toString(); // 企业付款金额,最少为100,单位为分
    		
    		String desc = "恭喜你,提现成功"; // 企业付款操作说明信息。必填。
    		String spbill_create_ip = "127.0.0.1"; // 用户的ip地址
    		// 2.0 生成map集合
    	    SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();    
    		//Map<String, String> packageParams = new HashMap<String, String>();
    		packageParams.put("mch_appid", appid); // 微信公众号的appid
    		packageParams.put("mchid", mch_id); // 商务号
    		packageParams.put("nonce_str", nonce_str); // 随机生成后数字,保证安全性
    		packageParams.put("partner_trade_no", partner_trade_no); // 生成商户订单号
    		packageParams.put("openid", openid); // 支付给用户openid
    		packageParams.put("check_name", check_name); // 是否验证真实姓名呢
    		packageParams.put("re_user_name", re_user_name);// 收款用户姓名
    		packageParams.put("amount", amount); // 企业付款金额,单位为分
    		packageParams.put("desc", desc); // 企业付款操作说明信息。必填。
    		packageParams.put("spbill_create_ip", spbill_create_ip); // 调用接口的机器Ip地址
     
    		try {
                //3.0 签名
    		    String sign = XMLUtil.createSign("UTF-8", packageParams,key);  //获取签名  
    			packageParams.put("sign", sign);
    			// 5.0将当前的map结合转化成xml格式
    			//String xml = WXPayUtil.mapToXml(packageParams);
    			String xml = XMLUtil.getRequestXml(packageParams);//将请求参数转换成xml类型    
    			//String xml = MessageUtil.messageToXML(packageParams);// 打包要发送的xml
    			// 6.0获取需要发送的url地址
    			String wxUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; // 获取退款的api接口
    			System.out.println("发送前的xml为:" + xml);
    			// 7,向微信发送请求转账请求
    			String returnXml = CertHttpUtil.postData(wxUrl, xml, WXPayConstant.MCH_ID, WXPayConstant.CLIENT_CERT_NAME);
    			System.out.println("返回的returnXml为:" + returnXml);
    			// 8,将微信返回的xml结果转成map格式
    			Map returnMap = XMLUtil.doXMLParse(returnXml); 
    			
    			
    			if (returnMap.get("return_code").equals("SUCCESS")&&returnMap.get("return_msg").equals("")) {
    				//写你要处理的逻辑,一般是操作数据库,写公司的业务逻辑
    				return "退款成功 ";
    			
    			}
    			return "退款失败 ";
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		return null;
    	}
    	
    
    /**
    	 * 生成订单号
    	 * 
    	 * @param type
    	 *            订单类型
    	 * @return
    	 */
    	private String orderNo(String type) {
    		String yyMMdd = type + new SimpleDateFormat("yyMMdd").format(new Date());
    		if (!redisTemplate.hasKey(yyMMdd)) {
    			redisTemplate.opsForValue().set(yyMMdd, "0", 60 * 60 * 24, TimeUnit.SECONDS);
    		}
    		Long num = redisTemplate.opsForValue().increment(yyMMdd, 1);
    		return yyMMdd + String.format("%05d", num);
    	}
    
    
    

     

    发送请求转账消息 和加载证书 的util: CertHttpUtil

    package com.util;
    
    import java.io.IOException;
    
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.security.KeyStore;
     
    import javax.net.ssl.SSLContext;
     
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLContexts;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.util.EntityUtils;
    import org.springframework.core.io.ClassPathResource;
    
    
    public class CertHttpUtil {
    	
    	//写了
    	
    	 private static int socketTimeout = 10000;// 连接超时时间,默认10秒
         private static int connectTimeout = 30000;// 传输超时时间,默认30秒
         private static RequestConfig requestConfig;// 请求器的配置
         private static CloseableHttpClient httpClient;// HTTP请求器
      
         /**
          * 通过Https往API post xml数据
          *
          * @param url API地址
          * @param xmlObj 要提交的XML数据对象
         * @param mchId 商户ID
         * @param certPath 证书位置
          * @return
          */
         public static String postData(String url, String xmlObj, String mchId, String certPath) {
             // 加载证书
             try {
                 initCert(mchId, certPath);
             } catch (Exception e) {
                 e.printStackTrace();
             }
             String result = null;
             HttpPost httpPost = new HttpPost(url);
             // 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
             StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");
             httpPost.addHeader("Content-Type", "text/xml");
             httpPost.setEntity(postEntity);
             // 根据默认超时限制初始化requestConfig
             requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
             // 设置请求器的配置
             httpPost.setConfig(requestConfig);
             try {
                 HttpResponse response = null;
                 try {
                     response = httpClient.execute(httpPost);
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
                 HttpEntity entity = response.getEntity();
                 try {
                     result = EntityUtils.toString(entity, "UTF-8");
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             } finally {
                 httpPost.abort();
             }
             return result;
         }
      
         /**
          * 加载证书
          *
          * @param mchId 商户ID
          * @param certPath 证书位置
          * @throws Exception
          */
         private static void initCert(String mchId, String certPath) throws Exception {
             // 证书密码,默认为商户ID
             String key = mchId;
             // 证书的路径
             String path = certPath;
             // 指定读取证书格式为PKCS12
             KeyStore keyStore = KeyStore.getInstance("PKCS12");
             // 读取本机存放的PKCS12证书文件  
             ClassPathResource cp = new ClassPathResource(WXPayConstant.CLIENT_CERT_NAME);
             InputStream instream = cp.getInputStream();
             try {
                 // 指定PKCS12的密码(商户ID)
                 keyStore.load(instream, key.toCharArray());
             } finally {
                 instream.close();
             }
             SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray()).build();
             SSLConnectionSocketFactory sslsf =
                     new SSLConnectionSocketFactory(sslcontext, new String[] {"TLSv1"}, null,
                             SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
             httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
         }
    
    
    
    }
    

    获取随机数的util :

    package com.util;
    
    import java.util.Random;
    
    public class CreateRandomUtil {
    	public static final String numberChar ="0123456789";
    
    	/**
    	 * 根据系统时间获得指定位数的随机数
    	*
    	 * @return 获得的随机数
    	*/
    	public static String getRandom() {
    	
    		Long seed = System.currentTimeMillis();// 获得系统时间,作为生成随机数的种子
    	
    		StringBuffer sb = new StringBuffer();// 装载生成的随机数
    	
    		Random random = new Random(seed);// 调用种子生成随机数
    	
    		for (int i = 0; i < 16; i++) {
    	
    		sb.append(numberChar.charAt(random.nextInt(numberChar.length())));
    		}
    	
    		return sb.toString();
    
    	}
    	public static String getRandom(int w) {
    		
    		Long seed = System.currentTimeMillis();// 获得系统时间,作为生成随机数的种子
    		
    		StringBuffer sb = new StringBuffer();// 装载生成的随机数
    		
    		Random random = new Random(seed);// 调用种子生成随机数
    		
    		for (int i = 0; i < w; i++) {
    			
    			sb.append(numberChar.charAt(random.nextInt(numberChar.length())));
    		}
    		
    		return sb.toString();
    		
    	}
    
    }
    

    MD5加密解密util

    package com.util;
    
    import java.security.MessageDigest;
    
    public class MD5Util {
    	
    
    	private 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();    
        }    
    
        private 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 String MD5Encode(String origin, String charsetname) {    
            String resultString = null;    
            try {    
                resultString = new String(origin);    
                MessageDigest md = MessageDigest.getInstance("MD5");    
                if (charsetname == null || "".equals(charsetname))    
                    resultString = byteArrayToHexString(md.digest(resultString    
                            .getBytes()));    
                else    
                    resultString = byteArrayToHexString(md.digest(resultString    
                            .getBytes(charsetname)));    
            } catch (Exception exception) {    
            }    
            return resultString;    
        }    
        
        
        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;
            }
        }
    
        private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",    
                "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };    
        
        
      
    
    
    
    }
    

    XMLUtil

    package com.util;
    
    import java.io.ByteArrayInputStream;  
    import java.io.IOException;  
    import java.io.InputStream;
    import java.io.StringReader;
    import java.util.HashMap;  
    import java.util.Iterator;  
    import java.util.List;  
    import java.util.Map;
    import java.util.Set;
    import java.util.SortedMap;
    
    import org.jdom2.JDOMException;
    import org.jdom2.input.SAXBuilder;
    import org.xml.sax.InputSource;
    import org.jdom2.Document;  
    import org.jdom2.Element;  
    
    
    public class XMLUtil {
    	
    	 /**  
         * @author chenp 
         * @Description:sign签名  
         * @param characterEncoding  
         *            编码格式  
         * @param parameters  
         *            请求参数  
         * @return  
         */    
        public static String createSign(String characterEncoding, SortedMap<Object, Object> 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)) {    
                    sb.append(k + "=" + v + "&");    
                }    
            }    
            sb.append("key=" + API_KEY);    
            String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();    
            return sign;    
        }   
        
        
    
        /**  
         * @author chenp 
         * @Description:将请求参数转换为xml格式的string  
         * @param parameters  
         *            请求参数  
         * @return  
         */    
        public static String getRequestXml(SortedMap<Object, Object> parameters) {    
            StringBuffer sb = new StringBuffer();    
            sb.append("<xml>");    
            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 + ">" + "<![CDATA[" + v + "]]></" + k + ">");    
                } else {    
                    sb.append("<" + k + ">" + v + "</" + k + ">");    
                }    
            }    
            sb.append("</xml>");    
            return sb.toString();    
        }    
    
        
    	
    
    	
    	/**  
         * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。  
         * @param strxml  
         * @return  
         * @throws JDOMException  
         * @throws IOException  
         */    
        public static Map doXMLParse(String strxml)  {    
        	
        	try {
        		   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 = XMLUtil.getChildrenText(children);    
        	            }    
    
        	            m.put(k, v);    
        	        }    
    
        	        //关闭流    
        	        in.close();    
    
        	        return m;    
    		} catch (Exception e) {
    			// TODO: handle exception
    			e.printStackTrace();
    		}
        	return null;
         
        }
        
        
        
    	/**
     * 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;
    
    }
    
        
        /**  
         * 获取子结点的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(XMLUtil.getChildrenText(list));    
                    }    
                    sb.append(value);    
                    sb.append("</" + name + ">");    
                }    
            }    
    
            return sb.toString();    
        }    
    
    
    
    }
    

     

    展开全文
  • 我们在开发微信支付功能的时候首先必须确定两个非常重要的参数,就是商户号mchid和商户秘钥key,那么这两个参数在哪里获取呢,请仔细阅读下面的查询方法。一、微信支付商户号mchid的查找1.1、登录微信公众平台...

    我们在开发微信支付功能的时候首先必须确定两个非常重要的参数,就是商户号mchid和商户秘钥key,那么这两个参数在哪里获取呢,请仔细阅读下面的查询方法。

    一、微信支付商户号mchid的查找

    1.1、登录微信公众平台https://mp.weixin.qq.com/,点击左侧菜单“微信支付---》商户信息”,就可以看到商户号mchid的值。如下图所示

    二、微信支付商户秘钥key的生成

    2.1、首先登录微信商户平台,地址https://pay.weixin.qq.com 点击“账户中心---》API安全”

    2.2、安装操作证书

    点击安装操作证书按钮---》申请安装

    按照界面步骤安装即可。

    2.3、设置32位商户秘钥key

    证书安装成功后,点击"设置秘钥"按钮

    -

    自己设置32位密钥,推荐使用在线密码生成器生成(个人自己写的无法发起支付)http://suijimimashengcheng.51240.com 或 http://www.sexauth.com/

    上述设置的32位秘钥千万要记住,否则还需要重新设置


    展开全文
  • 参考:微信支付出现OUT_TRADE_NO_USED:商户订单重复 场景:使用微信支付,在微信支付界面,由于余额不足等原因,没有进行支付并关闭了支付页面,此时订单状态为“待支付”,从业务角度来说,应该允许用户继续支付。...

    参考:微信支付出现OUT_TRADE_NO_USED:商户订单号重复

    场景:使用微信支付,在微信支付界面,由于余额不足等原因,没有进行支付并关闭了支付页面,此时订单状态为“待支付”,从业务角度来说,应该允许用户继续支付。但是再次支付时,微信接口返回“201 商户订单号重复”的错误提示。

    解决办法:待支付的订单号(即商户订单号,out_trade_no),再次支付时,务必保持商品描述字段和上次请求的内容完全一致

        另外,如果价格改变,也不能重复提交,只能重新生成订单号,重新向微信发起支付请求

    展开全文
  • 这时,订单已经生成,订单状态为“待支付”,当用户继续支付时,微信报出了“201 商户订单重复”错误。问题原因:第一次支付失败、取消支付,再次支付时,前端将商品描述(body)字段的值改变了,造成了该问题。像...

    问题描述:

    使用微信支付时,在支付页面,由于用户第一次点击了取消或余额不足等原因,没有进行支付。这时,订单已经生成,订单状态为“待支付”,当用户继续支付时,微信报出了“201 商户订单号重复”错误。

    问题原因:

    第一次支付失败、取消支付,再次支付时,前端将商品描述(body)字段的值改变了,造成了该问题。像这种第一次没支付或支付失败,再次支付时,需要保证上面描述,价格等请求信息和第一次请求完全相同才可以,稍微有不同,微信会认为是不同的支付,就会要求不同的商户订单号(outTradeNo)。

    解决办法:

    确保再次支付时发起的请求参数和第一次保持一致即可。

    展开全文
  • 微信商户向个人退款(转账)---零钱入账 本屌一向抱着开源精神的态度,为大家分享文章和技巧,当然~分享出来的代码都是可以直接copy in。。。。望大家看完后点赞打赏收藏!谢谢~!如果有写的不对或者描述不正确的,...
  • 2 微信商户的商户 3 微信商户的秘钥 4 p12证书 注意事项:支付金额是以分为单位,最小金额为1元,最大金额为2万元,例如,要支付1.2元,则amount=120 (int 类型) 如果公众号被封,则需要更改公众号的app_id ...
  • 官方教程链接 开发流程概述 开通企业付款到余额功能 去商户后台获取商户账号appid、商户号、证书 生成签名 生成请求XML 向微信请求付款 付款结果分析保存 1、 ...
  • 使用场景:商户已有H5商城网站,用户通过消息或扫描二维码在微信内打开网页时,可以调用微信支付完成下单购买的流程。 说明:1.用户打开图文消息或者扫描二维码,在微信内置浏览器打开网页进行的支付。 2.商户...
  • 做微信相关开发有一段时间了,期间也对接了微信平台不少产品,这里写一份文档,简略总结一下微信商户平台的所有产品,把知识留在当下,这样就不怕以后遗忘了再走重复路,同时也供其它做微信相关开发的同学参考一下。...
  • 这个相对于支付要简单一些吧,个人理解,没有支付那么多操作,依旧是ssm框架+maven+... * @param money 依旧要求是整数而且提现微信硬性要求是金额必须大于5元的 * @throws ParseException */ @RequestMapping...
  • 但是再次支付时,微信接口返回“201 商户订单重复”的错误提示。 解决办法:待支付的订单(即商户订单,out_trade_no),再次支付时,务必保持商品描述字段和上次请求的内容完全一致。 ...
  • 摘要:最近在做h5支付,然后发现一个问题,微信自带浏览器不支持h5支付,然后后台又做了一个微信支付的接口,然后要传code参数,代码写好总结后,就发到这里记录一下; 因为有两个支付接口,所以首先判断打开页面...
  • 本文是【浅析微信支付】系列文章的第十二篇,主要讲解在商户存在的提现、商户付款到微信用户零钱或者银行卡需求。 浅析微信支付系列已经更新十二篇了哟~,没有看过的朋友们可以看一下哦。 浅析微信支付:支付验收...
  • 1、商户号(或同主体其他非服务商商户号)已入驻90日 2、商户号(或同主体其他非服务商商户号)有30天连续正常交易 3、登录微信支付商户平台-产品中心,开通企业付款。 付款资金 企业付款到零钱资...
  • 现将微信红包打造成“现金红包”,成为一款定向资金发放的营销工具,供商户使用. 二、 什么商户有资格申请 只要您开通了微信支付,并使用新支付接口开发(公众号支付、刷卡支付),都可以使用现金红包,无需申请 ...
  • 用户的账户里面有余额但是不足,需要剩余的部分调用微信支付来完成,而微信支付需要等待异步的通知才知道是否成功,现在的问题是用户的余额何时扣除,如果通知前扣除,在支付失败的情况怎么处理,要是在通知的时候...
  • 2、认证成功后,需要登录微信公众号,进入:服务-服务中心-商户功能,提交有关审核资料,准备好公司公章、运营人员身份证正反面、营业执照、财务资料等,提交后7个工作日内会给到审核结果; 3、通过审核的公众号,将...
  • 这篇文章是千米移动团队半年多时间使用微信平台开发多租户微店系统相关经验的分享与记录,涉及微信JSSDK,消息推送,微店支付等方面,微信开发的坑实在太多了,早期的时候官方文档也有不少问题。 文章后面还会持续...
1 2 3 4 5 ... 20
收藏数 1,395
精华内容 558