微信支付宝收款码转账H5免签出码带备注可回调成功率99.9%支持重复支付多种轮询规则提高存活率
本收款系统,可使用支付宝个人码 企业支付宝收款码 微信个人码收款,可以完成即时到账收款接口,并能实时通知到您的自定义网址。达到充值自动上分 增加金币自动发货等通知功能。免签接口高并发可以灵活配置风控规则,并支持一键升级省去后顾之忧,成功率稳定。支持支付
package com.zjy.xzlive.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.jdom.Element;
import org.jdom.Document;
import org.jdom.input.SAXBuilder;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.*;
public class WXAllUitls {
public static final String allChar = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
/**
* 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
*/
public static String createSign(String characterEncoding, SortedMap
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
Object v = entry.getValue();
if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + apiKey);
System.out.println(sb.toString());
String sign = MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}
public static String getRequestXml(SortedMap
StringBuffer sb = new StringBuffer();
sb.append("
Set es = parameters.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)) {
sb.append("<" + key + ">" + "" + key + ">");
} else {
sb.append("<" + key + ">" + value + "" + key + ">");
}
}
sb.append("
return sb.toString();
}
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;
}
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];
}
private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
//请求方法
public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
try {
URL url = new URL(requestUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
return buffer.toString();
} catch (ConnectException ce) {
System.out.println("连接超时:{}" + ce);
} catch (Exception e) {
System.out.println("https请求异常:{}" + e);
}
return null;
}
//随机字符串生成
public static String getRandomString(int length) { //length表示生成字符串的长度
String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
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();
}
public static Map doXMLParse(String strxml) throws Exception {
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 = getChildrenText(children);
}
m.put(k, v);
}
//关闭流
in.close();
return m;
}
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(getChildrenText(list));
}
sb.append(value);
sb.append("" + name + ">");
}
}
return sb.toString();
}
/**
* XML格式字符串转换为Map
*
* @param strXML XML字符串
* @return XML数据转换后的Map
* @throws Exception
*/
public static Map
Map
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int idx=0; idx
if (node.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.put(element.getNodeName(), element.getTextContent());
}
}
try {
stream.close();
}
catch (Exception ex) {
}
return data;
}
public static String generateString(int length) {
StringBuffer sb = new StringBuffer();
Random random = new Random();
for (int i = 0; i < length; i++) {
sb.append(allChar.charAt(random.nextInt(allChar.length())));
}
return sb.toString();
}
public static JSONObject httpsRequestALiYun(String url){
URL uri = null;
JSONObject result = null;
try {
uri = new URL(url);
HttpURLConnection conn = (HttpURLConnection) uri.openConnection();
conn.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String lines = "";
while ((lines = reader.readLine()) != null) {
result = JSON.parseObject(lines);
}
reader.close();
conn.disconnect();
}catch (Exception e){
e.printStackTrace();
}
return result;
}
public static String querySjNum(){
String a = "0123456789abcdefghijklmnopqrstuvwxyz";
String sjNumber="";
char[] rands = new char[32];
for (int i = 0; i < rands.length; i++)
{
int rand = (int) (Math.random() * a.length());
rands[i] = a.charAt(rand);
}
for(int i=0;i
}
return sjNumber;
}
}
微信扫码支付和H5的签名
//获取微信sign--H5支付
public String querySignH5(PayWechat payWechat,String price,String ip,String WXNonceStr,String WXOutTradeNo){
String sign = "";
SortedMap
mapSign.put("appid", payWechat.getAppid());
mapSign.put("mch_id", payWechat.getMchId());
mapSign.put("nonce_str", WXNonceStr);
mapSign.put("body", WXBody);
mapSign.put("out_trade_no", WXOutTradeNo);
mapSign.put("total_fee", price);
mapSign.put("spbill_create_ip", ip);
mapSign.put("notify_url", WXNotifyUrl);
mapSign.put("trade_type", trade_type_H5);
sign = WXAllUitls.createSign("UTF-8", mapSign, payWechat.getApiKey());
return sign;
}
//获取微信sign--扫码支付
public String querySignSaoma(PayWechat payWechat,String price,String ip,String WXNonceStr,String WXOutTradeNo){
String sign = "";
SortedMap
mapSign.put("appid", payWechat.getAppid());
mapSign.put("mch_id", payWechat.getMchId());
mapSign.put("nonce_str", WXNonceStr);
mapSign.put("body", WXBody);
mapSign.put("out_trade_no", WXOutTradeNo);
mapSign.put("total_fee", price);
mapSign.put("spbill_create_ip", ip);
mapSign.put("notify_url", WXNotifyUrl);
mapSign.put("trade_type", trade_type_SM);
sign = WXAllUitls.createSign("UTF-8", mapSign, payWechat.getApiKey());
return sign;
}
//获取公网ip,注意格式
public static String getPublicIp() {
try {
String path = "http://2018.ip138.com/ic.asp";// 要获得html页面内容的地址
//String path = "https://www.jiatui.com/new/js/city-picker.data.js";
URL url = new URL(path);//
// 创建url对象
HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 打开连接
conn.setRequestProperty("contentType", "GBK"); // 设置url中文参数编码
conn.setConnectTimeout(5 * 1000);// 请求的时间
conn.setRequestMethod("GET");// 请求方式
InputStream inStream = conn.getInputStream();
// readLesoSysXML(inStream);
BufferedReader in = new BufferedReader(new InputStreamReader(
inStream, "GBK"));
StringBuffer buffer = new StringBuffer();
String line = "";
// 读取获取到内容的最后一行,写入
while ((line = in.readLine()) != null) {
buffer.append(line);
}
String str = buffer.toString();
Document doc = Jsoup.parse(str);
Elements e = doc.select("center");
// System.out.println("str======"+str);
// String ipString1 = str.substring(str.indexOf("您的IP是:["));
// // 获取你的IP是中间的[182.149.82.50]内容
// String ipsString2 = ipString1.substring(ipString1.indexOf("[") + 1,
// ipString1.lastIndexOf("]"));
// //获取当前IP地址所在地址
// String ipsString3=ipString1.substring(ipString1.indexOf(": "),ipString1.lastIndexOf(""));
// System.err.println(ipsString3);
// 返回公网IP值
return e.text();
} catch (Exception e) {
System.out.println("获取公网IP连接超时");
return "";
}
}
发起支付
@ResponseBody
@RequestMapping("/sendWXpay")
public WXPayDto sendWXpay(String userGid, String price, String type, String loginName){
WXPayDto wXPayDto = new WXPayDto();
wXPayDto.setUserGid(userGid);
Double money = 0.0;
String code_url = null;
String ip = PublicInterIp.getPublicIp();
int first = ip.lastIndexOf("[");
int last = ip.lastIndexOf("]");
ip = ip.substring(first+1,last);
String WXNonceStr = WXAllUitls.getRandomString(32);
wXPayDto.setWXNonceStr(WXNonceStr);
String WXOutTradeNo =String.valueOf(System.currentTimeMillis());
wXPayDto.setWXOutTradeNo(WXOutTradeNo);
SortedMap
PayWechat payWechat = payWechatService.selectByPrimaryKey();
mapSign.put("appid", payWechat.getAppid());
mapSign.put("mch_id", payWechat.getMchId());
mapSign.put("nonce_str", WXNonceStr);
mapSign.put("body", WXBody);
mapSign.put("out_trade_no", WXOutTradeNo);//订单号(我方)
mapSign.put("total_fee", price);
mapSign.put("spbill_create_ip", ip);
mapSign.put("notify_url", WXNotifyUrl);
if(type.equals("1")){//扫码支付
String sign = querySignSaoma(payWechat,price,ip,WXNonceStr,WXOutTradeNo);
mapSign.put("trade_type", trade_type_SM);
mapSign.put("sign",sign);
String requestXML = WXAllUitls.getRequestXml(mapSign);
System.out.println(requestXML);
String result = WXAllUitls.httpsRequest(WXPayUrl, "POST", requestXML);
System.out.println(result);
Map
try {
map = WXAllUitls.doXMLParse(result);
String return_code = map.get("return_code");
if (return_code.contains("SUCCESS")) {
code_url = map.get("code_url");//获取到code_url
code_url = imgUrl(code_url,userGid);
wXPayDto.setCodeUrl(code_url);
}
}catch (Exception e){
e.printStackTrace();
}finally {
}
}else{//H5支付
String sign = querySignH5(payWechat,price,ip,WXNonceStr,WXOutTradeNo);
mapSign.put("trade_type", trade_type_H5);
mapSign.put("sign",sign);//scene_info
//mapSign.put("scene_info",scene_info);
String requestXML = WXAllUitls.getRequestXml(mapSign);
System.out.println(requestXML);
String result = WXAllUitls.httpsRequest(WXPayUrl, "POST", requestXML);
System.out.println(result);
Map
try {
map = WXAllUitls.doXMLParse(result);
String return_code = map.get("return_code");
if (return_code.contains("SUCCESS")) {
code_url = map.get("mweb_url");//获取到mweb_url为拉起微信支付收银台的中间页面,可通过访问该url来拉起微信客户端,完成支付,mweb_url的有效期为5分钟
wXPayDto.setCodeUrl(code_url);
}
}catch (Exception e){
e.printStackTrace();
}finally {
}
}
//处理业务信息
return null;
}
回调
推荐一个内网穿透地址https://www.ngrok.cc/
//支付完成回调
@RequestMapping("/WXCallBack")
public String payReturnRequest(HttpServletRequest request,HttpServletResponse response){
System.out.println("进入回调");
String tradState = "";
String xmlString = "";
String resXml = "";
try {
xmlString = getXmlString(request);
System.out.println("微信返回的回调结果是:::::::" + xmlString);
// 先解析返回的数据
Map
String returnCode = dataMap.get("return_code");//返回码
String outTradeNo = dataMap.get("out_trade_no");//商户订单号
String transactionId = dataMap.get("transaction_id");//微信支付订单号
String nonceStr = dataMap.get("nonce_str");//随机字符串
//
//查询微信订单号状态 tradState
// SUCCESS—支付成功
//
//REFUND—转入退款
//
//NOTPAY—未支付
//
//CLOSED—已关闭
//
//REVOKED—已撤销(刷卡支付)
//
//USERPAYING--用户支付中
//
//PAYERROR--支付失败(其他原因,如银行返回失败)
tradState = setQueryWXOrderInfo(userGid, outTradeNo,nonceStr);
System.out.println("该微信订单号状态:"+tradState);
// 通知微信闭嘴,交易完成无需回调
if("SUCCESS".equals(returnCode)){
resXml = "
+ "
//处理业务
}else{
resXml = "
+ "
//处理业务
}
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
}catch (Exception e){
e.printStackTrace();
}
return tradState;
}
//查询订单状态
@RequestMapping("/taskQueryOrderStatu")
public String setQueryWXOrderInfo(String gid,String WXOutTradeNo,String WXNonceStr){
String path = ServiceImgUrl+gid+".jpg";
String trade_state = "";
SortedMap
PayWechat payWechat = payWechatService.selectByPrimaryKey();
mapSign.put("appid", payWechat.getAppid());
mapSign.put("mch_id", payWechat.getMchId());
mapSign.put("nonce_str", WXNonceStr);
mapSign.put("out_trade_no", WXOutTradeNo);//订单号
String sign = WXAllUitls.createSign("UTF-8", mapSign, payWechat.getApiKey());
mapSign.put("sign",sign);
String requestXML = WXAllUitls.getRequestXml(mapSign);
String result = WXAllUitls.httpsRequest(queryWXOrderInfo, "POST", requestXML);
System.out.println(result);
Map
try {
map = WXAllUitls.doXMLParse(result);
String return_code = map.get("return_code");
if (return_code.contains("SUCCESS")) {
trade_state = map.get("trade_state");//获取到code_url
File file = new File(path);
if(file.exists()){
file.delete();
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
}
return trade_state;
}
二维码图片使用流返回即可
pom.xml