核心需求:用户点击按钮,生成一个二维码,微信扫码之后支付成功。要调用微信的接口,首先你需要引入微信支付的jar包,如下:

  1. 引入微信支付的jar包
<dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>

2.开发工具类:

package com.example.ffmpeg;

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 org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.wxpay.sdk.WXPay;

public class WXService {

    private static Logger logger = LoggerFactory.getLogger(WXService.class);
    private WXPay wxpay;
    private WXPayConfigImpl config;
    private static WXService INSTANCE;  

    private WXService() throws Exception {
        config = WXPayConfigImpl.getInstance();
        wxpay = new WXPay(config);
    }

    public static WXService getInstance() throws Exception {
        if (INSTANCE == null) {
            synchronized (WXPayConfigImpl.class) {
                if (INSTANCE == null) {
                    INSTANCE = new WXService();
                }
            }
        }
        return INSTANCE;
    }
3.下单接口:

    /**
     * 
     * 
     * @param out_trade_no
     * @param body
     * @param money
     * @param applyNo
     * @return
     */
    public String doUnifiedOrder(String out_trade_no, String body, Double money, String applyNo) {
        String amt = String.valueOf(money * 100);
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("body", body);
        data.put("out_trade_no", out_trade_no);
        data.put("device_info", "web");
        data.put("fee_type", "CNY");
        data.put("total_fee", amt.substring(0, amt.lastIndexOf(".")));
        data.put("spbill_create_ip", config.getSpbillCreateIp());
        data.put("notify_url", config.getNotifUrl());
        data.put("trade_type", config.getTradeType());
        data.put("product_id", applyNo);
        System.out.println(String.valueOf(money * 100));
        // data.put("time_expire", "20170112104120");

        try {
            Map<String, String> r = wxpay.unifiedOrder(data);
            logger.info("返回的参数是" + r);
            return r.get("code_url");
        } catch (Exception e) {
            e.printStackTrace();
            logger.info(e.getMessage());
            return null;
        }
    }
4. 退款接口:

    
    public void doRefund(String out_trade_no, String total_fee) {
        logger.info("退款时的订单号为:" + out_trade_no + "退款时的金额为:" + total_fee);
        String amt = String.valueOf(Double.parseDouble(total_fee) * 100);
        logger.info("修正后的金额为:" + amt);
        logger.info("最终的金额为:" + amt.substring(0, amt.lastIndexOf(".")));
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("out_trade_no", out_trade_no);
        data.put("out_refund_no", out_trade_no);
        data.put("total_fee", amt.substring(0, amt.lastIndexOf(".")));
        data.put("refund_fee", amt.substring(0, amt.lastIndexOf(".")));
        data.put("refund_fee_type", "CNY");
        data.put("op_user_id", config.getMchID());

        try {
            Map<String, String> r = wxpay.refund(data);
            logger.info("退款操作返回的参数为" + r);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
4. 验证接口:


    /**
       * 
     * @param out_trade_no
     * @param body
     * @param money
     * @param applyNo
     * @return
     * @throws DocumentException 
     */
    public boolean checkSign(String  strXML) throws DocumentException {
         SortedMap<String, String> smap = new TreeMap<String, String>();
         Document doc = DocumentHelper.parseText(strXML);
         Element root = doc.getRootElement();
         for (Iterator iterator = root.elementIterator(); iterator.hasNext();) {
             Element e = (Element) iterator.next();
             smap.put(e.getName(), e.getText());
         }
         return isWechatSign(smap,config.getKey());
    }


    private boolean isWechatSign(SortedMap<String, String> smap,String apiKey) {
         StringBuffer sb = new StringBuffer();
         Set<Entry<String, String>> es = smap.entrySet();
         Iterator<Entry<String, String>> it = es.iterator();
         while (it.hasNext()) {
             Entry<String, String> entry =  it.next();
             String k = (String) entry.getKey();
             String v = (String) entry.getValue();
             if (!"sign".equals(k) && null != v && !"".equals(v) && !"key".equals(k)) {
                 sb.append(k + "=" + v + "&");
             }
         }
         sb.append("key=" + apiKey);
         /** 验证的签名 */
         String sign = MD5Util.MD5Encode(sb.toString(), "utf-8").toUpperCase();
         /** 微信端返回的合法签名 */
         String validSign = ((String) smap.get("sign")).toUpperCase();
         return validSign.equals(sign);
     }
}
4. 配置类:

package com.example.ffmpeg;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import com.github.wxpay.sdk.WXPayConfig;

public class WXPayConfigImpl implements WXPayConfig{

     private byte[] certData;
        private static WXPayConfigImpl INSTANCE;

        private WXPayConfigImpl() throws Exception{
            String certPath = "F:\\weixin\\apiclient_cert.p12";
            File file = new File(certPath);
            InputStream certStream = new FileInputStream(file);
            this.certData = new byte[(int) file.length()];
            certStream.read(this.certData);
            certStream.close();
        }

        public static WXPayConfigImpl getInstance() throws Exception{
            if (INSTANCE == null) {
                synchronized (WXPayConfigImpl.class) {
                    if (INSTANCE == null) {
                        INSTANCE = new WXPayConfigImpl();
                    }
                }
            }
            return INSTANCE;
        }

        public String getAppID() {
            return "你的appid";
        }

        public String getMchID() {
            return "你的商户id";
        }

        public String getKey() {
            return "你设置的key值";
        }

        public String getNotifUrl() {
            return "微信通知回调的url接口";
        }

        public String getTradeType() {
            return "NATIVE";
        }

        public InputStream getCertStream() {
            ByteArrayInputStream certBis;
            certBis = new ByteArrayInputStream(this.certData);
            return certBis;
        }


        public int getHttpConnectTimeoutMs() {
            return 2000;
        }

        public int getHttpReadTimeoutMs() {
            return 10000;
        }

//      IWXPayDomain getWXPayDomain() {
//          return WXPayDomainSimpleImpl.instance();
//      }

        public String getPrimaryDomain() {
            return "api.mch.weixin.qq.com";
        }

        public String getAlternateDomain() {
            return "api2.mch.weixin.qq.com";
        }

        public int getReportWorkerNum() {
            return 1;
        }

        public int getReportBatchSize() {
            return 2;
        }

        public String getSpbillCreateIp() {
            // TODO Auto-generated method stub
            return "192.168.1.1";
        }
}
4. 配置类:
apiclient_cert.p12的证书文件。这个证书文件你可以登录微信的商户平台。在这里去下载你所需要的证书。WXPayConfigImpl 在构造方法里面去读取这个文件,所以构造方法抛了异常。因为构造器抛出异常,所以这里没有采用静态内部类而是采用双检锁的方式去实现单例。

回到WXService这个类中,代码往下走,在WXService的构造器中对config和wxpay进行了实例化。接下来同样是用双检锁的方式实现的单例。往下走,微信的下单接口,分别传入out_trade_no(外部订单号),body(商品描述), money(付款金额), applyNo(对应微信的product_id:商品id,由商户自定义)四个参数。进入方法后第一句话String amt = String.valueOf(money * 100);是把传入的钱数乘以100,并转换成字符串。这里之所以乘以100是因为微信那边会把我们传过去的钱数除以100得到应付金额,且不能传小数,所以下面的那一句amt.substring(0, amt.lastIndexOf(“.”))就是为了把金额中的小数点去掉。往下走,new出了一个hashmap,将参数传入hashmap中,然后调用wxpay.unifiedOrder(data);下单接口下单。得到返回的map集合,从map中获得的code_url这个参数就是微信返回给我们生成二维码的字符串。这样,下单的整个流程就跑通了,现在写个测试类来测试一下。

package com.example.ffmpeg;

public class MyTest {

    public static void main(String[] args) throws Exception {
        WXService wx = WXService.getInstance();
        String QRcode = wx.doUnifiedOrder("test001", "测试下单接口", 0.01, "a123456");
        System.out.println("得到的二维码是:"+QRcode);
    }
}