最近做了一下微信小程序发起的支付,所以记录一下,也希望能帮助同行们跳出微信支付这个大坑。
首先说一下微信支付我所理解的流程吧,首先会想后端发起统一下单的请求,后台进行统一下单,加密之类的,然后将数据返回给前端,然后前端拿着数据发起支付,支付成功开始回调。
这里发一下微信统一下单的api 可以对照着看一下 这样会更容易理解
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1&index=1
这篇文章主要说一下支付的统一下单和加密,至于回调(https://blog.csdn.net/qq_39897814/article/details/88890814)则会咋下一篇文章中解释。
先上代码
/**
*orderNo订单号
*openId 用户标识
*/
public Map<String, String> pay(String orderNo, String openId) {
OmsOrderParent orderParent = orderParentService.findByOrderNo(orderNo);
//小程序的
//1 封装参数 这里的参数时统一下单所需要的参数
Map<String, String> param = new HashMap<>();
param.put("appid", );//应用ID 注意 这里的appid是小写
param.put("mch_id", );//商户号
param.put("nonce_str", );//随机字符串
param.put("body",);//商品描述
param.put("out_trade_no", orderNo);//商户订单号 NoUtils.getNo()
param.put("total_fee", );//订单总金额(分) 这里要注意 支付的金额的单位是分,意思就是如果你支付的金额是1元的话 这里就是100不能有小数
param.put("spbill_create_ip", );//终端ip
param.put("notify_url",);//通知地址( 接收微信支付异步通知回调地址) 就是你后台回调的访问路径全路径 包括域名
param.put("trade_type", "JSAPI");//交易类型
param.put("openid", openId);//用户标识
try {
//这里对上面的数据进行第一次签名 WXPayUtil.generateSignature()方法是微信官方的 这里的KEY是你的api秘钥
String sign1 =WXPayUtil.generateSignature(param, KEY);
log.info("第一次签名:****************"+sign1+"*****************");
param.put("sign", sign1);//第一次加密的数据得到的签名
}catch (Exception e){
}
String xmlParam;//生成带有sign的XML格式字符串 WXPayUtil.generateSignedXml也是微信官方的
try {
xmlParam = WXPayUtil.generateSignedXml(param, WXMiniPayConfig.KEY);
} catch (Exception e) {
log.info("第-------个" + e.getMessage());
throw new IllegalArgumentException("生成签名失败");
}
//2 发送请求 统一下单 进行统一下单
HttpClient httpClient = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
httpClient.setHttps(true);
httpClient.setXmlParam(xmlParam);
httpClient.post();
//3 获取结果
String xmlResult = httpClient.getContent();
Map<String, String> mapResult;
try {
mapResult = WXPayUtil.xmlToMap(xmlResult);
} catch (Exception e) {
log.info("第一个" + e.getMessage());
throw new IllegalArgumentException("生成支付信息失败");
}
log.info("MINI-----调用微信统一下单接口返回的结果为===================================" + mapResult);
if(mapResult.get("prepay_id")==null){
log.error("不能加密,prepay_id为空");
}
//4 返回数据至APP端 二次加密获取签名 注意这个map中的参数不能多也不能少,不然无法调起支付,而且一下参数的大小写一定要注意
Map<String, String> map = new HashMap<>();
map.put("appId", mapResult.get("appid"));//应用ID 注意 这里的appId是大写 千万注意
map.put("nonceStr", ); //随机字符串,长度要求在32位以内
//这里的package 对应的预支付交易会话标识的格式必须是prepay_id=****不然前端无法调起支付
map.put("package", "prepay_id=" + mapResult.get("prepay_id")); //预支付交易会话标识prepayid
map.put("signType", "MD5"); //加密方式
map.put("timeStamp", ); //时间戳(10位数字,精确至秒)
try {
//二次加密 将次加密返回给前台 这里的KEY是你的api秘钥
String sign2 = WXPayUtil.generateSignature(map, KEY);
map.put("paySign", sign2);
} catch (Exception e) {
log.info("二次加密失败::::::" + e.getMessage());
throw new IllegalArgumentException("生成签名失败");
}
log.info("返回APP端的数据为=================================================" + map);
return map;
}
到这里统一下单 已经完成,如果没有意外的话 是可以调起支付的
下面贴上工具类
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.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* 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() {
HttpPost http = new HttpPost(url);
setEntity(http);
try {
execute(http);
} catch (IOException e) {
e.printStackTrace();
}
}
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() {
return content;
}
}
微信支付统一下单就这么多,