[Java]⽀付apiv3接⼊demo复制可⽤(jsapi⼩程序)
若⼲年前接过和⽀付宝,当时还是xml,接完以后当时就觉着的接⼝弄的烂的⼀批,,,。最近⼜有接⼊⽀付,相⽐之前好了⼀点吧,但是感觉还是弄的太散乱了。
以下内容仅为减少代码的重复劳动,并不提供接⼊流程、字段、配置说明,开始前请明确已经阅读过⽀付⽂档,了解接⼊流程,并获取了秘钥证书相关内容
包含的接⼝有,jsapi下单、⼩程序调起⽀付加签、回调数据处理、⽀付平台证书更新。功能包括数据加验签,加解密
代码中注意使⽤官⽅类库,以保证资⾦安全。当前为2021年8⽉,时间久远内容可能出现差异,注意识别
maven引⼊
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>0.2.2</version>
</dependency>
直接复制官⽅⽰例
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
pto.Cipher;
pto.NoSuchPaddingException;
pto.spec.GCMParameterSpec;
pto.spec.SecretKeySpec;
public class AesUtil {
static final int KEY_LENGTH_BYTE =32;
static final int TAG_LENGTH_BIT =128;
private final byte[] aesKey;
public AesUtil(byte[] key){
if(key.length != KEY_LENGTH_BYTE){
throw new IllegalArgumentException("⽆效的ApiV3Key,长度必须为32个字节");
}
this.aesKey = key;
}
public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException {
try {
Cipher cipher = Instance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData);
return new String(cipher.Decoder().decode(ciphertext)), "utf-8"); } catch (NoSuchAlgorithmException | NoSuchPaddingException e){
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e){
throw new IllegalArgumentException(e);
}
}
}
参数配置类
public class WeiXinProties {
@Getter
private static final String APP_ID ="⼩程序APPID";
@Getter
private static final String MERC_ID ="⽀付商户号";
@Getter
private static final String SECRET ="⼩程序安全码";
@Getter
private static final String SERIAL_NO ="⽀付证书编号";
@Getter
private static final String PRIVATE_KEY ="⽀付证书私钥,就是下载的apiclient_key.pem内容,去掉头尾换⾏";
@Getter
private static final String NOTIFY_URL ="⽀付结果回调地址";
@Getter
private static final String WEIXINPAY_URL ="h.weixin.qq/v3/pay/transactions/jsapi";//jsapi下单地址 @Getter
private static final String APIV3_KEY ="apiv3秘钥";
@Getter
private static final String API_KEY ="api秘钥,新版本v3接⼝好像没⽤";
@Getter
private static final String CERT_URL ="h.weixin.qq/v3/certificates";//平台证书地址
}
createOrder为jsapi预下单⽅法,传⼊单号、⾦额、openid
wxAppSign返回结果为⼩程序调起⽀付的数据
import com.alibaba.fastjson.JSONObject;
import com.ib.apache.httpclient.WechatPayHttpClientBuilder;
import com.ib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.ib.apache.httpclient.auth.PrivateKeySigner;
import com.ib.apache.httpclient.auth.WechatPay2Credentials;
import com.ib.apache.httpclient.auth.WechatPay2Validator;
import com.ib.apache.httpclient.util.PemUtil;
import org.apachemons.lang3.StringUtils;
import org.apache.hods.CloseableHttpResponse;
import org.apache.hods.HttpGet;
import org.apache.hods.HttpPost;
import org.apache.hods.HttpUriRequest;
import org.ity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import Certificate;
import X509Certificate;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class WeiXinPay {
private static String transaction ="TRANSACTION.SUCCESS";
private static String description ="充值";
private static String paySign ="%s\n%s\n%s\n%s\n";
private static String signType ="RSA";
private static String charSet ="UTF-8";
private static String contentType ="application/json";
private static String algorithm ="SHA256withRSA";
private static Map<String, X509Certificate> certSet = new HashMap<>();
private static Map<String, X509Certificate> certSet = new HashMap<>();
private static CloseableHttpClient httpClient;
private static PrivateKey merchantPrivateKey;
private static AesUtil aesUtil;
public WeiXinPay() throws IOException {
// 加载商户私钥(privateKey:私钥字符串)
merchantPrivateKey = PemUtil
.loadPrivateKey(new PRIVATE_KEY().getBytes(charSet)));
// 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
new MERC_ID(), new SERIAL_NO(), merchantPrivateKey)), APIV3_KEY().getBytes(charSet));
// 初始化httpClient
httpClient = ate()
.MERC_ID(), SERIAL_NO(), merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier)).build();
aesUtil = new APIV3_KEY().getBytes(charSet));
}
/**
* 预⽀付下单,jsapi
*
* @param orderId
* @param amt
* @param payerOpenId
* @return
* @throws Exception
*/
private String createOrder(String orderId, String amt, String payerOpenId) throws Exception {
//请求URL
HttpPost httpPost = new WEIXINPAY_URL());
//请求body参数
JSONObject reqdata = new JSONObject();
js获取json的key和valuereqdata.put("appid", APP_ID());
reqdata.put("mchid", MERC_ID());
reqdata.put("description", description);
reqdata.put("out_trade_no", orderId);
reqdata.put("notify_url", NOTIFY_URL());
JSONObject amount = new JSONObject();
//单位为分,传数字不能传字符串,需要对amt进⾏处理
amount.put("total", 1000);
amount.put("currency", "CNY");
reqdata.put("amount", amount);
JSONObject payer = new JSONObject();
payer.put("openid", payerOpenId);
reqdata.put("payer", payer);
StringEntity entity = new String());
entity.setContentType(contentType);
httpPost.setEntity(entity);
httpPost.setHeader("Accept", contentType);
return this.httpExecute(httpPost).getString("prepay_id");
}
private JSONObject httpExecute(HttpUriRequest uriRequest) throws Exception {
//完成签名并执⾏请求
CloseableHttpResponse response = ute(uriRequest);
try {
int statusCode = StatusLine().getStatusCode();
if(statusCode ==200){
return JSONObject.Entity()));
}else if(statusCode ==204){
throw new RuntimeException("⽀付状态204");
}else{
try {
throw new RuntimeException(JSONObject.Entity())).getString("message"));
} catch (Exception e){
throw new RuntimeException(StringUtils.join("⽀付状态", statusCode));
}
}
} finally {
response.close();
}
}
/**
* ⼩程序调起⽀付数据组织签名
*
* @param orderId
* @param amt
* @param payerOpenId
* @return
*/
public JSONObject wxAppSign(String orderId, String amt, String payerOpenId){
try {
JSONObject data = new JSONObject();
String orderPkg = ateOrder(orderId, amt, payerOpenId);
String appId = APP_ID();
String timeSmp = String.valueOf(System.currentTimeMillis());
String uuid = UUID.randomUUID().toString().replace("-", "");
String pkgInfo = StringUtils.join("prepay_id=", orderPkg);
data.put("appId", appId);
data.put("timeStamp", timeSmp);
data.put("nonceStr", uuid);
data.put("package", pkgInfo);
data.put("signType", signType);
data.put("paySign", this.sign(String.format(paySign, appId, timeSmp, uuid, pkgInfo), merchantPrivateKey));
return data;
} catch (Exception e){
throw new Message());
}
}
/**
* 私钥签名
*
* @param plainText
* @param privateKey
* @return
* @throws Exception
*/
private String sign(String plainText, PrivateKey privateKey) throws Exception {
Signature privateSignature = Instance(algorithm);
privateSignature.initSign(privateKey);
privateSignature.Bytes(charSet));
byte[] signature = privateSignature.sign();
Encoder().encodeToString(signature);
}
/**
* 验签
*
* @param serialNo
* @param verStr
* @param signStr
* @throws Exception
*/
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论