微信APP支付


微信APP支付:

一、涉及到的概念:https://www.cnblogs.com/whatlonelytear/p/9518077.html
1、微信开放平台:
    主要面对移动应用/网站应用开发者,为其提供微信登录、分享、支付等相关权限和服务。
    微信开放平台还提供了数据统计功能,用于开发者统计接入应用的登录、分享等数据情况。
    接入步骤
    已京东APP举例,比如京东APP需要使用微信登录、分享和微信支付功能,首先注册微信开发平台-开发者账号,并按照以下流程在微信开放平台创建京东APP:
    审核通过后,即可获得以下的初级权限,如要获得更高如微信支付权限,需要再单独申请,具体微信支付权限申请步骤详见附件《移动应用-微信支付权限申请流程》
2、微信公众平台
    用于管理、开放微信公众号(包括订阅号、服务号、企业号),简单的说就是微信公众号的后台运营、管理系统。
    后台功能(以服务号介绍)
    (1) 基础运营功能:公众号申请成功后即可获得群发功能、自动回复、自定义菜单、投票管理;
    (2) 高级功能:微信公众平台还提供了以下高级的功能来丰富公众号,以下权限需要二次开发。
    (3) 微信支付:提供公众号内微信支付能力,和移动应用一样也需要单独申请,流程和移动APP流程类似。
    (4)管理:包括已关注用户管理、消息管理、素材管理
    (5)推广:包括广告主(定向投放广告,精准推广自己的服务)和流量主(按月获取广告收入)
    (6)统计:用户分析、图文分析、消息分析、接口分析(自定义菜单调用量)

3、微信商户平台
    无论是申请 公众平台商户 还是 开放平台商户,申请成功后,都会拥有商户平台账号,可登陆商户平台进行操作。

    商户平台主要就是做微信支付用的,如果APP或者公众号需要接入支付功能,那么就需要在公众平台申请公众平台商户,或者在开放平台申请开放平台商户。申请成功后会分配商户平台账号。


二、
1、APP支付在挂接程序的时候,需要两个接口:
统一下单接口: https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
调起支付接口: https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12&index=2

“统一下单接口”一般是在服务器完成,“调起支付接口”一般是在客户端完成。但“调起支付接口”接口涉及到了一个商户平台的key,这个key是商户平台通用的一个key,所以不能给客户端。
key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置

这个两个接口一般是在服务器完成。
每个接口都会涉及到一个sign-md5的功能,这个功能是本接口对非sign的参数做个md5,然后再加上该sign参数,一起传递给微信,

    public String wxAppPaysign(final String openId,
                               final String appId,
                               final String mchId,
                               final String notifyUrl,
                               final String outTradeNo,
                               final String nonceStr,
                               final String body,
                               final String productId,
                               final String totalFee,
                               final PayTradeRecord payTradeRecord) {
        
        String returnResult = null;
        
        LOGGER.info("--wxAppPaysign--begin--");
        
        final SortedMap<String, String> signParams = new TreeMap<>();
        signParams.put("appid", appId);
        signParams.put("body", body);
        signParams.put("mch_id", mchId);
        signParams.put("nonce_str", nonceStr);
        signParams.put("notify_url", notifyUrl);
        
        signParams.put("out_trade_no", outTradeNo);
        signParams.put("product_id", productId);
        signParams.put("spbill_create_ip", WxPayConfig.WX_SPBILL_CREATE_IP);
        signParams.put("total_fee", totalFee);
        signParams.put("trade_type", TRADE_TYPE_APP);
        
        try {
            LOGGER.info("******PaymentService(getPaySignWx)******signParams:{}", signParams);
            // 签名
            final String sign = WxPayUtil.createSign(signParams);
            signParams.put("sign", sign);
            
            final String parameter = WxPayUtil.arrayToXml(signParams);
            final String url = WxPayConfig.WX_PAY_URL;
            
            LOGGER.info("******PaymentService(getPaySignWx)******parameter:{},url:{}", parameter, url);
            final String returnStr = WxPayUtil.urlPost(url, parameter);
            LOGGER.info("******PaymentService(getPaySignWx)******returnStr:{}", returnStr);
            if (Check.notEmpty(returnStr)) {
                // 预下单id
                String prepayId = null;
                //String nonceStr2 = null;
                //String sign2 = null;
                
                // 时间戳10分钟有效期
                final String timeStamp = String.valueOf(System.currentTimeMillis()).substring(0, 10);
                
                // 字符串转换XML
                
                final SortedMap<String, String> returnParams = new TreeMap<>();
                if (Check.notEmpty(prepayId)) {
                    final Map<String, String> returnMap = WxPayUtil.xmlToMap(returnStr);
                    if (returnMap != null) {
                        prepayId = returnMap.get("prepay_id");
                    }
                    LOGGER.info("******PaymentService(getPaySignWx)******prepayId:{}", prepayId);
                    returnParams.put("appid", appId);
                    returnParams.put("noncestr", nonceStr);
                    returnParams.put("package", "Sign=WXPay");
                    returnParams.put("partnerid", mchId);
                    returnParams.put("prepayid", prepayId);
                    returnParams.put("timestamp", timeStamp);
    
                    String returnSign = WxPayUtil.createSign(returnParams);
                    LOGGER.info("--PaymentService--returnSign:{}", returnSign);
                    
                    // 定义返回对象
                    final Map<String, Object> map = new HashMap<>(16);
                    map.put("type", PaymentConstants.PAY_TYPE_WX);
                    map.put("appId", appId);
                    map.put("mchId", mchId);
                    map.put("prepayId", prepayId);
                    map.put("nonceStr", nonceStr);
                    map.put("timeStamp", timeStamp);
                    map.put("sign", returnSign);
                    returnResult = JSONObject.toJSONString(map);
                }
            }
        } catch (final Exception e) {
            e.printStackTrace();
            final String errorInfo = signParams + "_" + e.getMessage();
            LOGGER.error(errorInfo, e);
            // 记录错误日志
            errorLog.error(getClass().getName(), Thread.currentThread().getStackTrace()[1].getMethodName(), e);
            return null;
        }
        LOGGER.info("--PaymentService--returnResult:{}", returnResult);
        return returnResult;
    }





