美文网首页
uni-app app端微信支付

uni-app app端微信支付

作者: 点亮橘子树 | 来源:发表于2019-07-30 17:58 被阅读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;
        }

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

    相关文章

      网友评论

          本文标题:uni-app app端微信支付

          本文链接:https://www.haomeiwen.com/subject/uhforctx.html