java微信支付创单APP、H5示例

以下是本人写的微信支付创单APP、H5的demo,没有什么封装,简易示例。
代码部分没有那么规范,只是练习使用的,例如:XMLUtil、MD5Encryption这样的命名不符合阿里P3C规约。望读者阅读后自行整改。

1.首先下载相关的包

log4j:请自行下载

jdom:https://mvnrepository.com/artifact/org.jdom/jdom2

如有其他缺少的包,请自行下载,下面主要看看代码部分。

2.WeChatPayUtil

package com.alipay.api.test.my;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.erlan.common.base.http.HttpRequest;
import com.erlan.common.util.MD5Encryption;
import com.erlan.common.util.XMLUtil;

/**
 * @Description: 微信支付工具类
 * @author admin
 * @date 2017年12月30日 下午1:55:21
 * @version V1.0
 */
public class WeChatPayUtil {

    private static Logger log = Logger.getLogger(WeChatPayUtil.class);

    public static void main(String[] args) {

        // APP支付测试
        Map appMap = unifiedorderAPP("1000010", "1", null, "这里填写统一下单回调接口(关于回调接口,下面有示例)");

        // H5支付测试(创单成功后,返回的url必须在H5申请的支付域名之下访问,这点要特别注意。而且我测试的是必须手机访问才成功,手机!手机!手机!三遍了,老铁们!),关于H5支付创单失败的问题,我其他文章有提到
        Map mwebMap = unifiedorderMWEB("1000012", "1", null, "这里填写统一下单回调接口(关于回调接口,下面有示例)");
    }

    /**
     * 统一下单(APP)
     *
     * @param outTradeNo 系统订单号
     * @param totalFee 金额(分)
     * @param attach 附加数据
     * @param notifyUrl 回调地址
     * @author admin
     * @date 2017年12月30日 下午2:18:29
     * @version V1.0
     */
    @SuppressWarnings("unchecked")
    public static Map unifiedorderAPP(String outTradeNo, String totalFee, String attach, String notifyUrl) {
        Map resultMap = new HashMap(8);
        resultMap.put("return_code", "FAIL");

        // ======================================
        // 以下有注释的代码,需要更改对应的值-Begin
        // ======================================

        // 连接商户key
        String key = "W8FFB955CA32319C3AAAE96286CC6666";

        // 统一下单接口
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        // 应用ID(微信开放平台审核通过的应用APPID)
        String appid = "******************";
        // 商户号(微信支付分配的商户号)
        String mch_id = "2506666250";
        // 随便的一个MD5加密字符串就行(工具类有提供,见下面)
        String nonce_str = "49ba59abbe56e057";
        String sign = "";
        // 支付的商品信息(测试随便输入,支付后在微信里面看下付费账单信息就明白了)
        String body = "**-微信支付";
        String detail = "**-微信支付";
        String out_trade_no = outTradeNo;
        String total_fee = totalFee;
        // 终端IP(改成你的服务器IP就行)
        String spbill_create_ip = "10.10.10.110";
        String notify_url = notifyUrl;
        String trade_type = "APP";
        // 这个值可以不给,如果不给的话,下面不要拼接,我下面有拼接此参数,所以给它一个值,详情官方文档说明
        attach = StringUtils.isBlank(attach) ? "no" : attach;

        // ======================================
        // 以上有注释的代码,需要更改对应的值-End
        // ======================================

        // 对参数按照key=value的格式,并按照参数名ASCII字典序排序生成字符串
        String signStr = "appid=" + appid + "&attach=" + attach + "&body=" + body + "&detail=" + detail + "&mch_id=" + mch_id + "&nonce_str="
                + nonce_str + "¬ify_url=" + notify_url + "&out_trade_no=" + out_trade_no + "&spbill_create_ip=" + spbill_create_ip + "&total_fee="
                + total_fee + "&trade_type=" + trade_type;
        // 连接商户key
        signStr += ("&key=" + key);
        System.out.println("signStr:" + signStr);
        // 生成sign并转成大写
        sign = MD5Encryption.toMD5(signStr).toUpperCase();
        System.out.println(sign);

        // 最终的提交xml:
        String params = "" + sign + "";

        try {
            System.out.println(params);
            String result = HttpRequest.sendPost(url, params);
            System.out.println(result);
            Map map = null;
            map = XMLUtil.doXMLParse(result);
            // System.out.println("return_code:" + map.get("return_code"));
            if (map.get("return_code").equals("SUCCESS")) {
                // 时间戳(秒)
                Date date = new Date();
                long time = date.getTime();
                time = (time / 1000);
                String timestamp = time + "";
                String resultAppid = map.get("appid").toString();
                String resultPartnerid = map.get("mch_id").toString();
                String resultPrepayid = map.get("prepay_id").toString();
                String resultPackage = "Sign=WXPay";
                String resultNoncestr = map.get("nonce_str").toString();
                // 对参数按照key=value的格式,并按照参数名ASCII字典序排序生成字符串
                String resultSignStr = "appid=" + resultAppid + "&noncestr=" + resultNoncestr + "&package=" + resultPackage + "&partnerid="
                        + resultPartnerid + "&prepayid=" + resultPrepayid + "×tamp=" + timestamp;
                // 连接商户key
                resultSignStr += ("&key=" + key);
                System.out.println("resultSignStr:" + resultSignStr);
                // 生成sign并转成大写
                String resultSign = MD5Encryption.toMD5(resultSignStr).toUpperCase();
                System.out.println("resultSign:" + resultSign);
                // APP支付所需参数(需要把这些信息返给APP开发者)
                resultMap.put("return_code", "SUCCESS");
                resultMap.put("appid", resultAppid);
                resultMap.put("partnerid", resultPartnerid);
                resultMap.put("prepayid", resultPrepayid);
                resultMap.put("package", resultPackage);
                resultMap.put("noncestr", resultNoncestr);
                resultMap.put("timestamp", timestamp);
                resultMap.put("sign", resultSign);
                System.out.println(resultMap.toString());
            }
        }
        catch (Exception e) {
            // TODO Auto-generated catch block
            log.error("APP统一下单异常");
            e.printStackTrace();
        }

        return resultMap;
    }

