起楚永世承,教崇忠孝,志尚宽平
清醒时做事,迷茫时读书,独处时思考,烦躁时运动,得意时淡然,失意时坦然,忙碌时专注,闲暇时蓄力。

微信小程序支付之统一下单(任何框架拿过来直接用,讲的是效率)

本来以前的用的web-java-tool用起来是挺不错的,现成的,不知领导想到什么,要求不用框架重新写一次,用原生的servlet重写接口,也因此web-java-tool的代码很多就不能用

因此,有了这次重新写的经历,话不多说直接上代码

至此用的的东西不多

1.hutool工具包(我这里用的是5.5.2版本的)

<dependency>
   <groupId>cn.hutool</groupId>
   <artifactId>hutool-all</artifactId>
   <version>${hutool-all.version}</version>
</dependency>

2.直接就是代码了

package com.sjcf.common;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

/**
 * 微信小程序的封装
 * 
 * @author luoc
 *
 */
public class WchartUtil {

    /**
     * 获得token接口调用凭据(access_token)
     * 
     * @return post
     */
    public static String getToken() {
        // 拼接url
        StringBuilder url = new StringBuilder("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential");
        url.append("&appid=");// appid设置
        url.append(Variables.APPID);// secret设置
        url.append("&secret=");// code设置
        url.append(Variables.APPSECRET);
        JSONObject result = new JSONObject(HttpUtil.get(url.toString()));
        System.out.println(result);
        return result.getStr("access_token");
    }

    /**
     * 通过openid获取用户信息
     * 
     * @param openid
     * @return
     */
    public static JSONObject getUserInfo(String openid) {
        StringBuilder url = new StringBuilder("https://api.weixin.qq.com/wxa/getpaidunionid?");
        url.append("access_token=");// appid设置
        url.append(WchartUtil.getToken());// secret设置
        url.append("&openid=");// code设置
        url.append(openid);
        JSONObject result = new JSONObject(HttpUtil.get(url.toString()));
        System.out.println(result.toString());
        return result;
    }

    /**
     * 获取openid
     * 
     * @param code
     * @return
     */
    public static JSONObject getOpenid(String code) {
        StringBuilder url = new StringBuilder("https://api.weixin.qq.com/sns/jscode2session?grant_type=authorization_code");
        url.append("&appid=");// appid设置
        url.append(Variables.APPID);// secret设置
        url.append("&secret=");// code设置
        url.append(Variables.APPSECRET);
        url.append("&js_code=");
        url.append(code);
        String result = HttpUtil.get(url.toString());
        System.out.println(result.toString());
        return new JSONObject(result);
    }

