微信扫码开发,只要你在官网上对应它文档一步一步的来,你最终会找到突破口。此链接为微信官方提供的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是扫码支付成功之后的回调地址,意识就是扫码支付之后调用的地址,这地址是由微信调用你写的这个地址(如有问题,可私信我)