微信支付java

不得不吐槽一下,微信支付真坑,相比之下支付宝的支付开发就简单多了

直接上代码,

1、工具类PayCommonUtil

import com.legendshop.payment.tenpay.util.MD5Util;
import com.legendshop.util.AppUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

public class PayCommonUtil {


    /**
     * @Date: 2018/6/6 11:08
     * @Descript: 因为公司app端与网页端商户号不一样,所以这里需要做一些判断
     */    
    
    /* 微信公众号  */
    public static final String appid_wap = "your appid";
    public static final String MCHID_wap = "商户号";

    /**
     * 微信原生
     * appid 查看方法:登录微信商户平台(https://pay.weixin.qq.com/index.php/core/home/login) --> 营销中心 --> 支付后配置
     */
    public static final String appid = "your appid";
    public static final String MCHID = "商户号";
    public static final String notify_url = "你的通知接口地址";
    /**
     * 两个商户号的key又是一样的,这里就共用一个变量。
     * key 查看方法:登录微信商户平台 --> 账户中心 --> API安全 --> API密钥
     */
    public static final String key = "your key";


    /**
     * 创建微信交易对象
     */
    public static SortedMap<Object, Object> getWXPrePayID(String tradeType, String openid) {
        SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();

        Boolean isWap = false;
        Boolean isWx = false;
        if (AppUtils.isNotBlank(tradeType)) {
            if (tradeType.equals("JSAPI")) {
                //微信浏览器内执行
                isWx = true;
                isWap = true;
            }
            if (tradeType.equals("MWEB")) {
                //H5
                isWap = true;
            }
        }


        parameters.put("appid", isWap ? appid_wap : appid);
        parameters.put("mch_id", isWap ? MCHID_wap : MCHID);
        parameters.put("nonce_str", createNoncestr());
        parameters.put("fee_type", "CNY");
        parameters.put("notify_url", notify_url);
        parameters.put("trade_type", AppUtils.isBlank(tradeType) ? "APP" : tradeType);
        if (isWx) {
            //微信浏览器内执行需要openid
            parameters.put("openid", openid);
        }
        return parameters;
    }

    /**
     * 再次签名(仅APP支付需要)
     */
    public static SortedMap<Object, Object> startWXPay(Map map) {
        try {

            SortedMap<Object, Object> parameterMap = new TreeMap<Object, Object>();
            parameterMap.put("appid", appid);
            parameterMap.put("partnerid", MCHID);
            parameterMap.put("prepayid", map.get("prepay_id"));
            parameterMap.put("package", "Sign=WXPay");
            parameterMap.put("noncestr", createNoncestr());
            // 本来生成的时间戳是13位,但是ios必须是10位,所以截取了一下
            parameterMap.put("timestamp",
                    Long.parseLong(String.valueOf(System.currentTimeMillis()).toString().substring(0, 10)));
            String sign = PayCommonUtil.createSign("UTF-8", parameterMap);
            parameterMap.put("sign", sign);
            return parameterMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /*
    * 获取真实IP
    * */
    public static String getRemortIP(HttpServletRequest request) {
        if (request.getHeader("x-forwarded-for") == null) {
            return request.getRemoteAddr();
        }
        return request.getHeader("x-forwarded-for");
    }

    /**
     * 创建随机数
     *
     * @param length
     * @return
     */
    public static String createNoncestr() {
        String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        String res = "";
        for (int i = 0; i < 16; i++) {
            Random rd = new Random();
            res += chars.charAt(rd.nextInt(chars.length() - 1));
        }
        return res;
    }

    /**
     * @param characterEncoding 编码格式
     * @param parameters        请求参数
     * @return
     * @Description:创建sign签名
     */
    public static String createSign(String characterEncoding, SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.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 + "&");
            }
        }
        sb.append("key=" + key);
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }

}


2、MD5Util(可以根据自己使用的jdk版本进行编写)

public class MD5Util {

    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++)
            resultSb.append(byteToHexString(b[i]));

        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n += 256;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes()));
            else
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes(charsetname)));
        } catch (Exception exception) {
        }
        return resultString;
    }

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

}

3、接下来是调用,这里只贴核心部分代码

    
    