    /**
     * 统一下单(H5)
     *
     * @param outTradeNo 系统订单号
     * @param totalFee 金额(分)
     * @param attach 附加数据
     * @param notifyUrl 回调地址
     * @author admin
     * @date 2017年12月30日 下午2:18:29
     * @version V1.0
     */
    @SuppressWarnings("unchecked")
    public static Map unifiedorderMWEB(String outTradeNo, String totalFee, String attach, String notifyUrl) {
        Map resultMap = new HashMap(8);
        resultMap.put("return_code", "FAIL");

        // ======================================
        // 以下有注释的代码,需要更改对应的值-Begin
        // ======================================

        // 连接商户key
        String key = "W8FFB955CA32319C3AAAE96286CC6666";

        // 统一下单接口
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        // 应用ID(微信开放平台审核通过的应用APPID)
        String appid = "******************";
        // 商户号(微信支付分配的商户号)
        String mch_id = "2506666250";
        // 随便的一个MD5加密字符串就行(工具类有提供,见下面)
        String nonce_str = "49ba59abbe56e057";
        String sign = "";
        // 支付的商品信息(测试随便输入,支付后在微信里面看下付费账单信息就明白了)
        String body = "**-微信支付";
        String detail = "**-微信支付";
        String out_trade_no = outTradeNo;
        String total_fee = totalFee;
        // 终端IP(改成你的服务器IP就行)
        String spbill_create_ip = "10.10.10.110";
        String notify_url = notifyUrl;
        String trade_type = "APP";

        // 商户平台申请开通H5支付,对应的信息,详见官方文档(bundle_id的值在微信开放平台-管理中心-对应的产品里面查看)
        String scene_info = "{\"h5_info\": {\"type\":\"IOS\",\"app_name\": \"你的产品名称\",\"bundle_id\": \"cn.**.**\"}}";

        attach = StringUtils.isBlank(attach) ? "no" : attach;
        // ======================================
        // 以上有注释的代码,需要更改对应的值-End
        // ======================================

        // 对参数按照key=value的格式,并按照参数名ASCII字典序排序生成字符串
        String signStr = "appid=" + appid + "&attach=" + attach + "&body=" + body + "&detail=" + detail + "&mch_id=" + mch_id + "&nonce_str="
                + nonce_str + "¬ify_url=" + notify_url + "&out_trade_no=" + out_trade_no + "&scene_info=" + scene_info + "&spbill_create_ip="
                + spbill_create_ip + "&total_fee=" + total_fee + "&trade_type=" + trade_type;
        // 连接商户key
        signStr += ("&key=" + key);
        System.out.println("signStr:" + signStr);
        // 生成sign并转成大写
        sign = MD5Encryption.toMD5(signStr).toUpperCase();
        System.out.println(sign);

        // 最终的提交xml:
        String params = "" + sign + "";

        try {
            System.out.println(params);
            String result = HttpRequest.sendPost(url, params);
            System.out.println(result);
            Map map = null;
            map = XMLUtil.doXMLParse(result);
            System.out.println("return_code:" + map.get("return_code"));
            if (map.get("return_code").equals("SUCCESS")) {
                String mwebUrl = map.get("mweb_url").toString();
                // H5支付所需要的URL(必须在H5申请的支付域名之下访问,而且我测试的是必须手机访问才成功,手机!手机!手机!三遍了,老铁们!)
                resultMap.put("url", mwebUrl);
                resultMap.put("return_code", "SUCCESS");
                System.out.println(resultMap.toString());
            }
        }
        catch (Exception e) {
            // TODO Auto-generated catch block
            log.error("H5统一下单异常");
            e.printStackTrace();
        }

        return resultMap;
    }

}

3.MD5Encryption

package com.alipay.api.test.my;

import java.security.MessageDigest;

/**
 * @Description: MD5工具类
 * @author admin
 * @date 2018年1月12日 上午9:10:39
 * @version V1.0
 */
public class MD5Encryption {

