微信app支付(后端代码) - Go语言中文社区

微信app支付(后端代码)


一、准备

二、接入

  • 步骤1可以不用管,直接进入步骤2,调用统一下单代码:

       //第一次签名
        Map<String, String> paraMap = new HashMap<>();
        //订单总金额,单位为分
        paraMap.put("total_fee", "1");
        //微信开放平台审核通过的应用APPID
        paraMap.put("appid",WeChatAppPayUtils.APPID);
        //商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一。详见https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_2
        paraMap.put("out_trade_no", System.currentTimeMillis()+"test");
        //附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
        paraMap.put("attach", "扩展字段");
        //商品描述交易字段格式根据不同的应用场景按照以下格式: APP——需传入应用市场上的APP名字-实际商品名称,天天爱消除-游戏充值。
        paraMap.put("body", "XXXX-充值");
        //微信支付分配的商户号
        paraMap.put("mch_id", WeChatAppPayUtils.MCH_ID );
        //商品详细描述,对于使用单品优惠的商户,改字段必须按照规范上传,详见
        paraMap.put("detail", "XXXX-充值");
        //随机字符串,不长于32位。
        paraMap.put("nonce_str",  WeChatAppPayUtils.getNonceStr());
        //接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
        paraMap.put("notify_url", WeChatAppPayUtils.NOTIFY_URL);
        //用户端实际ip
        paraMap.put("spbill_create_ip", "14.111.58.XX");
        //交易类型,取值如下:JSAPI,NATIVE,APP
        paraMap.put("trade_type", "APP");

        //将参数字典序列排序
        String stringSignTemp =  WeChatAppPayUtils.formatUrlMap(paraMap, false, false);

        stringSignTemp = stringSignTemp + "&key=" + WeChatAppPayUtils.MCH_ID_KEY;

        //得到签名
        String sign = MD5Utils.MD5Encoding(stringSignTemp).toUpperCase();
        //拼接xml
        StringBuffer xml = new StringBuffer();
        xml.append("<xml>");
        for (Map.Entry<String, String> entry : paraMap.entrySet()) {
            xml.append("<" + entry.getKey() + ">");
            xml.append(entry.getValue());
            xml.append("</" + entry.getKey() + ">" + "n");
        }
        xml.append("<sign>");
        xml.append(sign);
        xml.append("</sign>");
        xml.append("</xml>");
        log.info("xml n {} ", xml.toString());

        //请求接口返回prepay_id等等数据
        String responseBosy = HttpUtils.sentPost(WeChatAppPayUtils.PAYURL, xml.toString(), "UTF-8");

        log.info("responseBosy [ {} ]",responseBosy);

  • 下面就是步骤3:步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appid,partnerid,prepayid,noncestr,timestamp,package。注意:package的值格式为Sign=WXPay
 //将返回的xml转为map
        Map<String,String> resultMap = WeChatAppPayUtils.readStringXmlOut(responseBosy);
        String prepay_id = resultMap.getOrDefault("prepay_id", "");

        String return_code = resultMap.getOrDefault("return_code", "");
        if(return_code != null && "SUCCESS".equals(return_code)  && prepay_id != null && !"".equals(prepay_id)){
            log.info(" prepay_id  [ {} ]",prepay_id);
            //要返回给app端的支付参数
            //APP端调起支付的参数列表
            Map<String, String> paraMapApp = new HashMap<>();
            //微信开放平台审核通过的应用APPID
            paraMapApp.put("appid",WeChatAppPayUtils.APPID);
            //	微信支付分配的商户号
            paraMapApp.put("partnerid",WeChatAppPayUtils.MCH_ID);
            paraMapApp.put("prepayid",prepay_id);
            paraMapApp.put("package","Sign=WXPay");
            paraMapApp.put("noncestr",WeChatAppPayUtils.getNonceStr());
            String timeStamp = String.valueOf(WeChatAppPayUtils.getSecondTimestamp(new Date()));
            paraMapApp.put("timestamp",timeStamp);

           String stringSignTempApp = WeChatAppPayUtils.formatUrlMap(paraMapApp,false,false);
            stringSignTempApp = stringSignTempApp + "&key=" + WeChatAppPayUtils.MCH_ID_KEY;
            log.info("stringSignTempApp [ {} ]",stringSignTempApp);
            //得到app支付签名
            String signApp = MD5Utils.MD5Encoding(stringSignTempApp).toUpperCase();
            paraMapApp.put("sign",signApp);

            log.info("返回给app的参数 [ {} ]",paraMapApp);

            return paraMapApp;
        }else {
            log.info("获取prepay_id失败 [ {} ]",resultMap.getOrDefault("return_msg",""));
        }
  • 最后就是把结果返回给app端了,下面贴下支付的完整的代码:
   private static final Logger log = LoggerFactory.getLogger(WeChatAppPay.class);

 /***
     *发起支付
     * */
    public Map<String,String> gateway( Map<String, String> params) {
        //第一次签名
        Map<String, String> paraMap = new HashMap<>();
        //订单总金额,单位为分
        paraMap.put("total_fee", "1");
        //微信开放平台审核通过的应用APPID
        paraMap.put("appid",WeChatAppPayUtils.APPID);
        //商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一。详见https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_2
        paraMap.put("out_trade_no", System.currentTimeMillis()+"test");
        //附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
        paraMap.put("attach", "扩展字段");
        //商品描述交易字段格式根据不同的应用场景按照以下格式: APP——需传入应用市场上的APP名字-实际商品名称,天天爱消除-游戏充值。
        paraMap.put("body", "XXXX-充值");
        //微信支付分配的商户号
        paraMap.put("mch_id", WeChatAppPayUtils.MCH_ID );
        //商品详细描述,对于使用单品优惠的商户,改字段必须按照规范上传,详见
        paraMap.put("detail", "XXXX-充值");
        //随机字符串,不长于32位。
        paraMap.put("nonce_str",  WeChatAppPayUtils.getNonceStr());
        //接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
        paraMap.put("notify_url", WeChatAppPayUtils.NOTIFY_URL);
        //用户端实际ip
        paraMap.put("spbill_create_ip", "14.111.58.XX");
        //交易类型,取值如下:JSAPI,NATIVE,APP
        paraMap.put("trade_type", "APP");

        //将参数字典序列排序
        String stringSignTemp =  WeChatAppPayUtils.formatUrlMap(paraMap, false, false);

        stringSignTemp = stringSignTemp + "&key=" + WeChatAppPayUtils.MCH_ID_KEY;

        //得到签名
        String sign = MD5Utils.MD5Encoding(stringSignTemp).toUpperCase();
        //拼接xml
        StringBuffer xml = new StringBuffer();
        xml.append("<xml>");
        for (Map.Entry<String, String> entry : paraMap.entrySet()) {
            xml.append("<" + entry.getKey() + ">");
            xml.append(entry.getValue());
            xml.append("</" + entry.getKey() + ">" + "n");
        }
        xml.append("<sign>");
        xml.append(sign);
        xml.append("</sign>");
        xml.append("</xml>");
        log.info("xml n {} ", xml.toString());

        //请求接口返回prepay_id等等数据
        String responseBosy = HttpUtils.sentPost(WeChatAppPayUtils.PAYURL, xml.toString(), "UTF-8");

        log.info("responseBosy [ {} ]",responseBosy);

        //将返回的xml转为map
        Map<String,String> resultMap = WeChatAppPayUtils.readStringXmlOut(responseBosy);
        String prepay_id = resultMap.getOrDefault("prepay_id", "");

        String return_code = resultMap.getOrDefault("return_code", "");
        if(return_code != null && "SUCCESS".equals(return_code)  && prepay_id != null && !"".equals(prepay_id)){
            log.info(" prepay_id  [ {} ]",prepay_id);
            //要返回给app端的支付参数
            //APP端调起支付的参数列表
            Map<String, String> paraMapApp = new HashMap<>();
            //微信开放平台审核通过的应用APPID
            paraMapApp.put("appid",WeChatAppPayUtils.APPID);
            //	微信支付分配的商户号
            paraMapApp.put("partnerid",WeChatAppPayUtils.MCH_ID);
            paraMapApp.put("prepayid",prepay_id);
            paraMapApp.put("package","Sign=WXPay");
            paraMapApp.put("noncestr",WeChatAppPayUtils.getNonceStr());
            String timeStamp = String.valueOf(WeChatAppPayUtils.getSecondTimestamp(new Date()));
            paraMapApp.put("timestamp",timeStamp);

           String stringSignTempApp = WeChatAppPayUtils.formatUrlMap(paraMapApp,false,false);
            stringSignTempApp = stringSignTempApp + "&key=" + WeChatAppPayUtils.MCH_ID_KEY;
            log.info("stringSignTempApp [ {} ]",stringSignTempApp);
            //得到app支付签名
            String signApp = MD5Utils.MD5Encoding(stringSignTempApp).toUpperCase();
            paraMapApp.put("sign",signApp);

            log.info("返回给app的参数 [ {} ]",paraMapApp);

            return paraMapApp;
        }else {
            log.info("获取prepay_id失败 [ {} ]",resultMap.getOrDefault("return_msg",""));
        }

        return null;
    }
  • 步骤4:是app端得到刚才接口的返回调用微信sdk,弹出支付界面。
  • 步骤5是接收支付完成后的异步回调(微信端调用notify_url参数的地址):
 /***
     * 微信支付后异步回调
     * */
    public String callback(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        params.put("body", getBody(request));
        //读取xml内容转为map
        params = WeChatAppPayUtils.readStringXmlOut(params.getOrDefault("body", ""));

        log.info("微信支付回调参数 [ {} ]",params);

        //商户订单号
        String out_trade_no = params.getOrDefault("out_trade_no", "");
        //业务结果SUCCESS或者FAIL
        String result_code = params.getOrDefault("result_code", "");
        //支付金额 (分)
        String total_fee = params.getOrDefault("total_fee", "");
        //支付完成时间
        String time_end = params.getOrDefault("time_end", "");

        //签名
        String sign = params.getOrDefault("sign","");

        //商家数据包,原样返回
        String attach = params.getOrDefault("attach","");

        //排除sign参数的所有参数,参与签名 , 验证微信回调的签名
        Map<String, String> map = new HashMap<>();
        for (String s : params.keySet()) {
            String value = params.get(s);
            if (StringUtils.isNotBlank(value) && !StringUtils.equals(s, "sign")) {
                map.put(s, value);
            }
        }

        String comSign = WeChatAppPayUtils.getSign(map , WeChatAppPayUtils.MCH_ID_KEY);

        if (null != result_code && "SUCCESS".equals(result_code)) {
            if (StringUtils.equals(sign, comSign)) {
                //TODO  通过out_trade_no或者attach查询到数据库里的订单,再进行验证等
                return "SUCCESS";
            }else{
                log.info("验证签名失败 [ {} ]",params);
            }
        }else{
            log.info("支付失败 [ {} ]",params);
        }

        return "FAIL";
    }

    private String getBody(HttpServletRequest request) {
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
            CharArrayWriter data = new CharArrayWriter();
            char[] buf = new char[8192];
            int ret;
            while ((ret = in.read(buf, 0, 8192)) != -1) {
                data.write(buf, 0, ret);
            }
            return data.toString();
        } catch (Exception e) {
            System.err.println("接收BODY内容失败:"+ e);
        }
        return null;
    }
  • 步骤6就不说了,一般很少用到的查询订单。

  • 下面贴下完整的代码:
    WeChatAppPay.java :