/**
* body:订单标题
* out_trade_no:结算单流水号,一般用商城订单号就可以了,但是这样会有个问题就是在不同平台(微信浏览器内、微信外的浏览器、APP等)分别提交订单会出现“201 订单重复“的问题,可根据实际业务需求做处理
* fee:最小是1,表示1分钱
* tradeType:JSAPI(微信浏览器支付)、MWEB(微信以外的浏览器)、APP(原生支付)
* openid:当tradeType = JSAPI,该属性是必须的
* redirectUrl:当tradeType = MWEB,支付成功后的跳转地址
*/    
    
    
    private Map getWXPay(String body,String out_trade_no,String fee,String tradeType,String openid,String redirectUrl) throws Exception{


        SortedMap<Object, Object> parameters = PayCommonUtil.getWXPrePayID(tradeType,openid); // 获取预付单,此处已做封装,需要工具类


//        String body = "雅量商品支付";
//
//        String out_trade_no = PayCommonUtil.getDateStr();
//
//        String fee = "1";


        parameters.put("body", AppUtils.isBlank(body) ? "雅量商品支付" : body);

        //获取ip要注意反向代理的ip获取配置
        parameters.put("spbill_create_ip", PayCommonUtil.getRemortIP(request));
        parameters.put("out_trade_no", out_trade_no); 
        parameters.put("total_fee", fee); 

        /**
         * 签名(签名规则:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3,)
         * 注意:使用SortedMap已符合”参数名ASCII码从小到大排序(字典序)“
         */
        String sign = PayCommonUtil.createSign("UTF-8", parameters);
        parameters.put("sign", sign);


        // 封装请求参数结束
        String requestXML = PayCommonUtil.getRequestXml(parameters); // 获取xml结果
        
        /** 
        * 调用统一下单接口(APP、微信内支付、H5都是使用该接口)
        *
        * 区别:
        * APP支付:统一下单 --> 二次签名 --> 返回数据给客户端调起支付
        * 微信内支付:统一下单 --> 返回数据给客户端调起支付
        * H5支付:统一下单 --> 返回链接给客户端,客户端进行跳转
        */
        String result = PayCommonUtil.httpsRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST",
                requestXML);


        System.out.println("===================================");
        System.out.println(JSON.toJSONString(parameters));
        System.out.println("===================================");
        System.out.println(JSON.toJSONString(result));
        System.out.println("===================================");

        Map<String, String> map = XMLUtil.doXMLParse(result);


        Map allData = new HashedMap();
        Map runRs = new HashedMap();
        String rsCode = map.get("result_code").toString();
        runRs.put("result_code", rsCode);
        if(rsCode.equals("FAIL")){
            runRs.put("err_code_des",map.get("err_code_des"));
        }
        allData.put("runRs",runRs);


        if(AppUtils.isNotBlank(tradeType) && (tradeType.equals("JSAPI") || tradeType.equals("MWEB"))){




            SortedMap<Object, Object> signData = new TreeMap<Object, Object>();

            signData.put("appId",map.get("appid"));

            signData.put("timeStamp",
                    Long.parseLong(String.valueOf(System.currentTimeMillis()).toString().substring(0, 10)));

            signData.put("nonceStr",map.get("nonce_str"));

            signData.put("package","prepay_id=" + map.get("prepay_id"));

            signData.put("signType","MD5");

            String paySign = PayCommonUtil.createSign("UTF-8", signData);

            signData.put("paySign",paySign);


            if(tradeType.equals("MWEB")){

                signData.put("mwebUrl",map.get("mweb_url") + "&redirect_url=" + redirectUrl);
            }

            allData.put("data",signData);


        }else{
            SortedMap<Object, Object> parMap = PayCommonUtil.startWXPay(map);


            System.out.println("==============================RS=====");
            System.out.println(JSON.toJSONString(parMap));
            System.out.println("===============================RS====");


            allData.put("data",parMap);
        }

        return allData;


    }

最后要说的是千万要注意微信的参数大小写问题,一个接口一个样

条码支付很简单,下载demo和证书下来配置一下就可以直接运行

微信条码支付demo:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1

微信签名要求:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3

微信APP支付开发文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_1

猜你喜欢

转载自www.cnblogs.com/cjh-notes/p/9144490.html
今日推荐