uni-app教程支付php,uni-app app端微信支付

本文档记录了一位开发者在实现uni-app小程序微信支付后,尝试在APP端实现微信支付时遇到签名验证失败的问题。经过一系列尝试和调试,最终通过复制同事的代码解决了问题。主要涉及的步骤包括统一下单、异步通知处理、订单状态查询等,同时也展示了Java后台处理微信支付的相关代码片段。
摘要由CSDN通过智能技术生成

开篇第一件事 说微信,这是一个怎样的平台,做完了uni-app 小程序端的微信支付 ,心想app还不是信手拈来???然而事实就是 支付签名验证失败是的一搜才发现 全是骂微信的,这样才好受点,尝试了各种方法,后台也是焦头烂额,我也不细说了,看到的都试了,大小写,二次加密,时间戳10位,签名验证。等等。。。都没用 ,最后就从以前一个同事那里 复制了一份代码,我们是java后台 ,然后就好了 直接上代码吧 我全部复制 无所谓的。 好像jsapi支付不可以用来app支付

package com.pop121.server.service.impl.api;

import com.pop121.server.entity.TOtoCommodityOrder;

import com.pop121.server.entity.dto.CommodityOrderInfo;

import com.pop121.server.service.business.OrderBusinessServiceImpl;

import com.pop121.server.util.HttpUtils;

import com.usejee.util.DateUtil;

import com.usejee.util.IpUtils;

import com.usejee.util.StringUtil;

import com.usejee.util.crypto.MD5Util;

import org.apache.commons.io.Charsets;

import org.apache.commons.io.IOUtils;

import org.apache.commons.lang3.StringUtils;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;

import javax.xml.stream.XMLInputFactory;

import javax.xml.stream.XMLStreamConstants;

import javax.xml.stream.XMLStreamException;

import javax.xml.stream.XMLStreamReader;

import java.io.ByteArrayInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.UnsupportedEncodingException;

import java.math.BigDecimal;

import java.net.URLEncoder;

import java.security.MessageDigest;

import java.text.ParseException;

import java.util.*;

/**

* APP微信付款

* Created by 杨建亮

* on 2017/8/6.

*/

@Service