package com.rw.pay.services;



import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.CharArrayWriter;
import java.io.InputStreamReader;
import java.util.*;

/**
 * @author Zhou Zhong Qing

 * @Description: 微信原生app支付
 * @date 2018/6/14 15:16
 */
public class WeChatAppPay {


    private static final Logger log = LoggerFactory.getLogger(WeChatAppPay.class);


    /***
     *发起支付
     * */
    public Map<String,String> gateway( Map<String, String> params) {
        //第一次签名
        Map<String, String> paraMap = new HashMap<>();
        //订单总金额,单位为分
        paraMap.put("total_fee", "1");
        //微信开放平台审核通过的应用APPID
        paraMap.put("appid",WeChatAppPayUtils.APPID);
        //商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一。详见https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_2
        paraMap.put("out_trade_no", System.currentTimeMillis()+"test");
        //附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
        paraMap.put("attach", "扩展字段");
        //商品描述交易字段格式根据不同的应用场景按照以下格式: APP——需传入应用市场上的APP名字-实际商品名称,天天爱消除-游戏充值。
        paraMap.put("body", "XXXX-充值");
        //微信支付分配的商户号
        paraMap.put("mch_id", WeChatAppPayUtils.MCH_ID );
        //商品详细描述,对于使用单品优惠的商户,改字段必须按照规范上传,详见
        paraMap.put("detail", "XXXX-充值");
        //随机字符串,不长于32位。
        paraMap.put("nonce_str",  WeChatAppPayUtils.getNonceStr());
        //接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
        paraMap.put("notify_url", WeChatAppPayUtils.NOTIFY_URL);
        //用户端实际ip
        paraMap.put("spbill_create_ip", "14.111.58.XX");
        //交易类型,取值如下:JSAPI,NATIVE,APP
        paraMap.put("trade_type", "APP");

        //将参数字典序列排序
        String stringSignTemp =  WeChatAppPayUtils.formatUrlMap(paraMap, false, false);

        stringSignTemp = stringSignTemp + "&key=" + WeChatAppPayUtils.MCH_ID_KEY;

        //得到签名
        String sign = MD5Utils.MD5Encoding(stringSignTemp).toUpperCase();
        //拼接xml
        StringBuffer xml = new StringBuffer();
        xml.append("<xml>");
        for (Map.Entry<String, String> entry : paraMap.entrySet()) {
            xml.append("<" + entry.getKey() + ">");
            xml.append(entry.getValue());
            xml.append("</" + entry.getKey() + ">" + "n");
        }
        xml.append("<sign>");
        xml.append(sign);
        xml.append("</sign>");
        xml.append("</xml>");
        log.info("xml n {} ", xml.toString());

        //请求接口返回prepay_id等等数据
        String responseBosy = HttpUtils.sentPost(WeChatAppPayUtils.PAYURL, xml.toString(), "UTF-8");

        log.info("responseBosy [ {} ]",responseBosy);

        //将返回的xml转为map
        Map<String,String> resultMap = WeChatAppPayUtils.readStringXmlOut(responseBosy);
        String prepay_id = resultMap.getOrDefault("prepay_id", "");

        String return_code = resultMap.getOrDefault("return_code", "");
        if(return_code != null && "SUCCESS".equals(return_code)  && prepay_id != null && !"".equals(prepay_id)){
            log.info(" prepay_id  [ {} ]",prepay_id);
            //要返回给app端的支付参数
            //APP端调起支付的参数列表
            Map<String, String> paraMapApp = new HashMap<>();
            //微信开放平台审核通过的应用APPID
            paraMapApp.put("appid",WeChatAppPayUtils.APPID);
            //	微信支付分配的商户号
            paraMapApp.put("partnerid",WeChatAppPayUtils.MCH_ID);
            paraMapApp.put("prepayid",prepay_id);
            paraMapApp.put("package","Sign=WXPay");
            paraMapApp.put("noncestr",WeChatAppPayUtils.getNonceStr());
            String timeStamp = String.valueOf(WeChatAppPayUtils.getSecondTimestamp(new Date()));
            paraMapApp.put("timestamp",timeStamp);

           String stringSignTempApp = WeChatAppPayUtils.formatUrlMap(paraMapApp,false,false);
            stringSignTempApp = stringSignTempApp + "&key=" + WeChatAppPayUtils.MCH_ID_KEY;
            log.info("stringSignTempApp [ {} ]",stringSignTempApp);
            //得到app支付签名
            String signApp = MD5Utils.MD5Encoding(stringSignTempApp).toUpperCase();
            paraMapApp.put("sign",signApp);

            log.info("返回给app的参数 [ {} ]",paraMapApp);

            return paraMapApp;
        }else {
            log.info("获取prepay_id失败 [ {} ]",resultMap.getOrDefault("return_msg",""));
        }

        return null;
    }



