java微信小程序支付
程序员文章站
2022-06-14 23:28:21
...
微信支付的流程:统一下单----->前端支付------>支付回调
流程很简单首先先看下官方统一下单文档:
官方文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1
官方统一下单接口,只需要我们后端调用这个接口就能完成统一下单,接下来是参数:
参数中有必传和非必传根据我们的需要选定好参数,我做的是小程序所以我需要的参数都有:
"<xml>"
+"<appid>小程序appid</appid>"
+"<mch_id>商户号</mch_id>"
+"<nonce_str>"+nonce_str+"</nonce_str>"
+"<body>支付测试</body>"
+"<out_trade_no>"+id+"</out_trade_no>"
+"<total_fee>1</total_fee>"
+"<spbill_create_ip>终端IP</spbill_create_ip>"
+"<notify_url>"+notify_url+"</notify_url>"
+"<trade_type>JSAPI</trade_type>"
+"<openid>"+openid+"</openid>"
+"<sign>"+sign+"</sign>"
+"</xml>";
这是最后传的参数,微信支付的参数和返回值都是xml格式
下面上代码
用的pom依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.48</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
主体方法
@Override
public JSONObject payOrder(String id,String openid) {
String nonce_str= UUID.randomUUID().toString().replace("-", "");//32位随机数我直接用的uuid
String notify_url = "https://localhost:1013/pay_back";//微信回调的地址,必须是外网能直接访问的https接口
String sign = sign("wx161332eed75bbba8","1521752201",nonce_str,"支付测试",
id,"1","47.92.254.214",notify_url,"JSAPI",openid);//签名方法
String aa ="<xml>"
+"<appid>小程序appid</appid>"
+"<mch_id>商户号</mch_id>"
+"<nonce_str>"+nonce_str+"</nonce_str>"
+"<body>支付测试</body>"
+"<out_trade_no>"+id+"</out_trade_no>"
+"<total_fee>1</total_fee>"
+"<spbill_create_ip>47.92.254.214</spbill_create_ip>"
+"<notify_url>"+notify_url+"</notify_url>"
+"<trade_type>JSAPI</trade_type>"
+"<openid>"+openid+"</openid>"
+"<sign>"+sign+"</sign>"
+"</xml>";
String bb = HttpClientUtil.doPostJson("https://api.mch.weixin.qq.com/pay/unifiedorder",aa);//请求微信统一下单接口 这样统一下单就完成了 如果成功会返回我们支付时候需要的值,将前端支付需要的值返回就可以了
System.out.println(bb.toString());
//返回值是xml格式,所以要进行转化
Document doc = null;
try {
doc = DocumentHelper.parseText(bb);
} catch (DocumentException e) {
e.printStackTrace();
}
Map<String,String> map = new HashMap<>();
Element root = doc.getRootElement();
//前端发起支付的需要的签名
String paySign = paySing("小程序appid",String.valueOf(new Date().getTime()),
UUID.randomUUID().toString().replace("-", ""),root.element("prepay_id").getTextTrim(),
"MD5");
map.put("package","prepay_id="+root.element("prepay_id").getTextTrim());//统一下单返回的预支付交易会话标识
map.put("timeStamp", String.valueOf(new Date().getTime()));//时间戳
map.put("nonceStr", UUID.randomUUID().toString().replace("-", ""));//随机字符串
map.put("signType", "MD5");//加密方式
map.put("paySign", paySign);//前端发起支付的签名
//打包返回给前端
JSONObject end = new JSONObject();
end.put("status","200");
end.put("prepay_order",map);
end.put("order_id",id);
return end;
}
同意下签名方法
//统一下单签名算法
private String sign(String appid,String mch_id,String nonce_str,String body,String out_trade_no,
String total_fee,String spbill_create_ip,String notify_url,String trade_type,String openid){
String A="appid="+appid+"&body="+body+"&mch_id="+mch_id+"&nonce_str="+nonce_str+"¬ify_url="+notify_url+
"&openid="+openid+"&out_trade_no="+out_trade_no+"&spbill_create_ip="+spbill_create_ip+"&total_fee="+
total_fee+"&trade_type="+trade_type;
String SignTemp=A+"&key=sfsdf34534wrrewergdfghrty4564564";
String sign = MD5Util.getMD5(SignTemp).toUpperCase();
return sign;
}
发起支付签名算法
//发起支付签名算法
private String paySing(String appid,String timeStamp,String nonceStr,String prepay_id,String signType){
String A = "appid="+appid+"&nonceStr="+nonceStr+"&package="+prepay_id+"&signType="+signType+
"&timeStamp="+timeStamp;
String sign = MD5Util.getMD5(A).toUpperCase();
return sign;
}
MD5加密工具类
package com.mengxiang.utils;
import java.security.MessageDigest;
public class MD5Util {
private final static String[] HEXDIGITS = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
public final static String getMD5(String str) {
if (str != null) {
try {
// 创建具有指定算法名称的信息摘要
MessageDigest md = MessageDigest.getInstance("MD5");
// 使用指定的字节数组对摘要进行最后更新,然后完成摘要计算
byte[] results = md.digest(str.getBytes()); // 将得到的字节数组变成字符串返回
StringBuffer resultSb = new StringBuffer();
String a = "";
for (int i = 0; i < results.length; i++) {
int n = results[i];
if (n < 0)
n = 256 + n;
int d1 = n / 16;
int d2 = n % 16;
a = HEXDIGITS[d1] + HEXDIGITS[d2];
resultSb.append(a);
}
return resultSb.toString();
} catch (Exception ex) {
ex.printStackTrace();
}
}
return null;
}
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;
}
/***
* MD5加码 生成32位md5码
*/
public static String string2MD5(String inStr) {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return "";
}
char[] charArray = inStr.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16)
hexValue.append("0");
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
// 测试主函数
public static void main(String args[]) {
String s = new String("ale123123");
System.out.println("原始:" + s);
System.out.println("MD5后:" + string2MD5(s));
}
}
回调接口
/**
* 接收返回值
* */
@RequestMapping("/pay_back")
@ResponseBody
public String pay_back(HttpServletRequest req, HttpServletResponse resp){
InputStream ins = null;
try {
ins = req.getInputStream();
byte[] rebyte = readStream(ins);
String remess = new String(rebyte);
System.out.println("XML报文内容为:" + remess);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return "success";
}
接收返回值主要就是将接收到的xml格式解析,读取返回值,有一点主意微信会回调多次,所以需要自行根据业务判断数据是否已经修改
上一篇: 微信小程序支付
下一篇: 行为型模式——状态模式