    public static String toMD5(String plainText) {
        try {
            if ("".equals(plainText) || plainText == null) {
                return "erlan";
            }
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(plainText.getBytes());
            byte b[] = md.digest();

            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0) {
                    i += 256;
                }
                if (i < 16) {
                    buf.append("0");
                }
                buf.append(Integer.toHexString(i));
            }
            return buf.toString();
            // System.out.println("32λ: " + buf.toString());// 32位
            // System.out.println("16λ: " + buf.toString().substring(8, 24));// 16位
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // public static void main(String[] args) {
    // MD5Encryption md5 = new MD5Encryption();
    // String md52 = md5.toMD5("123456ERlan");
    // System.out.println(md52.toUpperCase());
    // }

}

4.XMLUtil

package com.erlan.common.util;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

/**
 * @Description: XML解析工具类
 * @author admin
 * @date 2018年1月12日 上午9:10:10
 * @version V1.0
 */
public class XMLUtil {
    
    /**
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
     * 
     * @param strxml
     * @return
     * @throws JDOMException
     * @throws IOException
     */
    public static Map doXMLParse(String strxml) throws JDOMException, IOException {
        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
        if (null == strxml || "".equals(strxml)) {
            return null;
        }

        Map m = new HashMap();

        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List list = root.getChildren();
        Iterator it = list.iterator();
        while (it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List children = e.getChildren();
            if (children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = XMLUtil.getChildrenText(children);
            }

            m.put(k, v);
        }

        // 关闭流
        in.close();

        return m;
    }

    /**
     * 获取子结点的xml
     * 
     * @param children
     * @return String
     */
    public static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if (!children.isEmpty()) {
            Iterator it = children.iterator();
            while (it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if (!list.isEmpty()) {
                    sb.append(XMLUtil.getChildrenText(list));
                }
                sb.append(value);
                sb.append("");
            }
        }

        return sb.toString();
    }

    /**
     * 获取xml编码字符集
     * 
     * @param strxml
     * @return
     * @throws IOException
     * @throws JDOMException
     */
    public static String getXMLEncoding(String strxml) throws JDOMException, IOException {
        InputStream in = HttpClientUtil.String2Inputstream(strxml);
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        in.close();
        return (String) doc.getProperty("encoding");
    }

    /**
     * 支付成功,返回微信那服务器
     * 
     * @param return_code
     * @param return_msg
     * @return
     */
    public static String setXML(String return_code, String return_msg) {
        return "";
    }

    public static String createXML(Map map) {
        Set> set = map.entrySet();
        set.iterator();
        return null;
    }

}

4.WeChatController
这里要注意了!例如你的这个接口是针对APP支付成功后的业务处理,访问你这个接口的地址是:http://192.168.0.110:8080//wechat/successRechargeNotify
那么上面提到的unifiedorderAPP方法里的参数notifyUrl的值就是这个接口地址,例如:
unifiedorderAPP("1000010", "1", null, "http://192.168.0.110:8080//wechat/successRechargeNotify");

package com.erlan.mobile.controller.pay;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.jdom2.JDOMException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.dubbo.config.annotation.Reference;
import com.erlan.api.service.TbOrderService;
import com.erlan.api.service.TbUserService;
import com.erlan.common.util.XMLUtil;
import com.erlan.common.util.wxpay.WeChatPayConfig;

/**
 * @Description: 微信支付成功回调
 * @author admin
 * @date 2017年12月29日 上午9:19:25
 * @version V1.0
 */
@RestController
@RequestMapping("/wechat")
public class WeChatController {

    private static Logger log = Logger.getLogger(WeChatController.class);

    @Reference
    private TbOrderService tbOrderService;

    @Reference
    private TbUserService tbUserService;

    /**
     * 订单支付成功回调
     *
     * @param param
     * @return
     * @author admin
     * @date 2017年12月27日 下午2:21:53
     * @version V1.0
     */
    @SuppressWarnings({ "unchecked" })
    @RequestMapping("/successPayNotify")
    public String successPayNotify(HttpServletRequest request, HttpServletResponse response) {
        log.info("pay......success");
        String notifyResult = "";

        try {
            System.out.println("微信支付回调");
            // PrintWriter writer = response.getWriter();
            InputStream inStream = request.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            outSteam.close();
            inStream.close();
            String result = new String(outSteam.toByteArray(), "utf-8");
            System.out.println("微信支付通知结果:" + result);
            Map map = null;
            try {
                /**
                 * 解析微信通知返回的信息
                 */
                map = XMLUtil.doXMLParse(result);
            }
            catch (JDOMException e) {
                // TODO Auto-generated catch block
                log.error("微信支付回调解析异常");
                e.printStackTrace();
            }
            System.out.println("=========:" + result);
            // 若支付成功,则告知微信服务器收到通知
            if (map.get("return_code").equals("SUCCESS")) {

                // 这里可以写你的系统业务逻辑......

            }
        }
        catch (Exception e) {
            // TODO: handle exception
            log.error("微信支付回调异常");
        }

        System.out.println("notifyResult:" + notifyResult);
        return notifyResult;
    }
}

你可能感兴趣的:(java微信支付创单APP、H5示例)