    public static void main(String[] args) {
        new WeChatAppPay().gateway(new HashMap<>());
    }






    /***
     * 微信支付后异步回调回调
     * */
    public String callback(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        params.put("body", getBody(request));
        //读取xml内容转为map
        params = WeChatAppPayUtils.readStringXmlOut(params.getOrDefault("body", ""));

        log.info("微信支付回调参数 [ {} ]",params);

        //商户订单号
        String out_trade_no = params.getOrDefault("out_trade_no", "");
        //业务结果SUCCESS或者FAIL
        String result_code = params.getOrDefault("result_code", "");
        //支付金额 (分)
        String total_fee = params.getOrDefault("total_fee", "");
        //支付完成时间
        String time_end = params.getOrDefault("time_end", "");

        //签名
        String sign = params.getOrDefault("sign","");

        //商家数据包,原样返回
        String attach = params.getOrDefault("attach","");

        //排除sign参数的所有参数,参与签名 , 验证微信回调的签名
        Map<String, String> map = new HashMap<>();
        for (String s : params.keySet()) {
            String value = params.get(s);
            if (StringUtils.isNotBlank(value) && !StringUtils.equals(s, "sign")) {
                map.put(s, value);
            }
        }

        String comSign = WeChatAppPayUtils.getSign(map , WeChatAppPayUtils.MCH_ID_KEY);

        if (null != result_code && "SUCCESS".equals(result_code)) {
            if (StringUtils.equals(sign, comSign)) {
                //TODO  通过out_trade_no或者attach查询到数据库里的订单,再进行验证等
                return "SUCCESS";
            }else{
                log.info("验证签名失败 [ {} ]",params);
            }
        }else{
            log.info("支付失败 [ {} ]",params);
        }

        return "FAIL";
    }

