微信支付第三彈--SpringBoot整合微信APP支付
原文鏈接: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兩個參數,不然微信會一直進行回調
參數配置
-
#微信APP支付參數
-
wxpayconfig:
-
#商戶應用appId
-
appid: wx383123456fbb7826
-
#商戶ID
-
mch_id: 1234567011
-
#設備號
-
device_info: WEB
-
#商戶key:api秘鑰(32位)
-
key: VfnmAMI111111111EQjhvglWzDDO
-
#統一下單接口
-
url: https: //api.mch.weixin.qq.com/pay/unifiedorder
-
#回調接口
-
notify_url: http: //baidu.com/home/wechatnotify
-
wx_package: Sign=WXPay
微信配置類
-
/**
-
* WxpayConfig.java
-
* com.prereadweb.order.config
-
* Copyright (c) 2019,
-
*/
-
package com.prereadweb.order.config;
-
-
import lombok.Data;
-
import org.springframework.boot.context.properties.ConfigurationProperties;
-
import org.springframework.stereotype.Component;
-
-
/**
-
* @Description: 微信配置類
-
* @author: Administrator
-
* @date: 2019/6/17 19:35
-
*/
-
-
-
-
public class WxpayConfig {
-
-
private String appid; // 公眾賬號ID
-
-
private String mch_id; // 商戶號
-
-
private String device_info; // 設備號
-
-
private String key; // 商戶的key【API密匙】
-
-
private String url; // api請求地址
-
-
private String notify_url; // 服務器異步通知頁面路徑
-
-
private String return_url; // 服務器同步通知頁面路徑
-
private String wx_package;
-
}
統一下單代碼
controller層
-
/**
-
* @Function: 去支付
-
* @author: YangXueFeng
-
* @Date: 2019/6/14 16:46
-
*/
-
-
public Object goWeChatPay(
-
return weChatService.goWeChatPay(orderId, request);
-
}
service層代碼
-
/**
-
* @Function: 去支付
-
* @author: YangXueFeng
-
* @Date: 2019/6/14 16:50
-
*/
-
@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);
-
// 微信開放平台審核通過的應用APPID
-
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); // "127.0.0.1";
-
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("total_fee", total_fee);
-
*/
-
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);
-
-
// 構造xml參數
-
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;
-
}
-
// 開始拼接App調起微信的參數
-
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層
聲明:此處要有返回值,如果你的項目配置了攔截器,記得把這個方法的路徑放開,不然微信會訪問不到
-
/**
-
* @Function: 微信支付回調
-
* @author: YangXueFeng
-
* @Date: 2019/6/18 18:50
-
*/
-
-
public String weChatNotify(HttpServletRequest request) {
-
String returnXML = null;
-
try {
-
returnXML = weChatService.weChatNotify(request);
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
return returnXML;
-
}
service層
-
/**
-
* @Function: 微信回調接口
-
* @author: YangXueFeng
-
* @Date: 2019/6/17 11:05
-
*/
-
@ 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();
-
// 解析xml成map
-
Map<String, String> m = new HashMap<String, String>();
-
m = WXSignUtils.doXMLParse(sb.toString());
-
// 過濾空 設置 TreeMap
-
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);
-
}
-
// 微信支付的API密鑰
-
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);
-
}
-
//返回狀態存入redis中
-
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);
-
}
-
/**
-
* @Function: 是否簽名正確,規則是:按參數名稱a-z排序,遇到空值的參數不參加簽名。
-
* @author: YangXueFeng
-
* @Date: 2019/6/17 17:10
-
*/
-
@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);
-
}
相關工具類
微信簽名工具類
-
/**
-
* WXSignUtils.java
-
* com.prereadweb.order.util
-
* Copyright (c) 2019,
-
*/
-
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.*;
-
-
/**
-
* @Description: 微信支付簽名
-
* @author: Administrator
-
* @date: 2019/6/17 15:43
-
*/
-
public class WXSignUtils {
-
-
/* API秘鑰 */
-
private static String Key ="VfnmAMasdasdasdasWzDDO";
-
-
/**
-
* 微信支付簽名算法sign
-
* @param characterEncoding
-
* @param parameters
-
* @return
-
*/
-
public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){
-
StringBuffer sb = new StringBuffer();
-
Set es = parameters.entrySet();//所有參與傳參的參數按照accsii排序(升序)
-
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;
-
}
-
-
/**
-
* @Function: 獲取IP
-
* @author: YangXueFeng
-
* @Date: 2019/6/17 16:44
-
*/
-
public static String getRemortIP(HttpServletRequest request) {
-
if (request.getHeader("x-forwarded-for") == null) {
-
return request.getRemoteAddr();
-
}
-
return request.getHeader("x-forwarded-for");
-
}
-
-
/**
-
* @Function: 解析XML
-
* @author: YangXueFeng
-
* @Date: 2019/6/17 17:07
-
*/
-
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解析
-
/**
-
* ParseXMLUtils.java
-
* com.prereadweb.order.util
-
* Copyright (c) 2019, 北京聚智未來科技有限公司版權所有.
-
*/
-
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;
-
-
/**
-
* @Description: DOM解析
-
* @author: Administrator
-
* @date: 2019/6/17 15:50
-
*/
-
public class ParseXMLUtils {
-
-
/**
-
* 1、DOM解析
-
*/
-
@SuppressWarnings( "rawtypes")
-
public static void beginXMLParse(String xml){
-
Document doc = null;
-
try {
-
doc = DocumentHelper.parseText(xml); // 將字符串轉為XML
-
-
Element rootElt = doc.getRootElement(); // 獲取根節點smsReport
-
-
System. out.println("根節點是:"+rootElt.getName());
-
-
Iterator iters = rootElt.elementIterator( "sendResp"); // 獲取根節點下的子節點sms
-
-
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"); // 拿到sms節點下的子節點stat值
-
-
String smsID = recordEle.elementTextTrim( "smsID"); // 拿到sms節點下的子節點stat值
-
-
System. out.println(phone+":"+smsID);
-
}
-
}
-
} catch (DocumentException e) {
-
e.printStackTrace();
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
-
-
/**
-
* 2、DOM4j解析XML(支持xpath)
-
* 解析的時候自動去掉CDMA
-
* @param xml
-
*/
-
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();
-
}
-
}
-
-
/**
-
* 3、JDOM解析XML
-
* 解析的時候自動去掉CDMA
-
* @param xml
-
*/
-
@SuppressWarnings( "unchecked")
-
public static UnifiedorderResult jdomParseXml(String xml){
-
UnifiedorderResult unifieorderResult = new UnifiedorderResult();
-
try {
-
StringReader read = new StringReader(xml);
-
// 創建新的輸入源SAX 解析器將使用 InputSource 對象來確定如何讀取 XML 輸入
-
InputSource source = new InputSource(read);
-
// 創建一個新的SAXBuilder
-
SAXBuilder sb = new SAXBuilder();
-
// 通過輸入源構造一個Document
-
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())){//微信支付的第一個坑,這里返回了OK,23333
-
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類
-
/**
-
* StringUtil.java
-
* com.prereadweb.utils
-
* Copyright (c) 2019, 北京聚智未來科技有限公司版權所有.
-
*/
-
package com.prereadweb.utils;
-
-
import java.util.Map;
-
-
/**
-
* @Description: String工具類
-
* @author: Administrator
-
* @date: 2019/6/19 11:31
-
*/
-
public class StringUtil {
-
-
/**
-
* @Function: 將map轉換為xml
-
* @author: YangXueFeng
-
* @Date: 2019/6/19 11:32
-
*/
-
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,如果有參數的值是中文,可以暫時改成英文,如果英文簽名成功,基本鎖定就是編碼格式問題了
大部分錯誤都是在這幾點上,耐下心思慢慢排,可以多百度一下,總有能解決你的問題的博客