    /**
     * 生成32位md5码
     * 
     * @param key
     * @return
     */
    public static String md5Password(String key) {
        char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        try {
            byte[] btInput = key.getBytes();
            // 获得MD5摘要算法的 MessageDigest 对象
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            // 使用指定的字节更新摘要
            mdInst.update(btInput);
            // 获得密文
            byte[] md = mdInst.digest();
            // 把密文转换成十六进制的字符串形式
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            return null;
        }
    }
    /**
     * 1老版微信统一下单
     * 
     * @throws Exception
     */
    public static JSONObject createOrderOld(String openid, HttpServletRequest request) throws Exception {
        try {
            // 生成的随机字符串
            String nonce_str = IdUtil.simpleUUID();
            // 商品名称
            String body = "测试商品名称";
            // 获取本机的ip地址
            String spbill_create_ip = ServletUtil.getClientIP(request);
            // 订单号
            String orderNo = IdUtil.simpleUUID();
            // 支付金额,单位:分,这边需要转成字符串类型,否则后面的签名会失败
            String money = "1";

            SortedMap<String, Object> packageParams = new TreeMap<String, Object>();
            packageParams.put("appid", Variables.APPID);
            packageParams.put("mch_id", Variables.MCH_ID);//商户号
            packageParams.put("nonce_str", nonce_str);// 生成的随机字符串
            packageParams.put("body", body);// 商品名称
            packageParams.put("out_trade_no", orderNo);// 商户订单号
            packageParams.put("total_fee", money);// 支付金额,这边需要转成字符串类型,否则后面的签名会失败
            packageParams.put("spbill_create_ip", spbill_create_ip);
            packageParams.put("notify_url", Variables.NOTIFY_URL);
            packageParams.put("trade_type", Variables.TRADETYPE);
            packageParams.put("openid", openid);//微信openid

            // 除去数组中的空值和签名参数
            // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
            // MD5运算生成签名,这里是第一次签名,用于调用统一下单接口
            String mysign = createSign(packageParams, Variables.MCH_KEY);
            System.out.println("===========第一次签名:" + mysign + "==============");
            // 拼接统一下单接口使用的xml数据,要将上一步生成的签名一起拼接进去
            String xml = "<xml>" 
            + "<appid>" + Variables.APPID + "</appid>" 
                    + "<body><![CDATA[" + body + "]]></body>"
                    + "<mch_id>" + Variables.MCH_ID + "</mch_id>" 
                    + "<nonce_str>" + nonce_str + "</nonce_str>"
                    + "<notify_url>" + Variables.NOTIFY_URL + "</notify_url>" 
                    + "<openid>" + openid + "</openid>"
                    + "<out_trade_no>" + orderNo + "</out_trade_no>" 
                    + "<spbill_create_ip>" + spbill_create_ip+ "</spbill_create_ip>" 
                    + "<total_fee>" + money + "</total_fee>" 
                    + "<trade_type>"+ Variables.TRADETYPE + "</trade_type>" 
                    + "<sign>" + mysign + "</sign>" + "</xml>";

            System.out.println("调试模式_统一下单接口 请求XML数据:" + xml);
            // 调用统一下单接口,并接受返回的结果
            String result = HttpUtil.post(Variables.pay_url, xml);
            System.out.println(result);
            JSONObject map = new JSONObject(getMapFromXML(result));
            //二次签名
            packageParams = new TreeMap<String, Object>();
            packageParams.put("appId", Variables.APPID);
            packageParams.put("nonceStr", map.getStr("nonce_str"));
            packageParams.put("package", "prepay_id="+map.getStr("prepay_id"));
            packageParams.put("signType", "MD5");
            packageParams.put("timeStamp", DateUtil.date().toString());
            packageParams.put("key", Variables.MCH_KEY);
            String paySign = createSign(packageParams, Variables.MCH_KEY);
            packageParams.put("paySign", paySign);
            
            JSONObject resultJson = new JSONObject(packageParams);
            return resultJson;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 1微信支付签名算法sign
     * 
     * @param parameters
     * @param key        微信小程序商户 key
     * @return
     */
    public static String createSign(SortedMap<String, Object> parameters, String key) {
        StringBuffer sb = new StringBuffer();
        Set<Entry<String, Object>> es = parameters.entrySet();// 所有参与传参的参数按照accsii排序(升序)
        Iterator<Entry<String, Object>> it = es.iterator();
        while (it.hasNext()) {
            Entry<String, Object> entry = it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        // 这里是商户那里设置的key
        sb.append("key=" + key);
        System.out.println("签名字符串:" + sb.toString());
//            System.out.println("签名MD5未变大写:" + MD5Util.MD5Encode(sb.toString(), characterEncoding));
        String sign = md5Password(sb.toString()).toUpperCase();
        return sign;
    }

    /**
     * XML转换为map
     * @param strXML
     * @return Map
     * @throws Exception
     */
    public static Map<String, Object> getMapFromXML(String strXML) throws Exception {
        try {
            Map<String, Object> data = new HashMap<String, Object>();
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            documentBuilderFactory.setXIncludeAware(false);
            documentBuilderFactory.setExpandEntityReferences(false);
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
            org.w3c.dom.Document doc = documentBuilder.parse(stream);
            doc.getDocumentElement().normalize();
            NodeList nodeList = doc.getDocumentElement().getChildNodes();
            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                Node node = nodeList.item(idx);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
                    data.put(element.getNodeName(), element.getTextContent());
                }
            }
            try {
                stream.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return data;
        } catch (Exception ex) {
            throw ex;
        }
    }
}

3.最后献上截图(1.微信开发工具  2.手机测验截图)

 

 

 这已经就成功了,如果代码那里有问题的可以留言,我看到了一定回复的

posted @ 2020-12-24 18:05  一蹴而就  阅读(293)  评论(0编辑  收藏  举报