    private String getBody(HttpServletRequest request) {
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
            CharArrayWriter data = new CharArrayWriter();
            char[] buf = new char[8192];
            int ret;
            while ((ret = in.read(buf, 0, 8192)) != -1) {
                data.write(buf, 0, ret);
            }
            return data.toString();
        } catch (Exception e) {
            System.err.println("接收BODY内容失败:"+ e);
        }
        return null;
    }


}

WeChatAppPayUtils.java:

package com.rw.pay.services;

import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;


import java.net.URLEncoder;
import java.util.*;

/**
 * @author Zhou Zhong Qing
 * @Title: ${file_name}
 * @Package ${package_name}
 * @Description: 微信支付的工具类
 * @date 2018/6/14 16:38
 */
public class WeChatAppPayUtils {



    public static final String APPID = "这里填写APPID";


    public final String APPSECRET = "这里填写秘钥APPSECRET";

    //商户号
    public static final String MCH_ID = "这里填写商户id MCH_ID";

    //商户密钥
    public static final String MCH_ID_KEY = "这里填商户密钥MCH_ID_KEY";

    //统一下单地址
    public final static String PAYURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    /***
     * 异步回调地址
     * */
    public final static String NOTIFY_URL = "http://pay.test.com/notify/6";


    /**
     * 获取精确到秒的时间戳 10 位数
     *
     * @return
     */
    public static int getSecondTimestamp(Date date) {
        if (null == date) {
            return 0;
        }
        String timestamp = String.valueOf(date.getTime());
        int length = timestamp.length();
        if (length > 3) {
            return Integer.valueOf(timestamp.substring(0, length - 3));
        } else {
            return 0;
        }
    }

