从微信开发者文档获取部分代码 https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1
1、CommonUtils包含方法 md5,uuid等
//生成 uuid, 即用来标识一笔单,也用做 nonce_str
public static String generateUUID() {
return UUID.randomUUID().toString().replaceAll("-", "")
.substring(0, 32);
}
//MD5工具类
public static String MD5(String data) {
try {
java.security.MessageDigest md = MessageDigest.getInstance("MD5");
byte[] array = md.digest(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toUpperCase();
} catch (Exception exception) {
}
return null;
}
2、WXPayUtil包含方法 xmlToMap,mapToXml,createSign,isCorrectPaySign
package net.gaven.video.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
/**
* @program: video
* @description: 微信支付的工具类
* xml----map
* map----xml
* 生成签名
*
*
*
* @author: Mr.lee
* @create: 2020-02-25 21:42
**/
public class WXPayUtil {
/**
* XML格式字符串转换为Map
*
* @param strXML XML字符串
* @return XML数据转换后的Map
* @throws Exception
*/
public static Map<String, String> xmlToMap(String strXML) throws Exception {
try {
Map<String, String> data = new HashMap<String, String>();
DocumentBuilder documentBuilder = WXPayXmlUtil.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 < nodeList.getLength(); ++idx) {
Node node = nodeList.item(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) {
// do nothing
}
return data;
} catch (Exception ex) {
WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
throw ex;
}
}
/**
* 日志
* @return
*/
public static Logger getLogger() {
org.slf4j.Logger logger = LoggerFactory.getLogger("wxpay java sdk");
return logger;
}
/**
* 将Map转换为XML格式的字符串
*
* @param data Map类型数据
* @return XML格式的字符串
* @throws Exception
*/
public static String mapToXml(Map<String, String> data) throws Exception {
org.w3c.dom.Document document = WXPayXmlUtil.newDocument();
org.w3c.dom.Element root = document.createElement("xml");
document.appendChild(root);
for (String key: data.keySet()) {
String value = data.get(key);
if (value == null) {
value = "";
}
value = value.trim();
org.w3c.dom.Element filed = document.createElement(key);
filed.appendChild(document.createTextNode(value));
root.appendChild(filed);
}
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
DOMSource source = new DOMSource(document);
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.transform(source, result);
String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
try {
writer.close();
}
catch (Exception ex) {
}
return output;
}
/**
* 生成签名
* 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签名方式
* @param sortedMap 传入的对象信息
* @param key 传入的密钥
* @return
*/
public static String createSign(SortedMap<String,String> sortedMap, String key){
StringBuilder sb=new StringBuilder();
Set<Map.Entry<String, String>> entries = sortedMap.entrySet();
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
while (iterator.hasNext()){
Map.Entry<String, String> next = iterator.next();
if (null!=next.getValue()&&""!=next.getValue()&&"key"!=next.getKey()&&"singn"!=next.getKey()){
/**
* 所有条件都满足才进行拼接
* 空属性不进行签名 (wx文档)
*/
sb.append(next.getKey()+"="+next.getValue()+"&");
}
}
//拼接密钥
sb.append("key=").append(key);
String stmpKey = sb.toString();
String sign = CommonUtils.MD5(stmpKey).toUpperCase();
return sign;
}
/**
* 校验sign 与生成sign步骤相同,只是把传来的sign与计算的sign进行比较
* @param sortedMap
* @param key
* @return
*/
public static boolean isCreateSign(SortedMap<String,String> sortedMap,String key){
String sign = createSign(sortedMap, key);
String beCheckedSign = sortedMap.get("sign");
return beCheckedSign.equals(sign);
}
}
https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=4_3
信支付下单API接口和签名开发
下单接口开发和微信支付签名生成开发,并设置微信回调地址(用于用户微信支付成功后,通知我们服务器完成更新订单状态)
1、统一下单参数需要微信签名,签名规则如下
文档地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_3
签名生成的通用步骤如下:
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
参数
SortedMap<String, String> params = new TreeMap<>();
params.put("appid", wxPayConfig.getAppId()); //公众账号ID
params.put("mch_id", wxPayConfig.getMchId()); //商户号
params.put("nonce_str", CommonUtil.generateNonceStr()); //随机字符串
params.put("body", videoOrder.getVideoTitle()); // 商品描述
params.put("out_trade_no", videoOrder.getOutTradeNo()); //商户订单号,商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|* 且在同一个商户号下唯一
params.put("total_fee", videoOrder.getTotalFee().toString()); //标价金额 分
params.put("spbill_create_ip", videoOrder.getIp());
params.put("notify_url", wxPayConfig.getDomain()+wxPayConfig.getCallbackUrl()); //通知地址
params.put("trade_type", "NATIVE"); //交易类型 JSAPI 公众号支付 NATIVE 扫码支付 APP APP支付
//生成签名
String sign = WXPayUtil.createSign(params, wxPayConfig.getKey());
params.put("sign", sign);
//参数转xml
String requestXMl = WXPayUtil.mapToXml(params);
生成签名后,通过工具去校验
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=20_1
2、测试地址:localhost:8081/api/v1/order/add?video_id=2
3、课程测试签名结果
sign: 85118C91DFCB052FB02AC183BF3D57D2
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xml>
<appid>wx5beac15ca207cdd40c</appid>
<body>高级教程666</body>
<mch_id>1503808832</mch_id>
<nonce_str>b11446ae6fc14ddb89c9bc5fa291dc43</nonce_str>
<notify_url>16web.tunnel.qydev.com/pub/api/v1/wechat/order/callback1</notify_url>
<out_trade_no>2a273e4b9f8c453380a08c7930fc3b6b</out_trade_no>
<sign>85118C91DFCB052FB02AC183BF3D57D2</sign>
<spbill_create_ip>0:0:0:0:0:0:0:1</spbill_create_ip>
<total_fee>500</total_fee>
<trade_type>NATIVE</trade_type>
</xml>
调用微信统一下单接口实战
调用微信统一下单接口实战,发送post请求,并获取响应转成map,获取交易会话的二维码链接code_url
1、配置统一下单接口
2、发送请求验证
微信统一下单响应
<xml><return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx5beac15ca207c40c]]></appid>
<mch_id><![CDATA[1503809911]]></mch_id>
<nonce_str><![CDATA[Go5gDC2CYL5HvizG]]></nonce_str>
<sign><![CDATA[BC62592B9A94F5C914FAAD93ADE7662B]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<prepay_id><![CDATA[wx262207318328044f75c9ebec2216783076]]></prepay_id>
<trade_type><![CDATA[NATIVE]]></trade_type>
<code_url><![CDATA[weixin://wxpay/bizpayurl?pr=hFq9fX6]]></code_url>
</xml>
3、获取code_url
遇到问题,根据错误码解决
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1