不得不说,微信支付接入比支付宝做的差多了,支付宝支付接入给人的感觉是简单,优雅。微信支付接入给人的感觉恶心,烦躁,想吐槽,踩了不少坑,最后发现使用完全使用官方提供的sdk肯定接入不成功,采用了自己的方式请求调用接口,终于调通了。
接入微信支付扫码支付,微信支付官方提供了两种模式,模式一商户必须在公众平台后台设置支付回调URL。URL实现的功能:接收用户扫码后微信支付系统回调的productid和openid;模式二,流程更为简单,不依赖设置的回调支付URL。商户后台系统先调用微信支付的统一下单接口,微信后台系统返回链接参数code_url,商户后台系统将code_url值生成二维码图片,用户使用微信客户端扫码后发起支付。注意:code_url有效期为2小时,过期后扫码不能再发起支付。本次接入采用模式二:
多说无用,直接晒代码:
1、微信官方下载微信支付接入sdk
2、配置WXPayConfig,自定义MyWXPayConfig继承sdk中WXPayConfig
import java.io.InputStream;
public class MyWXPayConfig extends WXPayConfig{
@Override
String getAppID() {
// TODO Auto-generated method stub
return "wxcf1*******";
// return "wx839******";
}
@Override
String getMchID() {
// TODO Auto-generated method stub
return "1557******";
// return "147*****";
}
@Override
String getKey() {
// TODO Auto-generated method stub
return "Xq1crLeoFeOxL6*******";
// return "8A627A457********";
}
@Override
InputStream getCertStream() {
// TODO Auto-generated method stub
return null;
}
@Override
IWXPayDomain getWXPayDomain() {
IWXPayDomain iwxPayDomain = new IWXPayDomain() {
public void report(String domain, long elapsedTimeMillis, Exception ex) {
}
public DomainInfo getDomain(WXPayConfig config) {
return new IWXPayDomain.DomainInfo(WXPayConstants.DOMAIN_API, true);
}
};
return iwxPayDomain;
}
}
3、自定义微信支付服务
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import com.alibaba.fastjson.JSONObject;
public class WXPayService {
//获取微信扫码支付二维码链接
public static Map<String, String> getWXPay(TSecurityOrderEntity order) throws Exception{
WXPayConfig config = new MyWXPayConfig();
WXPay wxpay = new WXPay(config);
String tradeNo = “aaabbbccc”; //随机字符串
Map<String, String> data = new LinkedHashMap<String, String>();
data.put("appid", config.getAppID());
data.put("body", "订阅支付");
data.put("mch_id", config.getMchID());
data.put("nonce_str", WXPayUtil.generateNonceStr());
data.put("notify_url", "http://a31ef7db.ngrok.io/WeChatPay/WeChatPayNotify");
data.put("out_trade_no", tradeNo);
data.put("spbill_create_ip", "127.0.0.1");
data.put("total_fee", “100”);
data.put("trade_type", "NATIVE"); // 此处指定为扫码支付
data.put("product_id", "12235413214070356458058");
//2.生成要发送的xml
String xmlParam = WXPayUtil.generateSignedXml(data, config.getKey());
System.out.println(xmlParam);
HttpClient client=new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
client.setHttps(true);
client.setXmlParam(xmlParam);
client.post();
//3.获得结果
String result = client.getContent();
System.out.println(result);
Map<String, String> map = WXPayUtil.xmlToMap(result);
// report(reportParams.toString());
if (map.get("return_code").toString().equals("SUCCESS") && map.get("result_code").toString().equals("SUCCESS") ) {
String urlCode = (String) map.get("code_url");
System.out.println(urlCode);
map.put("tradeNo", tradeNo);
return map;
}
return null;
}
//根据返回订单号tradeNo查询订单支付状态
public static boolean tradeQuery(String tradeNo) throws Exception{
WXPayConfig config = new MyWXPayConfig();
Map param=new HashMap();
param.put("appid", config.getAppID());//公众账号ID
param.put("mch_id", config.getMchID());//商户号
param.put("out_trade_no", tradeNo);//订单号
param.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串
String url="https://api.mch.weixin.qq.com/pay/orderquery";
String xmlParam = WXPayUtil.generateSignedXml(param, config.getKey());
HttpClient client=new HttpClient(url);
client.setHttps(true);
client.setXmlParam(xmlParam);
client.post();
String result = client.getContent();
Map<String, String> map = WXPayUtil.xmlToMap(result);
if (map.get("return_code").toString().equals("SUCCESS") && map.get("result_code").toString().equals("SUCCESS")
&& "SUCCESS".equals(map.get("trade_state").toString())) {
System.out.println("支付成功");
return true;
}
return false;
}
public static void main(String[] args) throws Exception {
Map<String, String> map = getWXPay(new TSecurityOrderEntity());
while(true){
boolean flag = tradeQuery(map.get("tradeNo"));
if(flag){
System.out.println("支付成功");
}else{
System.out.println("未支付");
}
Thread.sleep(3000);
}
}
}
4、请求微信支付接口工具类
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
/**
* http请求客户端
*
* @author Administrator
*
*/
public class HttpClient {
private String url;
private Map<String, String> param;
private int statusCode;
private String content;
private String xmlParam;
private boolean isHttps;
public boolean isHttps() {
return isHttps;
}
public void setHttps(boolean isHttps) {
this.isHttps = isHttps;
}
public String getXmlParam() {
return xmlParam;
}
public void setXmlParam(String xmlParam) {
this.xmlParam = xmlParam;
}
public HttpClient(String url, Map<String, String> param) {
this.url = url;
this.param = param;
}
public HttpClient(String url) {
this.url = url;
}
public void setParameter(Map<String, String> map) {
param = map;
}
public void addParameter(String key, String value) {
if (param == null)
param = new HashMap<String, String>();
param.put(key, value);
}
public void post() throws ClientProtocolException, IOException {
HttpPost http = new HttpPost(url);
setEntity(http);
execute(http);
}
public void put() throws ClientProtocolException, IOException {
HttpPut http = new HttpPut(url);
setEntity(http);
execute(http);
}
public void get() throws ClientProtocolException, IOException {
if (param != null) {
StringBuilder url = new StringBuilder(this.url);
boolean isFirst = true;
for (String key : param.keySet()) {
if (isFirst)
url.append("?");
else
url.append("&");
url.append(key).append("=").append(param.get(key));
}
this.url = url.toString();
}
HttpGet http = new HttpGet(url);
execute(http);
}
/**
* set http post,put param
*/
private void setEntity(HttpEntityEnclosingRequestBase http) {
if (param != null) {
List<NameValuePair> nvps = new LinkedList<NameValuePair>();
for (String key : param.keySet())
nvps.add(new BasicNameValuePair(key, param.get(key))); // 参数
http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数
}
if (xmlParam != null) {
http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
}
}
private void execute(HttpUriRequest http) throws ClientProtocolException,
IOException {
CloseableHttpClient httpClient = null;
try {
if (isHttps) {
SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(null, new TrustStrategy() {
// 信任所有
public boolean isTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
.build();
} else {
httpClient = HttpClients.createDefault();
}
CloseableHttpResponse response = httpClient.execute(http);
try {
if (response != null) {
if (response.getStatusLine() != null)
statusCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
// 响应内容
content = EntityUtils.toString(entity, Consts.UTF_8);
}
} finally {
response.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
httpClient.close();
}
}
public int getStatusCode() {
return statusCode;
}
public String getContent() throws ParseException, IOException {
return content;
}
}
5、根据返回链接生成图片二维码代码
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import javax.imageio.ImageIO;
import javax.swing.filechooser.FileSystemView;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
public class QrCodeUtil {
public static void main(String[] args) {
String url = "https://qr.alipay.com/bax03926jk9mvqchcxon00ec";
String path = FileSystemView.getFileSystemView().getHomeDirectory() + File.separator + "testQrcode";
String fileName = "temp.jpg";
createQrCode(url, path, fileName);
}
public static String createQrCode(String url, String path, String fileName) {
try {
Map<EncodeHintType, String> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 400, 400, hints);
File file = new File(path, fileName);
if (file.exists() || ((file.getParentFile().exists() || file.getParentFile().mkdirs()) && file.createNewFile())) {
writeToFile(bitMatrix, "jpg", file);
System.out.println("搞定:" + file);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
BufferedImage image = toBufferedImage(matrix);
if (!ImageIO.write(image, format, file)) {
throw new IOException("Could not write an image of format " + format + " to " + file);
}
}
static void writeToStream(BitMatrix matrix, String format, OutputStream stream) throws IOException {
BufferedImage image = toBufferedImage(matrix);
if (!ImageIO.write(image, format, stream)) {
throw new IOException("Could not write an image of format " + format);
}
}
private static final int BLACK = 0xFF000000;
private static final int WHITE = 0xFFFFFFFF;
private static BufferedImage toBufferedImage(BitMatrix matrix) {
int width = matrix.getWidth();
int height = matrix.getHeight();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
}
}
return image;
}
}