    /**
     * @param xml
     * @return Map
     * @description 将xml字符串转换成map
     */
    public static Map<String, String> readStringXmlOut(String xml) {
        Map<String, String> map = new HashMap<String, String>();
        Document doc = null;
        try {
            doc = DocumentHelper.parseText(xml); // 将字符串转为XML
            Element rootElt = doc.getRootElement(); // 获取根节点
            @SuppressWarnings("unchecked")
            List<Element> list = rootElt.elements();// 获取根节点下所有节点
            for (Element element : list) { // 遍历节点
                map.put(element.getName(), element.getText()); // 节点的name为map的key,text为map的value
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    /*
  * 生成32位随机字符串
  * */
    public static String getNonceStr() {
        UUID uuid = UUID.randomUUID();
        return uuid.toString().replace("-", "");
    }


    /**
     * 方法用途: 对所有传入参数按照字段名的Unicode码从小到大排序(字典序),并且生成url参数串<br>
     * 实现步骤: <br>
     *
     * @param paraMap    要排序的Map对象
     * @param urlEncode  是否需要URLENCODE
     * @param keyToLower 是否需要将Key转换为全小写
     *                   true:key转化成小写,false:不转化
     * @return
     */
    public static String formatUrlMap(Map<String, String> paraMap, boolean urlEncode, boolean keyToLower) {
        String buff = "";
        Map<String, String> tmpMap = paraMap;
        try {
            List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(tmpMap.entrySet());
            // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
            Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
                @Override
                public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
                    return (o1.getKey()).toString().compareTo(o2.getKey());
                }
            });
            // 构造URL 键值对的格式
            StringBuilder buf = new StringBuilder();
            for (Map.Entry<String, String> item : infoIds) {
                if (StringUtils.isNotBlank(item.getKey())) {
                    String key = item.getKey();
                    String val = item.getValue();
                    if (urlEncode) {
                        val = URLEncoder.encode(val, "utf-8");
                    }
                    if (keyToLower) {
                        buf.append(key.toLowerCase() + "=" + val);
                    } else {
                        buf.append(key + "=" + val);
                    }
                    buf.append("&");
                }

            }
            buff = buf.toString();
            if (buff.isEmpty() == false) {
                buff = buff.substring(0, buff.length() - 1);
            }
        } catch (Exception e) {
            return null;
        }
        return buff;
    }


