微信扫码开发,只要你在官网上对应它文档一步一步的来,你最终会找到突破口。此链接为微信官方提供的API链接:点击打开链接
如图所示楼主选择的是扫码支付,点进去,你就会看到它的要求,有模式一和模式二两种,模式二比较简单,所以选择的第二种模式。
两种模式都需要求一个注册了的商户号,商户号就是你扫码支付成功之后,钱流转到了哪个微信账户,这个商户号可不是普通的微信用户,所以在微信商户平台注册一个微信商户号才能对接微信的扫码支付。为什么必须要商户号呢?请看下面两张图
前提步骤:1.注册微信商户号 https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F
2.登录微信商户平台,在立面设置开通微信支付
3.在立面找到AppID,mch_id,Appkey(这三个是必要的参数,我的理解是定位到你要扫码支付的商户对象)
代码步骤:说明:代码是从官网直接拷下来的demo,然后修改了几个传入的参数,和部分代码,使用main方法进行测试得到code_url(二维码)
注意:我的代码只是部分,官网可下载完整代码,结合我说的,自己设置参数,进行main方法参数,里面涉及到maven jar包,直接依赖我的代码去写,88%会失败
测试类
package com.lanyuan.weixin.util.test.tool; import java.util.HashMap; import java.util.Map; import com.lanyuan.weixin.util.tool.WXPay; import com.lanyuan.weixin.util.tool.WXPayConstants; import com.lanyuan.weixin.util.tool.WXPayUtil; import com.lanyuan.weixin.util.tool.WXPayConstants.SignType; public class TestWXPay { private WXPay wxpay; private WXPayConfigImpl config; private String out_trade_no; private String total_fee; public TestWXPay() throws Exception { config = WXPayConfigImpl.getInstance(); config.setAppID("1111111111");//自己的AppID config.setMchID("111111111111");//自己的MchId config.setKey("111111111111111");//自己的Appkey wxpay = new WXPay(config); total_fee = "1"; // out_trade_no = "201701017496748980290321"; out_trade_no = "20171309105959000000343348fw4"; } /** * 扫码支付 下单 */ public void doUnifiedOrder() { HashMap<String, String> data = new HashMap<String, String>(); data.put("body", "充值0.1元"); data.put("out_trade_no", out_trade_no); data.put("device_info", "WEB"); data.put("fee_type", "CNY"); data.put("total_fee", "10"); data.put("spbill_create_ip", "123.12.12.123"); data.put("notify_url", "http://test.letiantian.me/wxpay/notify"); data.put("trade_type", "NATIVE"); data.put("product_id", "fmwijfief4648584488484848484"); // data.put("time_expire", "20170112104120"); try { Map<String, String> r = wxpay.unifiedOrder(data); System.out.println(r); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { System.out.println("--------------->"); TestWXPay dodo = new TestWXPay(); System.out.println("-----了之咯--------"); dodo.doUnifiedOrder(); System.out.println("<---------------"); // wx2016112510573077 } }
package com.lanyuan.weixin.util.test.tool; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import com.lanyuan.weixin.util.tool.IWXPayDomain; import com.lanyuan.weixin.util.tool.WXPayConfig; /** * * @author Lzl * */ public class WXPayConfigImpl extends WXPayConfig{ private byte[] certData; private static WXPayConfigImpl INSTANCE; private String appID; private String mchID; private String key; //暂时不需要证书 // private WXPayConfigImpl() throws Exception{ // String certPath = "D://CERT/common/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 void setAppID(String appID) { this.appID = appID; } public String getAppID() { return appID; // return "wxcfa32bdbcca4cdfa"; } public void setMchID(String mchID) { this.mchID = mchID; } public String getMchID() { return mchID; } public void setKey(String key) { this.key = key; } public String getKey() { return key; } public InputStream getCertStream() { ByteArrayInputStream certBis; certBis = new ByteArrayInputStream(this.certData); return certBis; } public int getHttpConnectTimeoutMs() { return 3*1000;//调用微信统一下单最长时间限制 } public int getHttpReadTimeoutMs() { return 10000; } public IWXPayDomain getWXPayDomain() { return WXPayDomainSimpleImpl.instance(); } public String getPrimaryDomain() { return "api.mch.weixin.qq.com"; } public String getAlternateDomain() { return "api2.mch.weixin.qq.com"; } @Override public int getReportWorkerNum() { return 1; } @Override public int getReportBatchSize() { return 2; } }
工具类
package com.lanyuan.weixin.util.tool; import java.util.HashMap; import java.util.Map; import com.lanyuan.weixin.util.test.tool.WXPayConfigImpl; import com.lanyuan.weixin.util.tool.WXPayConstants.SignType; public class WXPay { private WXPayConfigImpl config; private SignType signType; private boolean autoReport; private boolean useSandbox; private String notifyUrl; private WXPayRequest wxPayRequest; public WXPay(final WXPayConfigImpl config) throws Exception { this(config, null, true, false); } public WXPay(final WXPayConfigImpl config, final boolean autoReport) throws Exception { this(config, null, autoReport, false); } public WXPay(final WXPayConfigImpl config, final boolean autoReport, final boolean useSandbox) throws Exception{ this(config, null, autoReport, useSandbox); } public WXPay(final WXPayConfigImpl config, final String notifyUrl) throws Exception { this(config, notifyUrl, true, false); } public WXPay(final WXPayConfigImpl config, final String notifyUrl, final boolean autoReport) throws Exception { this(config, notifyUrl, autoReport, false); } public WXPay(final WXPayConfigImpl config, final String notifyUrl, final boolean autoReport, final boolean useSandbox) throws Exception { this.config = config; this.notifyUrl = notifyUrl; this.autoReport = autoReport; this.useSandbox = useSandbox; if (useSandbox) { this.signType = SignType.MD5; // 沙箱环境 } else { this.signType = SignType.HMACSHA256; } this.wxPayRequest = new WXPayRequest(config); } private void checkWXPayConfig() throws Exception { if (this.config == null) { throw new Exception("config is null"); } if (this.config.getAppID() == null || this.config.getAppID().trim().length() == 0) { throw new Exception("appid in config is empty"); } if (this.config.getMchID() == null || this.config.getMchID().trim().length() == 0) { throw new Exception("appid in config is empty"); } if (this.config.getCertStream() == null) { throw new Exception("cert stream in config is empty"); } // if (this.config.getPrimaryDomain() == null || this.config.getPrimaryDomain().trim().length() == 0) { // throw new Exception("primary domain in config is empty"); // } // // // todo 海外就填两个相同的? 下面的逻辑待考虑 // if (this.config.getAlternateDomain() == null || this.config.getAlternateDomain().trim().length() == 0) { // throw new Exception("alternate domain in config is empty"); // } if (this.config.getWXPayDomain() == null){ throw new Exception("config.getWXPayDomain() is null"); } if (this.config.getHttpConnectTimeoutMs() < 10) { throw new Exception("http connect timeout is too small"); } if (this.config.getHttpReadTimeoutMs() < 10) { throw new Exception("http read timeout is too small"); } } /** * 向 Map 中添加 appid、mch_id、nonce_str、sign_type、sign <br> * 该函数适用于商户适用于统一下单等接口,不适用于红包、代金券接口 * * @param reqData * @return * @throws Exception */ public Map<String, String> fillRequestData(Map<String, String> reqData) throws Exception { reqData.put("appid", config.getAppID()); reqData.put("mch_id", config.getMchID()); reqData.put("nonce_str", WXPayUtil.generateUUID()); if (SignType.MD5.equals(this.signType)) { reqData.put("sign_type", WXPayConstants.MD5); } else if (SignType.HMACSHA256.equals(this.signType)) { reqData.put("sign_type", WXPayConstants.HMACSHA256); } reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), this.signType)); return reqData; } /** * 判断xml数据的sign是否有效,必须包含sign字段,否则返回false。 * * @param reqData 向wxpay post的请求数据 * @return 签名是否有效 * @throws Exception */ public boolean isResponseSignatureValid(Map<String, String> reqData) throws Exception { // 返回数据的签名方式和请求中给定的签名方式是一致的 return WXPayUtil.isSignatureValid(reqData, this.config.getKey(), this.signType); } /** * 判断支付结果通知中的sign是否有效 * * @param reqData 向wxpay post的请求数据 * @return 签名是否有效 * @throws Exception */ public boolean isPayResultNotifySignatureValid(Map<String, String> reqData) throws Exception { String signTypeInData = reqData.get(WXPayConstants.FIELD_SIGN_TYPE); SignType signType; if (signTypeInData == null) { signType = SignType.MD5; } else { signTypeInData = signTypeInData.trim(); if (signTypeInData.length() == 0) { signType = SignType.MD5; } else if (WXPayConstants.MD5.equals(signTypeInData)) { signType = SignType.MD5; } else if (WXPayConstants.HMACSHA256.equals(signTypeInData)) { signType = SignType.HMACSHA256; } else { throw new Exception(String.format("Unsupported sign_type: %s", signTypeInData)); } } return WXPayUtil.isSignatureValid(reqData, this.config.getKey(), signType); } /** * 不需要证书的请求 * @param urlSuffix String * @param reqData 向wxpay post的请求数据 * @param connectTimeoutMs 超时时间,单位是毫秒 * @param readTimeoutMs 超时时间,单位是毫秒 * @return API返回数据 * @throws Exception */ public String requestWithoutCert(String urlSuffix, Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception { String msgUUID = reqData.get("nonce_str"); String reqBody = WXPayUtil.mapToXml(reqData); String resp = this.wxPayRequest.requestWithoutCert(urlSuffix, msgUUID, reqBody, connectTimeoutMs, readTimeoutMs, autoReport); return resp; } /** * 需要证书的请求 * @param urlSuffix String * @param reqData 向wxpay post的请求数据 Map * @param connectTimeoutMs 超时时间,单位是毫秒 * @param readTimeoutMs 超时时间,单位是毫秒 * @return API返回数据 * @throws Exception */ public String requestWithCert(String urlSuffix, Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception { String msgUUID= reqData.get("nonce_str"); String reqBody = WXPayUtil.mapToXml(reqData); String resp = this.wxPayRequest.requestWithCert(urlSuffix, msgUUID, reqBody, connectTimeoutMs, readTimeoutMs, this.autoReport); return resp; } /** * 处理 HTTPS API返回数据,转换成Map对象。return_code为SUCCESS时,验证签名。 * @param xmlStr API返回的XML格式数据 * @return Map类型数据 * @throws Exception */ public Map<String, String> processResponseXml(String xmlStr) throws Exception { String RETURN_CODE = "return_code"; String return_code; Map<String, String> respData = WXPayUtil.xmlToMap(xmlStr); if (respData.containsKey(RETURN_CODE)) { return_code = respData.get(RETURN_CODE); } else { throw new Exception(String.format("No `return_code` in XML: %s", xmlStr)); } if (return_code.equals(WXPayConstants.FAIL)) { return respData; } else if (return_code.equals(WXPayConstants.SUCCESS)) { if (this.isResponseSignatureValid(respData)) { return respData; } else { throw new Exception(String.format("Invalid sign value in XML: %s", xmlStr)); } } else { throw new Exception(String.format("return_code value %s is invalid in XML: %s", return_code, xmlStr)); } } /** * 作用:统一下单<br> * 场景:公共号支付、扫码支付、APP支付 * @param reqData 向wxpay post的请求数据 * @return API返回数据 * @throws Exception */ public Map<String, String> unifiedOrder(Map<String, String> reqData) throws Exception { return this.unifiedOrder(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs()); } /** * 作用:统一下单<br> * 场景:公共号支付、扫码支付、APP支付 * @param reqData 向wxpay post的请求数据 * @param connectTimeoutMs 连接超时时间,单位是毫秒 * @param readTimeoutMs 读超时时间,单位是毫秒 * @return API返回数据 * @throws Exception */ public Map<String, String> unifiedOrder(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception { String url; if (this.useSandbox) { url = WXPayConstants.SANDBOX_UNIFIEDORDER_URL_SUFFIX; } else { url = WXPayConstants.UNIFIEDORDER_URL_SUFFIX; } if(this.notifyUrl != null) { reqData.put("notify_url", this.notifyUrl); } String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs); return this.processResponseXml(respXml); } /** * 作用:交易保障<br> * 场景:刷卡支付、公共号支付、扫码支付、APP支付 * @param reqData 向wxpay post的请求数据 * @return API返回数据 * @throws Exception */ public Map<String, String> report(Map<String, String> reqData) throws Exception { return this.report(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs()); } /** * 作用:交易保障<br> * 场景:刷卡支付、公共号支付、扫码支付、APP支付 * @param reqData 向wxpay post的请求数据 * @param connectTimeoutMs 连接超时时间,单位是毫秒 * @param readTimeoutMs 读超时时间,单位是毫秒 * @return API返回数据 * @throws Exception */ public Map<String, String> report(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception { String url; if (this.useSandbox) { url = WXPayConstants.SANDBOX_REPORT_URL_SUFFIX; } else { url = WXPayConstants.REPORT_URL_SUFFIX; } String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs); return WXPayUtil.xmlToMap(respXml); } } // end class最终main方法里得到的结果
拿code_url去百度搜索qrCode.js里面有个二维码生成工具,把code_url复制进去就可以生成二维码了
注意:notify_url是扫码支付成功之后的回调地址,意识就是扫码支付之后调用的地址,这地址是由微信调用你写的这个地址(如有问题,可私信我)