public final class WxPayUtil {
    
    /**
     * Log4J日志输出
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(WxPayUtil.class);
    
    /**
     * 请求的参数
     */
    private SortedMap<String, String> parameters;
    
    public SortedMap<String, String> getParameters() {
        return parameters;
    }
    
    public void setParameters(final SortedMap<String, String> parameters) {
        this.parameters = parameters;
    }
    
    /**
     * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名
     *
     * @param signParams 参数对象
     * @return 验签结果字符串
     */
    public static String createSign(final SortedMap<String, String> signParams) {
        final StringBuilder sb = new StringBuilder();
        final Set<Entry<String, String>> es = signParams.entrySet();
        final Iterator<Entry<String, String>> it = es.iterator();
        while (it.hasNext()) {
            final Entry<String, String> entry = it.next();
            final String k = entry.getKey();
            final String v = entry.getValue();
            if (Check.notEmpty(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + WxPayConfig.WX_APP_KEY);
        
        LOGGER.info("--createSign--sb.toString():{}--", sb.toString());
        
        final String sign = MD5Util.getMD5(sb.toString()).toUpperCase();
        
        return sign;
    }
    
    /**
     * 生成微信统一下单参数
     *
     * @param arr 参数对象
     * @return XML字符串
     */
    public static String arrayToXml(final SortedMap<String, String> arr) {
        String xml = "<xml>";
        final Iterator<Entry<String, String>> iterator = arr.entrySet().iterator();
        while (iterator.hasNext()) {
            final Entry<String, String> entry = iterator.next();
            final String key = entry.getKey();
            final String val = entry.getValue();
            xml += "<" + key + ">" + val + "</" + key + ">";
        }
        xml += "</xml>";
        return xml;
    }
    
    /**
     * XML格式字符串转换为Map
     *
     * @param strXML XML字符串
     * @return XML数据转换后的Map
     * @throws Exception
     */
    public static Map<String, String> xmlToMap(final String strXML) throws Exception {
        final Map<String, String> data = new HashMap<>(16);
        try {
            final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            final String feature = "http://apache.org/xml/features/disallow-doctype-decl";
            documentBuilderFactory.setFeature(feature, true);
            
            final DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            final InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
            final Document doc = documentBuilder.parse(stream);
            doc.getDocumentElement().normalize();
            final NodeList nodeList = doc.getDocumentElement().getChildNodes();
            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                final Node node = nodeList.item(idx);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    final Element element = (Element) node;
                    data.put(element.getNodeName(), element.getTextContent());
                }
            }
            try {
                stream.close();
            } catch (final Exception ex) {
                ex.printStackTrace();
            }
        } catch (final Exception ex) {
            ex.printStackTrace();
        }
        return data;
    }
    
    /**
     * Post请求调用发起
     *
     * @param urlStr 请求地址
     * @param param 参数对象
     * @return 请求结果
     */
    public static String urlPost(final String urlStr, final String param) {
        OutputStreamWriter out = null;
        BufferedReader in = null;
        final StringBuilder sb = new StringBuilder();
        try {
            final URL url = new URL(urlStr);
            final URLConnection con = url.openConnection();
            con.setDoOutput(true);
            con.setDoInput(true);
            con.setConnectTimeout(8000);
            /* con.setRequestProperty("Pragma:", "no-cache");*/
            con.setRequestProperty("Cache-Control", "no-cache");
            con.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
            
            out = new OutputStreamWriter(con.getOutputStream(), "utf-8");
            final String xmlInfo = param;
            
            out.write(xmlInfo);
            out.flush();
            out.close();
            in = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
            String line = "";
            for (line = in.readLine(); line != null; line = in.readLine()) {
                sb.append(line);
            }
        } catch (final MalformedURLException e) {
            e.printStackTrace();
        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (final IOException ex) {
                ex.printStackTrace();
            }
        }
        return sb.toString();
    }
    
    /**
     * 私有构造方法
     */
    private WxPayUtil() {
        
    }
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值