    /**
     * 获取参数签名
     * @param paramMap  签名参数
     * @param paySecret 签名密钥
     * @return
     */
    public static String  getSign (Map<String , String> paramMap , String paySecret){
        SortedMap<String, String> smap = new TreeMap<String, String>(paramMap);

        StringBuffer stringBuffer = new StringBuffer();
        for (Map.Entry<String, String> m : smap.entrySet()) {
            Object value = m.getValue();
            if (value != null && StringUtils.isNotBlank(String.valueOf(value))&&!"sign".equals(m.getKey())){
                stringBuffer.append(m.getKey()).append("=").append(value).append("&");
            }
        }

        String argPreSign = stringBuffer.append("key=").append(paySecret).toString();
        return MD5Utils.MD5Encoding(argPreSign).toUpperCase();
    }

}

MD5Utils.java:

package com.rw.pay.services;

import java.security.MessageDigest;

public class MD5Utils {

    private static final char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    /*
    * 先转为utf-8
    * */
    public static String MD5Encoding(String s) {
        byte[] btInput = null;
        try {
            btInput = s.getBytes("UTF-8");
        }catch (Exception e){
        }
        return MD5(btInput, 32);
    }


    public static String MD5(String s) {
        byte[] btInput = s.getBytes();
        return MD5(btInput, 32);
    }

    public static String MD5_16(String str) {
        byte[] btInput = str.getBytes();
        return MD5(btInput, 16);
    }

