uni-app app端微信支付

2019-07-30  本文已影响0人  点亮橘子树

开篇第一件事 说微信,这是一个怎样的平台,做完了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<String, String> 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<String, String> paramsMap = null;
        Map<String, String> 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<String> keyset = paramsMap.keySet();
            List<String> 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 = "<xml>\n" +
                        "   <return_code><![CDATA[SUCCESS]]></return_code>\n" +
                        "   <return_msg><![CDATA[OK]]></return_msg>\n" +
                        "</xml>\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<String, String> 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<String, String> 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<String, String> weixinMap = xmlToMap(xmlResponse);
        if("SUCCESS".equalsIgnoreCase(weixinMap.get("return_code"))){
            Map<String, String> 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<String, String> params) {
        StringBuilder string1 = new StringBuilder();
        for (Map.Entry<String, String> 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<String, String> 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<String, String> 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<String, String> params, boolean urlEncoder) {
        // 先将参数以其参数名的字典序升序进行排序
        TreeMap<String, String> sortedParams = new TreeMap<String, String>(params);
        // 遍历排序后的字典,将所有参数按"key=value"格式拼接在一起
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for (Map.Entry<String, String> 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<bytes.length; 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<String, String> arr) {
        StringBuffer xml = new StringBuffer("<xml>");

        for (Map.Entry<String, String> entry : arr.entrySet()) {
            String key = entry.getKey();
            String val = entry.getValue();
            xml.append("<").append(key).append(">").append(val).append("</").append(key).append(">");
        }

        xml.append("</xml>");
        return xml.toString();
    }

    /**
     * 解析xml 为Map
     */
    public static Map<String, String> 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<String, String> 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<String, String> 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<String, String> weixinMap = xmlToMap(xmlResponse);
        String qr_code =weixinMap.get("code_url");
        return qr_code;
    }

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

上一篇 下一篇

猜你喜欢

热点阅读