微信支付第三弹--SpringBoot整合微信APP支付
原文链接:https://blog.csdn.net/qq_37345604/article/details/93039953
2019年06月20日 15:40:12 Snow、杨 阅读数 366
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:
https://blog.csdn.net/qq_37345604/article/details/93039953
吐槽
做完APP微信支付,就两个字:心累,并不是这个功能有多难,就是想吐槽一下微信,太TMD的店大欺客了!签名,呵呵,参数顺序都得按照他们的排序。。。。。。。。
吐槽归吐槽,还是做一下知识复盘,下面是做APP微信支付步骤和代码,框架用的是SpringBoot
步骤
必备参数:
①:appid:微信开放平台上面的应用appid,和公众号appid不同
②:mch_id:商户ID,微信商户平台上商户信息
③:key:商户key(API秘钥)
登录微信商户平台--->账户中心--->API安全--->设置秘钥
步骤
①、根据账号参数拼接进行签名
②、根据参数和签名发起微信统一下单接口
③、把微信统一下单返回参数返回移动端
④、移动端根据参数拉起微信支付
⑤、支付成功后微信进行回调通知
⑥、判断微信返回状态,成功处理当前平台业务并返回微信return_code和return_msg两个参数,不然微信会一直进行回调
参数配置
wxpayconfig:
appid: wx383123456fbb7826
mch_id:
1234567011
device_info: WEB
key: VfnmAMI111111111EQjhvglWzDDO
url: https:
notify_url: http:
wx_package: Sign=WXPay
微信配置类
package com.prereadweb.order.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix="wxpayconfig")
public class WxpayConfig {
private String appid;
private String mch_id;
private String device_info;
private String key;
private String url;
private String notify_url;
private String return_url;
private String wx_package;
}
统一下单代码
controller层
@RequestMapping("/gowechatpay")
public Object goWeChatPay(@Param("orderId") Long orderId, HttpServletRequest request, HttpServletResponse response) throws Exception {
return weChatService.goWeChatPay(orderId, request);
}
service层代码
@Override
public Map<String, Object> goWeChatPay(Long orderId, HttpServletRequest request) {
Map<String, Object>
map = new HashMap<>();
if(Util.isEmpty(orderId)) {
map.put("code", UserStatusEnum.ERROR.intKey());
map.put("msg", UserStatusEnum.ERROR.value());
return map;
}
PayParameterForm payParameter = orderMapper.getPayParameter(orderId);
double price = payParameter.getActualPrice();
System.out.
println("price:" + price);
System.out.
println("appid是:" + wxpayconfig.getAppid());
System.out.
println("mch_id是:" + wxpayconfig.getMch_id());
String nonce_str = Util.getRandomString(
30);
System.out.
println("随机字符串是:" + nonce_str);
int total_fee = (int) (price * 100);
String total_price = null;
String spbill_create_ip = WXSignUtils.getRemortIP(request);
System.out.
println("spbill_create_ip===="+spbill_create_ip);
String notify_url = wxpayconfig.getNotify_url();
System.out.
println("notify_url是:" + notify_url);
String trade_type =
"APP";
SortedMap<Object, Object> parameters =
new TreeMap<Object, Object>();
parameters.put(
"appid", wxpayconfig.getAppid());
parameters.put(
"body", payParameter.getTitle());
parameters.put(
"mch_id", wxpayconfig.getMch_id());
parameters.put(
"nonce_str", nonce_str);
parameters.put(
"notify_url", notify_url);
parameters.put(
"out_trade_no", String.valueOf(payParameter.getOrderId()));
parameters.put(
"spbill_create_ip",spbill_create_ip);
parameters.put(
"total_fee", 1);
parameters.put(
"trade_type", trade_type);
String sign = WXSignUtils.createSign(
"UTF-8", parameters);
System.out.
println("签名是:" + sign);
Unifiedorder unifiedorder =
new Unifiedorder();
unifiedorder.setAppid(wxpayconfig.getAppid());
unifiedorder.setBody(payParameter.getTitle());
unifiedorder.setMch_id(wxpayconfig.getMch_id());
unifiedorder.setNonce_str(nonce_str);
unifiedorder.setNotify_url(notify_url);
unifiedorder.setOut_trade_no(String.valueOf(payParameter.getOrderId()));
unifiedorder.setSpbill_create_ip(spbill_create_ip);
unifiedorder.setTotal_fee(
1);
unifiedorder.setTrade_type(trade_type);
unifiedorder.setSign(sign);
String xmlInfo = HttpXmlUtils.xmlInfo(unifiedorder);
System.out.
println("xmlInfo:" + xmlInfo);
String wxUrl =
"https://api.mch.weixin.qq.com/pay/unifiedorder";
String method =
"POST";
String weixinPost = HttpXmlUtils.httpsRequest(wxUrl, method, xmlInfo).toString();
System.out.
println("weixinPost:" + weixinPost);
UnifiedorderResult unifiedorderResult = ParseXMLUtils.jdomParseXml(weixinPost);
if (unifiedorderResult != null) {
if ("SUCCESS".equals(unifiedorderResult.getReturn_code())) {
if("INVALID_REQUEST".equals(unifiedorderResult.getErr_code())){
map.put("code", UserStatusEnum.ERROR.intKey());
map.put("msg", "参数错误");
return map;
}
SortedMap<Object, Object> wxAppparameters =
new TreeMap<Object, Object>();
wxAppparameters.put(
"appid", unifiedorderResult.getAppid());
wxAppparameters.put(
"partnerid", unifiedorderResult.getMch_id());
wxAppparameters.put(
"prepayid", unifiedorderResult.getPrepay_id());
wxAppparameters.put(
"package", wxpayconfig.getWx_package());
wxAppparameters.put(
"noncestr", nonce_str);
wxAppparameters.put(
"timestamp", String.valueOf(new Date().getTime()).substring(0, 10));
wxAppparameters.put(
"sign", WXSignUtils.createSign("UTF-8", wxAppparameters));
map.put("code", UserStatusEnum.SUCCESS.intKey());
map.put("msg", UserStatusEnum.SUCCESS.value());
map.put("data", wxAppparameters);
return map;
}
else {
System.out.
println("错误原因为:" + unifiedorderResult.getReturn_msg());
map.put("code", UserStatusEnum.ERROR.intKey());
map.put("msg", unifiedorderResult.getReturn_msg());
return map;
}
}
else {
System.out.
println("服务端请求微信的返回值异常。");
map.put("code", UserStatusEnum.ERROR.intKey());
map.put("msg", "服务端请求微信的返回值异常。");
return map;
}
}
此处签名时参数的排序如下↓
谨记!这是微信挖的一个坑,如果不按照这个排序的话,你的统一下单接口很有可能会一直返回:签名失败
返回参数:
微信回调函数
controller层
声明:此处要有返回值,如果你的项目配置了拦截器,记得把这个方法的路径放开,不然微信会访问不到
@RequestMapping("/wechatnotify")
public String weChatNotify(HttpServletRequest request) {
String returnXML =
null;
try {
returnXML = weChatService.weChatNotify(request);
}
catch (Exception e) {
e.printStackTrace();
}
return returnXML;
}
service层
@
Override
public String weChatNotify(HttpServletRequest request) throws Exception {
Map<String, String> map = new HashMap<>();
System.out.println("----------------微信回调开始啦----------------------");
InputStream inputStream;
StringBuffer sb = new StringBuffer();
inputStream = request.getInputStream();
String s;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null) {
sb.append(s);
}
in.close();
inputStream.close();
Map<String, String> m = new HashMap<String, String>();
m =
WXSignUtils.doXMLParse(sb.toString());
SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
Iterator<String> it = m.keySet().iterator();
while (it.hasNext()) {
String parameter = it.next();
String parameterValue = m.get(parameter);
String v = "";
if (null != parameterValue) {
v = parameterValue.trim();
}
System.out.println("p:" + parameter + ",v:" + v);
packageParams.put(parameter, v);
}
String key = wxpayconfig.getKey();
if(!isTenpaySign("UTF-8", packageParams, key)){
map.put("return_code", "FAIL");
map.put("return_msg", "return_code不正确");
return StringUtil.GetMapToXML(map);
}
if(m.get("return_code").equals("SUCCESS")){
RedisUtil.set("wx"+m.get("out_trade_no"),m.get("result_code"),300);
}
if (isTenpaySign("UTF-8", packageParams, key)) {
if ("SUCCESS".equals((String) packageParams.get("result_code"))) {
String out_trade_no = (String) packageParams.get("out_trade_no");
if (!Util.isEmpty(out_trade_no)) {
OrderEntity order = orderMapper.getOrderInfo(Long.valueOf(out_trade_no));
if(!Util.isEmpty(order)){
order.setStatus(
CalculatStaticConstant.CHECK_ONE);
order.setCompleteTime(
DateUtil.currentDate());
orderMapper.updateOrder(order);
System.out.println("----------------修改订单状态----------------------");
}
OrderPayEntity orderPay = new OrderPayEntity();
orderPay.setId(
Long.valueOf(IdUtils.getPrimaryKey()));
orderPay.setOrderId(order.getId());
orderPay.setUserId(order.getUserId());
orderPay.setPayPrice(order.getActualPrice());
orderPay.setPayType(
PayTypeEnum.WE_CHAT_PAY.intKey());
orderPay.setStatus(
CalculatStaticConstant.CHECK_ONE);
orderPay.setPayTime(
DateUtil.currentDate());
orderMapper.saveOrderPay(orderPay);
System.out.println("----------------添加支付信息----------------------");
map.put("return_code", "SUCCESS");
map.put("return_msg", "OK");
return StringUtil.GetMapToXML(map);
}
}
}
else {
System.out.println("支付失败");
map.put("return_code", "error");
map.put("return_msg", "支付失败");
return StringUtil.GetMapToXML(map);
}
System.out.println("支付失败");
System.out.println("支付失败");
map.put("return_code", "error");
map.put("return_msg", "支付失败");
return StringUtil.GetMapToXML(map);
}
@SuppressWarnings(
"rawtypes")
public
static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams,
String API_KEY) {
StringBuffer sb =
new StringBuffer();
Set es = packageParams.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
if (!"sign".equals(k) && null != v && !"".equals(v)) {
sb.append(k +
"=" + v + "&");
}
}
sb.append(
"key=" + API_KEY);
String mysign = MD5Util.MD5Encode(sb.toString()).toLowerCase();
String tenpaySign = ((String) packageParams.get("sign")).toLowerCase();
return tenpaySign.equals(mysign);
}
相关工具类
微信签名工具类
package com.prereadweb.order.util;
import com.prereadweb.utils.MD5Util;
import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
public
class WXSignUtils {
private
static String Key ="VfnmAMasdasdasdasWzDDO";
public
static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){
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=" + Key);
System.out.println(
"字符串拼接后是:"+sb.toString());
String sign = MD5Util.MD5Encode(sb.toString()).toUpperCase();
return sign;
}
public
static String getRemortIP(HttpServletRequest request) {
if (request.getHeader("x-forwarded-for") == null) {
return request.getRemoteAddr();
}
return request.getHeader("x-forwarded-for");
}
public
static Map doXMLParse(String strxml) throws JDOMException,
IOException {
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);
org.jdom.Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while (it.hasNext()) {
org.jdom.Element e = (org.jdom.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()) {
org.jdom.Element e = (org.jdom.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();
}
}
统一下单提交微信参数实体类
/**
* UnifiedorderResult.java
* com.prereadweb.order.util
* Copyright (c)
2019,
*/
package com.prereadweb.order.util;
import lombok.Data;
/**
* @Description: 统一下单提交(微信参数)
* @author: Administrator
* @
date: 2019/6/17 16:11
*/
@Data
public class UnifiedorderResult {
private String return_code;
private String return_msg;
private String appid;
private String mch_id;
private String device_info;
private String nonce_str;
private String sign;
private String result_code;
private String err_code;
private String err_code_des;
private String trade_type;
private String prepay_id;
}
DOM解析
package com.prereadweb.order.util;
import com.prereadweb.utils.Util;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.jdom.input.SAXBuilder;
import org.xml.sax.InputSource;
import java.io.StringReader;
import java.util.Iterator;
import java.util.List;
public class ParseXMLUtils {
@SuppressWarnings(
"rawtypes")
public static void beginXMLParse(String xml){
Document doc =
null;
try {
doc = DocumentHelper.parseText(xml);
Element rootElt = doc.getRootElement();
System.
out.println("根节点是:"+rootElt.getName());
Iterator iters = rootElt.elementIterator(
"sendResp");
while (iters.hasNext()) {
Element recordEle1 = (Element) iters.next();
Iterator iter = recordEle1.elementIterator(
"sms");
while (iter.hasNext()) {
Element recordEle = (Element) iter.next();
String phone = recordEle.elementTextTrim(
"phone");
String smsID = recordEle.elementTextTrim(
"smsID");
System.
out.println(phone+":"+smsID);
}
}
}
catch (DocumentException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
}
public static void xpathParseXml(String xml){
try {
StringReader read =
new StringReader(xml);
SAXReader saxReader =
new SAXReader();
Document doc = saxReader.read(read);
String xpath =
"/xml/appid";
System.
out.print(doc.selectSingleNode(xpath).getText());
}
catch (DocumentException e) {
e.printStackTrace();
}
}
@SuppressWarnings(
"unchecked")
public static UnifiedorderResult jdomParseXml(String xml){
UnifiedorderResult unifieorderResult =
new UnifiedorderResult();
try {
StringReader read =
new StringReader(xml);
InputSource source =
new InputSource(read);
SAXBuilder sb =
new SAXBuilder();
org.jdom.Document doc;
doc = (org.jdom.Document) sb.build(source);
org.jdom.Element root = doc.getRootElement();
List<org.jdom.Element> list = root.getChildren();
if(list != null && list.size() > 0){
boolean flag1 =
true;
boolean flag2 =
true;
for (org.jdom.Element element : list) {
System.
out.println("key是:"+element.getName()+",值是:"+element.getText());
if("return_code".equals(element.getName())){
if("FAIL".equals(element.getText())){
flag1 =
false;
}
else{
unifieorderResult.setReturn_code(element.getText());
}
}
if("return_msg".equals(element.getName())){
if(element.getText() != null && !"OK".equals(element.getText())){
System.
out.println("统一下单参数有误,错误原因为:"+element.getText());
return null;
}
}
if(flag1){
if("appid".equals(element.getName())){
unifieorderResult.setAppid(element.getText());
}
if("mch_id".equals(element.getName())){
unifieorderResult.setMch_id(element.getText());
}
if("nonce_str".equals(element.getName())){
unifieorderResult.setNonce_str(element.getText());
}
if("sign".equals(element.getName())){
unifieorderResult.setSign(element.getText());
}
if("err_code".equals(element.getName())){
unifieorderResult.setErr_code(element.getText());
}
if("err_code_des".equals(element.getName())){
unifieorderResult.setErr_code_des(element.getText());
}
if("result_code".equals(element.getName())){
if("FAIL".equals(element.getText())){
flag2 =
false;
System.
out.println("统一下单业务结果有误,无法返回预支付交易会话标识");
}
else{
unifieorderResult.setResult_code(element.getText());
}
}
}
if(flag1 && flag2 && flag2 == true){
if("trade_type".equals(element.getName())){
unifieorderResult.setTrade_type(element.getText());
}
if("prepay_id".equals(element.getName())){
System.
out.println("统一下单接口成功返回预支付交易会话标识!");
unifieorderResult.setPrepay_id(element.getText());
}
}
}
return unifieorderResult;
}
else{
return null;
}
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static boolean parseInt(String key){
if(!Util.isEmpty(key)){
if(key.equals("total_fee")||key.equals("cash_fee")||key.equals("coupon_fee")||key.equals("coupon_count")||key.equals("coupon_fee_0")){
return true;
}
}
return false;
}
}
post提交xml格式的参数
/**
* HttpXmlUtils.java
* com.prereadweb.order.util
* Copyright (c) 2019, 北京聚智未来科技有限公司版权所有.
*/
package com.prereadweb.order.util;
import com.prereadweb.order.form.Unifiedorder;
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* @Description: post提交xml格式的参数
* @author: Administrator
* @date: 2019/6/17 15:46
*/
public class HttpXmlUtils {
/**
* 开始post提交参数到接口
* 并接受返回
* @param url
* @param xml
* @param method
* @param contentType
* @return
*/
public static String xmlHttpProxy(String url,String xml,String method,String contentType){
InputStream is = null;
OutputStreamWriter os = null;
try {
URL _url = new URL(url);
HttpURLConnection conn = (HttpURLConnection) _url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-type", "text/xml");
conn.setRequestProperty("Pragma:", "no-cache");
conn.setRequestProperty("Cache-Control", "no-cache");
conn.setRequestMethod("POST");
os = new OutputStreamWriter(conn.getOutputStream());
os.write(new String(xml.getBytes(contentType)));
os.flush();
//返回值
is = conn.getInputStream();
return getContent(is, "utf-8");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
if(os!=null){os.close();}
if(is!=null){is.close();}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
/**
* 解析返回的值
* @param is
* @param charset
* @return
*/
public static String getContent(InputStream is, String charset) {
String pageString = null;
InputStreamReader isr = null;
BufferedReader br = null;
StringBuffer sb = null;
try {
isr = new InputStreamReader(is, charset);
br = new BufferedReader(isr);
sb = new StringBuffer();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
pageString = sb.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null){
is.close();
}
if(isr!=null){
isr.close();
}
if(br!=null){
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
sb = null;
}
return pageString;
}
/**
* 构造xml参数
* @param xml
* @return
*/
public static String xmlInfo(Unifiedorder unifiedorder){
//构造xml参数的时候,至少又是个必传参数
/*
*
<xml>
<appid>wx2421b1c4370ec43b</appid>
<attach>支付测试</attach>
<body>JSAPI支付测试</body>
<mch_id>10000100</mch_id>
<nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
<notify_url>http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php</notify_url>
<openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
<out_trade_no>1415659990</out_trade_no>
<spbill_create_ip>14.23.150.211</spbill_create_ip>
<total_fee>1</total_fee>
<trade_type>JSAPI</trade_type>
<sign>0CB01533B8C1EF103065174F50BCA001</sign>
</xml>
*/
if(unifiedorder!=null){
StringBuffer bf = new StringBuffer();
bf.append("
<xml>");
bf.append("
<appid><![CDATA[");
bf.append(unifiedorder.getAppid());
bf.append("]]>
</appid>");
bf.append("
<body><![CDATA[");
bf.append(unifiedorder.getBody());
bf.append("]]>
</body>");
bf.append("
<mch_id><![CDATA[");
bf.append(unifiedorder.getMch_id());
bf.append("]]>
</mch_id>");
bf.append("
<nonce_str><![CDATA[");
bf.append(unifiedorder.getNonce_str());
bf.append("]]>
</nonce_str>");
bf.append("
<notify_url><![CDATA[");
bf.append(unifiedorder.getNotify_url());
bf.append("]]>
</notify_url>");
bf.append("
<out_trade_no><![CDATA[");
bf.append(unifiedorder.getOut_trade_no());
bf.append("]]>
</out_trade_no>");
bf.append("
<spbill_create_ip><![CDATA[");
bf.append(unifiedorder.getSpbill_create_ip());
bf.append("]]>
</spbill_create_ip>");
bf.append("
<total_fee><![CDATA[");
bf.append(unifiedorder.getTotal_fee());
bf.append("]]>
</total_fee>");
bf.append("
<trade_type><![CDATA[");
bf.append(unifiedorder.getTrade_type());
bf.append("]]>
</trade_type>");
bf.append("
<sign><![CDATA[");
bf.append(unifiedorder.getSign());
bf.append("]]>
</sign>");
bf.append("
</xml>");
return bf.toString();
}
return "";
}
/**
* post请求并得到返回结果
* @param requestUrl
* @param requestMethod
* @param output
* @return
*/
public static String httpsRequest(String requestUrl, String requestMethod, String output) {
try{
URL url = new URL(requestUrl);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setRequestMethod(requestMethod);
if (null != output) {
OutputStream outputStream = connection.getOutputStream();
outputStream.write(output.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = connection.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;
connection.disconnect();
return buffer.toString();
}catch(Exception ex){
ex.printStackTrace();
}
return "";
}
}
将map转换为xml类
package com.prereadweb.utils;
import java.util.Map;
public class StringUtil {
public static String GetMapToXML(Map<String,String> param){
StringBuffer sb =
new StringBuffer();
sb.append(
"<xml>");
for (Map.Entry<String,String> entry : param.entrySet()) {
sb.append(
"<"+ entry.getKey() +">");
sb.append(entry.getValue());
sb.append(
"</"+ entry.getKey() +">");
}
sb.append(
"</xml>");
return sb.toString();
}
}
至此微信APP支付完成,功能其实不难,就是微信官方的API有点CD,大部分做微信支付遇到错误基本都是【签名错误】这个东西下面是遇到这个错误的排查方法
【签名错误排查】
1、xml拼接时候排序一定要按照下面这张图,每次说到这里就想吐槽微信*****
2、使用微信签名工具检查签名和程序生成的是否一致,选择MD5、XML,然后把请求的参数xml(xmlInfo)放进去,看看是否校验通过:签名校验
3、如果签名工具校验通过,说明程序没有问题,如果到了这一步,大部分可以锁定是你的账号问题或者是API秘钥的问题了
首先检查账户有没有开通APP支付功能,还有一点,你开通后,微信会给你账户打一笔验证款,你要点击确认和输入金额,这不操作是一定要有的具体操作请参照微信开放平台
4、API秘钥这里有两点需要声明,API秘钥有时候会出现第一次设置的不能使用,需要多设置几次,还有就是微信官方说的,API秘钥设置成功15分钟后才会生效
5、调用微信统一下单时候传的订单金额total_fee参数是int类型,这也是一个坑坑坑
6、调用统一下单接口时传参数名称要和微信上面的一样,千万别出现大写,不然绝对签名错误:统一下单接口传参
7、如果使用签名工具校验没通过,大部分错误是出在编码格式上面,可以把所有编码格式改成UTF-8,如果有参数的值是中文,可以暂时改成英文,如果英文签名成功,基本锁定就是编码格式问题了
大部分错误都是在这几点上,耐下心思慢慢排,可以多百度一下,总有能解决你的问题的博客
转载于:https://www.cnblogs.com/linwenbin/p/11355925.html