public class WeixinPayServiceImpl {

private static final Logger LOG = LoggerFactory.getLogger(WeixinPayServiceImpl.class);

String AppId = "";

String paternerKey = ""; //商户api密钥

String mch_id = ""; //微信支付分配的商户号

String notify_url = "";// 统一下单后微信回调通知url

String weixinPayUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";// 统一下单url

String weixinPayQueryUrl = "https://api.mch.weixin.qq.com/pay/orderquery";// 查询订单

@Autowired

private OrderBusinessServiceImpl orderBusinessService;

/**

* 向微信支付请求统一下单

*/

public String unifiedorder(HttpServletRequest request, CommodityOrderInfo orderDTO) {

String realCost = orderDTO.getOrder_total_price(); //金额,单位分

BigDecimal cost = new BigDecimal(realCost);

int sendCost = (cost.multiply( new BigDecimal(100) ) ).intValue();//转化为分

String orderid = orderDTO.getOrder_id(); //下单批次号。本地系统生成多条记录,批次号一样。

Map reqMap = new LinkedHashMap<>();

reqMap.put("appid", AppId);

//        reqMap.put("attach", attach); //暂无附加数据

reqMap.put("body", "1111 - 购买会员 " + orderDTO.getProduct_name());

reqMap.put("mch_id", mch_id); //微信支付分配的商户号

reqMap.put("nonce_str", create_nonce_str());

reqMap.put("notify_url", notify_url);// 此路径是微信服务器调用支付结果通知路径

reqMap.put("out_trade_no", orderid); //

reqMap.put("spbill_create_ip", IpUtils.getRemoteAddr(request));

reqMap.put("total_fee", String.valueOf(sendCost)); //订单总金额,单位为分

reqMap.put("trade_type", "APP");

String sign = getSign(reqMap, paternerKey); //以上参数通过参数名ASCII字典序排序

reqMap.put("sign", sign);

String reqXml = mapToXml(reqMap);

LOG.debug("send req Xml ======>{}", reqXml);

// System.out.println("send req Xml ======>{}"+ reqXml);

String xmlResponse = HttpUtils.doPostXml(weixinPayUrl, reqXml); //发送给微信下单

LOG.debug("get Response Xml ======>{}", xmlResponse);

//  System.out.println("get Response Xml ======>{}"+ xmlResponse);

return convertToAppForm( xmlResponse );

}

/**

* 接收微信支付返回异步通知消息

*/

public String async(HttpServletRequest request) {

Map paramsMap = null;

Map sortMap = new LinkedHashMap<>(); //对paramsMap的key字母排序,去除sign参数

boolean signVerfied = false;

String msg = StringUtil.EMPTY;

try {

InputStream inputStream = request.getInputStream();

String resp = IOUtils.toString(inputStream, "UTF-8");

LOG.debug(resp);

paramsMap = xmlToMap(resp); // 得到微信发送来到参数map

String result_code = paramsMap.get("result_code"); // 微信通知返回码

String return_msg = paramsMap.get("return_msg"); // 返回信息

if( !result_code.equals("SUCCESS") ){

throw new RuntimeException(return_msg);

}

//以上参数通过参数名ASCII字典序排序

Collection keyset = paramsMap.keySet();

List list = new ArrayList<>(keyset);

Collections.sort(list);

for (int i = 0; i < list.size(); i++) {

String key = list.get(i);

if( !"sign".equalsIgnoreCase(key) ){

sortMap.put(key, paramsMap.get(key));

}

}

//            LOG.debug(JSONUtil.toJson(sortMap));

String returnSign = paramsMap.get("sign");

String total_fee = paramsMap.get("total_fee");//金额

String mySign = getSign(sortMap, paternerKey);

signVerfied = mySign.equalsIgnoreCase(returnSign);//验证sign签名是否正确

//校验返回的订单金额是否与商户侧的订单金额一致?

//todo query db compare total_fee

} catch (Exception e) {

LOG.error("{}", e);

throw new RuntimeException(e);

}

if (signVerfied) {// 验证成功

String trade_status = paramsMap.get("result_code"); // 交易状态码

String order_no = paramsMap.get("out_trade_no"); // 订单号

String trade_no = paramsMap.get("transaction_id"); // 交易号

if ( trade_status.equals("SUCCESS") ) {

//支付成功

// 更新本系统中数据库里的订单数据状态,标记为交易支付完成。

orderBusinessService.updateDbOrderToPayment(order_no, trade_no);

msg = "\n" +

"   \n" +

"   \n" +

"\n";

}else {

// 支付失败

String err_code = paramsMap.get("err_code"); //

String err_code_des = paramsMap.get("err_code_des"); //

throw new RuntimeException( err_code_des + " [ " + err_code + " ]");

}

} else {// 验证失败

throw new RuntimeException("签名错误");

}

return msg;

}

/**

* 主动查询订单并更新本地状态

* @param commodityOrder

* @return

*/

public void updateOrderStatusByWeixinPay(TOtoCommodityOrder commodityOrder){

Map reqMap = new LinkedHashMap<>();

reqMap.put("appid", AppId);

reqMap.put("mch_id", mch_id); //微信支付分配的商户号

reqMap.put("nonce_str", create_nonce_str());

if( StringUtil.isBlank(commodityOrder.getTransId()) ){

reqMap.put("out_trade_no", commodityOrder.getOrderId());

}else {

reqMap.put("transaction_id", commodityOrder.getTransId());

}

String sign = getSign(reqMap, paternerKey); //以上参数通过参数名ASCII字典序排序

reqMap.put("sign", sign);

String reqXml = mapToXml(reqMap);

LOG.debug("send req Xml ======>{}", reqXml);

String xmlResponse = HttpUtils.doPostXml(weixinPayQueryUrl, reqXml);

LOG.debug("get Response Xml ======>{}", xmlResponse);

Map weixinMap = xmlToMap(xmlResponse);

if("SUCCESS".equalsIgnoreCase(weixinMap.get("return_code"))){

String trade_state = weixinMap.get("trade_state");

if("SUCCESS".equalsIgnoreCase(trade_state)){

orderBusinessService.updateDbOrderToPayment(commodityOrder.getOrderId(), commodityOrder.getTransId());

//只更新本次查询的对象,数据库交给异步通知处理。

}

}else {

LOG.error("微信支付订单信息查询失败!");

//            throw new RuntimeException("微信支付订单信息查询失败!");

}

}

/**

* 把微信统一下单返回来的数据,重新组织成APP客户端发起支付需要的参数。

*/

private String convertToAppForm(String xmlResponse){

Map weixinMap = xmlToMap(xmlResponse);

if("SUCCESS".equalsIgnoreCase(weixinMap.get("return_code"))){

Map clientMap = new LinkedHashMap<>();//签名按key字母顺序

clientMap.put("appid", weixinMap.get("appid")==null?"":weixinMap.get("appid"));//客户端如果取不到appid值,说明服务器有错。

clientMap.put("noncestr", weixinMap.get("nonce_str"));

clientMap.put("package", "Sign=WXPay");

clientMap.put("partnerid", weixinMap.get("mch_id"));

clientMap.put("prepayid", weixinMap.get("prepay_id"));

String seconds = StringUtil.EMPTY;

try {

Date startDate = DateUtil.parseDate("1970-01-01 00:00:00");

seconds = String.valueOf( (new Date()).getTime() - startDate.getTime() / 1000).substring(0, 10);

} catch (ParseException e) {

LOG.error("{}", e);

}

clientMap.put("timestamp", seconds);//标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数。注意:部分系统取到的值为毫秒级,需要转换成秒(10位数字)。

String sign = StringUtil.isBlank(seconds)?StringUtil.EMPTY:getSign(clientMap, paternerKey);

clientMap.put("sign", sign);

//            String json = JSON.toJSONString(clientMap);

return buildUrlParamStr(clientMap).toString();

}else {

return StringUtil.EMPTY;

}

}

private String create_timestamp() {

return Long.toString(System.currentTimeMillis() / 1000);

}

private String create_nonce_str() {

String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

StringBuilder res = new StringBuilder();

for (int i = 0; i < 16; i++) {

Random rd = new Random();

res.append( chars.charAt(rd.nextInt(chars.length() - 1)) );

}

return res.toString();

}

public StringBuilder buildUrlParamStr(Map params) {

StringBuilder string1 = new StringBuilder();

for (Map.Entry entry : params.entrySet()) {

if (StringUtils.isNotBlank(entry.getValue())) { //如果参数的值为空不参与签名;

if (StringUtils.isNotBlank(string1)) {

string1.append( "&" );

}

string1.append( entry.getKey() ).append( "=" ).append( entry.getValue() );

}

}

return string1;

}

public String getSign(Map params, String paternerKey) {

StringBuilder string1 = buildUrlParamStr(params);

String stringSignTemp = string1.append("&key=" ).append( paternerKey ).toString();

LOG.debug(stringSignTemp);

return MD5Util.MD5(stringSignTemp).toUpperCase();

}

public static String createSign(Map params, String partnerKey) { //key为商户平台设置的密钥key

// 生成签名前先去除sign

params.remove("sign");

String stringA = packageSign(params, false);

String stringSignTemp = stringA + "&key=" + partnerKey;

return md5(stringSignTemp).toUpperCase();

}

public static String md5(String srcStr){

return hash("MD5", srcStr);

}

public static String hash(String algorithm, String srcStr) {

try {

MessageDigest md = MessageDigest.getInstance(algorithm);

byte[] bytes = md.digest(srcStr.getBytes("utf-8"));

return toHex(bytes);

}

catch (Exception e) {

throw new RuntimeException(e);

}

}

public static String packageSign(Map params, boolean urlEncoder) {

// 先将参数以其参数名的字典序升序进行排序

TreeMap sortedParams = new TreeMap(params);

// 遍历排序后的字典,将所有参数按"key=value"格式拼接在一起

StringBuilder sb = new StringBuilder();

boolean first = true;

for (Map.Entry param : sortedParams.entrySet()) {

String value = param.getValue();

if (isBlank(value)) {

continue;

}

if (first) {

first = false;

} else {

sb.append("&");

}

sb.append(param.getKey()).append("=");

if (urlEncoder) {

try {

value = urlEncode(value);

} catch (UnsupportedEncodingException e) {

}

}

sb.append(value);

}

return sb.toString();

}

public static String urlEncode(String src) throws UnsupportedEncodingException {

return URLEncoder.encode(src, Charsets.UTF_8.name()).replace("+", "%20");

}

public static boolean isBlank(String str) {

if (str == null) {

return true;

}

int len = str.length();

if (len == 0) {

return true;

}

for (int i = 0; i < len; i++) {

switch (str.charAt(i)) {

case ' ':

case '\t':

case '\n':

case '\r':

// case '\b':

// case '\f':

break;

default:

return false;

}

}

return true;

}

private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();

private static String toHex(byte[] bytes) {

StringBuilder ret = new StringBuilder(bytes.length * 2);

for (int i=0; i

ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);

ret.append(HEX_DIGITS[bytes[i] & 0x0f]);

}

return ret.toString();

}

