微信支付(小程序微信支付)

微信开放平台(分享)

微信支付 - 中国领先的第三方支付平台 | 微信支付提供安全快捷的支付方式

微信公众平台(公众号,订阅号)

先区分以上三个微信官网概念:分别实现什么功能

小程序支付官方文档:微信支付-开发者文档

前期准备工作

1.注册小程序

2.注册微信支付账号(由于需要营业执照等信息,暂无法注册)

一,模块架构

分为两部分 1.小程序(公众号) 2.微信支付(中)

 二,关键概念

1.首先注册成为商户

2.小程序APPID 登录小程序-开发-开发管理-开发设置

3.商家的商户ID,就是注册的用户名

4.商家的API私钥,就是下面设置的秘钥

5.openid,这是很重要参数,下单需要。对接不同载体获取方式不同。

openid是微信用户在appid下的唯一用户标识(appid不同,则获取到的openid就不同),可用于永久标记一个用户。openid获取方式请参考以下文档小程序获取openid公众号获取openidAPP获取openid

且前提要有code,这个code是前端传入。

 三,接入准备

微信支付-开发者文档

 四,签约产品

即购买什么支付方法,二维码,还是JSAPI等

产品中心 - 微信支付商户平台

五,设置回调地址

支付完成之后,程序服务端接收微信支付成功的回调信息,之后进行其他业务逻辑处理,比如更新订单状态

 六,绑定微信支付与小程序

七,签名

类似token,调用接口传参。注意签名并不需要apiV3密钥,构建客户端需要。

微信支付-普通下单开发者文档

微信支付-开发者文档

八,构建客户端

GitHub - wechatpay-apiv3/wechatpay-apache-httpclient: 微信支付 APIv3 Apache HttpClient装饰器(decorator)

 重要概念:

/**
 * merchantId商户号。
 * merchantSerialNumber商户API证书的证书序列号。
 * merchantPrivateKey商户API私钥,如何加载商户API私钥请看常见问题。
 * wechatpayCertificates微信支付平台证书。你也可以使用后面章节提到的“自动更新证书功能”,而不需要关心平台证书的来龙去脉。
 * apiV3Key是String格式的API v3密钥 参考: https://kf.qq.com/faq/180830E36vyQ180830AZFZvu.html
 * <p>
 * 参考文档 开发指引:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_7_2.shtml
 */

客户端:

@Slf4j
public class WechatPayHttpClientUtil {

    /**
     * merchantId商户号。
     * merchantSerialNumber商户API证书的证书序列号。
     * merchantPrivateKey商户API私钥,如何加载商户API私钥请看常见问题。
     * wechatpayCertificates微信支付平台证书。你也可以使用后面章节提到的“自动更新证书功能”,而不需要关心平台证书的来龙去脉。
     * apiV3Key是String格式的API v3密钥 参考: https://kf.qq.com/faq/180830E36vyQ180830AZFZvu.html
     * <p>
     * 参考文档 开发指引:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_7_2.shtml
     */
    @Value("${wxpay.merchantId:merchantId}")
    private String merchantId;

    @Value("${wxpay.merchantSerialNumber:merchantSerialNumber}")
    private String merchantSerialNumber;

    @Value("${wxpay.merchantPrivateKey:merchantPrivateKey}")
    private String merchantPrivateKey;

    @Value("${wxpay.apiV3Key:apiV3Key}")
    private String apiV3Key;

