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


    本来以前的用的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.手机测验截图)

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

  • 相关阅读:
    【转载】褪去华衣 裸视学习 探讨系列
    最简单的视频网站(JavaEE+FFmpeg)
    过段时间要换博客了
    计网3
    计网1
    物理层计算题
    计网4
    子网划分与CIDR
    百度=残留在墙后的垃圾
    计网2
  • 原文地址:https://www.cnblogs.com/study-together/p/14185528.html
Copyright © 2020-2023  润新知