    private static String MD5(byte[] btInput, int length) {
        try {
            // 获得MD5摘要算法的 MessageDigest 对象
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            // MessageDigest mdInst = MessageDigest.getInstance("SHA-1");
            // 使用指定的字节更新摘要
            mdInst.update(btInput);
            // 获得密文
            byte[] md = mdInst.digest();
            // 把密文转换成十六进制的字符串形式
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (byte byte0 : md) {
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            String result = new String(str);
            return length == 16 ? result.substring(8, 24) : result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

HttpUtils.java:

package com.rw.pay.services;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.*;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class HttpUtils {

	private static final int TIME_OUT = 5;
	private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
	/**
	 * 通过HTTP GET 发送参数
	 * 
	 * @param httpUrl
	 * @param parameter
	 */
	public static String sendGet(String httpUrl, Map<String, String> parameter) {
		if (parameter == null || httpUrl == null) {
			return null;
		}

		StringBuilder sb = new StringBuilder();
		Iterator<Entry<String, String>> iterator = parameter.entrySet().iterator();
		while (iterator.hasNext()) {
			if (sb.length() > 0) {
				sb.append('&');
			}
			Entry<String, String> entry = iterator.next();
			String key = entry.getKey();
			String value;
			try {
				value = URLEncoder.encode(entry.getValue(), "UTF-8");
			} catch (UnsupportedEncodingException e) {
				value = "";
			}
			sb.append(key).append('=').append(value);
		}
		String urlStr = null;
		if (httpUrl.lastIndexOf('?') != -1) {
			urlStr = httpUrl + '&' + sb.toString();
		} else {
			urlStr = httpUrl + '?' + sb.toString();
		}

		HttpURLConnection httpCon = null;
		String responseBody = null;
		try {
			URL url = new URL(urlStr);
			log.info("request url [ {} ]",urlStr);
			httpCon = (HttpURLConnection) url.openConnection();
			httpCon.setDoOutput(true);
			httpCon.setRequestMethod("GET");
			httpCon.setConnectTimeout(TIME_OUT * 1000);
			httpCon.setReadTimeout(TIME_OUT * 1000);
			// 开始读取返回的内容
			InputStream in = httpCon.getInputStream();
			byte[] readByte = new byte[1024];
			// 读取返回的内容
			int readCount = in.read(readByte, 0, 1024);
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			while (readCount != -1) {
				baos.write(readByte, 0, readCount);
				readCount = in.read(readByte, 0, 1024);
			}
			responseBody = new String(baos.toByteArray(), "UTF-8");
			baos.close();
		} catch (Exception e) {
		} finally {
			if (httpCon != null)
				httpCon.disconnect();
		}
		return responseBody;
	}

	/**
	 * 使用HTTP POST 发送文本
	 * 
	 * @param httpUrl
	 *            发送的地址
	 * @param postBody
	 *            发送的内容
	 * @return 返回HTTP SERVER的处理结果,如果返回null,发送失败
	 */
	public static String sentPost(String httpUrl, String postBody) {
		return sentPost(httpUrl, postBody, "UTF-8", null);
	}

	/**
	 * 使用HTTP POST 发送文本
	 * 
	 * @param httpUrl
	 *            发送的地址
	 * @param postBody
	 *            发送的内容
	 * @return 返回HTTP SERVER的处理结果,如果返回null,发送失败
	 */
	public static String sentPost(String httpUrl, String postBody, String encoding) {
		return sentPost(httpUrl, postBody, encoding, null);
	}

	/**
	 * 使用HTTP POST 发送文本
	 * @param httpUrl   目的地址
	 * @param postBody  post的包体
	 * @param headerMap 增加的Http头信息
	 * @return
	 */
	public static String sentPost(String httpUrl, String postBody, Map<String, String> headerMap) {
		return sentPost(httpUrl, postBody, "UTF-8", headerMap);
	}

	/**
	 * 使用HTTP POST 发送文本
	 * 
	 * @param httpUrl
	 *            发送的地址
	 * @param postBody
	 *            发送的内容
	 * @param encoding
	 *            发送的内容的编码
	 * @param headerMap 增加的Http头信息          
	 * @return 返回HTTP SERVER的处理结果,如果返回null,发送失败
	 * .................
	 */
	public static String sentPost(String httpUrl, String postBody, String encoding, Map<String, String> headerMap) {
		HttpURLConnection httpCon = null;
		String responseBody = null;
		URL url = null;
		try {
			url = new URL(httpUrl);
		} catch (MalformedURLException e1) {
			return null;
		}
		try {
			httpCon = (HttpURLConnection) url.openConnection();
		} catch (IOException e1) {
			return null;
		}
		if (httpCon == null) {
			return null;
		}
		httpCon.setDoOutput(true);
		httpCon.setConnectTimeout(TIME_OUT * 1000);
		httpCon.setReadTimeout(TIME_OUT * 1000);
		httpCon.setDoOutput(true);
		httpCon.setUseCaches(false);
		try {
			httpCon.setRequestMethod("POST");
		} catch (ProtocolException e1) {
			return null;
		}
		if (headerMap != null) {
			Iterator<Entry<String, String>> iterator = headerMap.entrySet().iterator();
			while (iterator.hasNext()) {
				Entry<String, String> entry = iterator.next();
				httpCon.addRequestProperty(entry.getKey(), entry.getValue());
			}
		}
		OutputStream output;
		try {
			output = httpCon.getOutputStream();
		} catch (IOException e1) {
			return null;
		}
		try {
			output.write(postBody.getBytes(encoding));
		} catch (UnsupportedEncodingException e1) {
			return null;
		} catch (IOException e1) {
			return null;
		}
		try {
			output.flush();
			output.close();
		} catch (IOException e1) {
			return null;
		}
		// 开始读取返回的内容
		InputStream in;
		try {
			in = httpCon.getInputStream();
		} catch (IOException e1) {
			return null;
		}
		/**
		 * 这个方法可以在读写操作前先得知数据流里有多少个字节可以读取。
		 * 需要注意的是,如果这个方法用在从本地文件读取数据时,一般不会遇到问题,
		 * 但如果是用于网络操作,就经常会遇到一些麻烦。
		 * 比如,Socket通讯时,对方明明发来了1000个字节,但是自己的程序调用available()方法却只得到900,或者100,甚至是0,
		 * 感觉有点莫名其妙,怎么也找不到原因。
		 * 其实,这是因为网络通讯往往是间断性的,一串字节往往分几批进行发送。
		 * 本地程序调用available()方法有时得到0,这可能是对方还没有响应,也可能是对方已经响应了,但是数据还没有送达本地。
		 * 对方发送了1000个字节给你,也许分成3批到达,这你就要调用3次available()方法才能将数据总数全部得到。
		 * 
		 * 经常出现size为0的情况,导致下面readCount为0使之死循环(while (readCount != -1) {xxxx}),出现死机问题
		 */
		int size = 0;
		try {
			size = in.available();
		} catch (IOException e1) {
			return null;
		}
		if (size == 0) {
			size = 1024;
		}
		byte[] readByte = new byte[size];
		// 读取返回的内容
		int readCount = -1;
		try {
			readCount = in.read(readByte, 0, size);
		} catch (IOException e1) {
			return null;
		}
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		while (readCount != -1) {
			baos.write(readByte, 0, readCount);
			try {
				readCount = in.read(readByte, 0, size);
			} catch (IOException e) {
				return null;
			}
		}
		try {
			responseBody = new String(baos.toByteArray(), encoding);
		} catch (UnsupportedEncodingException e) {
			return null;
		} finally {
			if (httpCon != null) {
				httpCon.disconnect();
			}
			if (baos != null) {
				try {
					baos.close();
				} catch (IOException e) {
				}
			}
		}
		return responseBody;
	}
}

到这儿基本结束了,另外文章代码或者我理解有误的地方,希望能批评指出。

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/baidu_19473529/article/details/82827431
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