/**

* map转成xml

*

* @param arr

* @return

*/

public static String mapToXml(Map arr) {

StringBuffer xml = new StringBuffer("");

for (Map.Entry entry : arr.entrySet()) {

String key = entry.getKey();

String val = entry.getValue();

xml.append("").append(val).append("").append(key).append(">");

}

xml.append("");

return xml.toString();

}

/**

* 解析xml 为Map

*/

public static Map xmlToMap(String xml) {

if (StringUtils.isBlank(xml)) {

return Collections.EMPTY_MAP;

}

InputStream inputStream = null;

try {

inputStream = new ByteArrayInputStream(xml.getBytes("utf-8"));

} catch (UnsupportedEncodingException e) {

LOG.error("parseXmlToMap error : {}", e);

throw new RuntimeException(e);

}

Map map = new HashMap<>();

XMLInputFactory factory = XMLInputFactory.newInstance();

XMLStreamReader reader = null;

try {

reader = factory.createXMLStreamReader(inputStream, "utf-8");

while (reader.hasNext()) {

int type = reader.next();

if (type == XMLStreamConstants.START_ELEMENT) {

String tagName = reader.getName().toString();

if (!"xml".equalsIgnoreCase(tagName)) { //没有内容的节点调用一下方法会报错

String val = reader.getElementText();

//                            System.out.println( tagName + "==" + val);

map.put(tagName, val);

}

}

}

return map;

} catch (Exception e) {

LOG.error("parseXmlToMap error : {}", e);

throw new RuntimeException(e);

} finally {

if (reader != null) {

try {

reader.close();

} catch (XMLStreamException e) {

LOG.error("parseXmlToMap error : {}", e);

}

}

if (inputStream != null) {

try {

inputStream.close();

} catch (IOException e) {

LOG.error("parseXmlToMap error : {}", e);

}

}

}

}

