微信支付第三弹--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,如果有参数的值是中文,可以暂时改成英文,如果英文签名成功,基本锁定就是编码格式问题了
大部分错误都是在这几点上,耐下心思慢慢排,可以多百度一下,总有能解决你的问题的博客