微信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 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 returnParams = new TreeMap<>();
                if (Check.notEmpty(prepayId)) {
                    final Map 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 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 parameters;
    
    public SortedMap getParameters() {
        return parameters;
    }
    
    public void setParameters(final SortedMap parameters) {
        this.parameters = parameters;
    }
    
    /**
     * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名
     *
     * @param signParams 参数对象
     * @return 验签结果字符串
     */
    public static String createSign(final SortedMap signParams) {
        final StringBuilder sb = new StringBuilder();
        final Set> es = signParams.entrySet();
        final Iterator> it = es.iterator();
        while (it.hasNext()) {
            final Entry 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 arr) {
        String xml = "";
        final Iterator> iterator = arr.entrySet().iterator();
        while (iterator.hasNext()) {
            final Entry entry = iterator.next();
            final String key = entry.getKey();
            final String val = entry.getValue();
            xml += "<" + key + ">" + val + "";
        }
        xml += "";
        return xml;
    }
    
    /**
     * XML格式字符串转换为Map
     *
     * @param strXML XML字符串
     * @return XML数据转换后的Map
     * @throws Exception
     */
    public static Map xmlToMap(final String strXML) throws Exception {
        final Map 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() {
        
    }
}

 

 

 

 

 

你可能感兴趣的:(Java)