1.需要一个可以登陆微信商户平台的账号,此账号是服务号并开通了微信支付,商户在申请开通时,客服会发送邮件到你的邮箱,


上图中有几个重要信息:商户号和appid,务必记住商户号和appid。其中登陆账号和密码用于登陆微信支付首页点击打开链接

2.点击上图中的下载api证书,设置api密码。这个证书主要在微信支付api中需要证书的地方使用中的退款等功能提示需要证书。



注:什么时候加载使用该证书?当要实现微信退款时,发起退款请求前,需要先加载安全证书

package com.jy.common.pay.weixinpay;

import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.security.KeyStore;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
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;

/*
 * 加载安全证书、退款等需要证书的请求使用此类中的方法
 * */
public class ClientCustomSSL {
	public static String doRefund(String url, String data) throws Exception {
		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		URL luj = Thread.currentThread().getContextClassLoader().getResource("apiclient_cert.p12");//src目录下的证书文件
		FileInputStream is = new FileInputStream(new File(luj.toURI()));
		try {
		keyStore.load(is, "这个是你设置的安全证书的密码".toCharArray());// 这里写密码..默认是你的mchid,也就是前面发送给你的
邮件中的商户号
		} finally {
		is.close();
		}

		// Trust own CA and all self-signed certs
		SSLContext sslcontext = SSLContexts.custom()
		.loadKeyMaterial(keyStore, "商户号".toCharArray())// 这里也是写密码的
		.build();
		// Allow TLSv1 protocol only
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		try {
		HttpPost httpost = new HttpPost(url); // 设置响应头信息
		httpost.addHeader("Connection", "keep-alive");
		httpost.addHeader("Accept", "*/*");
		httpost.addHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
		httpost.addHeader("Host", "api.mch.weixin.qq.com");
		httpost.addHeader("X-Requested-With", "XMLHttpRequest");
		httpost.addHeader("Cache-Control", "max-age=0");
		httpost.addHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
		httpost.setEntity(new StringEntity(data, "UTF-8"));
		CloseableHttpResponse response = httpclient.execute(httpost);
		try {
		HttpEntity entity = response.getEntity();

		String jsonStr = EntityUtils.toString(response.getEntity(),
		"UTF-8");
		EntityUtils.consume(entity);
		return jsonStr;
		} finally {
		response.close();
		}
		} finally {
		httpclient.close();
		}
	}
}


上面返回的jsonStr则是:你发起退款时返回的一些json信息,这里一般将其转为map方便使用。

其中上面调用的方法需要2个参数:url,data

url:微信支付提供的退款接口https://api.mch.weixin.qq.com/secapi/pay/refund

data:这个参数微信支付官方推荐使用xml格式,所以一般都是用String字符串构造一个xml,这个xml和官方文档一样

<xml>
 <appid>wx2421b1c4370ec43b</appid>
 <mch_id>10000100</mch_id>
 <nonce_str>6cefdb308e1e2e8aabd48cf79e546a02</nonce_str> 
 <out_refund_no>1415701182</out_refund_no>
 <out_trade_no>1415757673</out_trade_no>
 <refund_fee>1</refund_fee>
 <total_fee>1</total_fee>
 <transaction_id></transaction_id>
 <sign>FE56DD4AA85C0EECA82C35595A69E153</sign>
 </xml>

data就是上面这个xml的字符串,一般先将退款接口需要的参数放入到map中,在将map转为xml字符串。


3.在实现预支付订单前应先获取到开发需要的一些参数:如openid、随机字符串、签名、

1.openid获取:

String url="https://api.weixin.qq.com/sns/oauth2/access_token?"
         + "appid="+你的appid+ "&secret="+你的secret
         + "&code="+code
         + "&grant_type=authorization_code";
JSONObject jsonObject=HttpGet.getRes(url);
String usersWeixinId=jsonObject.getString("openid");

secret是公众号的appsecret,这个在微信支付平台中的开发者中心可以找到

code是应用授权作用域,官方提供两个,任选一个:snsapi_base(不弹出授权窗口,只获取openid),snsapi_userinfo(弹出授权窗口.....)

2.随机字符串获取:这个参数一般是32位以内的大写字母和0-9数字的随机组合,不能超出32位

3.签名获取:签名详细算法地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3

获取签名步骤:

根据上图中的参数生成字符串

stringA="appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA";

再接着串联:

stringSignTemp=stringA+"&key=192006250b4c09247ec02edce69f6a2d" //注:key为商户平台设置的密钥key
sign=MD5(stringSignTemp).toUpperCase()="9A0A8659F005D6984697E2CA0A9CF3B7" //注:MD5签名方式
sign=hash_hmac("sha256",stringSignTemp,key) //注:HMAC-SHA256签名方式

两种签名方式任选,sign这就是我们需要的签名

4.简单地说:实现微信支付中的各种功能只需要3个大步骤:1.微信公众号支付的各个接口。2.生成发起订单等功能的XML字符串。3.发送http请求,输出返回的结果

1.预支付订单接口:https://api.mch.weixin.qq.com/pay/unifiedorder

预支付订单的通知地址:http://www.weixin.qq.com/wxpay/pay.php(即发起订单后的回调接口),此接口不能携带参数

2.查询预支付订单的接口:https://api.mch.weixin.qq.com/pay/orderquery

查询预支付订单时需要一个参数:微信订单号或者商户订单号任选一个,一般优先微信订单号,商户订单号的详细算法地址:

https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_2,就是拼接各个参数

这两个订单号的详细资料地址:http://www.tuicool.com/articles/vIFR7rJ

3.关闭订单接口:https://api.mch.weixin.qq.com/pay/closeorder

4.申请退款接口:https://api.mch.weixin.qq.com/secapi/pay/refund 此功能需要安全证书,自己去开发者中心下载

退款接口中需要的商户订单号与商户退款订单号是一致的,主要实现:

public  
 static  
 String getRandomStringByLength( 
 int  
 length) { 

 
 
  
 String base =  
 "0123456789" 
 ; 

 
 
  
 Random random =  
 new  
 Random(); 

 
 
  
 StringBuffer sb =  
 new  
 StringBuffer(); 

 
 
  
 for  
 ( 
 int  
 i =  
 0 
 ; i < length; i++) { 

 
 
  
 int  
 number = random.nextInt(base.length()); 

 
 
  
 sb.append(base.charAt(number)); 

 
 
  
 } 

 
 
  
 return  
 sb.toString(); 

 
 
  
 } 

 

    

 

    

 
 
  
 /** 

 
 
  
 * @function 生成商户订单号/退款单号 

 
 
  
 * @date 2015-12-17 

 
 
  
 * @return String 

 
 
  
 */ 

 
 
  
 public  
 static  
 String getOrderNo(){ 

 
 
  
 SimpleDateFormat sdf =  
 new  
 SimpleDateFormat( 
 "yyyyMMddHHmmssSSS" 
 ); 

 
 
  
 Date date =  
 new  
 Date(); 

 
 
  
 return  
 sdf.format(date) + getRandomStringByLength( 
 4 
 ); 

 
 
  
 }

5.查询退款接口:https://api.mch.weixin.qq.com/pay/refundquery


6.下载对账单:https://api.mch.weixin.qq.com/pay/downloadbill

7.支付结果通知:https://pay.weixin.qq.com/wxpay/pay.action或者http://www.weixin.qq.com/wxpay/pay.php

8.获取openid接口:https://api.weixin.qq.com/sns/oauth2/access_token需要部分参数,上面有例子