/**

* 向微信支付请求统一下单

*/

public String tradePrecreatePay(HttpServletRequest request, CommodityOrderInfo orderDTO) {

String realCost = orderDTO.getOrder_total_price(); //金额,单位分

BigDecimal cost = new BigDecimal(realCost);

int sendCost = (cost.multiply( new BigDecimal(100) ) ).intValue();//转化为分

String orderid = orderDTO.getOrder_id(); //下单批次号。本地系统生成多条记录,批次号一样。

Map reqMap = new LinkedHashMap<>();

reqMap.put("appid", AppId);

reqMap.put("mch_id", mch_id); //微信支付分配的商户号

reqMap.put("attach","康兮运动");//attach 附加数据

reqMap.put("body", "康兮 - 购买会员 " + orderDTO.getProduct_name());

reqMap.put("nonce_str", create_nonce_str());

reqMap.put("out_trade_no", orderid); //

reqMap.put("trade_type", "NATIVE");

reqMap.put("product_id", orderDTO.getProductId().toString());

reqMap.put("total_fee", String.valueOf(sendCost)); //订单总金额,单位为分

reqMap.put("notify_url", notify_url);// 此路径是微信服务器调用支付结果通知路径

reqMap.put("spbill_create_ip", IpUtils.getRemoteAddr(request));

reqMap.put("time_stamp",String.valueOf(System.currentTimeMillis()));

// String sign = getSign(reqMap, paternerKey); //以上参数通过参数名ASCII字典序排序

String createSign=createSign(reqMap, paternerKey);

//        reqMap.put("attach", attach); //暂无附加数据

reqMap.put("sign", createSign);

String reqXml = mapToXml(reqMap);

LOG.debug("send req Xml ======>{}", reqXml);

// System.out.println("send req Xml ======>{}"+ reqXml);

String xmlResponse = HttpUtils.doPostXml(weixinPayUrl, reqXml); //发送给微信下单

LOG.debug("get Response Xml ======>{}", xmlResponse);

//  System.out.println("get Response Xml ======>{}"+ xmlResponse);

Map weixinMap = xmlToMap(xmlResponse);

String qr_code =weixinMap.get("code_url");

return qr_code;

}

}

然后调取 就没问题了。其实就那几个参数 多数  多数是后台出错了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值