    public HttpClient createHttpClient() {
	try {
	    // 加载商户私钥(privateKey:私钥字符串)
	    PrivateKey privateKey = PemUtil
			    .loadPrivateKey(new ByteArrayInputStream(merchantPrivateKey.getBytes("utf-8")));

	    // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
	    //https://github.com/wechatpay-apiv3/wechatpay-apache-httpclient 自动更新证书功能
	    AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
			    new WechatPay2Credentials(merchantId,
					    new PrivateKeySigner(merchantSerialNumber, privateKey)),
			    apiV3Key.getBytes("utf-8"));

	    return WechatPayHttpClientBuilder.create().withMerchant(merchantId, merchantSerialNumber, privateKey)
			    .withValidator(new WechatPay2Validator(verifier)).build();
	} catch (Exception e) {
	    log.error("createHttpClient exception ", e);

	}
	return null;
    }

    public String httpPost(String url, String param, Map<String, Object> headers) throws IOException {
	BufferedReader bufferedReader = null;
	try {
	    HttpPost httpPost = new HttpPost(url);
	    httpPost.setHeader("Content-Type", "application/json;charset=utf-8");
	    httpPost.addHeader("Accept", "application/json");
	    if (headers != null) {
		headers.keySet().forEach(key -> {
		    httpPost.setHeader(key, headers.get(key).toString());
		});
	    }
	    if (StringUtils.isNotBlank(param)) {
		HttpEntity httpEntity = new StringEntity(param, "utf-8");
		httpPost.setEntity(httpEntity);
	    }
	    HttpResponse httpResponse = createHttpClient().execute(httpPost);
	    if (httpResponse.getStatusLine().getStatusCode() != 200) {
		log.error("httpPost failed: url: {}, httpResponse: {}", url, JSON.toJSONString(httpResponse));
	    }
	    String output;
	    bufferedReader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(), "utf-8"));
	    StringBuilder stringBuilder = new StringBuilder();
	    while ((output = bufferedReader.readLine()) != null) {
		stringBuilder.append(output);
	    }
	    return stringBuilder.toString();
	} catch (IOException e) {
	    e.printStackTrace();
	    throw e;
	} finally {
	    if (bufferedReader != null)
		bufferedReader.close();
	}
    }

    public String httpPost2(String url, String body) {
	//	HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
	HttpPost httpPost = new HttpPost(url);
	httpPost.addHeader("Accept", "application/json");
	httpPost.addHeader("Content-type", "application/json; charset=utf-8");

	ByteArrayOutputStream bos = new ByteArrayOutputStream();
	ObjectMapper objectMapper = new ObjectMapper();
	ObjectNode rootNode = objectMapper.createObjectNode();
	rootNode.put("mchid", "1900009191").put("appid", "wxd678efh567hg6787").put("description", "Image形象店-深圳腾大-QQ公仔")
			.put("notify_url", "https://www.weixin.qq.com/wxpay/pay.php")
			.put("out_trade_no", "1217752501201407033233368018");
	rootNode.putObject("amount").put("total", 1);
	rootNode.putObject("payer").put("openid", "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o");

	String bodyAsString = null;
	try {
	    objectMapper.writeValue(bos, rootNode);
	    //	    httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
	    httpPost.setEntity(new StringEntity(body, "UTF-8"));
	    HttpResponse response = createHttpClient().execute(httpPost);
	    bodyAsString = EntityUtils.toString(response.getEntity());
	} catch (IOException e) {
	    e.printStackTrace();
	}
	return bodyAsString;
    }

}

签名:

public class TokenUtil {

    /**
     * merchantId商户号。
     * merchantSerialNumber商户API证书的证书序列号。
     * merchantPrivateKey商户API私钥,如何加载商户API私钥请看常见问题。
     * wechatpayCertificates微信支付平台证书。你也可以使用后面章节提到的“自动更新证书功能”,而不需要关心平台证书的来龙去脉。
     * apiV3Key是String格式的API v3密钥 参考: https://kf.qq.com/faq/180830E36vyQ180830AZFZvu.html
     * <p>
     * 参考文档 开发指引:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_7_2.shtml
     */
    @Value("${wxpay.merchantId:merchantId}")
    private String merchantId;

    @Value("${wxpay.merchantSerialNumber:merchantSerialNumber}")
    private String merchantSerialNumber;

    @Value("${wxpay.merchantPrivateKey:merchantPrivateKey}")
    private String merchantPrivateKey;

    @Value("${wxpay.apiV3Key:apiV3Key}")
    private String apiV3Key;

    /**
     * 签名生成
     * https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml
     *
     * @param method
     * @param url
     * @param body
     * @return
     */
    String getToken(String method, HttpUrl url, String body) {
	String nonceStr = "your nonce string";
	long timestamp = System.currentTimeMillis() / 1000;
	String message = buildMessage(method, url, timestamp, nonceStr, body);
	String signature = null;
	try {
	    signature = sign(message.getBytes("utf-8"));
	} catch (Exception e) {
	    e.printStackTrace();
	}

	return "mchid=\"" + merchantId + "\"," + "nonce_str=\"" + nonceStr + "\"," + "timestamp=\"" + timestamp + "\"," + "serial_no=\"" + merchantSerialNumber + "\"," + "signature=\"" + signature + "\"";
    }

    private String sign(byte[] message) throws SignatureException {
	Signature sign = null;
	try {
	    // 加载商户私钥(privateKey:私钥字符串)
	    PrivateKey privateKey = PemUtil
			    .loadPrivateKey(new ByteArrayInputStream(merchantPrivateKey.getBytes("utf-8")));

	    sign = Signature.getInstance("SHA256withRSA");
	    sign.initSign(privateKey);
	    sign.update(message);
	    return Base64.getEncoder().encodeToString(sign.sign());
	} catch (Exception e) {
	    e.printStackTrace();
	}
	return "";
    }

    private String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
	String canonicalUrl = url.encodedPath();
	if (url.encodedQuery() != null) {
	    canonicalUrl += "?" + url.encodedQuery();
	}
	return method + "\n" + canonicalUrl + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";
    }

    /**
     * 获取私钥。
     *
     * @param filename 私钥文件路径  (required)
     * @return 私钥对象
     */
    public static PrivateKey getPrivateKey(String filename) throws IOException {
	String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");
	try {
	    String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
			    .replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");

	    KeyFactory kf = KeyFactory.getInstance("RSA");
	    return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
	} catch (NoSuchAlgorithmException e) {
	    throw new RuntimeException("当前Java环境不支持RSA", e);
	} catch (InvalidKeySpecException e) {
	    throw new RuntimeException("无效的密钥格式");
	}
    }
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值